![cover](https://img-blog.csdnimg.cn/direct/2e79d277561b41c68692425fd755076e.png)
Micro-ros系列教程(1) 在STM32上部署micro-ros包括自定义消息类型
本文比较详细的介绍了在stm32平台上如何生成micro-ros的静态库
前言
国内已经有许多介绍关于如何在Arduino平台上部署micro-ros的方法,但是对于stm32平台上部署micro-ros的方法却很少。micro-ros对于单片机来说,无非是一个静态库(xx.a)和头文件,目前stm32生成静态库很多人会推荐参考官方给的一个例子:cubemx生成静态库
但是按照步骤文档步骤成功率非常低,主要是网络原因,需要解决docker内部的科学上网问题才能成功。而且用官方的这个文档,很多地方我们都不能自己配置,比如如何自定义消息类型等等。我们更希望能不借助docker,直接在本地环境编译出静态库。
在官方给出的文档里面,会用docker运行
docker pull microros/micro_ros_static_library_builder:humble
docker run --rm -v <ABSOLUTE_PATH_TO_PROJECT>:/project --env MICROROS_LIBRARY_FOLDER=micro_ros_stm32cubemx_utils/microros_static_library_ide microros/micro_ros_static_library_builder:humble
实际上,它就是把生成的配置文件给导入docker里面去
然后在docker里面执行library_generation.sh这个脚本文件
library_generation.sh脚本文件内容就是docker里面执行的内容,其实大家看得懂里面的内容就知道怎么去编译静态库了。看不懂也没关系,我们接下来会一步步教你编译。
编译micro-ros静态库
环境
- ros2版本 Humble
- 生成环境 WSL2-Ubuntu-22.04
安装交叉编译器
我们需要再我们的wsl2里面生成能够在arm 32位cpu上运行的静态库,所以必须使用交叉编译器。
sudo apt-get update
sudo apt-get install -y gcc-arm-none-eabi
输入arm-none-eabi-gcc -v
查看是否安装成功
由于是使用arm-none-eabi-gcc编译出来的静态库,所以是无法在KEIL里面和IAR里面使用。笔者推荐可以熟悉下如何搭建linux下的STM32开发环境。
下载
下载官方的功能包
source /opt/ros/$ROS_DISTRO/setup.bash
mkdir uros_ws && cd uros_ws
git clone -b humble https://github.com/micro-ROS/micro_ros_setup.git src/micro_ros_setup
在src目录里面我们找到了有micro-ros-setup这个功能包,接着我们编译一下
rosdepc update && rosdepc install --from-paths src --ignore-src -y
colcon build
source install/local_setup.bash
由于rosdep是国外的服务器,所以这里我采用了小鱼社区的rosdepc
生成静态库
上一步我们编译出了可执行文件,接下来我们借助功能包编译出静态库
首先我们修改一下create_firmware_ws.sh里面的东西,这个sh文件在uros_ws/src/micro_ros_setup/scripts里面113行把rosdep改为rosdepc
这一步需要从github下载大量的源码,不使用代理速度很慢,失败率也很高,建议开启下代理。失败后下次生成会提示firmware已经存在,要rm这个文件夹。
ros2 run micro_ros_setup create_firmware_ws.sh generate_lib
输出这个说明源码生成成功了
自定义消息类型
回到工作空间下,现在我们应该有五个文件夹
build
fireware
install
log
src
其中fireware
是我们生成micro-ros的空间,我们在mcu_ws
创建我们的自定义的消息类型即可,参考官方文档
micro-ros自定义消息类型
创建配置文件
这里面的colcon.meta和toolchain.cmake就是我们生成静态库需要指定的配置文件了,其中colcon.meta描述了我们micro-ros的配置,toolchain.cmake描述了单片机的平台。cubemx生成静态库的教程里面,library_generation.sh会找到cubemx生成的Makefile,然后从这里面知道单片机的信息,这里我们完全可以参考给的例子自己重新写。
新建这两个文件
toolchain.cmake里面的内容
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_CROSSCOMPILING 1)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# SET HERE THE PATH TO YOUR C99 AND C++ COMPILERS
# 在这里添加编译器路径
set(PIX /opt/gcc-arm-none-eabi-10.3-2021.10/bin)
set(CMAKE_C_COMPILER ${PIX}/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER ${PIX}/arm-none-eabi-g++)
set(CMAKE_C_COMPILER_WORKS 1 CACHE INTERNAL "")
set(CMAKE_CXX_COMPILER_WORKS 1 CACHE INTERNAL "")
# SET HERE YOUR BUILDING FLAGS
set(FLAGS "-O2 -ffunction-sections -fdata-sections -fno-exceptions -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -nostdlib -mthumb --param max-inline-insns-single=500 -D'RCUTILS_LOG_MIN_SEVERITY=RCUTILS_LOG_MIN_SEVERITY_NONE'" CACHE STRING "" FORCE)
#-mcpu=cortex-m3 改成 -mcpu=cortex-m7
# 加入 mfpu=fpv5-d16 -mfloat-abi=hard 支持硬件浮点编译
set(CMAKE_C_FLAGS_INIT "-std=c11 ${FLAGS} -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_INIT "-std=c++11 ${FLAGS} -fno-rtti -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='" CACHE STRING "" FORCE)
set(__BIG_ENDIAN__ 0)
里面就是cmake的写法,我首先指定了我arm-none-eabi-gcc的位置,然后主要修改的就是编译的标志,-mcpu=cortex-m7 -mfpu=fpv5-d16
因为笔者手里的单片机是H7系列的,是M7内核,有M4或者M3内核的同学请自行修改这两项,其他基本不需要改动。从这块我们也可以看出来,生产的静态库一个系列应该都是通用的!
colcon.meta里面的内容
{
"names": {
"tracetools": {
"cmake-args": [
"-DTRACETOOLS_DISABLED=ON",
"-DTRACETOOLS_STATUS_CHECKING_TOOL=OFF"
]
},
"rosidl_typesupport": {
"cmake-args": [
"-DROSIDL_TYPESUPPORT_SINGLE_TYPESUPPORT=ON"
]
},
"rcl": {
"cmake-args": [
"-DBUILD_TESTING=OFF",
"-DRCL_COMMAND_LINE_ENABLED=OFF",
"-DRCL_LOGGING_ENABLED=OFF"
]
},
"rcutils": {
"cmake-args": [
"-DENABLE_TESTING=OFF",
"-DRCUTILS_NO_FILESYSTEM=ON",
"-DRCUTILS_NO_THREAD_SUPPORT=ON",
"-DRCUTILS_NO_64_ATOMIC=ON",
"-DRCUTILS_AVOID_DYNAMIC_ALLOCATION=ON"
]
},
"microxrcedds_client": {
"cmake-args": [
"-DUCLIENT_PIC=OFF",
"-DUCLIENT_PROFILE_UDP=OFF",
"-DUCLIENT_PROFILE_TCP=OFF",
"-DUCLIENT_PROFILE_DISCOVERY=OFF",
"-DUCLIENT_PROFILE_SERIAL=OFF",
"-UCLIENT_PROFILE_STREAM_FRAMING=ON",
"-DUCLIENT_PROFILE_CUSTOM_TRANSPORT=ON",
"-DUCLIENT_PROFILE_SHARED_MEMORY=ON", #允许内存共享
"-DUCLIENT_SHARED_MEMORY_MAX_ENTITIES=20"
]
},
"rmw_microxrcedds": {
"cmake-args": [
"-DRMW_UXRCE_MAX_NODES=5", #最大节点数
"-DRMW_UXRCE_MAX_PUBLISHERS=6", #最大发布者数量
"-DRMW_UXRCE_MAX_SUBSCRIPTIONS=4", #最大订阅者数量
"-DRMW_UXRCE_MAX_SERVICES=6", #最大服务端数量
"-DRMW_UXRCE_MAX_CLIENTS=1", #最大客户端数量
"-DRMW_UXRCE_MAX_HISTORY=4",
"-DRMW_UXRCE_TRANSPORT=custom" #自定义传输接口
]
}
}
}
这里面配置micro-ros的内容我大多和官方的例子一样,也有几个区别:由于我使用FreeRTOS需要多个任务进行ros的发布订阅等,所以我开启了`“-DUCLIENT_PROFILE_SHARED_MEMORY=ON”``允许内存共享来完成多任务接入ros,其实官方有针对FreeRTOS的多线程处理,但是我没有做成功,也期待有大佬可以弄出来做个教程,有人在GitHub上提出过这个问题FreeRTOS开启多线程支持。使用内存共享后,那些最大数量就应该尽量开的大一些。
编译
退到ws目录下
ros2 run micro_ros_setup build_firmware.sh $(pwd)/firmware/toolchain.cmake $(pwd)/firmware/colcon.meta
编译完成后可以在firmware/build
里面看到静态库和头文件
头文件偏移
上述直接得到的头文件包含的比较深,外面还有一层文件夹,,比如我需要rclc的库可能得
#include <rcl/rcl/rcl.h>
所以需要偏移一下
这里参考library_generation.sh里面的内容写个脚本文件,在firware里面建立脚本fix_include.sh
,里面的内容如下:
#!/bin/bash
######## Fix include paths ########
BASE_PATH=build
pushd mcu_ws > /dev/null
INCLUDE_ROS2_PACKAGES=$(colcon list | awk '{print $1}' | awk -v d=" " '{s=(NR==1?s:s d)$0}END{print s}')
popd > /dev/null
for var in ${INCLUDE_ROS2_PACKAGES}; do
if [ -d "${BASE_PATH}/include/${var}/${var}" ]; then
rsync -r ${BASE_PATH}/include/${var}/${var}/* $BASE_PATH/include/${var}
rm -rf ${BASE_PATH}/include/${var}/${var}
fi
done
然后执行
sudo chmod 777 fix_include.sh
./fix_include.sh
然后可以发现每个头文件外面的一层没了,这样firmware/build
里面的内容就是我们想要的micro-ros的头文件和静态库了
总结
本文比较详细的介绍了在stm32平台上如何生成micro-ros的静态库,根据官方的文档,剖析docker里面到底干了什么,但是移植到stm32上面还需要一些其他的文件,这个我们将在下一节介绍。
限笔者水平有限,以上若有不正确的地方,欢迎大家批评指正。
如果对您有帮助,麻烦点个star★★★加个关注吧!我会继续努力分享更多ROS2小知识
版权声明:本文为博主原创文章,未经博主允许不得转载。
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)