Не все китайские вертолеты одинаково полезны. Разбор протокола передачи данных от 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 я не настоящий сталевар ежели что, просто сегодня пятница, здесь по пятницам так принято, сломать не смог решил возглавить )))