Робототехническая операционная система ROS является довольно мощной платформой для создания робототехнических систем, которая включает все необходимое для разработки своих проектов от простейших программных компонентов, называемых “узлами”, и протокола обмена данными до среды симулирования реальной робототехнической платформы Gazebo. В основном ROS используется в связке с такими микроконтроллерами на платформе Arduino. Интернет переполнен всевозможными туториалами о связке ROS и Arduino.
В данный момент не существует информации об использовании робототехнической операционной системы ROS в связке с микроконтроллером STM32. Интернет переполнен только вопросами.
![](https://habrastorage.org/r/w1560/webt/r3/xo/-i/r3xo-ix7liahiwhpqfbrcqncg9c.png)
Для работы с STM32 нам понадобится STM32CubeMX и SystemworkbenchforSTM32. Информации об их установке в сети предостаточно, не будем на этом останавливаться.
Для конфигурации контроллера зайдем в STM32CubeMX
Создадим новый проект.
![](https://habrastorage.org/r/w1560/webt/vz/j9/ps/vzj9psilnxbv70jt76mfjd2sqf4.png)
Выберем микроконтроллер, у меня STM32f103c8t6.
![](https://habrastorage.org/r/w1560/webt/er/1e/da/er1edan5rp-bs93zy8pilw-od-y.png)
В периферии указываем, что у на подключен внешний кварцевый резонатор, у нас их 2
![](https://habrastorage.org/r/w1560/webt/sy/db/ac/sydbacocbufrmk9l22wle_hvpuy.png)
Настраиваем выводы, через которые можно включать отладку контроллера, (забегая вперед, если проект будет на С++, отладка может не работать)
![](https://habrastorage.org/r/w1560/webt/tc/3s/_a/tc3s_aixqy6w1nkdkozxvwclwii.png)
Настроим 13 вывод порта С, к нему подключен встроенный светодиод.
![](https://habrastorage.org/r/w1560/webt/ow/ne/4_/owne4_udwfi9iih_vdu1bp0iarg.png)
Настроим выводы UART.
![](https://habrastorage.org/r/w1560/webt/nm/yv/js/nmyvjsjhwx6dgrzfe-xjdwkzpq4.png)
Перейдем в Сlock_configuration и выполним настройки как на картинке.
![](https://habrastorage.org/r/w1560/webt/gm/rm/c_/gmrmc_agfm2tyflepfoa0y0g56o.png)
UART
Настройка скорости обмена данных.
![](https://habrastorage.org/r/w1560/webt/dr/40/xg/dr40xgaz113_lo3rtadkfrkwnmg.png)
Настройка DMA.
![](https://habrastorage.org/r/w1560/webt/sp/k2/ev/spk2ev7ycm_vl_479vnmiauxhqc.png)
![](https://habrastorage.org/r/w1560/webt/5p/bj/pe/5pbjperakd3brrhxunktphz7ehu.png)
Настройка прерывания, нужно указать глобальное прерывание по UART
![](https://habrastorage.org/r/w1560/webt/yg/rv/gc/ygrvgcoshvrwetba3nfgeo76rca.png)
![](https://habrastorage.org/r/w1560/webt/i2/ch/ey/i2cheyaelog_qpsrtwoclx5ig9k.png)
![](https://habrastorage.org/r/w1560/webt/zw/lj/_i/zwlj_i4e7f0phoetsvdfbezigys.png)
Ждем пока соберется
![](https://habrastorage.org/r/w1560/webt/hy/wr/z0/hywrz0g0d9hu0rqokae4lpihrhi.png)
Открываем проект,
![](https://habrastorage.org/r/w1560/webt/x8/jl/ie/x8jliev2ccwcuf0wj9-tqvgkdmi.png)
Открыв данный проект в SW4STM32, дописав некоторое управление периферией, собрав его, и прошив контроллер, я не получил никакого результата.
Поэтому создаем новый проект по следующей инструкции, и переносим конфигурацию полученную STM32CubeMX.
1) Нажмите File > New > C Project
2) C Project
1) Введите название проекта
2) Выберите тип проекта: Executable > Ac6 STM32 MCU Project
3) Выберите Toolchains: Ac6 STM32 MCU GCC
4) Нажмите «Далее»
![](https://habrastorage.org/r/w1560/webt/pl/ll/ed/pllledbfjtuwsaqwlj2vb2ndun8.png)
3) Выбираем микроконтроллер
1) Нажмите «Create a new custom board»
1) Сохранить Определение новой платы
2) Введите имя новой платы: STM32F103
3) Выберите чип платы: STM32F1
4) Выберите МСU: STM32F103RCTx
5) Нажмите «ОК».
2) Выберите плату, которое вы только что создали!
1) Выбрать серию: STM32F1
2) Выберите плату: STM32F103
3) Нажмите «Далее»
![](https://habrastorage.org/r/w1560/webt/6j/m-/gc/6jm-gc_rykla5chzbymmfw-vxem.png)
4) Подключаем библиотеки HAL
![](https://habrastorage.org/r/w1560/webt/ky/-z/bo/ky-zboy5nsakqwym1wgggs9mbqk.png)
5) Нажмите «Finish»
Копируем содержимое файлов src и inc, созданных кубом в наши файлы, также копируем STM32F103C8Tx_FLASH.ld
![](https://habrastorage.org/r/w1560/webt/yu/iw/ky/yuiwkyljb6jmjbrgywjc4axj8v0.png)
Для проверки работоспособности самой STM32 и кода в цикл while прописываем следующие строки
Тут мы просто моргаем светодиодом.
При сборке могут возникнуть проблемы в файле stm32f1xx_hal_msp.c
Ошибку связанную с функцией void HAL_MspInit(void) исправляем следующим образом.
Открываем папку с библиотекой HAL_Driver, идем /src открываем файл stm32f1xx_hal_msp_template.c и закомментируем эту же функцию:
![](https://habrastorage.org/r/w1560/webt/jb/rq/5w/jbrq5wpklb-ztmqzuklqepwgh5g.png)
Собираем заново (должно собраться без ошибок)
Забыл упомянуть для прошивки контроллера понадобится утилита st-flash.
Использование ST link
Проверка обнаружения ST link:
В ответ мы должны увидеть что-то вроде:
Для прошивки контроллера переходим в папку нашего проекта и и прошиваем контроллер через следующий команду:
Проверили. Все работает. Двигаемся дальше.
Так как библиотеки ROS написаны на C++, переводим наш проект в проект С++, и изменяем формат файлов main.c, stm32f1xx_hal_msp.c, stm32f1xx_it.c в .cpp
Клонируем мой репозиторий с библиотеками рос и нужными файлами для работы rosserial на STM32.
Вставляем склонированную папку в проект
![](https://habrastorage.org/r/w1560/webt/c5/a9/yx/c5a9yx2j6uf7wevljunc0bks0og.png)
![](https://habrastorage.org/r/w1560/webt/3_/4h/jh/3_4hjhqbl-psljdqsrlikkqvsmy.png)
Перейдем в настройки проект (Properties), первым делом подключаем библиотеку, переходим…
![](https://habrastorage.org/r/w1560/webt/us/dp/6l/usdp6l8xeq7qk5qvxu2fnbcqhdu.png)
![](https://habrastorage.org/r/w1560/webt/zx/n7/u_/zxn7u_v5m9yvc2oupzjmy0a93we.png)
![](https://habrastorage.org/r/w1560/webt/cd/uv/cf/cduvcfrjdw-xxniumtmlzbrxpdm.png)
Изменяем компоновщик
![](https://habrastorage.org/r/w1560/webt/pp/ux/e_/ppuxe_icwxsytenafdelbhzewzq.png)
![](https://habrastorage.org/r/w1560/webt/a4/aw/t9/a4awt9_8ztkfqqjrusjrvcq0mfy.png)
Выполняем оптимизацию
![](https://habrastorage.org/r/w1560/webt/52/dk/vk/52dkvkhaq9_ql7fqbqxodty5mrw.png)
![](https://habrastorage.org/r/w1560/webt/od/ji/_-/odji_-8zr16qykp3cafrpy4a304.png)
Ну теперь внесем некие изменения в main.cpp, так как он почти пустой, первое что делаем подключаем библиотеку ROS, и библиотеки для взаимодействия с топиками ROS, а точней с типами данных этих топиков.
Создадим узел, топик публикующий данный и принимающий
Инициализируем узел и топики в main.
Также добавим переменные для работы со временем и то что будем публиковать.
В цикле while у нас будет следующее. Будем публиковать нашу фразу через определенное время.
Собираем проект.
Могут появится следующие ошибки:
![](https://habrastorage.org/r/w1560/webt/_e/im/mx/_eimmxwleimawe2wtzilcvhgwe4.png)
![](https://habrastorage.org/r/w1560/webt/yy/wn/fp/yywnfpvkeqjycws0cvtiqo6lulo.png)
Собираем заново и прошиваем.
Теперь непосредственно само взаимодействие с ROS.
В одном терминале запускаем ROS.
В следующем запускаем узел.
Получаем следующее
Далее в новом окне терминала, смотрим, топики
Получаем следующие топики:
В топик chatter контроллер публикует фразу.
Можем его послушать через команду
![](https://habrastorage.org/r/w1560/webt/go/ov/fr/goovfriahknpo0ep99v9h7ycqn4.png)
Теперь отправим данные в топик led.
И у нас должно изменится состояние светодиода.
В данный момент не существует информации об использовании робототехнической операционной системы ROS в связке с микроконтроллером STM32. Интернет переполнен только вопросами.
![](https://habrastorage.org/webt/r3/xo/-i/r3xo-ix7liahiwhpqfbrcqncg9c.png)
Начнем работу
Для работы с STM32 нам понадобится STM32CubeMX и SystemworkbenchforSTM32. Информации об их установке в сети предостаточно, не будем на этом останавливаться.
Для конфигурации контроллера зайдем в STM32CubeMX
Создадим новый проект.
![](https://habrastorage.org/webt/vz/j9/ps/vzj9psilnxbv70jt76mfjd2sqf4.png)
Выберем микроконтроллер, у меня STM32f103c8t6.
![](https://habrastorage.org/webt/er/1e/da/er1edan5rp-bs93zy8pilw-od-y.png)
В периферии указываем, что у на подключен внешний кварцевый резонатор, у нас их 2
![](https://habrastorage.org/webt/sy/db/ac/sydbacocbufrmk9l22wle_hvpuy.png)
Настраиваем выводы, через которые можно включать отладку контроллера, (забегая вперед, если проект будет на С++, отладка может не работать)
![](https://habrastorage.org/webt/tc/3s/_a/tc3s_aixqy6w1nkdkozxvwclwii.png)
Настроим 13 вывод порта С, к нему подключен встроенный светодиод.
![](https://habrastorage.org/webt/ow/ne/4_/owne4_udwfi9iih_vdu1bp0iarg.png)
Настроим выводы UART.
![](https://habrastorage.org/webt/nm/yv/js/nmyvjsjhwx6dgrzfe-xjdwkzpq4.png)
Перейдем в Сlock_configuration и выполним настройки как на картинке.
![](https://habrastorage.org/webt/gm/rm/c_/gmrmc_agfm2tyflepfoa0y0g56o.png)
Перейдем к более детальной настройке периферии
UART
Настройка скорости обмена данных.
![](https://habrastorage.org/webt/dr/40/xg/dr40xgaz113_lo3rtadkfrkwnmg.png)
Настройка DMA.
![](https://habrastorage.org/webt/sp/k2/ev/spk2ev7ycm_vl_479vnmiauxhqc.png)
![](https://habrastorage.org/webt/5p/bj/pe/5pbjperakd3brrhxunktphz7ehu.png)
Настройка прерывания, нужно указать глобальное прерывание по UART
![](https://habrastorage.org/webt/yg/rv/gc/ygrvgcoshvrwetba3nfgeo76rca.png)
Настройка GPIO
![](https://habrastorage.org/webt/i2/ch/ey/i2cheyaelog_qpsrtwoclx5ig9k.png)
Настройка сборки проекта
![](https://habrastorage.org/webt/zw/lj/_i/zwlj_i4e7f0phoetsvdfbezigys.png)
Ждем пока соберется
![](https://habrastorage.org/webt/hy/wr/z0/hywrz0g0d9hu0rqokae4lpihrhi.png)
Открываем проект,
![](https://habrastorage.org/webt/x8/jl/ie/x8jliev2ccwcuf0wj9-tqvgkdmi.png)
Создание проекта под System Workbench For STM32
Открыв данный проект в SW4STM32, дописав некоторое управление периферией, собрав его, и прошив контроллер, я не получил никакого результата.
Поэтому создаем новый проект по следующей инструкции, и переносим конфигурацию полученную STM32CubeMX.
Создание проекта под System Workbench For STM32
1) Нажмите File > New > C Project
2) C Project
1) Введите название проекта
2) Выберите тип проекта: Executable > Ac6 STM32 MCU Project
3) Выберите Toolchains: Ac6 STM32 MCU GCC
4) Нажмите «Далее»
![](https://habrastorage.org/webt/pl/ll/ed/pllledbfjtuwsaqwlj2vb2ndun8.png)
3) Выбираем микроконтроллер
1) Нажмите «Create a new custom board»
1) Сохранить Определение новой платы
2) Введите имя новой платы: STM32F103
3) Выберите чип платы: STM32F1
4) Выберите МСU: STM32F103RCTx
5) Нажмите «ОК».
2) Выберите плату, которое вы только что создали!
1) Выбрать серию: STM32F1
2) Выберите плату: STM32F103
3) Нажмите «Далее»
![](https://habrastorage.org/webt/6j/m-/gc/6jm-gc_rykla5chzbymmfw-vxem.png)
4) Подключаем библиотеки HAL
![](https://habrastorage.org/webt/ky/-z/bo/ky-zboy5nsakqwym1wgggs9mbqk.png)
5) Нажмите «Finish»
Добавление файлов
Копируем содержимое файлов src и inc, созданных кубом в наши файлы, также копируем STM32F103C8Tx_FLASH.ld
![](https://habrastorage.org/webt/yu/iw/ky/yuiwkyljb6jmjbrgywjc4axj8v0.png)
Для проверки работоспособности самой STM32 и кода в цикл while прописываем следующие строки
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(100);
Тут мы просто моргаем светодиодом.
При сборке могут возникнуть проблемы в файле stm32f1xx_hal_msp.c
Ошибку связанную с функцией void HAL_MspInit(void) исправляем следующим образом.
Открываем папку с библиотекой HAL_Driver, идем /src открываем файл stm32f1xx_hal_msp_template.c и закомментируем эту же функцию:
![](https://habrastorage.org/webt/jb/rq/5w/jbrq5wpklb-ztmqzuklqepwgh5g.png)
Собираем заново (должно собраться без ошибок)
Забыл упомянуть для прошивки контроллера понадобится утилита st-flash.
$ sudo apt-get install cmake
$ sudo apt-get install libusb-1.0.0
$ git clone github.com/texane/stlink.git
$ cd stlink
$ make release
$ cd build/Release; sudo make install
$ sudo ldconfig
Использование ST link
Проверка обнаружения ST link:
$ st-info —probe
В ответ мы должны увидеть что-то вроде:
Found 1 stlink programmers
serial: 563f7206513f52504832153f
openocd: "\x56\x3f\x72\x06\x51\x3f\x52\x50\x48\x32\x15\x3f"
flash: 262144 (pagesize: 2048)
sram: 65536
chipid: 0x0414
descr: F1 High-density device
Для прошивки контроллера переходим в папку нашего проекта и и прошиваем контроллер через следующий команду:
cd workspace/ros_stm32_2/
st-flash write Debug/ros_stm32_2.bin 0x8000000
Проверили. Все работает. Двигаемся дальше.
Так как библиотеки ROS написаны на C++, переводим наш проект в проект С++, и изменяем формат файлов main.c, stm32f1xx_hal_msp.c, stm32f1xx_it.c в .cpp
Клонируем мой репозиторий с библиотеками рос и нужными файлами для работы rosserial на STM32.
git clone https://gitlab.com/ivliev123/ros_lib
Вставляем склонированную папку в проект
![](https://habrastorage.org/webt/c5/a9/yx/c5a9yx2j6uf7wevljunc0bks0og.png)
![](https://habrastorage.org/webt/3_/4h/jh/3_4hjhqbl-psljdqsrlikkqvsmy.png)
Перейдем в настройки проект (Properties), первым делом подключаем библиотеку, переходим…
![](https://habrastorage.org/webt/us/dp/6l/usdp6l8xeq7qk5qvxu2fnbcqhdu.png)
![](https://habrastorage.org/webt/zx/n7/u_/zxn7u_v5m9yvc2oupzjmy0a93we.png)
![](https://habrastorage.org/webt/cd/uv/cf/cduvcfrjdw-xxniumtmlzbrxpdm.png)
Изменяем компоновщик
![](https://habrastorage.org/webt/pp/ux/e_/ppuxe_icwxsytenafdelbhzewzq.png)
![](https://habrastorage.org/webt/a4/aw/t9/a4awt9_8ztkfqqjrusjrvcq0mfy.png)
Выполняем оптимизацию
![](https://habrastorage.org/webt/52/dk/vk/52dkvkhaq9_ql7fqbqxodty5mrw.png)
![](https://habrastorage.org/webt/od/ji/_-/odji_-8zr16qykp3cafrpy4a304.png)
Ну теперь внесем некие изменения в main.cpp, так как он почти пустой, первое что делаем подключаем библиотеку ROS, и библиотеки для взаимодействия с топиками ROS, а точней с типами данных этих топиков.
#include <ros.h>
#include <std_msgs/String.h>
#include <std_msgs/UInt16.h>
Создадим узел, топик публикующий данный и принимающий
void led_cb( const std_msgs::UInt16& cmd_msg){
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
ros::NodeHandle nh;
std_msgs::String str_msg;
ros::Publisher chatter("chatter", &str_msg);
ros::Subscriber<std_msgs::UInt16> sub("led", led_cb);
Инициализируем узел и топики в main.
nh.initNode();
nh.advertise(chatter);
nh.subscribe(sub);
Также добавим переменные для работы со временем и то что будем публиковать.
const char * hello = "Hello World!!";
int chatter_interval = 1000.0 / 2;
int chatter_last = HAL_GetTick();
В цикле while у нас будет следующее. Будем публиковать нашу фразу через определенное время.
if (nh.connected())
{
if(HAL_GetTick() - chatter_last > chatter_interval)
{
str_msg.data = hello;
chatter.publish(&str_msg);
chatter_last = HAL_GetTick();
}
}
nh.spinOnce();
Собираем проект.
Могут появится следующие ошибки:
![](https://habrastorage.org/webt/_e/im/mx/_eimmxwleimawe2wtzilcvhgwe4.png)
![](https://habrastorage.org/webt/yy/wn/fp/yywnfpvkeqjycws0cvtiqo6lulo.png)
![](https://habrastorage.org/webt/k0/tj/mm/k0tjmm6aap31tbezwmuqoddtkq4.png)
Собираем заново и прошиваем.
Теперь непосредственно само взаимодействие с ROS.
В одном терминале запускаем ROS.
roscore
В следующем запускаем узел.
rosrun rosserial_python serial_node.py /dev/ttyUSB0
Получаем следующее
[INFO] [1551788593.109252]: ROS Serial Python Node
[INFO] [1551788593.124198]: Connecting to /dev/ttyUSB0 at 57600 baud
[INFO] [1551788595.233498]: Requesting topics...
[INFO] [1551788595.258554]: Note: publish buffer size is 2048 bytes
[INFO] [1551788595.259532]: Setup publisher on chatter [std_msgs/String]
[INFO] [1551788595.275572]: Note: subscribe buffer size is 2048 bytes
[INFO] [1551788595.276682]: Setup subscriber on led [std_msgs/UInt16]
Далее в новом окне терминала, смотрим, топики
rostopic list
Получаем следующие топики:
/chatter
/diagnostics
/led
/rosout
/rosout_agg
В топик chatter контроллер публикует фразу.
Можем его послушать через команду
rostopic echo /chatter
![](https://habrastorage.org/webt/go/ov/fr/goovfriahknpo0ep99v9h7ycqn4.png)
Теперь отправим данные в топик led.
rostopic pub /led std_msgs/UInt16 "data: 0"
И у нас должно изменится состояние светодиода.