Не все китайские вертолеты одинаково полезны. Разбор протокола передачи данных от ir пульта.
- Войдите на сайт для отправки комментариев
Использование ИК пульта от мини вертолета
Как говорится Доброго времени суток.
Был у меня когда-то мини вертолет название не вспомню вид приблизительно такой
Он благополучно сломался а пульт управления остался. Спустя время я решил сделать ардуино машинку управляемую с пульта. Долго размышлял ка прицепить дуалшок от ps3 но там заморочки с протоколом. Нестандартный протокол и описание его я не смог найти. И по этому выбор пал на IR пульт от вертолета. Найдя единственную статью размноженную десятки раз с описанием протокола связи сел за паяльник и начал ваять. Но не тут то было оказалось что не все китайские вертолеты «одинаково полезны». Протокол описанный в статье https://habr.com/ru/post/189248/ не подошел к моему пульту.
С этого и начались мои исследования.
Во первых в отличии от пульта описанного в выше упомянутой сатье цитата « кодируются длительностью паузы между сигналами: логический ноль — это 600 микросекунд, логическая единица — 1200 микросекунд.»
В моем пульте кодировка идет не только паузами между сигналами но и длительностью сигнала.
Помог маленький китайский осциллограф. Данные идут с промежутком в ~18000мс
Первый стартовый сигнал в районе 3000мс. потом пакет данных 32 сигнала и 32 промежутка между сигналами итого 64 бита но используются не все. Логический ноль до 700 мс. логическая единица до 1300 мс. значения приблизительные разбег бывает в пару сотен мс. (погрешность измерений).
Подключил к ардуино уно ir приемник написал небольшую программу для передачи данных в порт на компьютер. не судите строго программа писалось методом проб и ошибок.
#define IN_PIN 2 // входной пин uint32_t us[4],com[2];// us масив с зашифрованным сигналом. 0 и 1 значение временные в которых записываются комманды в процессе получения //us[2и3] записываются во время паузы между командами иначе команды будут прииходить частично измененные так как частота сигнала меньше частоты процессора int tim_pause = 5000;// минимальная задержка между командами если пауза дольше этого значения счетчики обнуляются и ждем новой команды uint32_t prevUs;//переменная для хранения времени предыдущего срабатывания int count = 0;//счетчик сигналов bool first, prevS, flag = 0; byte bit1, bit2 ; void setup() { Serial.begin(115200); delay(100); pinMode(IN_PIN, INPUT_PULLUP); attachInterrupt(0, preriv, CHANGE);//инициалилируем прерывание на изменение состояние пина 2 } void loop(){ if ( (us[2]!=com[0])||(us[3]!=com[1])){// для того чтоб в мониторе порта не выводились повторные значения завел еще 2 переменных для контроля изменений com[0]=us[2]; com[1]=us[3]; for (int j=31; j>=0; j--) {//выводим их со страршего бита Serial.print(bitRead(us[2], j));//если старшие биты равны нулю то при обычном выводе они не покажутся для этого делаем цикл с условием если бит раве1 то выводит 1 если нулю // Serial.print(";"); //выводим между значениями ; для того чтоб при открытии екселем разделять значения в разные колонки. } //Serial.print(us[2], BIN);// способ не работает пропускает старшие нули Serial.print(" ");//промежуток между переменными легче ориентироваться. for (int i=31; i>=0; i--) { //здесь все тоже самое Serial.print(bitRead(us[3], i)); //Serial.print(";"); //Serial.println(us[3], BIN); } Serial.println(); } } void comand() { } void preriv() { // читаем время uint32_t now = micros(); if ((now - prevUs)>tim_pause) {//если время с последнего срабатывания превышает tim_pause обнуляем счетчики us[2]=us[0];//записываем временные переменные в постоянное место переменная полностью изменилась us[3]=us[1]; flag=0; count=0; bit1=0; bit2=0; } if (!flag) { // триггер (первое срабатывание) flag = 1; // запомнили prevUs = now; // время первого } else { // измеряем следующие if (count>0) { //пропускаем второе срабатывание так как это был стартовый сигнал if (count<33){//так как максимальная (стабильно работающая)переменная uint32_t содержит 32 бита а у нас их 64 делим данные на 2 переменных bitWrite(us[0] ,(31-bit1), ((now - prevUs)>800)) ;//если время предыдущего срабатывания минус текущее время больше 800 мс записываем 1 иначе 0 в соответствующий бит bit1++;//добавляем в счетчик битов 1 }else { if (count<64){ //проделываем тоже самое для второй переменной bitWrite(us[1] ,(31-bit2), ((now - prevUs)>800)); bit2++; } } } prevUs = now; // запомнили время count++; } }
скетч с подробными коментариями: https://github.com/GodVine/ir_verto
Данные из порта перекинул в таблицы мукрасофта. если когото интересует исходник таблицы вот он https://disk.yandex.ru/i/rE-yVP3jagg8ug . В итоге получилось такая картина:
с 63 по 57 биты это акселиратор скорость вращения несущих винтов (номирация идет с младшего бита и с нуля как все в ардуино)
с 54 по 51 биты это в лево в право 50 бит направление 0 в лево 1 в право
56 и 47 биты ререключение режимов(или устройств)
с 45 по 43 калибровка вращения главных винтов 42 бит направление калибровки
с 28 по 25 вперед назад 24 бит направление 0 назад 1 вперед
теперь осталось взять эти биты (например с 63 по 57) и перевезти его в отдельную переменную акселиратор изменяестя от 12 до 100 почему не с 1 не знаю возможно дефект потенциометра в пульте.
также передаются контрольные суммы и еще какие-то данные которые мне не удалось расшивровать.
Как я "приделал" этот пульт к своим самоделкам смотрите в следующей части.
коментариями
когото
акселиратор
номирация
в лево ...в право ...в лево ...в право
акселиратор
я указал только систематические ошибки, явные опечатки пропустил. Запятые, которые сэкономлены, явно проданы на привозе! ;))
Код я конечно не стал читать. Кровь из глаз мешает. ;))
Тоже "мёртвую петлю" делал?
я указал только систематические ошибки, явные опечатки пропустил. Запятые, которые сэкономлены, явно проданы на привозе! ;))
запятые ладно... а вот то, что ТС, описывая таймслоты протокола(то есть то, в чем собственно самая соль его сообщения), систематически путает МИКРОсекунды и МИЛЛИсекунды - никуда не годится.
Да ладно, разберёмся мы с этими микросекундами
Код я конечно не стал читать. Кровь из глаз мешает. ;))
Немного потерял.
Это один из многочисленных кодов, которые вроде и работают, но иногда (причём, нерегулярно, а время от времени, без видимых причин) глючат. Понятное дело, что в самом-то коде всё правильно, просто плата китайская :-(
Понял, принял. Следующую статью буду писать академическим слогом.
Понятное дело, что в самом-то коде всё правильно, просто плата китайская :-(
вот вот обидно, что иногда такой код используют в своих библиотеках и, более 20 таких нашёл
Следующую статью буду писать академическим слогом.
может не надо? а то..."академическим виделся текст, а на поверку про..." )))
PS я не настоящий сталевар ежели что, просто сегодня пятница, здесь по пятницам так принято, сломать не смог решил возглавить )))