赞
踩
`本文主要分享一下如何快速在stm32f103或stm32系列的任意板子上运行microros的具体步骤。(所需要的文件已经生成好了)。
生成的步骤极其踩坑,是一段令人痛苦的回忆。
生成静态链接库的踩坑主要内容就是 所有资源都是外网,需要代理,如果网络不通畅所有的步骤都得重新来,尤其是在docker 容器运行时的代理配置,直接给我干吐血了…
好的废话不多说,此篇文章的只需要下载工程后,即可使用(对于stm32f103rct6),其他芯片的可通过cubemx软件选择对应芯片即可。
对于microros如何从源码开始编译可点击以下链接
microros部署教程
microros github源码
microros 官网
链接:https://pan.baidu.com/s/1QUw-3e9ZpeAaA7Khyjd_Dg?pwd=iebe
提取码:iebe
–来自百度网盘超级会员V4的分享
microros2pc_test 用于开发板与linux端ros2通信测试功能包
microros_ws 构建静态链接库,agent等功能包的setup功能包 具体使用可参考microros官网
microros_agent_ws linux端运行microros的agent功能包
freertos_rosnode stm32工程文件,包含了静态链接 .a文件
在freertos_rosnode下的micro_ros_stm32cubemx_utils文件夹是极其重要的文件夹,一般不做修改,移植所需文件夹 。同时可参考其中的main.c文件如何编程microros
打开stm32 cubemx,创建一个新的工程 (我以stm32f103rct6为例)
1.正常配置时钟树即可
2.rcc配置 HSE选择crystal
选择中间件 middleware,选择freertos。如下配置 选择v2版本 选择tasks and queues双击已存在的tasks
配置 stack size 3000 allocation static
3.配置usart:
mode 选择asynchronous
dma settings 点击add
rx mode选择circular
tx默认即可
两者优先级都为非常高
nvic settings 打开中断
配置图如下
4.sys配置
打开debug
timebase source 选择tim1
5.工程管理:
toolchan/ide 选择makefile
6.代码生成:
生成代码 打开工程所在位置,将百度网盘下载的工程中的micro_ros_stm32cubemx_utils文件夹复制到新生成的工程文件夹目录下
如图所示
使用你最常用的ide或者编辑器打开工程(我以clion为例,配置文件可复制.idea文件夹到新工程目录下):需要配置好工具链,如果没有配置,可参考稚晖君配置教程(clion)
编辑makefile文件:
将以下内容复制到 build the application之前
####################################### # micro-ROS addons ####################################### LDFLAGS += micro_ros_stm32cubemx_utils/microros_static_library/libmicroros/libmicroros.a C_INCLUDES += -Imicro_ros_stm32cubemx_utils/microros_static_library/libmicroros/microros_include # Add micro-ROS utils C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/custom_memory_manager.c C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_allocators.c C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_time.c # Set here the custom transport implementation C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_transports/dma_transport.c print_cflags: @echo $(CFLAGS)
最好按照cubemx语法规则放入注释之间,这样在cubemx软件新添配置后代码不会被覆盖
/* USER CODE BEGIN PM */
/* USER CODE END PM */
将以下头文件复制到freertos.c文件中
#include "usart.h"
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <uxr/client/transport.h>
#include <rmw_microxrcedds_c/config.h>
#include <rmw_microros/rmw_microros.h>
#include <std_msgs/msg/int32.h>
bool cubemx_transport_open(struct uxrCustomTransport * transport);
bool cubemx_transport_close(struct uxrCustomTransport * transport);
size_t cubemx_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err);
size_t cubemx_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err);
void * microros_allocate(size_t size, void * state);
void microros_deallocate(void * pointer, void * state);
void * microros_reallocate(void * pointer, size_t size, void * state);
void * microros_zero_allocate(size_t number_of_elements, size_t size_of_element, void * state);
再将StartDefaultTask()函数中的内容替换为以下内容
void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ // micro-ROS configuration rmw_uros_set_custom_transport( true, (void *) &huart1, cubemx_transport_open, cubemx_transport_close, cubemx_transport_write, cubemx_transport_read); rcl_allocator_t freeRTOS_allocator = rcutils_get_zero_initialized_allocator(); freeRTOS_allocator.allocate = microros_allocate; freeRTOS_allocator.deallocate = microros_deallocate; freeRTOS_allocator.reallocate = microros_reallocate; freeRTOS_allocator.zero_allocate = microros_zero_allocate; if (!rcutils_set_default_allocator(&freeRTOS_allocator)) { printf("Error on default allocators (line %d)\n", __LINE__); } // micro-ROS app rcl_publisher_t publisher; std_msgs__msg__Int32 msg; rclc_support_t support; rcl_allocator_t allocator; rcl_node_t node; allocator = rcl_get_default_allocator(); //create init_options rclc_support_init(&support, 0, NULL, &allocator); // create node rclc_node_init_default(&node, "cubemx_node", "", &support); // create publisher rclc_publisher_init_default( &publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), "cubemx_publisher"); msg.data = 0; for(;;) { rcl_ret_t ret = rcl_publish(&publisher, &msg, NULL); if (ret != RCL_RET_OK) { printf("Error publishing (line %d)\n", __LINE__); } msg.data++; osDelay(10); } /* USER CODE END StartDefaultTask */ }
添加syscalls.c:
在工程目录的core/src目录下新建syscalls.c文件,并复制以下内容到新建文件中
/** ***************************************************************************** ** ** File : syscalls.c ** ** Author : Auto-generated by System workbench for STM32 ** ** Abstract : System Workbench Minimal System calls file ** ** For more information about which c-functions ** need which of these lowlevel functions ** please consult the Newlib libc-manual ** ** Target : STMicroelectronics STM32 ** ** Distribution: The file is distributed “as is,” without any warranty ** of any kind. ** ***************************************************************************** ** @attention ** ** <h2><center>© COPYRIGHT(c) 2019 STMicroelectronics</center></h2> ** ** Redistribution and use in source and binary forms, with or without modification, ** are permitted provided that the following conditions are met: ** 1. Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright notice, ** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. ** 3. Neither the name of STMicroelectronics nor the names of its contributors ** may be used to endorse or promote products derived from this software ** without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ***************************************************************************** */ // the code was modified by Fynn Boyer /* Includes */ #include <sys/stat.h> #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <signal.h> #include <time.h> #include <sys/time.h> #include <sys/times.h> /* Variables */ //#undef errno extern int errno; extern int __io_putchar(int ch) __attribute__((weak)); extern int __io_getchar(void) __attribute__((weak)); register char * stack_ptr asm("sp"); char *__env[1] = { 0 }; char **environ = __env; extern char _estack; // see ld file extern char _Min_Stack_Size; // see ld file /* Functions */ void initialise_monitor_handles() { } int _getpid(void) { return 1; } int _kill(int pid, int sig) { errno = EINVAL; return -1; } void _exit (int status) { _kill(status, -1); while (1) {} /* Make sure we hang here */ } __attribute__((weak)) int _read(int file, char *ptr, int len) { int DataIdx; for (DataIdx = 0; DataIdx < len; DataIdx++) { *ptr++ = __io_getchar(); } return len; } __attribute__((weak)) int _write(int file, char *ptr, int len) { int DataIdx; for (DataIdx = 0; DataIdx < len; DataIdx++) { __io_putchar(*ptr++); } return len; } caddr_t _sbrk(int incr) { extern char __heap_start__ asm("end"); // Defined by the linker. static char *heap_end; char *prev_heap_end; if (heap_end == NULL) heap_end = &__heap_start__; prev_heap_end = heap_end; if (heap_end + incr > &_estack - _Min_Stack_Size) { __asm("BKPT #0\n"); errno = ENOMEM; return (caddr_t)-1; } heap_end += incr; return (caddr_t)prev_heap_end; } int _close(int file) { return -1; } int _fstat(int file, struct stat *st) { st->st_mode = S_IFCHR; return 0; } int _isatty(int file) { return 1; } int _lseek(int file, int ptr, int dir) { return 0; } int _open(char *path, int flags, ...) { /* Pretend like we always fail */ return -1; } int _wait(int *status) { errno = ECHILD; return -1; } int _unlink(char *name) { errno = ENOENT; return -1; } int _times(struct tms *buf) { return -1; } int _stat(char *file, struct stat *st) { st->st_mode = S_IFCHR; return 0; } int _link(char *old, char *new) { errno = EMLINK; return -1; } int _fork(void) { errno = EAGAIN; return -1; } int _execve(char *name, char **argv, char **env) { errno = ENOMEM; return -1; }
再编辑makefile文件,加入syscalls.c文件路径
在
######################################
source
######################################
C sources
下加入
Core/Src/syscalls.c \
最后编译即可
最后下载固件到开发板上即可。
1.将agent功能包上传到linux中(linux需安装ros2系统,版本为foxy)
2.最好编译一下,source功能包后运行以下命令
ros2 run micro_ros_agent micro_ros_agent serial -b 115200 --dev /dev/ttyUSB0
其中ttyUSB0要根据开发板连接的代号来修改
注意 一定要先运行上述命令后再连接开发板
效果如下
出现以下情况后连接开发板,会出现以下情况
说明开发板与ros2连接成功
再运行`
ros2 topic echo /cubemx_publisher
可查看microros发布的信息
如图
运行以下命令 可查看节点信息
rqt_graph
说明stm32f103的节点已启动!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。