前言
在机器人开发的实际场景中,嵌入式传感器的数据流与 ROS 系统的指令流如何顺畅对接,是决定项目落地效率的关键环节。ESP32 的普及降低了嵌入式开发的门槛,而 ROS 2 的成熟则为机器人系统提供了标准化的开发范式,二者的结合成为小体积、低成本机器人项目的优选方案。本文从环境搭建、代码编写、通信调试到功能验证,逐步拆解整个实现流程。通过本文的案例分析,快速掌握二者通信的核心逻辑与实操技巧,为后续开展机器人导航、环境感知、远程控制等应用提供案例。
基础环境:
-
VMware虚拟机 -
Ubuntu:24.04
搭建PlatformIO开发环境
插件安装
在扩展中搜索PlatformIO,选择后点击安装即可。
安装完成后在侧方栏应该可以看到一个蚂蚁头的图标,这个就是PIO,点击图标,点击上访的Open就可以打开PIO HOME。
新建工程测试
首先点击New Project。
-
输入工程名 example01_helloworld -
选择开发板,这里选择Adafruit ESP32 Feather -
选择开发框架,这里我们用Arduino,PIO还支持IDF(IoT Development FrameWork) -
开发位置可以选择默认的位置,也可以自定义位置
最后点击Finish即可。
编译项目
如果是ESP32S3的配置,则PlatformIO的设置为:
[env:esp32s3]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
下载项目
安装第三方库
方法一:在插件中添加第三方库
方法二:直接在ini文件中添加第三方库
更多方法参考安装第三方开源库
接入MicroROS
ESP32端
1、在main.py文件中输入以下代码:
#include <Arduino.h>
#include <micro_ros_platformio.h>
#include <rcl/rcl.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
// 添加头文件
#include <std_msgs/msg/float32.h>
#include <ctime>
#include <chrono>
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
// 声明话题发布者
rcl_publisher_t publisher;
// 声明消息文件
std_msgs__msg__Float32 pub_msg;
// 定义定时器接收回调函数
void timer_callback(rcl_timer_t *timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL)
{
rcl_publish(&publisher, &pub_msg, NULL);
}
}
void setup()
{
Serial.begin(115200);
// 设置通过串口进行MicroROS通信
set_microros_serial_transports(Serial);
// 延时时一段时间,等待设置完成
delay(2000);
// 初始化内存分配器
allocator = rcl_get_default_allocator();
// 创建初始化选项
rclc_support_init(&support, 0, NULL, &allocator);
// 创建节点 topic_sub_test
rclc_node_init_default(&node, "topic_pub_test", "", &support);
// 订阅者初始化
rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Float32),
"random_topic_test");
// 创建定时器,200ms发一次
constunsignedint timer_timeout = 200;
rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback);
// 创建执行器
rclc_executor_init(&executor, &support.context, 1, &allocator);
// 给执行器添加定时器
rclc_executor_add_timer(&executor, &timer);
}
void loop()
{
delay(100);
// 循环处理数据
rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
auto now = std::chrono::system_clock::now();
auto ms_ts = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
float float_ms_ts = static_cast<float>(ms_ts.count());
pub_msg.data = float_ms_ts;
}
2、编译并下载程序
上位机
1、ubuntu安装ros2
wget http://fishros.com/install -O fishros && . fishros
2、Ubuntu安装docker
# 下载并执行Docker官方安装脚本
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
3、启动代理
sudo docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host docker.1ms.run/microros/micro-ros-agent:$ROS_DISTRO serial --dev /dev/ttyACM0 -v
启动代理后,重启单片机即可看到以下输出:
验证测试
-
查看节点 ros2 node list
-
查看话题 ros2 topic list
3. 查看话题输出
ros2 topic echo "random_topic_test"
4. 查看话题频率
ros2 topic hz "random_topic_test"
当改小发送时间间隔后,发现ESP32话题发布的最大频率限制在9.3Hz。
总结
本文围绕鱼香 ROS《动手学 ROS2》中的经典案例展开完整复现,全程覆盖开发环境搭建、ESP32 硬件接入 ROS2 系统、功能验证与测试三大核心环节,通过一步步落地实操,深入体验了 MicroROS 在嵌入式硬件与 ROS2 生态联动中的应用逻辑。 在整个实操过程中,最直观的感受便是框架选择对开发效率的显著影响 ——Arduino 框架接入 MicroROS 的流程远比 ESP-IDF 框架简洁易用。相比之下,Arduino 框架对 MicroROS 的适配更成熟,相关的库文件、配置模板及教程资源也更丰富,只需按照案例指引完成库安装、代码烧录、通信配置等几步基础操作,就能快速实现 ESP32 与 ROS2 的互联互通,几乎没有遇到繁琐的底层配置问题。而 ESP-IDF 框架则截然不同,尽管其在硬件控制精细化、资源占用优化等方面有潜在优势,但我前后多次尝试接入 MicroROS 均以失败告终:要么卡在编译阶段出现依赖库冲突,要么烧录后无法建立通信连接,反复排查配置文件、调整编译参数也未能解决,不得不暂时搁置,实在有些惭愧。后续还需针对性研究 ESP-IDF 与 MicroROS 的适配要点,弥补这一技术缺口。 在功能验证环节,我重点测试了 ESP32 的话题发布性能,却发现一个值得关注的现象:话题发布的最大频率稳定在 9.3Hz 左右,未能达到预期的更高频率。结合实操过程分析,这一限制可能源于两方面原因:一方面是通信链路的瓶颈,此次实操采用串口通信方式,串口的波特率设置、数据传输延迟或许对发布频率形成了约束;另一方面也可能与参数配置有关,比如 MicroROS 的 QoS(服务质量)设置、ESP32 的任务调度优先级、数据缓存大小等参数,是否存在可优化的空间尚未可知。目前已记录下这一问题,后续计划通过更换通信方式(如 WiFi)、调整核心参数、对比不同配置组合的测试结果等方式,进一步定位原因并尝试优化,力求突破当前的频率限制。 整体而言,本次案例复现不仅成功打通了 ESP32 与 ROS2 的连接通路,更在框架选型、问题排查等方面积累了宝贵的实操经验,也为后续的技术优化明确了方向。
参考
-
https://github.com/micro-ROS/micro_ros_espidf_component -
https://fishros.com/d2lros2/#/ -
https://platformio.org/