如果你现在的心情是:打开PlatformIO新建ESP32工程,结果卡在Downloading 0%半天不动;想跑一个micro-ROS节点,发现镜像一直拉不下来;折腾两天还是停留在Hello World,别急。我已经在ESP32上用Arduino IDE把micro-ROS 2.0.5(对应ROS 2 Humble)完整跑通了,这篇就把整套流程和所有坑一次性写清楚。
先说明立场:PlatformIO本身很好,只是在我们这个场景里它给了太多不必要的负担。目标很朴素——让ESP32作为ROS 2的一个节点,能发话题、能收话题。用Arduino IDE来干这件事,代码不用变,依赖不用折腾,几分钟就能出结果。接下来我会从整体架构讲起,把环境搭建、第一个Publisher节点、Agent串口/WiFi两种连接方式、高频踩坑逐一说透。看完你至少能少走两天的弯路。
1. 为什么我会从PlatformIO逃到Arduino IDE
1.1 我踩过的PlatformIO的坑(下载0%、索引拉不下来)
先讲点真实的体验。如果你用过PlatformIO创建ESP32工程,大概率见过这个画面:工程创建后一直卡在“Downloading 0%”,有时候等十几分钟还是0%,最后不得不Ctrl+C。这不是你的操作问题,而是PlatformIO在初始化时会去拉取平台索引、编译器工具链、库依赖索引,这个过程中任何一个环节网络慢一点,整个工程就没法继续。
我遇到过更头疼的是“PlatformIO: Configuring project”阶段,看似在配置,实际是去拉一个几百MB的toolchain-sdadm等,一旦下载中断,下一次还得重新来。如果你还用PlatformIO的Library Manager去装micro_ros_arduino库,它还会顺带解析一大堆依赖,经常卡在某个子模块上。等你终于把环境折腾好了,可能已经过去了几个小时。
我不是说PlatformIO一无是处。它的跨平台构建、多环境管理、CI支持在正式项目里确实很强。但对我们这种“先把micro-ROS跑起来看看”的原型验证阶段,它属于杀鸡用了牛刀。Arduino IDE的上游是Espressif官方提供的arduino-esp32核心,工具链下载走官方CDN,配合国内镜像加速器,整体成功率比PlatformIO在默认网络环境下高太多。
1.2 micro-ROS的基本原理:ESP32上的ROS2到底是怎么跑的
很多人第一次接触micro-ROS时会有个疑问:ROS 2不是跑在Ubuntu上的吗?ESP32这种资源受限的MCU怎么跑得动?这里的关键在于micro-ROS并不是在MCU上完整运行ROS 2,而是跑了一个精简的XRCEDDS客户端。
解释一下背景:ROS 2的核心通信层是DDS,完整版Fast DDS或Cyclone DDS对内存和CPU的要求非常高,动辄几十MB内存,ESP32这种只有520KB SRAM的芯片根本扛不住。micro-ROS的做法是搞了一个中间层:ESP32上只跑一个“轻量客户端”,它不直接和ROS 2网络进行完整DDS通信,而是用带外协议连到一个叫micro-ROS Agent的进程上,由Agent在MCU和ROS 2之间做翻译和转发。
打个比方:完整DDS就像把所有人请进同一个会议室开大会,每个成员都要能听懂所有人的发言,这对MCU来说连椅子都放不下。micro-ROS相当于给ESP32配了一个“传话秘书”Agent,ESP32只需要用很短的暗号跟秘书说“我要发一个数字、我要订阅一个消息”,秘书再以标准DDS身份替它参加ROS 2的会议。所以你在ESP32代码里照样写rcl_publish、rclc_executor_spin_some,感觉跟ROS 2一模一样,但底层早就被micro-ROS抽象过一遍了。
1.3 先看清整体架构:三台设备三条路
如果你要跑通一个最简单的micro-ROS节点,整个环境里有三个角色必须同时在线:
- 开发机(你的电脑):运行ROS 2 Humble环境和micro-ROS Agent。Agent可以用Docker启动,也可以用二进制直接跑。
- ESP32开发板:烧录micro-ROS固件,作为客户端节点。
- 通信链路:串口(USB转TTL)或WiFi(UDP),二选一。
串口方式适合刚上手时排错,因为你只有一根USB线,Agent和ESP32直接通过串口通信,逻辑简单、延迟低,还能看到串口日志。缺点是线缆限制,节点离电脑稍微远一点就不方便。
WiFi方式更适合产品原型,ESP32通过WiFi连接路由器,Agent监听一个UDP端口,两边在同一局域网内用广播发现彼此。缺点是无线链路偶尔会有丢包,而且第一次配置网络参数(IP地址、端口)容易出错。两种方式本篇文章后面都会给出可复制的命令和代码。
2. 搭建Arduino IDE开发环境,半小时一次到位
2.1 安装Arduino IDE并添加ESP32开发板支持
Arduino IDE的版本选2.x即可,1.8.x也能用,但2.x的库管理器、串口监视器体验好很多。装好后第一步是添加ESP32开发板支持:
打开文件 -> 首选项 -> Additional boards manager URLs,填入官方JSON源:
https://espressif.github.io/arduino-esp32/package_esp32_index.json然后打开工具 -> 开发板 -> 开发板管理器,搜索“esp32”,找到esp32 by Espressif Systems,点击安装。这一步会下载较长时间,取决于网络状况。装完后在工具 -> 开发板列表里能看到一大批ESP32型号。
有一点要注意:Arduino IDE首次安装ESP32核心时,会同时下载XTensa工具链和一堆编译依赖,这个下载走的是Espressif的官方服务器。如果速度慢或失败,重试几次基本能过。我自己在Linux下装的时候,有一次卡在“Downloading tools”阶段,手动清理了~/.arduino15目录下的残留文件后重新装就好了。
2.2 安装micro_ros_arduino库,选对版本是关键
接下来在库管理器里搜索micro_ros_arduino,作者是micro-ROS官方团队。安装的时候注意版本选择:一定要选与ROS 2 Humble匹配的版本。
micro-ROS的版本号和我们常用的ROS 2版本对应关系比较特殊。ROS 2 Humble本身对应的是micro-ROS 2.0.x系列,所以你要在库管理器的版本下拉框里找类似2.0.5-humble的版本,或者直接选版本号带humble标记的release。我实测下来2.0.5-humble跟标题里的Humble版是完全匹配的。
这里有个常见坑:如果你不小心选了最新版本,而最新版本可能是为更高版本的ROS 2(比如Iron、Jazzy)设计的,编译时会遇到一堆头文件缺失或API不匹配的报错,最常见的就是找不到micro_ros_utilities/string_utilities.h。遇到这种错误,别再往下查了,先去换版本。
库装好之后,在文件 -> 示例 -> micro_ros_arduino里可以看到官方示例,其中micro-ros_publisher和micro-ros_subscriber是我们马上要用的。这个库内部包含了micro-ROS客户端栈的全部代码和生成的头文件,所以体积很大,装完后项目编译时间会明显变长,这是正常的。
2.3 分区表、Flash大小、开发板型号三个关键设置
很多人用Arduino IDE烧ESP32时,直接在“开发板”里选一个ESP32 Dev Module就开刷,结果micro-ROS固件烧进去后运行异常或者直接启动不了。这里有个非常隐蔽的坑:默认分区表放不下micro-ROS的固件。
micro-ROS固件编译出来通常有1.3MB以上,而Arduino默认分区方案给APP分区只有1.2MB左右,刚好放不下。解决办法是在工具菜单里把Partition Scheme改成**Huge APP (3MB No OTA/1MB SPIFFS)**或类似的大APP分区方案。这一步必须做,否则编译能通过,但烧录后板子要么反复重启,要么干脆没有运行micro-ROS的日志。
另外三项设置建议按这样选:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Board | ESP32 Dev Module / ESP32S3 Dev Module | 根据手上的芯片选 |
| Partition Scheme | Huge APP (3MB No OTA/1MB SPIFFS) | 给APP留足空间 |
| Flash Size | 4MB(按实际板子选) | 多数ESP32开发板是4MB |
| Upload Speed | 921600 | 烧录速度快,不稳就降到115200 |
| Flash Mode | DIO / QIO | 大多数板子DIO能稳定运行 |
如果你是ESP32-S3开发板,在开发板列表里找ESP32S3 Dev Module,分区表和上传方式类似。S3的USB口可能是原生USB CDC,烧录时偶尔需要手动进入下载模式,具体的我在排查章节里会展开说。
2.4 提前处理最容易卡住的镜像拉取问题
环境准备的最后一步是搞定Agent镜像。很多人第一次跑Docker命令时,会遇到这个报错:
Unable to find image 'microros/micro-ros-agent:humble' locally这行日志本身不是错误,表示本地没有该镜像,Docker会自动去远程仓库拉取。真正的问题是拉取过程非常慢,或者直接超时。我在实际使用中碰到过三种情况:
第一种是网络波动导致拉取中断,解决办法是配置Docker镜像加速器。现在主流的容器镜像服务商都提供国内加速地址,在Docker Daemon配置里加上registry-mirrors后重启Docker服务即可。配置好后重新执行docker pull microros/micro-ros-agent:humble,速度会有明显提升。
第二种是镜像标签写错了。micro-ROS Agent的镜像标签和ROS 2版本严格对应,Humble版就是humble标签,如果你想跑Humble却写成galactic或iron,Agent会报协议不匹配。
第三种是CPU架构问题。如果你的电脑是ARM架构(比如Apple Silicon Mac),Docker一般会自动拉取对应的multi-arch镜像,但如果你的Docker版本较老,可能会拉错架构导致启动失败。这种情况建议升级Docker后重试。
3. 把第一个micro-ROS节点跑起来
3.1 一个最简单的Publisher节点完整代码
直接上代码。下面的示例是从官方micro-ros_publisher基础上改的,我加了注释,串口模式直接可用,WiFi模式的代码也用注释保留着,方便你切换。
#include <micro_ros_arduino.h> #include <stdio.h> #include <rcl/rcl.h> #include <rcl/error_handling.h> #include <rclc/rclc.h> #include <rclc/executor.h> #include <std_msgs/msg/int32.h> rcl_publisher_t publisher; std_msgs__msg__Int32 msg; rclc_executor_t executor; rclc_support_t support; rcl_allocator_t allocator; rcl_node_t node; rcl_timer_t timer; #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}} #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}} void error_loop(){ while(1){ delay(100); } } void timer_callback(rcl_timer_t * timer, int64_t last_call_time){ (void)last_call_time; if (timer != NULL){ msg.data++; RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL)); } } void setup() { // 方式一:串口模式,用板载USB口 set_microros_serial_transports(Serial); // 方式二:WiFi模式,取消注释并替换SSID、密码、Agent IP、端口 // IPAddress agent_ip(192, 168, 1, 100); // uint16_t agent_port = 8888; // set_microros_wifi_transports("你的WiFiSSID", "你的WiFi密码", agent_ip, agent_port); delay(1000); allocator = rcl_get_default_allocator(); // 创建init_options RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); // 创建节点 RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support)); // 创建发布者,话题名micro_ros_arduino_node_publisher,消息类型Int32 RCCHECK(rclc_publisher_init_best_effort( &publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), "micro_ros_arduino_node_publisher")); // 创建1秒定时器 const unsigned int timer_timeout = 1000; RCCHECK(rclc_timer_init_default(&timer, &support, RCL_MS_TO_NS(timer_timeout), timer_callback)); // 创建执行器 RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator)); RCCHECK(rclc_executor_add_timer(&executor, &timer)); msg.data = 0; } void loop() { RCCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100))); delay(1); }这个代码干了三件事:初始化节点、建立一个话题发布者micro_ros_arduino_node_publisher、然后每秒钟把计数器数值加1并发布出去。你不需要理解每一行,先烧进去看到它跑起来,后面再慢慢啃细节。
3.2 编译烧录的正确姿势
把代码复制到Arduino IDE后,先在工具 -> 开发板里确认选对了你的板子型号,然后按上面说的把分区表改成Huge APP。接着选择端口号:Windows下一般是COM口,Linux下通常是/dev/ttyUSB0,macOS下可能是/dev/cu.usbserial-xxx。
点上传按钮后,首次编译会比较慢,我实测在几年前的笔记本上要等差不多两分钟,期间CPU占用会很高,别以为卡死了。Arduino IDE编译micro-ROS固件时要处理一大批micro-ROS生成的头文件,这个过程没法跳过。
如果一切顺利,Arduino IDE会显示“Done uploading”。如果卡在“Connecting...”,说明板子没有自动进入下载模式。这时候按住开发板上的BOOT键不松手,再点一次上传,Arduino IDE开始连接时再松开BOOT键,基本就能成功。这个方法我在ESP32和ESP32-S3上都验证过,成功率接近100%。
烧录完成后,Arduino IDE的串口监视器会自动重连。注意此时串口监视器会占用串口,如果你要用micro-ROS的串口模式连Agent,监视器必须关掉,否则两者会抢串口。
3.3 串口监视器上出现这些日志就说明初始化对了
打开串口监视器,波特率选115200,然后按一下ESP32的RESET键。正常启动时,串口会输出类似下面的日志:
... Micro ROS initialized这行日志是micro_ros_arduino库在rclc_support_init成功后自动打印的,看到它说明ESP32已经成功和Agent建立连接,节点和发布者都初始化完成了。
如果没看到任何日志,先检查串口监视器的波特率是否正确,再看板子是否真的重新启动了。如果看到一堆乱码,通常是烧录时Flash Mode选错,或者USB转串口芯片的供电不稳,换一根短一点的USB线往往能解决。
另一种情况是无法建立连接,串口会反复打印重试日志。这是因为ESP32上的micro-ROS客户端在初始化时发现连不上Agent,会一直重试。此时不影响编译烧录,说明问题出在Agent那一端,接下来我们处理。
4. Agent端串口和WiFi两种连接实测
4.1 串口连接:共地、波特率、设备权限
串口是最稳定也最容易排查的通信方式。如果你用的是ESP32开发板,板载USB转串口芯片(CP2102、CH340等)已经帮你把USB信号转换好了,直接用USB线连接电脑即可。
启动Agent前,先确认串口没有被占用。在Linux下可以用这个命令查看:
ls /dev/ttyUSB*如果显示/dev/ttyUSB0,再确认权限:
ls -l /dev/ttyUSB0如果用户没有dialout组权限,Docker运行时会报“cannot open /dev/ttyUSB0: Permission denied”。处理方式是把当前用户加入dialout组,然后重新登录:
sudo usermod -aG dialout $USER接着启动micro-ROS Agent。我用的是Docker镜像,命令如下:
docker run -it --rm \ -v /dev/ttyUSB0:/dev/ttyUSB0 \ --device=/dev/ttyUSB0 \ microros/micro-ros-agent:humble \ serial --dev /dev/ttyUSB0 -b 115200这里解释一下参数的含义:-v /dev/ttyUSB0:/dev/ttyUSB0是把宿主机的串口设备映射进容器,--device是把物理设备直接透传给容器,两者配合才能让容器内的Agent读取串口数据。如果少了映射,Agent会在容器里根本找不到这个设备。
启动后,Agent会阻塞等待,日志停在等待连接的界面。此时按下ESP32的RESET键,让固件重新初始化客户端。几秒后,Agent会打印类似“client connected”的日志,说明握手成功。
如果你是外部USB转TTL模块接ESP32的UART,而不是用板载USB口,必须注意把模块的GND和ESP32的GND连在一起。否则两边电平参考不一样,即使波特率一致也会出现随机乱码或连接超时。硬件上最稳的做法是共地后,将模块的TX接ESP32的RX,模块的RX接ESP32的TX,交叉连接。
4.2 WiFi连接:网络发现机制和网段注意点
串口连接虽然稳,但没法做无线节点。接下来看WiFi方式。ESP32端需要把setup里的set_microros_serial_transports换成WiFi传输,并指定Agent的IP和端口:
IPAddress agent_ip(192, 168, 1, 100); uint16_t agent_port = 8888; set_microros_wifi_transports("你的WiFiSSID", "你的WiFi密码", agent_ip, agent_port);这里有几个特别容易踩的坑。第一个是ESP32不支持5GHz频段,如果你的路由器开了双频合一,手机连的可能是5GHz,而ESP32只能连2.4GHz,结果就是你手机能上网,ESP32却连不上WiFi。解决方法是把SSID分开或者临时开一个2.4GHz的手机热点测试。
第二个是Agent的IP地址必须填对。ESP32需要主动向Agent的IP和端口发起UDP连接,如果IP填错,心跳包根本送不到。可以用ip addr或ipconfig查一下开发机的局域网IP,然后填进去。
Agent端在Linux下推荐用--net=host方式启动:
docker run -it --rm --net=host microros/micro-ros-agent:humble udp4 --port 8888--net=host让容器直接共享主机的网络栈,这样Agent既能正常接收ESP32发来的UDP广播,也能用标准DDS和ROS 2通信。在Windows的Docker Desktop上,--net=host支持不完整,跑WiFi模式容易出问题,这也是我建议能用串口就先用串口的原因之一。
4.3 用Docker跑Agent的完整命令,以及日志怎么看
把两种方式的完整命令汇总一下:
# 串口模式(Linux示例) docker run -it --rm \ -v /dev/ttyUSB0:/dev/ttyUSB0 \ --device=/dev/ttyUSB0 \ microros/micro-ros-agent:humble \ serial --dev /dev/ttyUSB0 -b 115200 # WiFi模式(UDP4) docker run -it --rm --net=host \ microros/micro-ros-agent:humble \ udp4 --port 8888Agent日志里的关键信息有这么几类,我总结成一张表:
| 日志内容 | 含义 | 下一步 |
|---|---|---|
client connected | ESP32已和Agent握手成功 | 去ROS 2端执行ros2 topic list |
create session | 会话建立中 | 等待即可,正常会出现 |
unknown stream | 协议版本不匹配 | 检查Agent镜像标签和库版本是否都是Humble |
timeout | 连接超时 | 检查网段/串口/Agent是否被占用 |
Permission denied | 串口权限不足 | 加入dialout组或加--privileged |
连接成功后,就可以去ROS 2环境里验证了。在另一个终端执行:
source /opt/ros/humble/setup.bash ros2 topic list你会看到/micro_ros_arduino_node_publisher这个话题。再执行:
ros2 topic echo /micro_ros_arduino_node_publisher每秒钟能看到一次data: 数值的输出。到这里,你已经成功让ESP32走进了ROS 2的世界。
5. 高频问题和排查技巧实录
5.1 Agent收不到节点的“establish session error”
这个问题在串口模式下非常高频。现象是ESP32串口日志一直刷初始化失败,Agent端什么输出都没有,或者出现establish session error。
我遇到过的原因有四种:
第一种是串口被占用。Arduino IDE的串口监视器开着,Agent再去打开同一个串口,两边抢资源,结果谁都连不上。关闭串口监视器再重启Agent就好。
第二种是波特率不匹配。ESP32端set_microros_serial_transports默认用的是Serial的初始化波特率,也就是Agent命令里的-b 115200。如果Agent用了9600而固件端是115200,握手必然失败。解决办法是保持两边都是115200。
第三种是Agent容器没有正确映射串口。Docker命令里漏了-v或--device,容器内看不到设备。可以在容器里执行ls /dev/ttyUSB*确认一下,或者把挂载参数补齐后重试。
第四种比较隐蔽,是板子的USB转串口芯片和micro-ROS客户端在硬件串口上冲突。有些开发板的USB口虽然显示为串口,但走的是内置USB CDC,和Arduino核心里的Serial不是同一个底层。这种情况建议换用外部USB转TTL模块接到ESP32的UART2上,并在代码里用Serial2初始化:
set_microros_serial_transports(Serial2);烧录时依旧用板载USB口,运行时把USB-TTL模块插到电脑上当作通信串口,物理上分开,逻辑瞬间清晰。
5.2 编译报错一长串头文件找不到
在Arduino IDE里编译micro-ROS工程时,最常见的报错是一大串:
fatal error: micro_ros_utilities/string_utilities.h: No such file or directory这个错误几乎可以断定是micro_ros_arduino库版本不匹配。Arduino IDE的库管理器如果装了多个版本,编译时include路径可能指向了错误的版本。我的建议是先把库管理器里micro_ros_arduino相关的所有版本卸载干净,然后手动选择2.0.5-humble版本重新安装。
另一个不太常见但真实存在的原因是:你在编译一个从别处拷贝的工程,工程文件里残留了旧的库缓存。Arduino IDE 2.x会在~/Arduino/libraries下保留之前解压的库目录,如果这里存在多个版本,干脆手动删除旧目录,只留下你选择的版本。
5.3 烧录失败/一直重启的“按Boot键”解法
如果你在Arduino IDE里点击上传,提示timed out waiting for packet header或者一直循环Connecting...,说明ESP32没有进入下载模式。
ESP32的正常下载模式需要芯片在复位时检测到专用引脚的电平。自动下载电路通过DTR和RTS两个信号控制,但不同开发板的自动下载电路质量参差不齐,尤其是一些山寨板,时序不对就进不了下载模式。
最佳解法还是手动干预:按住BOOT键,然后点上传,看到Connecting...出现后马上松开BOOT键。我实测过,十次有九次都能成功。
还有一种情况是,烧录成功后板子不停重启,串口日志里循环打印错误或“Guru Meditation Error”。这大概率是分区表不对,尤其是编译产物超过默认APP分区容量时,固件被截断,启动后直接炸。重新按2.3节把分区表改成Huge APP再烧一次,基本能解决。
5.4 话题能看到但数据为空怎么办
连接成功后,ros2 topic list能列出/micro_ros_arduino_node_publisher,但ros2 topic echo收不到数据。这种问题在WiFi模式下更容易出现。
首先确认发布频率是否正常。上面的代码是1秒发一条,如果你改了代码后没有重新烧录,那自然看不到更新。接着检查WiFi信号强度,ESP32如果离路由器太远,UDP包大量丢失,Agent偶尔会漏掉数据。可以用ping ESP32的IP看延迟和丢包率,延迟大于几十毫秒就该挪位置或加路由器。
还有一种情况特别容易忽略:代码里用了rcl_publish,但发布的是Best Effort QoS,而你在ROS 2端用默认的Reliable QoS去订阅,两边QoS不匹配,数据会被DDS层过滤掉。处理方式是把ROS 2端订阅的QoS也改成Best Effort,或者反过来把ESP32端的发布策略改成Reliable。我在代码里用的是rclc_publisher_init_best_effort,你在ROS 2端可以这样订阅:
ros2 topic echo /micro_ros_arduino_node_publisher --qos-reliability best_effort这样就能正常看到数据了。
5.5 问题速查表
把前面提到的高频问题整理成一张速查表,建议截图保存:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| PlatformIO创建工程卡0% | 下载平台索引/工具链慢 | 换用Arduino IDE,或配置好镜像加速 |
| 镜像拉不下来 | 网络波动/标签错误 | 配置Docker镜像加速器,确认humble标签 |
| 编译报头文件缺失 | micro_ros_arduino版本不匹配 | 卸载后安装2.0.5-humble版本 |
| 上传卡在Connecting | 板子没进下载模式 | 按住BOOT键再上传 |
| 烧录后反复重启 | 分区表放不下固件 | 改成Huge APP分区 |
| Agent握手失败 | 串口占用/波特率不对/权限不足 | 关闭串口监视器,统一115200 |
| topic能看到但echo为空 | QoS不匹配/WiFi丢包 | 用best_effort订阅,检查WiFi信号 |
| ESP32连不上WiFi | 不支持5GHz/SSID混淆/密码错 | 用2.4GHz热点测试,确认SSID密码 |
我在实际使用中还有一个体会:如果你要长期做micro-ROS开发,最好还是把Linux + Docker + Arduino IDE这套组合固定下来,Windows下也能跑通,但串口设备、Docker网络模式的坑明显比Linux多。另外,micro-ROS调试最好“先串口后WiFi”,串口把数据链路打通了,再去切WiFi,问题定位会容易很多。
从PlatformIO切到Arduino IDE,我整个过程只花了一个晚上,但把上面这些坑一个一个记录下来用了更久。如果你跟我一样对PlatformIO有感情,可以把Arduino IDE当作一个轻量调试工具用,等工程复杂度上来,再切回PlatformIO或者直接用ESP-IDF也不迟。想继续深挖的话,可以试着让ESP32同时发布温湿度传感器数据、订阅一个控制指令去驱动电机,或者把OTA升级通道和micro-ROS的Agent控制逻辑结合起来,玩法会越来越多。