在STM32上部署micro-ros包括自定义消息类型——Micro-ros系列教程(1)

在STM32上部署micro-ros包括自定义消息类型

  • 前言
  • 编译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小知识
    版权声明:本文为博主原创文章,未经博主允许不得转载。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 在STM32上部署micro-ros包括自定义消息类型——Micro-ros系列教程(1)

    发表评论