使用Micro-ROS报错
-
使用CubeMX+IDE开发
下面是我freertos的Default代码void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ // 0. 上电自检打印 printf("\r\n[SYSTEM] Power On.\r\n"); printf("[SYSTEM] Stack Size: %d bytes\r\n", (int)(3000 * 4)); // 1. 初始化底层 (串口/内存) printf("[Init] Connecting to Agent...\r\n"); while(Micro_ROS_Patch_Init(&huart3) != 1) { printf("[Error] Patch Init Failed.\r\n"); osDelay(500); } // 2. 初始化分配器 allocator = rcl_get_default_allocator(); // 3. 握手连接 Agent rcl_ret_t rc_support = rclc_support_init(&support, 0, NULL, &allocator); while (rc_support != RCL_RET_OK) { printf("."); // 打印点点表示正在连接 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); // 快闪板载LED osDelay(200); // 重试 rc_support = rclc_support_init(&support, 0, NULL, &allocator); } printf("\r\n[Init] Agent Connected! (rc=%d)\r\n", (int)rc_support); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 灭灯 // 4. 创建节点 rclc_node_init_default(&node, "stm32_led_node", "", &support); // 5. 创建订阅者 (Reliable) rcl_ret_t rc_sub = rclc_subscription_init_default( &subscriber, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String), "led_control" ); if (rc_sub != RCL_RET_OK) { printf("[Fatal] Sub Init Failed: %d\r\n", (int)rc_sub); for(;;) osDelay(100); } // 6. 配置消息内存 std_msgs__msg__String__init(&sub_msg); sub_msg.data.data = msg_buffer; sub_msg.data.capacity = sizeof(msg_buffer); sub_msg.data.size = 0; // 7. 初始化执行器 rcl_ret_t rc_exec = rclc_executor_init(&executor, &support.context, 4, &allocator); if (rc_exec != RCL_RET_OK) { printf("[Fatal] Executor Init Failed: %d\r\n", (int)rc_exec); for(;;) osDelay(100); } // 8. 添加订阅者 rcl_ret_t rc_add = rclc_executor_add_subscription( &executor, &subscriber, &sub_msg, &Led_Control_Callback, ON_NEW_DATA ); if (rc_add != RCL_RET_OK) { printf("[Fatal] Add Sub Failed: %d\r\n", (int)rc_add); for(;;) osDelay(100); } printf("[Init] System Ready. Entering Loop...\r\n"); // ========================================================== // 主循环 // ========================================================== for(;;) { // Spin rcl_ret_t rc = rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)); if (rc == RCL_RET_OK) { // 正常: 收到消息处理完毕 // printf("OK "); // 刷屏太快,建议屏蔽 } else if (rc == RCL_RET_TIMEOUT) { // 正常: 没有消息 } else { // 🔴 真正的运行时错误捕获 printf("[Error] Spin: %d\r\n", (int)rc); osDelay(100); } osDelay(10); } /* USER CODE END StartDefaultTask */ }之后报错,下面是报错日志
[Init] Agent Connected! (rc=0) [Init] System Ready. Entering Loop... [Error] Spin: 900 [Error] Spin: 900 [Error] Spin: 900 [Error] Spin: 900 [Error] Spin: 900 [Error] Spin: 900 [Error] Spin: 900 -
问题解决了,源头出在一个补丁函数:
void * microros_reallocate(void * pointer, size_t size, void * state){ return NULL; // 静态策略下通常不使用 realloc }简单来说,就是micro-ROS 试图申请或调整内存时,需要用到这个函数,而我的函数直接返回了NULL值,导致了micro-ROS 无法调整内存
为此,求助LLM,对函数做出以下修改:void * microros_reallocate(void * pointer, size_t size, void * state){ // 情况 1: 如果指针为空,这就相当于 malloc (这是 Micro-ROS 初始化最常用的情况) if (pointer == NULL) { return pvPortMalloc(size); } // 情况 2: 如果大小为 0,这就相当于 free if (size == 0) { vPortFree(pointer); return NULL; } // 情况 3: 真正的 realloc (调整大小) // 由于 FreeRTOS 的 heap_4 不支持 realloc,我们需要手动“搬家” // ⚠️ 警告:我们不知道旧数据块的大小,这是一个风险点。 // 但 Micro-ROS 通常用它是为了扩大数组。 // 这里的策略是:申请新内存 -> 假定旧数据有效 -> 释放旧内存 void * new_ptr = pvPortMalloc(size); if (new_ptr != NULL) { // 这里的拷贝长度是个玄学,因为我们不知道旧块有多大。 // 但对于 wait_set 这种结构,通常是安全的,或者我们可以只拷贝一部分。 // 为了安全起见,我们假设旧数据也很重要,拷贝 size 长度 (可能会读越界,但在 RAM 连续的 MCU 上通常没事) // 更安全的做法是引入记录内存大小的机制,但太复杂。 // 这里采用最简单的“能跑就行”策略: memcpy(new_ptr, pointer, size); // 注意:如果 size < old_size,会截断;如果 size > old_size,可能会读到垃圾数据 vPortFree(pointer); } return new_ptr; }重新编译烧录,问题解决