Наконец дошли руки до публикации обещанного 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-элементы для облегчения сборки и мелкие поправки.
Моя предыдущая статья о проекте 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-элементы для облегчения сборки и мелкие поправки.