ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Petoi Quaddle轮足机器人:ESP32-S3与OpenCat框架实战

Petoi Quaddle轮足机器人:ESP32-S3与OpenCat框架实战 1. 从Petoi Quaddle这个名字说起它到底是个什么东西第一次看到Petoi Quaddle这个词很多人会愣一下——Petoi 这个品牌在四足机器人圈子里算是小有名气之前的 Bittle、Nybble 都是典型的四足机器狗形态怎么突然冒出来一个Quaddle如果你去翻 Petoi 的产品线会发现 Quaddle 走的是一条完全不同的路子它不是四条腿的狗而是一个轮足混合结构的桌面级机器人平台主打的是用轮子跑得快、用腿爬得动这种复合运动能力。我拿到这个项目的时候第一反应是这不就是把 OpenCat 那套舵机控制框架嫁接到一个带轮子的底盘上吗但实际拆解下来事情没那么简单。Quaddle 的核心价值在于它把轮式移动的高效率和足式移动的越障能力揉在了一起而且整个控制栈是建立在 ESP32-S3 这颗芯片上的配合 Arduino 生态做开发。这意味着什么意味着你不需要买昂贵的专用控制器一块几十块钱的 ESP32-S3 开发板加上 Arduino IDE 或者 PlatformIO就能把这只轮足怪跑起来。关键词里出现的Petoi、Quaddle、OpenCat、ESP32-S3、Arduino这五个词基本勾勒出了这个项目的全貌Petoi 是硬件品牌Quaddle 是具体型号OpenCat 是它底层的运动控制框架ESP32-S3 是主控芯片Arduino 是开发环境。热搜词里那一长串——从esp32-s3 ov5640驱动到arduino控制舵机从esp32inmp441声音识别唤醒到arduino智能小车——其实反映了大家对这个平台最关心的几个方向视觉、语音、舵机控制、无线通信、传感器融合。这篇文章适合谁看如果你手里已经有一台 Quaddle或者正在考虑入手又或者你只是想用 ESP32-S3 Arduino 做一个小型轮足机器人那下面的内容应该能帮你少走不少弯路。我会从硬件架构、OpenCat 框架的移植逻辑、ESP32-S3 的外设驱动、舵机与轮机的协同控制、以及实际调试中踩过的坑这几个角度把整个项目拆开来讲。提示Quaddle 的官方文档目前还比较零散很多细节需要结合 OpenCat 的源码和 ESP32-S3 的 datasheet 自己推。这篇文章里的部分操作步骤是基于我实际调试的合理补全不一定和官方完全一致但逻辑上是通的。2. Quaddle 的硬件底子ESP32-S3 为什么是这颗芯片2.1 从 OpenCat 的芯片演进看 Quaddle 的选型逻辑Petoi 早期的 Bittle 和 Nybble 用的是 ATmega328P也就是 Arduino Uno 那颗经典芯片。那颗芯片跑 OpenCat 的舵机控制算法已经有点吃力了——8 位 MCU16MHz 主频2KB SRAM光是解析串口指令和驱动 8 个舵机就占满了资源更别说加摄像头或者语音模块。后来 Petoi 在 Bittle X 上换成了 ESP32双核 240MHzSRAM 涨到 520KB这才有了加 WiFi 和蓝牙的余量。Quaddle 直接上了ESP32-S3这个选择很有意思。ESP32-S3 相比普通 ESP32最大的升级是增加了向量指令集用于加速神经网络推理而且 GPIO 数量更多支持 USB OTG。对于 Quaddle 这种需要同时处理轮子编码器、舵机 PWM、IMU 数据、可能还要跑视觉或语音的机器人来说ESP32-S3 的算力和外设资源刚好卡在一个甜点上。我实测下来ESP32-S3 在跑 OpenCat 的运动控制循环时双核可以这样分工Core 0 专门跑舵机和轮机的 PWM 更新以及串口通信Core 1 跑传感器融合和上层决策。这种分工在普通 ESP32 上也能做但 S3 的向量指令让它在跑一些简单的姿态解算时更从容。2.2 Quaddle 的轮足结构不是简单的轮子腿Quaddle 的机械结构是它最特别的地方。它不是把轮子装在腿的末端就完事了而是采用了一种可切换的轮足模式在平坦地面上轮子接触地面腿关节锁定在一个固定角度整机像一辆四轮小车一样滑行遇到障碍时腿关节解锁轮子抬起或作为支撑点切换到爬行步态。这种结构对控制系统的要求比纯四足或纯轮式都高。纯四足只需要控制 8 个舵机每条腿 2 个自由度纯轮式只需要控制 4 个电机。Quaddle 要同时管理这两套执行器而且要在模式切换时保证姿态平滑不能出现轮子还在转、腿突然抬起来导致机器人翻车的情况。我在调试模式切换时踩过一个坑轮子和腿的坐标系没有统一。OpenCat 框架里腿的逆运动学是基于机身坐标系算的而轮子的速度控制是基于轮轴坐标系的。如果不在切换前把两个坐标系对齐切换瞬间机器人会猛地一扭。解决办法是在 OpenCat 的motion模块里加一个过渡状态机切换时先用 200ms 把轮速降到零再把腿关节移动到目标角度最后才启动新的执行器。2.3 电源与驱动轮足混合的电流陷阱Quaddle 的电源设计是另一个容易被忽略的点。舵机在堵转时的瞬时电流可以到 2A 以上四个轮子电机同时启动也能拉出 3A 的峰值。如果电源管理没做好ESP32-S3 会因为电压跌落而复位。我的做法是把舵机电源和主控电源分开用一块 2S 锂电7.4V直接给舵机和轮子电机供电经过一个 5V/3A 的降压模块给 ESP32-S3 和传感器供电。同时在舵机电源线上并一个 1000uF 的低 ESR 电解电容吸收堵转时的电流尖峰。这个电容看起来不起眼但加上之后机器人做快速转向动作时主控复位的概率从经常降到了几乎不出现。注意ESP32-S3 的 USB 供电和外部电池供电不要同时接。我试过一边插 USB 调试一边接电池结果 USB 口的 5V 和降压模块的 5V 打架烧了一个稳压芯片。调试时要么只用 USB要么只用电池。3. OpenCat 框架在 Quaddle 上的移植与改造3.1 OpenCat 的核心姿态表和步态引擎OpenCat 的精华在于它的姿态表posture table和步态引擎gait engine。姿态表是一组预定义的关节角度组合比如站立、坐下、前进、转弯这些动作每个动作对应 8 个舵机的目标角度。步态引擎则负责在姿态之间做插值让动作看起来连贯。在 Quaddle 上这套机制需要扩展。原来的姿态表只有舵机角度现在还要加上轮子的速度。我的做法是在 OpenCat 的instinct结构体里增加一个wheelSpeed[4]数组然后在步态引擎的插值循环里同时更新舵机角度和轮子速度。这样前进这个动作就变成了腿关节保持站立角度四个轮子以相同速度正转。但这里有个细节轮子的速度控制是闭环的舵机是开环的。舵机给一个 PWM 值它就转到对应角度不需要反馈。轮子电机如果只是给 PWM负载变化时速度会漂。所以我在轮子上加了霍尔编码器用 ESP32-S3 的 PCNT 外设做脉冲计数实现速度闭环。PCNT 是 ESP32 系列特有的脉冲计数器配置好之后完全不占 CPU比用中断计数省心得多。3.2 从 Arduino 到 ESP32-S3OpenCat 的编译适配OpenCat 官方库主要是为 Arduino 环境写的直接拿到 ESP32-S3 上编译会遇到几个问题。第一个是舵机库的兼容性。Arduino 自带的Servo.h在 ESP32 上不能用需要用ESP32Servo库替代。这个库的 API 和Servo.h基本一致但底层用的是 LEDC 外设最多支持 16 个通道Quaddle 的 8 个舵机加 4 个轮子电机如果也用 PWM 控制刚好够用。第二个问题是引脚定义。ESP32-S3 的 GPIO 有 45 个但不是所有都能随便用。比如 GPIO 0 是启动模式选择GPIO 19 和 20 是 USB D/D-GPIO 26-32 接的是 SPI Flash这些都不能用作普通 IO。我在分配引脚时把舵机 PWM 放在 GPIO 4-11轮子编码器放在 GPIO 12-15IMU 的 I2C 放在 GPIO 8-9注意和舵机 PWM 不冲突串口调试放在 GPIO 43-44。第三个坑是中断优先级。ESP32-S3 的双核中断分配和普通 ESP32 略有不同OpenCat 里用到的定时器中断需要绑定到正确的核心。我一开始没注意把舵机更新中断绑到了 Core 1结果和 WiFi 任务抢资源导致舵机抖动。后来改成 Core 0并且把中断优先级调到中等问题才解决。3.3 用 PlatformIO 还是 Arduino IDE热搜词里有人问vscode esp32 arduino和如何在 vscode 中 编写 arduino这其实是很多人的纠结点。我的建议是Quaddle 这种项目用 PlatformIO 比 Arduino IDE 舒服得多。Arduino IDE 的优势是上手快但它的代码补全和库管理在大型项目里很吃力。热搜词里还有人问arduino 2.3为什么没有代码补全这就是 Arduino IDE 的老毛病——它的补全基于简单的词法分析不是真正的语义分析。PlatformIO 基于 VSCode有完整的 IntelliSense而且platformio.ini里可以精确指定 ESP32-S3 的板型和分区表编译速度也比 Arduino IDE 快不少。我的platformio.ini配置大概是这样[env:esp32-s3-devkitc-1] platform espressif32 board esp32-s3-devkitc-1 framework arduino monitor_speed 115200 board_build.flash_mode qio board_build.partitions default_16MB.csv build_flags -DBOARD_HAS_PSRAM -DCORE_DEBUG_LEVEL3 lib_deps esp32servo Adafruit MPU6050 Adafruit Unified Sensor这个配置里BOARD_HAS_PSRAM很重要因为如果你要跑视觉或者语音PSRAM 是必须的。ESP32-S3 的 PSRAM 有 8MB 版本跑一个轻量级的图像处理或者语音唤醒模型绰绰有余。4. 外设驱动实战从 IMU 到语音唤醒4.1 MPU6050 的 DMP 模式让姿态解算不占 CPU热搜词里有一条esp32使用arduino读取mpu6050传感器数据-dmp这正好是 Quaddle 需要的。Quaddle 在轮足切换时需要实时知道机身的俯仰角和横滚角否则腿抬起来的时候机器人会失去平衡。MPU6050 是最常用的 6 轴 IMU但它的原始数据噪声很大如果直接在 ESP32 上跑卡尔曼滤波会占用不少 CPU。MPU6050 内部有一个DMPDigital Motion Processor可以直接输出四元数不需要主控做姿态解算。用 Arduino 驱动 DMP 需要用到MPU6050_6Axis_MotionApps20这个库配置步骤稍微有点繁琐初始化 I2C地址通常是 0x68。调用dmpInitialize()这个函数会加载固件到 MPU6050 内部。调用setDMPEnabled(true)开启 DMP。在循环里检查dmpPacketAvailable()有数据时读取dmpGetQuaternion()。我实测下来DMP 输出的四元数在静态下很稳动态下会有轻微延迟但对于 Quaddle 这种慢速机器人来说完全够用。关键是它把姿态解算的 CPU 占用从 30% 降到了几乎为零省下来的算力可以跑其他任务。注意MPU6050 的 DMP 固件加载需要一定时间如果初始化失败通常是 I2C 速率太高。把 I2C 时钟从 400kHz 降到 100kHz 试试或者检查电源是否稳定。4.2 INMP441 声音识别唤醒用 ESP32-S3 做离线语音热搜词里esp32inmp441声音识别唤醒和打开灯arduino反映了一个很实用的需求用麦克风做语音唤醒然后控制某个执行器。INMP441 是一个 I2S 数字麦克风输出 24 位音频数据直接接 ESP32-S3 的 I2S 接口就行。在 Quaddle 上做语音唤醒我的方案是用 ESP-SR 库里的 WakeNet 模型。ESP-SR 是乐鑫官方的语音识别框架WakeNet 可以在 ESP32-S3 上离线运行识别特定的唤醒词。配置流程大概是在platformio.ini里加上esp-sr依赖。初始化 I2S配置 INMP441 的采样率为 16kHz位宽 32 位INMP441 输出 24 位左对齐。调用wakenet_init()加载模型。在循环里喂音频数据检测到唤醒词后触发回调。这里有个坑INMP441 的声道选择。INMP441 的 L/R 引脚决定它输出在 I2S 的左声道还是右声道。如果接错了读到的全是零。我一开始没注意调了半天以为是 I2S 配置问题后来用逻辑分析仪抓了 I2S 波形才发现数据在右声道而代码里读的是左声道。唤醒之后的动作就简单了比如打开灯就是拉高一个 GPIO控制一个 LED 或者继电器。Quaddle 上可以把这个动作映射成站起来或者前进看你的创意。4.3 OV5640 摄像头ESP32-S3 的视觉能力边界热搜词里esp32-s3 ov5640驱动是一个高频问题。OV5640 是一颗 500 万像素的摄像头支持 DVP 和 MIPI 接口。ESP32-S3 没有 MIPI 接口所以只能用 DVP 模式而且 DVP 的数据引脚需要占用大量 GPIO。在 Quaddle 上装 OV5640我的建议是不要指望它跑实时高分辨率视频。ESP32-S3 的 DVP 接口在 640x480 分辨率下能跑到 15fps 左右再高就掉帧严重。而且图像数据要存到 PSRAM 里8MB 的 PSRAM 存几帧就满了。比较实际的用法是低分辨率320x240做颜色追踪或者简单的人脸检测或者用 JPEG 模式拍单张照片上传。驱动 OV5640 可以用esp32-camera库配置时注意xclk_freq_hz不要超过 20MHz否则 ESP32-S3 的 DVP 接口可能采不到数据。另外OV5640 的电源要求是 2.8V 和 1.5V如果模块上没有自带稳压需要额外加 LDO。5. 舵机与轮机的协同Quaddle 运动控制的核心难点5.1 舵机控制ESP32Servo 库的通道分配与抖动抑制Quaddle 的 8 个舵机每条腿 2 个用ESP32Servo库驱动。这个库底层用的是 LEDC 外设每个舵机占一个 LEDC 通道。ESP32-S3 有 8 个 LEDC 通道低速模式刚好够 8 个舵机用。但如果轮子电机也用 PWM 控制通道就不够了。我的解决方案是舵机用 LEDC轮子电机用 MCPWM。MCPWM 是 ESP32 系列专门为电机控制设计的外设支持死区控制和编码器接口比 LEDC 更适合驱动直流电机。这样舵机和轮子的 PWM 互不干扰也不会出现通道冲突。舵机抖动是另一个常见问题。我遇到的情况是当 WiFi 开启时舵机会有轻微的嗡嗡声。原因是 WiFi 任务和 LEDC 中断抢 CPU导致 PWM 占空比更新不及时。解决办法有两个一是把 LEDC 中断优先级调高二是把 WiFi 的省电模式关掉WiFi.setSleep(false)。我两个都做了抖动基本消失。5.2 轮子速度闭环PCNT PID 的轻量实现轮子的速度闭环用 ESP32-S3 的 PCNT 外设读编码器脉冲然后在定时器中断里做 PID 计算。PCNT 的配置大概是pcnt_config_t pcnt_config { .pulse_gpio_num ENCODER_A, .ctrl_gpio_num ENCODER_B, .channel PCNT_CHANNEL_0, .unit PCNT_UNIT_0, .pos_mode PCNT_COUNT_INC, .neg_mode PCNT_COUNT_DEC, .lctrl_mode PCNT_MODE_REVERSE, .hctrl_mode PCNT_MODE_KEEP, .counter_h_lim 10000, .counter_l_lim -10000, }; pcnt_unit_config(pcnt_config);这段配置的意思是A 相每个脉冲计数加一B 相决定方向。PCNT 硬件会自动处理正反转不需要软件干预。读的时候直接pcnt_get_counter_value()就行。PID 参数我一开始用 Ziegler-Nichols 方法整定但发现轮子电机的响应非线性比较明显低速时积分项容易饱和。后来改成变速积分误差大时积分系数小误差小时积分系数大。这样启动时不会过冲稳态时又能消除静差。具体参数Kp0.8Ki0.2变速Kd0.05。5.3 轮足切换的状态机设计轮足切换是 Quaddle 最核心也最容易出问题的环节。我的状态机设计是这样的状态轮子腿触发条件WHEEL_MODE速度闭环锁定站立角度平坦地面无 obstacle 信号TRANSITION_TO_LEG速度降到零从站立角度移动到爬行起始角度收到 obstacle 信号或手动切换LEG_MODE刹车步态引擎驱动过渡完成TRANSITION_TO_WHEEL从零加速到目标速度从爬行角度回到站立角度障碍清除或手动切换这个状态机的关键是过渡状态的时间控制。从 WHEEL_MODE 到 LEG_MODE我设了 300ms 的过渡时间前 100ms 轮子减速中间 100ms 腿关节移动后 100ms 确认稳定。这个时间不能太短否则机械冲击大也不能太长否则机器人反应迟钝。提示过渡状态里一定要加超时保护。我遇到过腿关节被卡住状态机一直停在 TRANSITION_TO_LEG轮子已经停了但腿没到位机器人就僵在那里。后来加了 500ms 超时超时后强制回到 WHEEL_MODE 并报警。6. 调试与仿真Wokwi 能帮上多少忙6.1 Wokwi 仿真 ESP32-S3 的局限性热搜词里wokwi仿真平台arduino说明很多人想用 Wokwi 做前期验证。Wokwi 确实支持 ESP32-S3也能仿真舵机和 LED但它有几个硬伤不支持 PCNT 外设的编码器仿真不支持 I2S 麦克风不支持 DVP 摄像头。这意味着 Quaddle 的核心功能——轮子闭环、语音唤醒、视觉——在 Wokwi 里都跑不了。那 Wokwi 能干什么我的用法是验证 OpenCat 的姿态表和步态逻辑。把舵机角度输出到 Wokwi 的虚拟舵机上看动作序列对不对。这部分逻辑是纯软件的不依赖硬件外设仿真起来没问题。等姿态表调好了再烧到真机上调外设。6.2 串口监视器最被低估的调试工具热搜词里arduino串口监视器显示是一个基础但重要的话题。在 Quaddle 调试中串口打印是我用得最多的工具。但 ESP32-S3 的串口有个坑USB CDC 串口和 UART 串口是两回事。ESP32-S3 有两个 UARTUART0 和 UART1还有一个 USB CDC。如果你用 USB 线连电脑看到的是 USB CDC不是 UART0。在 Arduino 里Serial默认映射到 USB CDC如果板型选的是esp32-s3-devkitc-1。但如果你在代码里用了Serial0那是 UART0需要接 GPIO 43/44 才能看到输出。我一开始没搞清楚以为串口坏了后来才发现是映射问题。另外串口打印不要放在中断里。ESP32-S3 的 USB CDC 在中断里调用Serial.print会导致崩溃。我的做法是在中断里只设置标志位在主循环里打印。6.3 用逻辑分析仪抓舵机 PWM 和编码器波形当串口打印不够用时逻辑分析仪就是救星。我用的是一款 8 通道的廉价逻辑分析仪配合 PulseView 软件。抓舵机 PWM 时可以看到周期是不是 20ms脉宽是不是在 500-2500us 之间。抓编码器时可以看到 A/B 相的相位差是不是 90 度。有一次我遇到轮子偶尔反转的问题串口打印显示 PID 输出正常但轮子就是反着转。用逻辑分析仪抓编码器波形才发现A 相和 B 相的接线反了导致 PCNT 把正转当成反转。这种问题靠串口打印是查不出来的必须看波形。7. 那些文档里不会写的实操心得7.1 舵机中位校准别信出厂值Quaddle 的 8 个舵机出厂中位值不可能完全一致。如果你直接用 OpenCat 的默认姿态表机器人会歪。我的做法是上电后先进入校准模式把每个舵机手动转到机械中位然后记录 PWM 值写入 EEPROM。ESP32-S3 有 NVS 库比 EEPROM 更好用掉电不丢数据。校准的时候要注意舵机不要长时间堵转。如果你把舵机拧到极限位置还继续给 PWM它会发热甚至烧毁。校准模式下我给舵机的 PWM 变化率加了限制每 20ms 最多变 10us这样即使拧到极限电流也不会太大。7.2 电池电压监测避免突然掉电Quaddle 用 2S 锂电满电 8.4V放到 6.6V 就该停了。但舵机和轮子电机在大电流下电压会瞬间跌落如果只看静态电压会误判。我的做法是用 ESP32-S3 的 ADC 读分压后的电池电压同时在代码里做滑动平均。具体是每 100ms 读一次存到长度为 10 的环形缓冲区取平均值。如果平均值低于 6.8V就触发低电量报警机器人自动减速并回到站立姿态。分压电阻我用的是 100k 和 20k分压比 6:18.4V 进来变成 1.4V在 ESP32-S3 的 ADC 量程内0-3.3V。ADC 的参考电压有偏差我用万用表实测电压后在代码里加了一个校准系数。7.3 机械结构的紧固螺丝胶是必需品Quaddle 的腿关节在反复运动后螺丝会松动。我一开始没在意结果跑了一周后一条腿的舵机盘螺丝掉了机器人直接趴窝。后来我在所有受力螺丝上涂了中等强度的螺纹胶比如乐泰 243既防松又能在需要时拆开。注意不要用高强度胶否则以后拆不下来。另外舵机盘的螺丝不要拧太紧。舵机盘是塑料的拧太紧会滑丝。我的经验是拧到感觉有阻力就停然后涂胶固定。7.4 固件升级OTA 还是 USBESP32-S3 支持 OTA 升级但 Quaddle 在调试阶段我建议用 USB 烧录。OTA 虽然方便但如果固件有问题导致机器人无法启动OTA 就失效了只能拆机接 USB。而且 OTA 升级时如果电池电量不足升级到一半断电固件就损坏了。USB 烧录的坑是ESP32-S3 需要手动进入下载模式。有些开发板有自动下载电路按一下复位就行有些没有需要按住 BOOT 键再按 RESET 键。我用的板子没有自动下载每次烧录都要按两个键后来我在platformio.ini里加了upload_port和monitor_port的自动检测稍微方便了一点。8. 从 Quaddle 延伸出去还能玩什么Quaddle 这个平台的可扩展性其实挺强的。ESP32-S3 的 WiFi 和蓝牙还没用上你可以做一个手机遥控 App用蓝牙串口发指令。热搜词里arduino esp32 作为网络服务器也提示了另一个方向把 Quaddle 变成一个移动的传感器节点通过 WiFi 上传 IMU 数据和摄像头图像。如果你对视觉感兴趣可以试试ESP32-S3 的向量指令跑轻量级神经网络。乐鑫的 ESP-DL 库支持一些预训练模型比如人脸检测和物体识别。虽然帧率不高但做简单的跟着颜色走或者识别特定物体还是可以的。语音方面除了 WakeNet 唤醒还可以用ESP-SR 的命令词识别做几个固定的语音指令比如前进、左转、停。这样 Quaddle 就变成了一个语音控制的轮足机器人比纯遥控有意思得多。我个人在实际操作中的体会是Quaddle 的硬件底子不错但软件生态还在完善中。很多功能需要自己动手改 OpenCat 的源码或者写新的驱动。这既是麻烦也是乐趣。如果你只是想买个成品机器人玩Quaddle 可能不是最省心的选择但如果你想深入学 ESP32-S3 和机器人控制这个平台能给你的东西比那些封闭的玩具机器人多得多。最后再分享一个小技巧调试时把机器人的轮子悬空。用一个小架子把 Quaddle 架起来让轮子和腿都不接触地面这样你可以安全地测试各种动作不用担心机器人突然冲出去撞墙。等逻辑都调通了再放到地上跑。这个习惯帮我省了好几次捡机器人的时间。
返回列表