Не все китайские вертолеты одинаково полезны. Разбор протокола передачи данных от ir пульта.

GodVin
Offline
Зарегистрирован: 17.11.2021

Использование ИК пульта от мини вертолета

Как говорится Доброго времени суток.

Был у меня когда-то мини вертолет  название не вспомню вид приблизительно такой

Он благополучно сломался а пульт управления остался. Спустя время я решил сделать ардуино машинку управляемую с пульта. Долго размышлял ка прицепить дуалшок от ps3 но там заморочки с протоколом. Нестандартный протокол и описание его я не смог найти. И по этому выбор пал на IR пульт от вертолета. Найдя единственную статью размноженную десятки раз с описанием протокола связи сел за паяльник и начал ваять. Но не тут то было оказалось что не все китайские вертолеты «одинаково полезны». Протокол описанный в статье https://habr.com/ru/post/189248/ не подошел к моему пульту.

С этого и начались мои исследования.

Во первых в отличии от пульта описанного в выше упомянутой сатье  цитата « кодируются длительностью паузы между сигналами: логический ноль — это 600 микросекунд, логическая единица — 1200 микросекунд.»

В моем пульте кодировка идет не только паузами между сигналами но и длительностью сигнала.

Помог маленький китайский осциллограф. Данные идут с промежутком в ~18000мс

Первый стартовый сигнал в районе 3000мс. потом пакет данных 32 сигнала и 32 промежутка между сигналами итого 64 бита но используются не все. Логический ноль до 700 мс. логическая единица до 1300 мс.  значения приблизительные разбег бывает в пару сотен мс. (погрешность измерений).

Подключил к ардуино уно ir приемник написал небольшую программу для передачи данных в  порт на компьютер. не судите строго программа писалось методом проб и ошибок.

01#define IN_PIN 2        // входной пин
02 
03 
04uint32_t us[4],com[2];// us масив с зашифрованным сигналом. 0 и 1 значение временные в которых записываются комманды в процессе получения
05//us[2и3] записываются во время паузы между командами иначе команды будут прииходить частично измененные так как частота сигнала меньше частоты процессора
06int tim_pause = 5000;// минимальная задержка между командами если пауза дольше этого значения счетчики обнуляются и ждем новой команды
07 
08uint32_t prevUs;//переменная для хранения времени предыдущего срабатывания
09int count = 0;//счетчик сигналов
10bool  first, prevS, flag = 0;
11byte  bit1, bit2 ;
12void setup() {
13  Serial.begin(115200);
14  delay(100);
15 
16  pinMode(IN_PIN, INPUT_PULLUP);
17 
18  attachInterrupt(0, preriv, CHANGE);//инициалилируем прерывание на изменение состояние пина 2
19}
20 
21void loop(){
22  if ( (us[2]!=com[0])||(us[3]!=com[1])){// для того чтоб в мониторе порта не выводились повторные значения завел еще 2 переменных для контроля изменений
23   com[0]=us[2];
24   com[1]=us[3];
25   for (int j=31; j>=0; j--) {//выводим их со страршего бита
26    Serial.print(bitRead(us[2], j));//если старшие биты равны нулю то при обычном выводе они не покажутся для этого делаем цикл с условием если бит раве1 то выводит 1 если нулю
27//  Serial.print(";"); //выводим между значениями ; для того чтоб при открытии екселем разделять значения в разные колонки.
28     
29    
30   }
31   //Serial.print(us[2], BIN);// способ не работает пропускает старшие нули
32   Serial.print(" ");//промежуток между переменными легче ориентироваться.
33   for (int i=31; i>=0; i--) { //здесь все тоже самое
34     Serial.print(bitRead(us[3], i));
35   //Serial.print(";");
36   //Serial.println(us[3], BIN);
37   
38  }
39   Serial.println();
40}
41}
42 
43void comand() {
44   
45   
46}
47void preriv() {
48  // читаем время
49  uint32_t now = micros();
50  
51  if ((now - prevUs)>tim_pause) {//если время с последнего срабатывания превышает tim_pause обнуляем счетчики
52      us[2]=us[0];//записываем временные переменные в постоянное место переменная полностью изменилась
53      us[3]=us[1];
54      flag=0;
55      count=0;
56      bit1=0;
57      bit2=0;
58  }
59    if (!flag) {      // триггер (первое срабатывание)
60      flag = 1;       // запомнили
61      prevUs = now;   // время первого
62    } else {                      // измеряем следующие
63       if (count>0) { //пропускаем второе срабатывание так как это был стартовый сигнал
64          if (count<33){//так как максимальная (стабильно работающая)переменная uint32_t содержит 32 бита а у нас их 64 делим данные на 2 переменных
65            bitWrite(us[0] ,(31-bit1), ((now - prevUs)>800)) ;//если время предыдущего срабатывания минус текущее время больше 800 мс записываем 1 иначе 0 в соответствующий бит
66            bit1++;//добавляем в счетчик битов 1
67          }else {
68            if (count<64){ //проделываем тоже самое для второй переменной
69              bitWrite(us[1] ,(31-bit2), ((now - prevUs)>800));
70              bit2++;
71            }
72          }
73       }
74      prevUs = now;               // запомнили время
75      count++;
76    }
77}

скетч с подробными коментариями: 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 не знаю возможно дефект потенциометра в пульте. 

также передаются контрольные суммы и еще какие-то данные которые мне не удалось расшивровать.

Как я "приделал" этот пульт к своим самоделкам смотрите в следующей части.

 

 

 

 

 

 

 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

GodVin пишет:

коментариями

когото

акселиратор

номирация

в лево ...в право ...в лево   ...в право

акселиратор

я указал только систематические ошибки, явные опечатки пропустил. Запятые, которые сэкономлены, явно проданы на привозе! ;))

Код я конечно не стал читать. Кровь из глаз мешает. ;))

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Тоже "мёртвую петлю" делал?

b707
Offline
Зарегистрирован: 26.05.2017

wdrakula пишет:

я указал только систематические ошибки, явные опечатки пропустил. Запятые, которые сэкономлены, явно проданы на привозе! ;))

запятые ладно... а вот то, что ТС, описывая таймслоты протокола(то есть то, в чем собственно самая соль его сообщения), систематически путает МИКРОсекунды и МИЛЛИсекунды  - никуда не годится.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Да ладно, разберёмся мы с этими микросекундами

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

Код я конечно не стал читать. Кровь из глаз мешает. ;))

Немного потерял.

Это один из многочисленных кодов, которые вроде и работают, но иногда (причём, нерегулярно, а время от времени, без видимых причин) глючат. Понятное дело, что в самом-то коде всё правильно, просто плата китайская :-(

GodVin
Offline
Зарегистрирован: 17.11.2021

Понял, принял. Следующую статью буду писать академическим слогом.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

 Понятное дело, что в самом-то коде всё правильно, просто плата китайская :-(

вот вот обидно, что иногда такой код используют в своих библиотеках и, более 20 таких нашёл

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

GodVin пишет:

 Следующую статью буду писать академическим слогом.

может не надо? а то..."академическим виделся текст, а на поверку про..." )))

PS я не настоящий сталевар ежели что, просто сегодня пятница, здесь по пятницам так принято, сломать не смог решил возглавить )))