Наконец дошли руки до публикации обещанного SDK для проекта OMower (открытая программно-аппаратная платформа для колесных роботов на базе 32-битного контроллера ATSAM3X8E с поддержкой разработки в Arduino IDE). Уровень завершенности софта пока не очень хороший (например, отсутствуют классы для датчиков бамперов, дождя и травы, отладка некоторых функций не до конца завершена), но даже в текущем виде робот умеет ездить с высокой точностью по RTK GPS, поддерживает практически все что нужно для косилки — сонары, проводной периметр, навигацию по компасу и GPS, зарядку от зарядной станции или солнечной батареи.


Моя предыдущая статья о проекте OMower

Код SDK и Kicad-файлы со схемой и разводки платы лежит на гитхабе.

В настоящее время поддерживаются только две платформы — OMower board v3 с драйверами моторов Polulu dual MC33926 и связка из Arduino Due + драйвер моторов IHM12A1 (тестовая машинка на маленьком четырехколесном шасси). Возможно добавится поддержка ardumower на базе Arduino Due. Крайне желательно наличие платы IMU GY-80, без нее навигация не работает просто (хотя и можно сделать простого косильщика, который случайно ездит внутри проволочного периметра).

В новой, четвертой версии платы, планируется поставить на нее IMU MPU9250 и добавить FRAM-чип для сохранения пользовательских настроек не во внутреннем флэше контроллера (который обнуляется при перезаливке прошивки), ну и еще карты всякие в нем можно будет хранить. Также, наверное, увеличу размеры резисторных и конденсаторных сборок, паять 0402 «на коленке» феном было удовольствие ниже среднего, и места под разъемы увеличу, чтобы можно было ставить те, что с фиксаторами, не просто торчащие пины.

Код API написан в виде кучки классов (omower-*.h файлы), которые нужно включать в виде объектов в свой софт (причем, необязательно включать их все, можно брать только те что нужны, кроме базовых). Для упрощения понимания и тестирования, написан фирмварь OMower_Simple, который выполняет довольно большой набор команд, выдаваемых через pfodApp с любого смартфона.

SDK берет на себя управление всеми низкоуровневыми функциями и работает, в основном, по прерываниям, что дает программисту конечного софта возможность писать независимый от конкретных деталей конкретного робота софт, причем в очень свободной манере (можно писать конечный автомат, а можно просто вызвать функцию начала езды и ждать когда робот доедет до нужной точки). На плечи программиста ложатся только процедуры вызова функций инициализации и контроля езды робота (указания куда, собственно, ехать и обработка срабатываний сонаров и других датчиков).

Для подключения дополнительных внешних устройств на плате (и поддержка в SDK, конечно) — имеются много внешних разъемов. Например, стандартных сервоприводов с PPM-входом можно подключить до четырех штук (или даже шесть, если отказаться от двух моторов). «Стандартных» для косилки сенсоров — имеется с большим избытком, тех же сонаров можно подключить аж шесть штук, а датчиков периметра — четыре. Разумеется, в большинстве случаев столько не нужно и часть их разъемов можно использовать для подключения каких-то других устройств (выведены практически все выводы микроконтроллера). Интеллектуальную часть (обработка RTK GPS, коннективити с wifi) выполняет Orange PI Zero, который устанавливается в специальный разъем.

Заранее извиняюсь за кривой и недоделанный местами код, приходилось отвелкаться и на другие проекты, да и выявилось множество всяких трудностей, с которыми едва справлялся. Зато узнал много нового, например, то что кривизна эллипса Земли в наших местах — почти 40 метров, а магнитные полюса Земли кочуют из года в год на десятки километров (без учета этого — робот ездил из точки в точку весьма кривыми линиями). Временами казалось, что космическую ракету в запускаю, а не газон кошу. :)

Ну и как бонус, выложил еще исходники моей прошивки для ардуинки с Decawave DW1000, которая организует мини-сеть из этих девайсов и позволяет роботу определять свое местонахождение внутри помещений или там, где RTK GPS просто не может определить свои координаты (с поддержкой практически бесконечного количества тэгов и разбиением на комнаты). Эта прошивка еще очень и очень сырая, но может кому-то пригодится.

Update, решил дополнить статью рассказом как оно там внутри устроено:

Пользователь SDK должен определить все нужные ему объекты, вызвать для всех ф��нкцию begin() (аппаратная инициализация, только один раз), потом задать значения их параметров (прочитав их из флэша или просто дефолтовые значения), вызвать init() для всех (функция может применяться и для сброса устройства, за которое отвечает объект), задать функции хуков для poll10/poll20/poll50 (10, 20 и 50 раз в секунду) из которых должен вызывать соответствующие poll*() функции всех используемых объектов. Теоретически, можно было все это автоматизировать в коде самого SDK, но я решил так не делать из-за дополнительного расхода ресурсов контроллера. Пример использования нужно смотреть в OMower_Simple.ino

Один из главных классов это объект motors (omower-motors.h), контролирует драйвера моторов из своей poll10() функции. Пользователь просто вызывает функции roll/move (поворот и езда без навигации) или rollCourse/moveCourse (езда с навигацией/коррекцией по данным от какого-то объекта, дочернего от navThing класса, который через функций readCourseError() выдает значение отклонения от нужного направления езды).

Производные от navThing — это объекты классов imu и gps (omower-imu.h и omower-gps.h), первый отвечает за чтение и преобразования в удобный вид данных компаса/акселерометра/гироскопа (выдает в градусах значения компаса и наклона по двум осям). Второй — обрабатывает данные GPS и направляет объект motors в нужном направлении, если нужна езда по координатам GPS или RTK GPS (для последних еще высчитывается поправка при размещении антенны не в центре корпуса робота и краткосрочная коррекция по датчикам одометров). Пользовательская программа отвечает за коммуникации с собственно GPS приемником и передает NMEA-строки или готовые координаты объекту gps.

Объект mow (omower-mow.h) отвечает за стригущий мотор и его подъемник-актуатор с шаговым мотором (если есть). Пользователь говорит с какой скоростью тому вращаться и какую высоту стрижки задать.

Объект pwmServo (omower-pwmservo.h) управляет PWM-A/B/C/D/E/F/G/H выходами (через другие библиотеки этого делать нельзя из-за возможных конфликтов с таймерами).

Объект power (omower-power.h) отвечает за управление зарядными регуляторами и преобразование значений ADC в понятные всем вольты и амперы. Пользовательская программа должна детектировать появление напряжения на зарядных электродах и вызывать функцию включения зарядки, дальше оно само подберет PWM-циклы регуляторов, чтобы зарядный ток соответствовал заданному.

Так как использование стандартных ардуиновских объектов Serial* ��ожет нарушить обработку прерываний (см. ниже), для чтения и передачи последовательных портов есть объект serial (omower-serial.h). С шинами I2C, к сожалению, такая же проблема, их нужно использовать при помощи функций, определенных в due-i2c-blocking.h.

Функции других объектов понятны из их названий, можно просто смотреть комментарии в заголовочных файлах (omower-sonars.h, omower-rtc.h, omower-current*.h, omower-odometry.h и т.д.).

Теперь про прерывания на самом низком уровне. Объект chassis (omower-chassis.h) конфигурирует TIM7 на 100 прерываний в секунду. На каждом прерывании — читаются 12 каналов ADC-чипа MAX11617 (заносятся в специальный массив, откуда их значения читают объекты OMower SDK — max11617-adc-scan.h). На каждом втором — генерируется софтовое прерывание для хука функций poll50(), на каждом пятом — poll20(), на каждом десятом — poll10(). Все они работают асинхронно (что удобно, но накладывает ограничения на использование шины I2C, позже я планирую какие-нибудь транзакции/семафоры туда добавить).

Также конфигурируется таймер TIM5 на генерацию прерываний с частотой 38462 герца. Из этого прерывания читаются все каналы внутреннего ADC контроллера и заносятся в специальный массив (поддерживается также занесение каждого полученного значения для выбранного в кольцевой буфер, что делает, например, класс perimeter, фильтруя потом эти выборки при помощи преобразования фурье).

Для выдачи отладочной информации имеется функция debug() с заданием минимального приоритета для вывода сообщений (то есть пока отладка не ведется — на консоль ничего выдаваться не будет, но в любой момент можно включить хоть максимальный уровень, заспамит). В форматах отладочных значений (*printf-формат) поддерживается вывод чисел с плавающей точкой (в отличие от стандартных ардуиновских функций).

Update: Новая четвертая версия платы OMower, пока только схема (жду изготовления PCB). Дополнительно включает в себя компасс/акселерометр MPU9250, 128 килобайт F-RAM для сохранения настроек, карт, вейпоинтов и прочего, все коннекторы с защелками (Molex 22-11-20x3/10-11-20x3, совместимы со старым вариантов из одних 2.54-пинов), трансляторы логических уровней 74HC4050 для сонаров и одометров, более мощные преобразователи питания 3.3/5 вольт (до трех ампер), еще два PWM/PPM выхода на разъемах, отдельные линии для независимого управления вторым драйвером шагового мотора, больше буферных конденсаторов для стабильности, большие SMD-элементы для облегчения сборки и мелкие поправки.