ARTICLE DETAIL

资讯详情

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

富斯遥控器接入ROS机器人:从PPM/IBUS到cmd_vel完整方案

富斯遥控器接入ROS机器人:从PPM/IBUS到cmd_vel完整方案 把富斯遥控器FlySky接入ROS机器人是我在调试小车项目时做得最值的一件事。之前每次想微调机器人姿态要么抱着笔记本敲键盘、要么蹲在地上改参数后来用一台富斯FS-i6X加一个几十块钱的接收机直接把遥控器变成无线手柄油门杆、转向杆、急停开关全部映射到ROS的cmd_vel话题上整个调试效率立刻不一样了。这篇内容就是完整记录我从硬件接线、PPM/IBUS信号解析、Arduino采集、串口通信到ROS 2节点编写和整车标定的全部过程适合正在做ROS小车、想摆脱键盘控制或者准备参加机器人竞赛的朋友参考。先说结论这套方案不复杂核心难点不在遥控器而在信号解析和ROS端的消息转换踩过坑之后你会发现它比想象中稳定得多。1. 项目整体设计与方案选型1.1 这个项目到底解决了什么问题做ROS机器人的同学应该都有过这种体验在Gazebo仿真里用键盘控制小车很舒服一旦搬到实体车上键盘控制就变得极其别扭。键盘只有离散的按键按一下走一下没法做到平滑的无级调速手机App控制延迟又大而且依赖WiFi环境手柄虽然手感好但配对和驱动折腾一圈也要不少时间。富斯遥控器这类航模遥控设备本质上就是一个专业的无线模拟量输入设备。它的摇杆输出的是连续的脉宽信号PWM/PPM没有蓝牙配对问题没有WiFi依赖还自带物理急停开关可靠性远高于普通游戏手柄。把富斯遥控器接入ROS机器人后我能直接用手柄摇杆控制小车前进后退、左右转向还能用遥控器上的开关一键急停这在调试阶段救了我好几次至少三次差点撞墙都是靠急停拉回来的。这个项目适合的人群非常明确正在做ROS小车DIY、搞机器人竞赛、或者需要频繁在实体机器人上调试运动控制的开发者。只要你能接受用航模遥控器替代键盘后面这套流程基本是通用的换不同的机器人底盘只需要改速度和转向的映射关系。1.2 整体架构与方案选型整个系统的数据流是单向的遥控器发送2.4G信号给接收机接收机输出PPM或IBUS信号单片机Arduino/ESP32负责采集并解析摇杆通道数据然后通过串口USB转TTL发给运行ROS的电脑ROS节点把数据换算成线速度和角速度最终发布到/cmd_vel话题由底盘驱动节点消费。刚开始我也纠结过两个方案。第一个方案是用接收机的PWM输出直接接电机驱动板绕开ROS用硬件PWM控制电机第二个方案才是现在用的方式即让单片机做协议转换把所有控制信号以数据帧形式喂给ROS由ROS做运动学解算。最终我选了第二种原因很简单直接把PWM接到驱动板上虽然响应快但完全脱离了ROS体系没法在Gazebo仿真和实车之间无缝切换也没法利用ROS的代价地图、导航栈这些功能。而让ROS作为中间层仿真验证过的导航代码可以直接用在真车上遥控器只是提供了一个灵活的外部控制输入来源。桥接主控板选型上我对比了Arduino Nano、ESP32和STM32。Arduino Nano最省事5V供电兼容接收机外部中断采PPM很稳定配一个USB转TTL模块就行ESP32的优势是自带WiFi和蓝牙如果你后续想用micro-ROS走无线模式ESP32是首选STM32则适合你希望把信号采集和运动控制集成在同一个小板子上的场景。我自己的项目最终用了ESP32因为后面计划加micro-ROS无线方案一个板子两用不用反复改硬件。如果你的目标是快速跑通流程Arduino Nano 串口模块是最低成本的选择。2. 硬件选型与通信协议细节2.1 富斯遥控器和接收机怎么选富斯FlySky遥控器目前市面上用得最多的两代产品是FS-i6和FS-i6X。FS-i6的优点是便宜6通道够用FS-i6X多了几个辅助旋钮和开关支持扩展更多通道价格差距不大我建议直接上i6X多出来的两个三档开关和旋钮在机器人上非常实用可以用一个开关做急停一个旋钮做最大速度限制这个在后期调试机器人时价值很大。接收机方面和i6X匹配的是FS-IA6B或者FS-IA6C。IA6B是经典款带PPM输出功能通过一个跳线帽切换PWM/PPM模式IA6C价格便宜但只支持PWM输出。如果你用的是Arduino/ESP32采集方案务必买IA6B因为PPM一根线就能传所有通道数据非常方便如果你打算用PWM直连驱动板IA6C也够用。富斯接收机在空旷环境下实测拉距上百米没问题室内穿一堵墙也不会丢信号作为遥控器控制机器人完全够用。遥控器到手后第一件事是设置机型。在FS-i6X的系统菜单里把机型设为“固定翼”Fixed Wing千万别设成直升机直升机会带油门曲线和混控输出信号会被遥控器自己改掉导致你采集到的脉宽不是原始摇杆值。这里我浪费过一下午时间一开始遥控器默认直升机模式油门推杆在中位上下输出不对称还以为接收机坏了。2.2 PWM、PPM、IBUS和SBUS到底该用哪个航模接收机输出有几种协议搞清楚它们的区别方案选型就成功了一半。最基础的是PWM每个通道一根信号线接收机为每个通道单独输出一个1~2ms的脉宽信号PPM是PWM的打包版把所有通道的脉宽按顺序排在一根线上帧与帧之间用大于3ms的高电平间隔隔开接收机内部已经完成了时间上的“时分复用”。IBUS是富斯的串口总线协议用一根线以串口方式把通道数据发出去数据格式是数字量而不是脉宽SBUS则是类似IBUS的总线协议但信号是反相的常用于航模飞控富斯接收机支持SBUS的相对少一些。从接线的简单程度来看对单片机方案PPM和IBUS是最优选择。PPM的好处是兼容性好几乎任何单片机都能用外部中断测量脉宽IBUS的好处是数据已经是数字格式不需要精确测量时间直接用串口读取即可抗干扰能力更强。实际项目里我优先推荐IBUS因为它对单片机实时性要求低而且富斯接收机的IBUS引脚和PPM共用一根线通过跳线帽切换电路改动最小。SBUS在这个方案里没必要碰如果你的接收机只有SBUS还要额外加反相电路纯属给自己找麻烦。协议选型还有个隐藏问题PPM的脉宽测量对单片机的中断响应时间有要求。如果单片机主循环里同时塞着PID控制、屏幕刷新这类高优先级任务中断响应抖动会导致脉宽测量误差忽大忽小。这也是为什么我建议用IBUS的原因——串口读取是硬件模块完成的通道分辨率远高于PPM。2.3 主控板选型Nano、ESP32、STM32谁更适合桥接桥接板的核心任务是采集接收机信号、解析、打包、通过串口发出去。这个任务对算力要求极低但对中断响应或串口资源有要求所以选型主要看接口和生态。Arduino Nano是最无脑的选择。它5V逻辑电平直接和接收机兼容不用电平转换外部中断引脚多采PPM很稳板子本身带USB转串口插上电脑就能识别成/dev/ttyUSB0。缺点是串口只有一个调试输出和数据传输容易抢资源我的解决办法是数据帧用Serial发送调试信息全部注释掉线上跑的时候不开调试输出避免费时丢帧。ESP32的优势是支持3.3V逻辑接收机5V信号要分压或用电平转换模块但换来的是WiFi/蓝牙能力。用ESP32做桥接时可以用HardwareSerial对应独立串口后续想升级micro-ROS方案不用换硬件。STM32则适合你把信号采集、运动学解算、电机驱动集成在一块的场合代价是开发周期长一些。我的建议很简单想快速跑通用Nano想兼顾后续无线能力用ESP32想集成到量产控制板再用STM32。3. 信号采集端的实现把摇杆变成串口数据3.1 Arduino端读取PPM信号我用Arduino Nano采PPM信号时的接线是这样的IA6B接收机跳线帽拔掉PPM信号从接收机“S”引脚引出接Nano的D2引脚接收机负极接Nano的GND正极接5V。注意这里的共地问题接收机和单片机必须共地否则信号电平没有参考基准读出来的脉宽一定是乱的。PPM读取原理不复杂每个通道的脉宽在1000到2000微秒之间通道与通道之间的间隔约300到500微秒帧与帧之间的间隔大于3000微秒。单片机用外部中断检测信号上升沿或下降沿两次跳变之间的时间差就是一个通道的脉宽值时间差大于阈值就认为是一帧结束。核心代码是这样的volatile unsigned long lastTime 0; volatile int ppmValues[8] {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; volatile int ppmIndex 0; void setup() { Serial.begin(115200); pinMode(2, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(2), ppmInterrupt, FALLING); } void ppmInterrupt() { unsigned long now micros(); unsigned long dt now - lastTime; lastTime now; if (dt 3000) { // 超过3ms认为一帧结束回到第一个通道 ppmIndex 0; return; } if (ppmIndex 0 ppmIndex 8) { ppmValues[ppmIndex] (int)dt; ppmIndex; } } void loop() { // 在这里把ppmValues打包成串口数据帧发送 }初始化时我把所有通道默认值设成1500即中位脉宽这样即使遥控器没开机程序也有一个安全的初始值不会直接输出满速信号。实际调试中这个细节很关键我第一次没做初始化接收机没上电时数组里全是0ROS端解析出负向最大速度差点让小车原地窜出去。Interrupt里的代码要尽量短不要做串口打印这类耗时操作否则会影响下一次中断响应的精度。PPM的脉宽测量精度取决于中断响应时间Nano在跑16MHz的时候实测能稳定到±10微秒对应转成ROS端的速度误差约0.02m/s完全够用。PPM模式需要把IA6B接收机跳线帽拔掉让PPM信号从IBUS引脚输出。富斯的IA6B接收机正面有一个跳线帽默认插在靠近边缘的位置此时为PWM输出拔出来之后第三个接口的S引脚就变成PPM输出。如果你用的是IA6C它没有PPM功能直接别买。3.2 用IBUS协议替代PPM省心又稳定如果不想处理中断时序强烈建议改用IBUS。富斯IBUS是串口协议波特率115200数据格式为每14毫秒发送一帧每帧32字节开头两个字节0x20 0x40是帧头后面是14个通道数据每通道2字节小端序最后两字节是CRC校验。实际使用中很多项目只用了前28字节CRC不校验也能工作但为了稳定我还是建议做一次累加和校验。Arduino Nano只有一个硬件串口接了IBUS就没法和ROS通信所以我用软串口来接收IBUS硬件串口负责和ROS通信#include SoftwareSerial.h SoftwareSerial ibus(10, 11); // RX, TX uint8_t ibusBuffer[32]; int channelValues[14]; void setup() { Serial.begin(115200); // 与ROS通信 ibus.begin(115200); // IBUS信号 } void loop() { if (ibus.available() 32) { ibus.readBytes(ibusBuffer, 32); // 解析14个通道每个通道2字节小端序 for (int i 0; i 14; i) { channelValues[i] ibusBuffer[i * 2 2] | (ibusBuffer[i * 2 3] 8); } // 发送给ROS } }实测软串口接收IBUS在Nano上完全稳定因为IBUS是定时发送的不需要高精度中断只需要及时读取缓冲区。这种方案的抗干扰性比PPM更好不会因为中断抖动导致通道值跳动。唯一要注意的是软串口在高波特率下容易丢字节IBUS的115200波特率刚好在Nano软串口的极限附近所以接线尽量短不要超过20厘米。如果你的桥接板选的是ESP32IBUS接入更简单直接用HardwareSerial(1)的UART1接收波特率115200同时UART0负责和ROS通信两个串口互不干扰代码和上面大同小异。ESP32的逻辑电平是3.3V富斯接收机输出的5V信号需要接一个分压电阻或者电平转换模块否则长期使用可能烧引脚。3.3 串口数据帧格式的设计与实现桥接板和ROS端之间的通信需要自定义一个数据帧。帧格式设计要简单、可靠、易解析。我用的是这个协议字节位置内容说明00xA5帧头110x5A帧头22通道个数目前是63~14通道值每通道2字节小端序单位微秒(1000~2000)15累加和前面所有字节求和取低8位帧头用两个固定字节是为了避免错位。通道值用1000到2000的脉宽值而不是转换后的速度值原因是把原始数据传给ROS具体怎么映射成速度由ROS端决定这样桥接板就与机器人底盘无关换一辆车也不用改单片机代码。Arduino端发送代码这样写uint8_t txBuf[16]; void sendFrame() { txBuf[0] 0xA5; txBuf[1] 0x5A; txBuf[2] 6; for (int i 0; i 6; i) { txBuf[3 i * 2] ppmValues[i] 0xFF; txBuf[4 i * 2] (ppmValues[i] 8) 0xFF; } uint8_t sum 0; for (int i 0; i 15; i) { sum txBuf[i]; } txBuf[15] sum; Serial.write(txBuf, 16); }发送频率设置在20Hz左右也就是50毫秒发一帧这个频率对应ROS端控制周期完全够用。20Hz的好处是即使丢一帧下一帧也在50毫秒内到达机器人运动轨迹不会有明显卡顿。如果频率太高比如200Hz会把USB转串口的缓冲区占满影响其他调试数据。3.4 ESP32 micro-ROS方案进阶玩法如果你不想让ROS运行在电脑上而是想让ESP32直接成为ROS 2的一个节点就是micro-ROS的玩法。ESP32通过WiFi接入ROS 2的micro-ROS Agent直接收发ROS 2消息。这个方案我在第二版机器上试过整体链路变成遥控器 → IA6B接收机 → ESP32读取IBUS → WiFi → micro-ROS Agent → ROS 2的/cmd_vel。micro-ROS环境搭建比串口方案麻烦不少需要在Ubuntu上装micro-ROS Agent在ESP32上用PlatformIO或者Arduino IDE编译micro-ROS固件。但好处很明显机器人本体少一根USB线走无线控制如果你机器人的主控本身就是ESP32直接省掉一个桥接板。热词里提到的“ros 2 humble micro-ros esp32”就是这个方向我在试的时候用的代码框架是micro_ros_arduino库发布geometry_msgs/Twist消息到/cmd_vel编译前需要把WiFi SSID、密码和Agent IP地址配置好这个后续有机会单独写一篇完整的micro-ROS移植记录。4. ROS端的软件实现从串口数据到cmd_vel4.1 环境准备Ubuntu 22.04 ROS 2 HumbleROS端我用的系统是Ubuntu 22.04ROS版本是ROS 2 Humble Hawksbill。如果你也是新装系统装ROS 2建议直接用鱼香ROS的一键安装脚本省去手动配置源和一堆依赖的折磨。这个脚本在“鱼香ROS”开源社区很常用你可以在终端执行wget http://fishros.com/install -O fishros . fishros脚本运行后会提示选择安装项输入对应序号选择“ROS 2 Humble”桌面版或基础版。跑完后记得source /opt/ros/humble/setup.bash然后验证一下ros2 run demo_nodes_cpp talker能正常打日志就说明环境没问题。ROS 2 Humble在Ubuntu 22.04上是原生版本依赖都能从apt源装到比ROS 1 Noetic更省心。4.2 串口读取与解析节点ROS端的核心是一个串口读取节点。为了减少依赖我没有用serial包直接用了Python的pyserial库配rclpy这样连接口、改波特率都更直观。安装依赖sudo apt install python3-serial节点代码的逻辑是打开串口循环读取16字节校验帧头和累加和解析出6个通道值然后根据映射关系计算线速度和角速度最后发布Twist消息。#!/usr/bin/env python3 import serial import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist class FlySkyTeleop(Node): def __init__(self): super().__init__(flysky_teleop) self.pub self.create_publisher(Twist, cmd_vel, 10) self.ser serial.Serial(/dev/ttyUSB0, 115200, timeout0.01) self.timer self.create_timer(0.05, self.read_and_publish) def read_and_publish(self): data self.ser.read(16) if len(data) 16: return if data[0] ! 0xA5 or data[1] ! 0x5A: return if sum(data[:15]) 0xFF ! data[15]: return channels [] for i in range(6): ch data[3 i * 2] | (data[4 i * 2] 8) channels.append(ch) twist Twist() # 左摇杆上下 - 线速度, 右摇杆左右 - 角速度 linear_raw channels[2] - 1500 angular_raw channels[1] - 1500 # 死区处理 if abs(linear_raw) 30: linear_raw 0 if abs(angular_raw) 30: angular_raw 0 twist.linear.x float(linear_raw) / 500.0 * 0.8 # 最大0.8m/s twist.angular.z float(angular_raw) / 500.0 * 2.0 # 最大2.0rad/s self.pub.publish(twist) def main(argsNone): rclpy.init(argsargs) node FlySkyTeleop() try: rclpy.spin(node) except KeyboardInterrupt: pass finally: node.destroy_node() rclpy.shutdown() if __name__ __main__: main()把代码保存为flysky_teleop.py然后在终端执行python3 flysky_teleop.py如果你用ROS 1其实也一样把rclpy换成rospycreate_publisher换成rospy.Publisher即可。代码里/500.0是摇杆活动范围的一半。富斯遥控器摇杆从最下到最上对应1000到2000微秒中位1500所以最大偏移是500微秒。0.8和2.0是机器人底盘能接受的最大速度和最大角速度这两个值要按自己机器人底盘的实际情况标定一开始给保守值后面再调。4.3 串口权限和udev规则串口节点最常见的错误是Permission denied: /dev/ttyUSB0。这是因为当前用户不在dialout组里没有访问串口设备的权限。解决办法sudo usermod -aG dialout $USER执行完需要重新登录一次才能生效。如果你插上USB转TTL模块后系统不识别多半是驱动问题。Arduino Nano用的CH340芯片Ubuntu 22.04自带ch341驱动一般即插即用如果识别不到检查一下是不是买的劣质模块用了国产仿制芯片。为了让串口设备名固定避免插拔后ttyUSB0变成ttyUSB1影响启动建议写一个udev规则。在/etc/udev/rules.d/99-flysky.rules里加一行KERNELttyUSB*, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, MODE0666, SYMLINKflysky把idVendor和idProduct换成你实际设备的型号可以用lsusb查看插上后就会多一个/dev/flysky符号链接程序里改用这个固定路径再也不用担心设备名漂移。4.4 用launch文件一键启动手动跑Python节点当然可以但每次开机敲命令很烦我习惯写一个launch文件。ROS 2的launch文件可以是Python格式在包的launch目录下创建flysky_teleop.launch.pyfrom launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( packageflysky_teleop, executableflysky_teleop_node, nameflysky_teleop, outputscreen, parameters[{ port: /dev/flysky, baud: 115200, }] ) ])如果你只是临时用不建包也可以直接用ros2 run运行一个可执行脚本我在快速验证时直接用Python脚本加chmod x然后用./flysky_teleop.py跑效果一样。launch文件的优势在于后续要同时启动底盘驱动、激光雷达、导航栈时可以用一个launch文件统一管理不用开一堆终端。5. 整车联调与关键参数标定5.1 通道映射与摇杆模式设置联调之前先确认遥控器的摇杆模式。富斯i6X支持Mode 1和Mode 2两种模式切换Mode 2是左手油门这是航模默认模式左摇杆上下控制油门、左右控制方向舵右摇杆上下控制升降、左右控制副翼。做机器人时我更推荐把速度映射到左摇杆的上下转向映射到右摇杆的左右。因为右摇杆是自动回中的松手后转向自然回正符合驾驶直觉左摇杆在航模默认设置里是非回中的但我希望松手停车所以我在遥控器设置里把油门摇杆改成回中手感或者在固定翼模式下手动回中两种方式都行。具体通道映射关系富斯i6X的接收机通道输出顺序是固定的CH1副翼、CH2升降、CH3油门、CH4方向舵、CH5辅助1、CH6辅助2。在我的方案里CH3油门通道当作前进后退速度CH4方向舵当作转向CH5接到一个两段开关当作急停/使能开关。ROS节点里的channels[2]对应CH3channels[1]对应CH4注意下标从0开始这个容易搞混。5.2 中位校准与死区设置摇杆的中位脉宽理论值是1500微秒但实际遥控器摇杆多多少少会有偏差可能是1498也可能1503。如果不做校准机器人会认为摇杆没动的时候实际上在缓慢前进表现为小车“自走”。解决方法是记录实际中位值然后做死区处理。我在ROS节点里加了自动校准逻辑程序启动后前10帧数据取平均作为中位参考值。这个办法在遥控器开机后、摇杆居中时最有效能在软件层面消除硬件偏差。中位确定后死区范围我设在±30微秒换算成速度约0.048m/s既不会感到迟钝也不会因为手抖导致机器人抖动。死区太大小车会发飘死区太小摇杆轻微抖动都会触发运动30微秒是实测比较合适的平衡点。5.3 速度标定流程ROS节点里的0.8和2.0不是随便填的要根据你机器人底盘的实际能力标定。我的方法是把遥控器油门推到最大ROS端打印实际发布的linear.x值同时用卷尺测量小车在1秒内走过的距离逐步调整系数让软件上的最大速度和实际速度一致。角速度标定更麻烦一点。我用了一个笨办法把最大角速度设为一个猜测值然后让小车原地转圈记录转一圈的时间算实际角速度根据误差调整系数。多调两轮之后就能找到比较准确的对应关系。如果你有现成的IMU或轮式里程计可以直接用ros2 topic echo /odom里的速度反馈来标定会方便很多。5.4 安全开关与急停逻辑这是我整个项目里最看重的一块。遥控器有物理开关天生适合当急停我强烈建议你的ROS节点里必须加一个“使能控制”逻辑只有遥控器某个特定开关拨到指定位置节点才发布非零速度否则一律发布零速度。我的做法是用CH5两段开关拨到“ON”位置正常发布摇杆值拨到“OFF”位置强制发布linear.x0, angular.z0。这样即使摇杆误触小车也不会动。代码里在read_and_publish函数中加一个判断enable channels[4] 1500 if not enable: twist.linear.x 0.0 twist.angular.z 0.0 self.pub.publish(twist) return除了软件急停硬件上我也在电池正极串了一个物理急停开关这个开关不经过任何逻辑直接切断电机电源是最后一道保险。软件急停和硬件急停一起用双层保护才算靠谱。5.5 实际调试流程我的整车联调顺序是先在桌面上把机器人架起来轮子悬空验证通道映射和转向方向然后在空地上小范围测试只给20%的最大速度看转向响应最终才逐步加大速度。特别注意第一次下地时手随时放在遥控器急停开关上感觉不对立马切。方向反了怎么办如果你推左摇杆向上小车反而后退最简单的办法不是改代码而是在遥控器上把CH3通道方向反转遥控器设置菜单里Reverse选项调一下就行。如果左右转向反了同样在遥控器上反转CH4。我不建议在ROS端做负数映射因为这样调试的时候容易把自己绕晕遥控器端改方向更直观也和航模的习惯一致。6. 常见问题与排查技巧实录6.1 串口打不开、权限不足这是被问得最多的问题。现象是程序启动报错serial.serialutil.SerialException: [Errno 13] Permission denied: /dev/ttyUSB0。原因就是当前用户没有串口访问权限。两种解决方法一是sudo usermod -aG dialout $USER然后把用户加进dialout组重启或重新登录二是临时用sudo chmod 666 /dev/ttyUSB0这个只对当次生效重启后要重跑作为快速验证可以长期用一定要udev规则。我踩过的坑是直接用sudo跑Python节点导致后续文件权限混乱后来老老实实加到dialout组里一步到位。6.2 接收机不输出PPM信号IA6B接收机跳线帽没拔或者拔错位置是最常见原因。IA6B的跳线帽在接收机右上角拔掉后才切换成PPM/IBUS输出插着就是PWM模式。还有一种情况是遥控器型号和接收机对不上富斯i6X和IA6B必须用AFHDS 2A协议对码对不上接收机会一直闪灯。重新对码的方法接收机上电前按住接收机的BIND键不放同时给接收机上电然后遥控器进入绑定模式就能重新对码。另外注意有的IA6B接收机PPM输出引脚不是标准的通道1引脚而是右侧一个独立的S引脚具体看接收机丝印别接错。6.3 数据不稳定、通道值跳动通道值跳动的原因通常有三个供电不稳、信号线过长、共地不良。接收机最好单独用稳定5V供电不要和电机共用一个电源且不滤波电机启停瞬间会把电源拉垮导致接收机输出脉宽抖动。信号线不要超过20厘米太长会引入干扰。接收机GND和单片机GND必须连在一起两个板子各自用自己的电源时尤其容易忽略共地。如果用的是ESP32做桥接5V转3.3V的电平转换模块也别省直接IO口接5V信号短时间没事时间长了必烧引脚这我在一块ESP32 DevKit上付出过代价。6.4 ROS端收不到数据先确认桥接板串口有没有数据用minicom或screen看一眼sudo apt install minicom minicom -D /dev/ttyUSB0 -b 115200如果能看到A5 5A 06 ...这样的十六进制数据说明链路前半段正常问题在ROS节点代码如果minicom里全是乱码一般是波特率不对或者共地没接好。ROS节点收不到数据还有一个隐蔽问题Python的pyserial读串口时如果串口缓冲区一次性读到了不止16字节read(16)会读出一整帧加半帧导致帧头校验失败。我的办法是先用一个内部缓冲区拼接保证每次解析的都是完整帧。最简单的做法是每次读完清空输入缓冲区只保留最后16字节再做校验。6.5 小车原地抖动、转向发飘抖动主要来自两个地方死区太小摇杆中位附近微小的脉宽变化被当成有效输入导致电机频繁启动熄停另一个是速度反馈闭环的PID参数没调好这种情况下遥控器只是把速度指令发出来底盘自己的PID在震荡和遥控器无关。抖动排查思路先用ros2 topic echo /cmd_vel看一下实际发布的Twist值。如果指令平滑说明ROS端没问题问题在底盘PID如果指令值本身就在抖动大概率是通道值跳动或者死区设置太小。我在死区上做过对比实验死区10微秒时小车静止状态下电机每秒钟会抽动好几次声音也是那种滋滋响死区30微秒之后安静下来转向也不飘了。6.6 遥控器距离近、信号不好如果你发现遥控器靠近才能控制远了就丢信号第一检查接收机天线位置。接收机天线是那种短短的软线别把它塞在金属底盘下面或者碳纤维板中间要尽量竖起来、远离电机和电源线。第二检查遥控器发射功率设置i6X在设置菜单里可以调节射频功率室内测试用低功率省电可以室外一定要开满。第三是2.4G信号容易被WiFi干扰我遇到过一次在路由器旁边小车遥控距离缩短到五米内的诡异情况换到远离路由器的场地就好了。7. 一些实用的小技巧关于遥控器本身我用下来觉得有几个设置非常值得做。一是油门摇杆的回中手感如果是非回中油门可以在遥控器面板里把油门通道的“弹簧回中”功能打开或者换一个带回中弹簧的摇杆组件很便宜。二是遥控器里可以设置行程量EPA把油门输出限制在1200到1800微秒相当于软件限速这样即使你摇杆推到最大速度也只有全速的一半非常适合新手或者室内调试。三是双速率设置D/R可以在遥控器上设置一个开关切换不同的输出比例相当于一键切换“调试模式”和“巡航模式”。ROS端我这里还有个个人习惯在flysky_teleop节点里同时发布原始通道值到一个自定义话题比如/flysky/raw_channels这样调试的时候用ros2 topic echo /flysky/raw_channels就能实时看到所有通道的脉宽值排查问题不用重新编译代码。发布原始数据不影响控制链路多花不了几个CPU周期但排查起来省好多事。最后再提醒一句做这类硬件在环的控制系统任何一步改动都要遵循“先验证再上电先悬空再落地”的原则。我遇到过遥控器端反转设置改错了以为代码问题在ROS端折腾半天最后发现是遥控器输出逻辑搞反了。硬件调试最忌讳凭感觉改参数每一步都验证比什么都重要。这套富斯遥控器加ROS的控制方案我用了大半年从最初的Arduino Nano桥接做到现在的ESP32加micro-ROS稳定性一直在线希望这篇记录也能帮你的ROS小车跑起来。
返回列表