Магазин BangGood перед "черной пятницей" организует распродажу! По ссылке можно получить персональный купон на 9% на все товары!

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. Это должно еще больше поднять точность управления в симуляторе. Успешных тренировок!

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

  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. Этот комментарий был удален автором.

    ОтветитьУдалить
  15. Так вот этот чудо зверь самодельный. Спасибо будем пробовать.

    ОтветитьУдалить
  16. А на arduino nano можно собрать этот проект?если да ,то все делается аналогично?

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