26 февраля 2017

Самодельный беспроводной USB-адаптер для симулятора повышенной точности

Расскажу о том, как я сделал свой беспроводной USB-адаптер повышенной точности для симулятора. USB-адаптер был опробован в Heli-X, FPVFreeRider и LiftOff и показал прекрасный результат, оправдал все мои ожидания!


Перепробовав несколько вариантов USB-адаптеров для симулятора, стал искать возможность сделать такой самостоятельно. Ни один из продаваемых USB-адаптеров меня не устраивал по причине малой точности. То есть, на полный ход стика приходилось очень малое количество шагов. Например в последнем от OrangeRX было всего 168 шагов. Это самое большое, что я видел, и этого ужасно мало для нормального управления моделью в симуляторе.

Наткнулся в интернете на интересный проект самодельного USB-адаптера на базе маленькой платки Arduino Leonardo. Взял его за основу и немного переделал под себя. Во первых, отказался от прямой модификации файлов дистрибутива Arduino, использовав внешнюю библиотеку для работы с джойстиком. Во вторых, исключил деление исходных данных пополам. Это позволило более точно учитывать длину PPM-импульса. В третьих, сделал возможность задавать мертвую зону, чтобы исключить дребезг значений в около-нулевой зоне стика. Ну и конечно же, припаял к USB-адаптеру маленький приемник FrSky на 8 каналов с CPPM-выходом для беспроводного управления.


USB-адаптер может подключаться к тренерскому разъему вашего передатчика. Сигнальный провод надо подключить к четвертому выводу USB-адаптера.


Чтобы сделать USB-адаптер беспроводным, потребуется приемник с CPPM-выходом, подходящий для вашего передатчика. Вот небольшой список для примера: FrSky 8СHDEVO 8CH, FlySky 8CH, RadioLink 10CH, DSMX 6CH. Есть и другие варианты, можно выбрать любой с CPPM-выходом. Схема соединения предельно проста. На приемник нужно подать питание 5 вольт и подсоединить выход приемника к четвертому выводу USB-адаптера.


После монтажа можно подключить USB-адаптер к компьютеру и выполнить привязку приемника к передатчику. Не буду подробно останавливаться на этом моменте, у каждого данная процедура проходит по своему, в зависимости от модели передатчика и приемника. Я подключил USB-адаптер к передатчику DEVO10 с прошивкой Deviation и установленным модулем 4-в-1. Конфигурация модели очень простая.

Подключаем USB-адаптер к компьютеру и приступаем к программированию. Я подробно расскажу, как сделать USB-адаптер максимально настроенным для каждого индивидуального случая. Сложного тут ничего нет, разберется даже школьник:)

Перед началом работы нужно скачать и установить среду разработки Arduino IDE. Лучше скачать архив и распаковать его в отдельный каталог. Там есть выбор под все современные системы. Распаковать можно в любое удобное место. Затем запускаем исполняемый файл и попадаем в среду Arduino. Выбираем в меню "Инструменты" плату "Arduino Leonardo" и чуть ниже выбираем виртуальный COM-порт, к которому подключена плата.


Закрываем среду разработки. Надо установить дополнительную библиотеку для работы с джойстиком. Идем по ссылке, скачиваем, распаковываем и выполняем файл deploy.sh или deploy.bat в зависимости от операционной системы. По итогу, библиотека должна оказаться внутри каталога Arduino, который будет расположен в вашем домашнем каталоге, а не в том, куда распаковали среду разработки.


Если у вас Windows и самодельный USB-адаптер планируется использовать в симуляторе FPVFreeRider или любом другом, основанном на библиотеке Unity3D (а их большинство), то надо изменить одну строчку в файле установленной библиотеки для работы с джойстиком.


Открываем файл Joystick.cpp внутри каталога ...\Arduino\libraries\Joystick\src, находим строчку:

#define JOYSTICK_AXIS_MINIMUM -32767

и заменяем ее на:

#define JOYSTICK_AXIS_MINIMUM 0

Дело в том, что FPVFreeRider в Windows получает данные с джойстика в обход системы и никакая системная калибровка джойстика не нужна. Но тут есть маленький подвох. Симулятор FPVFreeRider понимает значения с осей джойстика в диапазоне от 0 до 32767, а системный джойстик может работать в диапазоне -32767 до 32767. Поэтому, если ваш джойстик может выдавать отрицательные значения, то у вас будут проблемы с его калибровкой в FPVFreeRider. Это касается только Windows, в других системах такой проблемы нет и ничего менять не надо.

Скачиваем код скетча, открываем его в среде Arduino и сразу же загружаем в USB-адаптер кнопкой "Загрузка". Все должно пройти без проблем и ошибок.


В общем, USB-адаптер уже может работать, но пока что не настроен. Надо определить максимальное, минимальное и центральное значения PPM-импульса, поступающего на вход адаптера с приемника или тренерского разъема. В передатчике все каналы должны быть выставлены +/-100% и убраны все триммеры в ноль. В Ubuntu значения можно получить, выполнив в консоли простую команду:

# cat /dev/ttyACM0

Для Windows придется установить бесплатную программу TeraTerm. Распаковываем и запускаем ttermpro.exe. Создаем новое соединение, выбираем виртуальный COM-порт, подтверждаем и видим на экране шесть колонок цифр. Это данные шести каналов, которые получает USB-адаптер со своего входа.


Шевелим стиками и смотрим на цифры. Надо определить и записать минимальное, максимальное и значение в центральном положении стика. Значения могут немного плыть на 1-4 единицы. Для минимального надо выбрать максимально минимальное. Для максимального минимально максимальное, для среднего - среднее. Например, у меня минимальное значение гуляет в диапазоне 2210-2214, значит беру 2214. Максимальное гуляет 3810-3812, беру 3810. Среднее гуляет 3011-3013, беру 3012.

Если все получилось, то в программе можно отключить вывод данных, поставив комментарий на следующую строку. Было:

#define SERIALOUT

Стало:

// #define SERIALOUT

Подставляем полученные значения в переменные ниже.

#define MIN_PULSE_WIDTH    2214 // Minimal pulse
#define CENTER_PULSE_WIDTH 3012 // Middle pulse
#define MAX_PULSE_WIDTH    3810 // Maximal pulse

Если у вас Windows, то меняем значение переменной USB_STICK_MIN на ноль. Для других операционных систем оставляем как есть.

#define USB_STICK_MIN 0

Заливаем скетч в USB-адаптер и проверяем его работу. В Ubuntu это можно сделать в программе jstest-gtk. Если она не установлена, то ставим:

# sudo apt-get install jstest-gtk

В самой программе заходим в калибровку и сбрасываем значения кнопкой Raw Events.


Значения должны изменяться от -32767 до 32765. В около-нулевой зоне стика будет небольшой дребезг. Надо добиться того, чтобы эти значения гуляли как в положительную зону, так и в отрицательную. Придется подкорректировать переменные MIN_PULSE_WIDTH, CENTER_PULSE_WIDTH и MAX_PULSE_WIDTH несколько раз, чтобы добиться нужного результата. При этом не должно быть холостого хода стика в крайних положениях. Калибровку выполнять не надо, а еще лучше сохранить обнуленные значения командой:

# sudo jscal-store /dev/input/js0

В Windows проверку диапазона работы USB-адаптера можно выполнить с помощью программы Joystick Tester. Значения по осям должны изменяться от 32767 до 65535, а центр должен быть на значении 49150. Как я уже говорил, это сделано для того, чтобы FPVFreeRider смог нормально работать с USB-адаптером.


На этом этапе уже можно считать настройку USB-адаптера завершенной и проверять его работу в различных симуляторах. Но можно пойти дальше, если есть желание:)

Переменная CENTER_PULSE_JITTER убирает дребезг в около-нулевой зоне стика. При нулевом значении фильтр не работает. Если не нравится наличие небольшого дребезга, то можно поставить значение от 5 до 10. Большие значения лучше не ставить, иначе потеряется чувствительность в около-нулевой зоне.

Переменная RC_CHANNELS_COUNT отвечает за количество входящих каналов. У меня с приемника идет восемь каналов, поэтому весь скетч сформирован именно под это число. Это можно изменить, но придется еще глубже залезать в дебри кода.

Следующая строка формирует собственно джойстик с заданными параметрами:

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 2, 0, true, true, true, true, true, true, false, false, false, false, false);

Третий параметр, там где стоит цифра 2, задает количество кнопок джойстика. Начиная с пятого параметра идет определение наличия осей. Шесть раз подряд true - это шесть осей USB-адаптера. Потом идет false - запрет оси. Всего можно задать 11 осей. Например, для USB-адаптера без кнопок и с четырьмя осями будет вот такая строка:

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 0, 0, true, true, true, true, false, false, false, false, false, false, false);

Переменная NEWFRAME_PULSE_WIDTH отвечает за определение паузы в микросекундах между PPM-пакетами. Лучше ее не изменять.

Следующий блок задает пороговые значения по осям:

Joystick.setXAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setYAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setZAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setRxAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setRyAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setRzAxisRange(USB_STICK_MIN, USB_STICK_MAX);

Если осей меньше шести, то количество строк можно сократить. Для четырех осей будет так:

Joystick.setXAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setYAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setZAxisRange(USB_STICK_MIN, USB_STICK_MAX);
Joystick.setRxAxisRange(USB_STICK_MIN, USB_STICK_MAX);

В следующем блоке происходит преобразование полученных на входе значений в данные джойстика:

Joystick.setXAxis(stickValue(rcValue[ROLL]));
Joystick.setYAxis(stickValue(rcValue[PITCH]));
Joystick.setZAxis(stickValue(rcValue[THROTTLE]));
Joystick.setRxAxis(stickValue(rcValue[YAW]));
Joystick.setRyAxis(stickValue(rcValue[AUX1]));
Joystick.setRzAxis(stickValue(rcValue[AUX2]));
Joystick.setButton(0, rcValue[AUX3] > CENTER_PULSE_WIDTH);
Joystick.setButton(1, rcValue[AUX4] > CENTER_PULSE_WIDTH);

Последние две строки формируют значения кнопок. Первый параметр в этой строке - это номер кнопки. Нумерация идет с нуля. Если оставить четыре оси и убрать кнопки, то блок будет выглядеть так:

Joystick.setXAxis(stickValue(rcValue[ROLL]));
Joystick.setYAxis(stickValue(rcValue[PITCH]));
Joystick.setZAxis(stickValue(rcValue[THROTTLE]));
Joystick.setRxAxis(stickValue(rcValue[YAW]));

Можно еще немного подчистить код, убирая лишние данные, но пусть это будет "домашним заданием" для желающих копнуть еще глубже:)

Самый лучший способ сравнить работу обычного USB-адаптера и самодельного - это тест на точность полета. Как нельзя лучше для этого подходит трасса на детской площадке в симуляторе FPVFreeRider. Смотрите сами. С адаптером от OrangeRX я раза с десятого смог записать весь полет. Очень сложно было удержаться на трассе.


Признаюсь честно, я был в шоке от того, как работает самодельный USB-адаптер! С удивлением обнаружил, что в FPVFreeRider я могу пролетать сложную трассу на довольно большой скорости, легко и непринужденно проходить все ворота. В Heli-X точность управления достигла небывалых высот. Наконец-то стало возможным отрабатывать элементы, требующие ювелирной работы шагом. С LiftOff не очень заладилось. USB-адаптер работал прекрасно, но сам симулятор какой-то не очень качественный. Может быть это от системы зависит и в Ubuntu он у всех работает с проблемами.

На следующем этапе попробую заставить работать USB-адаптер с приемником через шину S.BUS. Это должно еще больше поднять точность управления в симуляторе. Успешных тренировок!

30 комментариев :

  1. А как этот способ подключения по точности в сравнении с "штатным" подключением дево10 просто USB проводом и указанием протокола USBHID ?

    ОтветитьУдалить
    Ответы
    1. При этом способе абсолютно нет дребезга значений. Но зато всего 200 шагов на ход стика. Лететь чуть проще, чем с обычным свистком, но нет той точности, как с самодельным. Особенно в околонулевой зоне чувствуется. Все равно управление получается не плавное, а дерганное какое-то, ступенчатое.

      Удалить
  2. Отличная работа, спасибо огромное!

    ОтветитьУдалить
  3. А его можно заставить одновременно работать со всеми этими тремя симуляторами без перенастройки?

    ОтветитьУдалить
    Ответы
    1. Да, можно. В FPV-шных будет и так работать, а для Heli-X нужно еще сделать системную калибровку и все.

      Удалить
  4. Супер! С sbus еще не завели?

    ОтветитьУдалить
    Ответы
    1. Нет еще. По работе что-то накидали-накидали. Как подразгребусь, так и займусь.

      Удалить
  5. Доброго времени суток. Попытался повторить Ваш проект, но столкнулся с проблемой: не могу изменить диапазон. Меняю #define USB_STICK_MIN на 0, но в Joystick Tester все равно значения меняются от 0 до 65535... В файле Joystick.cpp тоже изменил значение на 0. В чем дело, не пойму :(

    ОтветитьУдалить
    Ответы
    1. После изменения в Joystick.cpp надо завершить и заново запустить среду Arduino. Только тогда значения из библиотек подтягиваются и можно заливать скетч.

      Удалить
    2. Да я так и делал, причем не один раз. Среда ардуины последняя, 1.8.2 nightly, библиотека там внутри, туда и закидывал всю директорию джойстика с измененным Joystick.cpp ... Полдня и так и этак, уже не знаю, куда копать дальше.

      Удалить
    3. Сейчас у себя попробую с версией 1.8.2...

      Удалить
  6. Таже самая ерунда. Тоже значения от 0 до 65535, хотя в Joystick.cpp значения на 0

    ОтветитьУдалить
  7. Разобрался, почему #define JOYSTICK_AXIS_MINIMUM 0 не срабатывал!!! У меня файл Joystick.cpp оказался не только в папке C:\Arduino\libraries\Joystick\src, но и еще и в папке C:\Users\dshevchenko\Documents\Arduino\libraries\Joystick\src. И вот что важно, файл по второму пути имел преимущество над первым! Я отредактировал файл по второму пути, дальше очистил eeeprom скетчем из семплов и заново залил скетч джойстика. Всё работает без нареканий.

    ОтветитьУдалить
    Ответы
    1. Отлично! Да, в пользовательском каталоге библиотеки имеют преимущество перед теми, которые в системном. Я стараюсь в системный ничего не кидать, ибо дистрибутив часто обновляется. А так, не думая старый каталог снес, новый развернул - пользовательские библиотеки на месте.
      А я бился-бился, не смог повторить результат - все получалось и получалось:)

      Удалить
  8. Доброго дня всем. Спасибо за ответы. Но у меня, в том-то и дело, что во всех каталогах, где есть библиотеки от ардуины, уже стоит правленый файл .срр . А вот еепром скетчем я не чистил, попробую еще этот вариант.

    ОтветитьУдалить
  9. Супер статья!
    Очень хотелось бы увидеть продолжение с SBUS:)

    ОтветитьУдалить
  10. Доброго времени суток. Продолжил борьбу за #define JOYSTICK_AXIS_MINIMUM 0 :) Сделал на другом ПК все процедуры, при запуске JoeTester значения меняются от 32ххх до 65ххх, т.е. работает все как надо! Обрадовавшись, подключаю к компу, где диапазон этих значений ни при каких условиях не изменялись (т.е. диапазон был 0 ... 65ххх)... И опять все тоже самое! Или глючит JoeTester? Что еще может быть?!

    ОтветитьУдалить
    Ответы
    1. Может попробовать сбросить данные калибровки джойстика в его свойствах? А в FPVFreeRider как калибруется?

      Удалить
    2. В FPVFreeRider калибруется нормально, работает тоже нормально. Глюк самой виндузы?

      Удалить
  11. Сделал, работает отлично! Спасибо огромное!
    Завтра сделаю второй вариант с SBUS. Если получиться - отпишу.
    Огромное спасибо за хорошую идею и простую реализацию.

    ОтветитьУдалить
    Ответы
    1. Если получится с SBUS - будет здорово! У меня с наскока не получилось, а плотно поэкспериментировать пока времени нет.

      Удалить
  12. Получилось сделать SBUS!
    Пришлось брать неинвертированный выход с резистора. Ставил свой инвертор на транзисторе - не вышло :( А так вышло еще интересней и очень стабильно.
    Вот код для Arduino:
    https://yadi.sk/d/mcE5Wg_O3GggS2

    Фото куда паяться:
    https://yadi.sk/i/0UXeGkDA3GggAC
    https://yadi.sk/i/U-zu8fr-3GggAh

    ОтветитьУдалить
    Ответы
    1. Класс! Нет слов! Попробую повторить. А если попробовать программно инвертировать?

      Удалить
    2. А с оригинальным приемником будет работать если просто в порт sbus воткну? Есть 7003 2 шт.

      Удалить
    3. Нужен инвертор :( Я сначала сделал инвертор на транзисторе, но что то пошло не так. Были ошибки чтения. Бился полдня, даже осциллограф подключил. Потом взял до транзистора (инвертора на приемнике) сигнал и все заработало. Можно еще попробовать не железный UART а SoftSerial покрутить, там наверное можно сделать программный инвертор. Будет меняться только одна строчка: #define port Serial1 надо будет замутить на SoftSerial.

      Удалить
  13. Работает, но идет помеха по всем каналам. В jstest видно как на разные каналы на фоне правильно высчитанных значений несколько раз в секунду выдаются произвольные числа. Пару кругов пролететь можно, а вот посадить практически нереально. Менял значения PULSE_WIDTH, переписывал stickValue - не помогло. Есть мысли что может себя так вести?

    ОтветитьУдалить
    Ответы
    1. А как свисток с пультом соединен? Через приемник или по проводу? По моему, тут проблема не в прошивке свистка, а во входящем сигнале. Если это приемник, то можно подключить его к любому полетнику и посмотреть через конфигуратор как ведут себя каналы приемника. Скорее всего и там будет такая же история - все каналы будут периодически хаотично дергаться. Аналогично можно и по проводу проверить. Так же подкинуть сигнал на полетник и посмотреть в конфигураторе результат.

      Удалить
    2. Приемник FlySky на pro mini, действительно с другим кодом заработало. Довольно точный адаптер получается, играть можно, хотя значения из PPM все равно немного плавают.

      Удалить
  14. Этот комментарий был удален автором.

    ОтветитьУдалить