测试日期:2023年11月28日
工具链:STM32CubeIDE++GCC
参考资料:micro_ros_stm32cubemx_utils
1、准备工作
1.1、安装STM32CubeIDE和STM32CubeMX
1.2、准备mirco_ros 支持cortex-m4的静态库,生成方法可参考我的一篇博文,或者直接下载地址
1.3、下载 micro_ros_stm32cubemx_utils
2、移植过程
2.1、创建STM32CubeMX项目选择芯片为STM32F405RGT6
2.2、工程配置
2.2.1、填写工程名称的路径
2.2.2、Toolchain/IDE配置:STM32CubeIDE
2.2.3、Code Generate 勾选 Generate peripheral initialization as a pair of ".cl.h’ files per peripheral
2.3、基本配置
2.3.1、时钟配置,根据开发板配置时钟源为外部8MHZ,系统时钟168M。
2.3.2、开启SW调试功能
2.3.3、因为freertos使用了systick,Timebase Source 这里选TIM14
2.4、配置外设
2.4.1、配置USART1 异步模式,波特率921600bps 8N1 用于printf输出
2.4.2、配置USART2 异步模式,波特率115200bps 8N1 使能DMA收发功能 用于mirco_ros 通讯接口
2.4.3、根据开发板配置PD2和PA15为输出,对应LED3和LED2
2.5、配置freertos并生成
2.5.1、配置默认任务栈大小位3000
2.5.2、生成CubeIDE工程
2.6、复制文件
2.6.1、复制micro_ros_stm32cubemx_utils\extra_sources文件夹到CubeIDE工作空间的Core文件夹。我们只使用USART2的DMA传输方式作为mirco_ros接口,因此需要禁用或者删除it_transport.c和usb_cdc_transport.c文件
extra_sources目录下文件说明:
(1)、microros_transports文件夹:与硬件相关的通讯接口实现,3个C文件分别提供了串口中断、串口DMA和USB虚拟串口传输案列,这里我们只用到串口DMA传输,即dma_transport.c
(2)、custom_memory_manager.c和microros_allocators.c 提供了microros的内寸分配接口实现
(3)、microros_time.c 提供了microros的时间相关接口实现
2.6.2、将静态库文件和头文件复制到工作空间,这里直接把M4lib文件夹直接复制到Core目录,然后禁用编译它们。这一步主要是方便后续引用,不一定要复制进来。
2.6.3、添加头文件路径
右键项目->Properties->C/C++Build->Setings->MCU GCC Compiler->include paths 点击右边的+图标选择工作空间下的/Core/M4lib/include 文件夹添加头文件路径,这时项目应该可以编译通过。
2.6.4、添加静态库文件和路径
右键项目->Properties->C/C++Build->Setings->MCU GCC linker->Library search path(-L) 点击右边的+图标选择工作空间下的/Core/M4lib 文件夹添加库文件路径,在Libraries(-l) 下添加库文件名microros,注意库文件名在文件夹下为libmicroros.a,GCC连接器-l选项自动添加前面的lib字符和后缀名,因此只需要填写microros
2.7、修改freertos.c文件
参考micro_ros_stm32cubemx_utils\sample_main.c文件,复制代码到用到的代码到freertos.c,这里这样操作是因为前面CubeMX设置时选了Generate peripheral initialization as a pair of ".cl.h’ files per peripheral,如果前面不选这个选项则应该复制到main.c文件。
2.7.1、添加头文件包含
在freertos.c合适位置添加以下内容
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#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>
/* USER CODE END Includes */
2.7.2、添加前置声明
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
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);
/* USER CODE END FunctionPrototypes */
2.7.3、复制例程代码
将freertos.c中StartDefaultTask函数修改成以下内容
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
// micro-ROS configuration
rmw_uros_set_custom_transport(
true,
(void *) &huart2,
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 */
}
2.7.4、printf打印支持
#include "stdio.h"
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
2.7.5、在DMA串口接收回调
在dma_transport.c中添加在DMA接收完成中断回调,重新启动接收,否则程序运行一段时间后打印Error publishing (line xxx)\n。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart2)
{
HAL_UART_Receive_DMA(&huart2, dma_buffer, UART_DMA_BUFFER_SIZE);
}
}
编译无报错,自此移植完成!
工程下载地址:https://gitee.com/lmmcloud/micro_ros.git
3、下载测试
3.1、运行WSL USB 程序,将连接开发板UASRT2和USB转TTL导入到WSL
3.2、在wsl命令行运行
MicroXRCEAgent serial --dev /dev/ttyUSB0 -b 115200
3.3、复位开发板,观察测试效果