Чтение нескольких каналов PWM от приёмника RC
- Войдите на сайт для отправки комментариев
Добрый день! Хочу попросить помощи у профи. Поправить скетч (если надо) и объяснить некоторые моменты.
Имея весьма примитивное представление о программировании Ардуины, я имел наглость попытаться решить не самую простую задачу. Для управления авиамоделью мне понадобилось преобразование 5 выходных каналов приёмника, с последующей раздачей на 4 сервы. Выходы приёмника - сигнал PWM с частотой 50 Гц. Длина плюсового управляющего импульса 1000 - 2000 мкс.
Главная задача в этой затее - максимально быстро и точно считать выходные сигналы.
Начал я с написания скетча на Pulsein. Он конечно заработал, но столь криво и медленно, что быстро пришло понимание - задачу можно решить только запуском таймеров на прерываниях. Почитал как это сделать для большего чем 2 каналов. Классика - библиотека PinChangeInt.h, альтернатива - библиотека Enableinterrupt.h. Автор и той и другой библиотеки рекомендует второй вариант, а PinChangeInt считает устаревшим.
После тщетных попыток врубиться в суть этих библиотеки, я нашёл готовый шаблон с библиотекой Enableinterrupt для чтения 6 каналов PWM и в меру своего понимания попытался приспособить его под свою задачу. Некоторый прогрес есть - ИДЕ перестала ругаться на мой опус и говорит, что всё ок. Но отдельных местах у меня сомнения.
Скетч для чтения каналов я взял отсюда: http://forum.arduino.cc/index.php?topic=420662.0 Третий по порядку код, пользователя Isaac96.
#include <EnableInterrupt.h> #define RX_PIN_THROTTLE 2 //input pins #define RX_PIN_ROLL 3 #define RX_PIN_PITCH 4 #define RX_PIN_YAW 5 #define RX_PIN_AUX1 6 #define RX_PIN_AUX2 7 PROGMEM const byte rxPins[6]={//makes the pinmode easier RX_PIN_YAW,RX_PIN_ROLL,RX_PIN_PITCH,RX_PIN_AUX1,RX_PIN_AUX2,RX_PIN_THROTTLE}; volatile byte rxState[4]={ 0,0,0,0}; volatile int rxPrev[6]={ 0,0,0,0,0,0}; void rxInit(){ for(byte i=0;i<6;i++){ pinMode(pgm_read_byte(&rxPins[i]),INPUT); digitalWrite(pgm_read_byte(&rxPins[i]),HIGH); } enableInterrupt(RX_PIN_THROTTLE,rxGoesHigh1,RISING); enableInterrupt(RX_PIN_ROLL,rxGoesHigh2,RISING); enableInterrupt(RX_PIN_PITCH,rxGoesHigh3,RISING); enableInterrupt(RX_PIN_YAW,rxGoesHigh4,RISING); enableInterrupt(RX_PIN_AUX1,rxGoesHigh5,RISING); enableInterrupt(RX_PIN_AUX2,rxGoesHigh6,RISING); } void rxGoesHigh1(){ enableInterrupt(RX_PIN_THRoTTLE,rxGoesLow1,FALLING); rxPrev[0]=micros(); } void rxGoesLow1(){ enableInterrupt(RX_PIN_THROTTLE,rxGoesHigh1,RISING); rxVal[0]=micros()-rxPrev[0]; } void rxGoesHigh2(){ enableInterrupt(RX_PIN_ROLL,rxGoesLow2,FALLING); rxPrev[1]=micros(); } void rxGoesLow2(){ enableInterrupt(RX_PIN_ROLL,rxGoesHigh2,RISING); rxVal[1]=micros()-rxPrev[1]; } void rxGoesHigh3(){ enableInterrupt(RX_PIN_PITCH,rxGoesLow3,FALLING); rxPrev[2]=micros(); } void rxGoesLow3(){ enableInterrupt(RX_PIN_PITCH,rxGoesHigh3,RISING); rxVal[2]=micros()-rxPrev[2]; } void rxGoesHigh4(){ enableInterrupt(RX_PIN_YAW,rxGoesLow4,FALLING); rxPrev[3]=micros(); } void rxGoesLow4(){ enableInterrupt(RX_PIN_YAW,rxGoesHigh4,RISING); rxVal[3]=micros()-rxPrev[3]; } void rxGoesHigh5(){ enableInterrupt(RX_PIN_AUX1,rxGoesLow5,FALLING); rxPrev[4]=micros(); } void rxGoesLow5(){ enableInterrupt(RX_PIN_AUX1,rxGoesHigh5,RISING); rxVal[4]=micros()-rxPrev[4]; } void rxGoesHigh6(){ enableInterrupt(RX_PIN_AUX2,rxGoesLow6,FALLING); rxPrev[5]=micros(); } void rxGoesLow6(){ enableInterrupt(RX_PIN_AUX2,rxGoesHigh6,RISING); rxVal[5]=micros()-rxPrev[5]; }
Этот код - шаблон, там нет основного цикла и настроек. Если их добавить, хоть с пустыми скобками, то ИДЕ начинает искать ошибки. Первая грамматическая, название переменной. Вторая - не назначены переменные rxVal[0-5], а вот тут я в сомнениях. Автор написал странную фразу: "The values are storeed in rxVal[0-5] in order TAER12" Что есть последовательностьTAER12, я тнигде на нашёл. Наверное, жаргон. В своём скетче я тупо пронумеровал эти переменные от нуля до 4-х (у меня на один канал меньше).
Второе что я правил без малейшего понимания, это последовательность назначения пинов в строках:
PROGMEM const byte rxPins[6]={//makes the pinmode easier RX_PIN_YAW,RX_PIN_ROLL,RX_PIN_PITCH,RX_PIN_AUX1,RX_PIN_AUX2,RX_PIN_THROTTLE};
Последовательность довольно странная и отличается от последовательности задания имён константам. Почему так? Это важно?
В итоге, скетч я написал такой:
Автор написал странную фразу: "The values are storeed in rxVal[0-5] in order TAER12" Что есть последовательностьTAER12, я тнигде на нашёл. Наверное, жаргон.
Это не жаргон, а обозначение каналов, в данном случае их 6шт(0-5) а ТАЕR12 это последовательность их расшивровки - THR, AIL, ELEV, RUDD, AUX1, AUX2 - газ, элерон, елеватор(РВ), руддер(РН) и два канала управления(режимы или доп каналы).
Можно вопрос- к чему этот проэкт, что будет управлятся? Может взять уже куски готового кода, правда это универсальная платформа автопилота, но там все это есть, можно надергать кусков, которые надо.
https://github.com/multiwii/multiwii-firmware
Можно вопрос- к чему этот проэкт, что будет управлятся? Может взять уже куски готового кода, правда это универсальная платформа автопилота, но там все это есть, можно надергать кусков, которые надо.
https://github.com/multiwii/multiwii-firmware
Потрясающе! Не допёр :) (это про ТАЕR12!)
Проект довольно завиральный. Эдакий "недоконвертоплан" : http://forum.rcdesign.ru/f90/thread483403.html
За пару дней я немерянно продвинулся, но цели пока не достиг. В примере с которого я много слизал есть явные ошибки, такие как переменные нигде не используемые. В итоге, состряпал нечто похожее. Последняя версия скетча в конце. Он работает, но крайне ненадёжно. С одним каналом - чисто шоколад. Но даже два канала одновременно приводят к быстрому сбою. Сериал начинает печатать 4-х значные числа. Что интересно: эти непонятные цифири зависят от входных сигналов, т.е. меняются при шевелении стиками.
Чтобы надёргать из готового, придётся его прочитать и понять. Не мой уровень, увы. Да и надо-то всего-навсего прочитать каналы.
Вы наверное скажете, что уж этого добра в готовом виде - завались. Увы, это не так. Я надёргал под десяток готовых кодолв для чиения нескольких каналов PWM, и ни один из них не работает! Что особенно убийственно, даже с официального сайта arduino.cc. Их вариант по ссылке: http://playground.arduino.cc/Code/ReadReceiver У меня их код даёт ошибку "error: within this context". Вот и догадайся, в котексте чего там должно быть :)
Илья МГУ, у вас сама идеология захвата шим не позволит работать без глюков. Нужно каждому входящему сигналу отдельное физическое прерывание, и таковых есть аж 6 в меге328. Два INT, три групповых PCINT и одно прерывание компаратора. Поскольку самостоятельно вы бы не написали вот вам шапка, в прерывания вставляете захват микросов, или что там вам нужно:
вот вам шапка, в прерывания вставляете захват микросов, или что там вам нужно:
Спасибо огромное!
Ещё вопрос, по обработчику прерываний. Похоже классика выглядит так:
Не зря ли я повёлся на сомнительную альтернативу, в виде двух функций и двух прерываний на каждый канал? Или, этот метод тоже работоспособен?
Илья МГУ, не знаю откуда вы выдрали этот кусок. Судя по всему он считает длительность в тактах таймера1. Я не считаю нужным привлекать к счёту времени таймер1, т.к. это потянет за собой новые проблемы.
Илья МГУ, не знаю откуда вы выдрали этот кусок.
Кусок отсюда: http://rcarduino.blogspot.ru/2012/11/how-to-read-rc-channels-rcarduinofastlib.html
Называется "Updated ISR" Чуть выше ещё один вариант.
Произошло невероятное. Мой скетч из поста №2 работает. Причём, работает отлично! Без сбоев и глюков. Проблема была в другом, а именно в характере принимаемых PWM сигналов. Об этом тут:
http://arduino.ru/forum/apparatnye-voprosy/vopros-po-signalam-pwm-dlya-servomashinok-arduino-biblioteka-servo#comment-271502
Илья МГУ, я вам об этом в #3 и писал, -одновременно все каналы тот вариант не может обслужить по принципиальным причинам. Вы читаете, или я пишу в пустоту?
Читаю, не сомневайтесь. На мысль об одновременности каналов автопилота навёл именно удачный опыт с приёмником и кодом из поста №2. Теперь понятно, что он работает только со сдвинутыми по времени импульсами. А мне надо считывать импульсы, которые накладываются друг на друга.
Ваш вариант позволит считать импульсы одновременно? Я не очень понимаю, как в этом случае огранизовать прерывания для считывания импульсов. Они ведь тоже должны осуществляться одновременно? Кая я всегда считал, Ардуино всё выполняет последовательно. Это не так?
Я не очень понимаю, как в этом случае огранизовать прерывания для считывания импульсов. Они ведь тоже должны осуществляться одновременно? Кая я всегда считал, Ардуино всё выполняет последовательно. Это не так?
Всё уже организовано, поднимите очи вверх. Вам осталось лишь собрать данные внутри прерываний. Ардуина обрабатывает последовательно, но в вашем коде, в случае прихода двух и более сигналов гарантированно обрабатывается только первый, а в моём все, но вектора прерываний выполнятся по-очереди.
dimax, в Вашем коде мне были знакомы отдельные слова типа void loop :) Сам бы ни в жисть не разобрался. Помог программист из ближайшего окружения. Получился такой код:
Гляньте (если не лень), всё ли правильно понято.
Эта конструкция очень не устойчивая. Если прерывание срабатывает на фронт, то надо вводить небольшую задержку несколько микросекунд с помощью цикла FOR, иначе будут ложные срабатывания при дребезге на фронте/спаде.
Спасибо!
Но откуда дребезг? К пинам подключаются цифровые выходы с автопилота. Никаких кнопок.