拓冰建站拓冰建站
首页 / 资讯中心 / 正文

RDK X5与ROS2机器人实战:从硬件选型到BPU模型部署与Nav2导航

我用RDK X5搭过两版ROS2机器人第一次是纯跑官方镜像当“能开机”用第二次才算是真正把底盘、雷达、算法串成一条整链路。这中间踩了很多文档上没有写明的地方尤其是BPU模型转换和串口权限这类细节官方资料经常一句话带过但实操起来能卡你一整天。这篇文章就当作一份完整的搭建记录从硬件选型到ROS2环境、底盘驱动、传感器接入、模型部署、Nav2建图导航一条线走到底适合手里有RDK X5、想做一台能感知能自主移动的ROS2机器人的朋友。1. 为什么选RDK X5当ROS2机器人主控先说选型逻辑。机器人主控的活儿不是“能跑Linux”就行。它要同时扛住三件事实时收发传感器数据、跑感知和决策算法、控制电机执行动作。树莓派4性能偏弱跑个YOLO基本就吃满CPUJetson Nano算力尚可但价格不友好更重要的是它的IO口和机器人常用的外设对接没有RDK X5顺手。RDK X5这块板子最吸引我的地方是它板载了BPU脑处理单元Bayesian Processing Unit10TOPS级别的算力推理一个YOLOv8s模型跑个几十毫秒很轻松功耗还低小车用电池带得动。再就是它的接口配置。一个板子能不能当机器人主控接口齐全度很关键。RDK X5带了双千兆网口、USB 3.0、M.2接口还有40Pin GPIO机器人常用的I2C、UART、PWM、CAN都能直接引出来省掉一堆转接板。我实际接的激光雷达走串口、IMU走I2C、电机驱动板走串口一个40Pin排针全部搞定不用额外扩展。软件生态方面地瓜官方提供了适配好的Ubuntu 22.04镜像和ROS2 Humble版本TROS工具链Humble是ROS2里最稳定的发行版之一官方支持到2027年。相比自己从零编译ROS2这个省了很多时间。RDK X5的CPU是8核Arm A55跑ROS2的节点和通信中间件毫无压力我把激光雷达、IMU、三个视觉节点、导航节点全开CPU占用也就一半左右。还值得说的是RDK X5的地平线工具链把模型转换的门槛降了不少。ONNX模型通过hobot_model_encoder工具转成BPU可执行的bin模型再用hobot_dnn订阅图像话题发布推理结果整个流程比较顺。对于没有太多嵌入式AI经验的ROS2开发者来说这块学习曲线要比自己手撸NPU驱动友好得多。当然它也有短板比如GPU能力弱跑GPU版CUDA程序基本别指望图像渲染之类的任务别压在它身上。但作为一台移动机器人的主控它定位很准确就是“感知决策执行闭环”。2. 系统烧录与ROS2 Humble环境搭建2.1 镜像烧录选对的镜像版本RDK X5出厂不带系统需要自己烧录。官方提供的是基于Ubuntu 22.04的Desktop或Server镜像我建议直接上Desktop版毕竟开发调试阶段需要可视化界面ROS2的工具链很多也要靠图形界面来配。烧录工具用balenaEtcher就行准备好一张至少32GB的SD卡。插卡、选镜像、烧录、插入板子、通电第一次开机系统会自动扩展分区耐心等两三分钟。注意RDK X5的电源最好用官方配套的USB-C电源至少5V 3A起步。电源功率不足会导致板子在跑AI推理时突然重启这种问题排查起来相当隐蔽。2.2 ROS2 Humble的安装方式选择系统起不来先别高兴接下来是环境痛点。RDK X5官方镜像里其实已经预装了一部分ROS2组件但版本可能不完全。我的建议是全部重新装一遍保证环境一致性。ROS2安装方式有几个选择我用的是鱼香ROS一键安装脚本它在国内网络环境下省事很多wget http://fishros.com/install -O fishros . fishros脚本执行后选择ROS2 Humble再选基础版ROS2脚本会自动配置apt源并安装全套核心包。如果你不习惯用第三方脚本也可以走官方apt源安装sudo apt update sudo apt install curl gnupg lsb-release sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release echo $UBUNTU_CODENAME) main | sudo tee /etc/apt/sources.list.d/ros2.list /dev/null sudo apt update sudo apt install ros-humble-desktop两种方式我都试过鱼香脚本在源的选择上更聪明一些安装速度和稳定性都更好。装完记得把环境变量写进bashrc不然后面每次开终端都要手动sourceecho source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc验证安装是否成功跑一下经典小乌龟ros2 run turtlesim turtlesim_node能弹出小乌龟窗口说明ROS2核心环境正常。这里有个小细节ros2 run能找到节点是因为有ament包索引如果提示找不到包先检查环境变量有没有正确加载。2.3 DDS与多机通信的选型ROS2的底层通信是DDSData Distribution ServiceRDK X5默认用的是Eclipse Cyclone DDS这个选择是地瓜做过权衡的。Fast DDS对标准Linux桌面支持好但其多播发现在嵌入式环境下偶尔有兼容问题Cyclone DDS内存占用更小、实时代理调度更好在单板环境里更稳。如果你想修改DDS配置在/etc/ros2/rmw.d/下新建一个rmw配置文件选择Cyclone作为中间件export RMW_IMPLEMENTATIONrmw_cyclonedds_cpp多机通信时候需要注意RDK X5和工控机要在同一个网段并且都启用同样的DDS发现协议。我遇到过RDK X5发布的话题工控机订阅不到的情况最后发现是两台机器的DDS实现不一致统一用CycloneDDS后问题就消失了。3. 硬件接口配置40Pin排针与底盘驱动打通3.1 点亮电机驱动板串口控制协议我的底盘是两轮差速驱动驱动板通过串口接收控制指令控制协议是自定义的ASCII协议格式大概是MOTOR LEFT_SPEED RIGHT_SPEED。RDK X5的40Pin排针引出多路UART需要确认用的是哪一路以及如何开启它。RDK X5默认的调试串口和机器人用途的UART是不同的。设备树里通常有一个UART默认被分配为控制台其他UART是空闲的。你需要修改设备树启用串口这步比较关键。在RDK X5上可以通过/sys/kernel/debug/pinctrl/查看引脚复用情况一般文档会说明某个UART对应的GPIO号。我用的UART3对应板载40Pin上的物理引脚8和10。启用UART3的操作是改/boot/firmware/config.txt新版本镜像路径可能不同enable_uart1 dtoverlayuart3修改后重启板子。然后检查串口设备是否出现ls /dev/ttyS* ls /dev/ttyUSB*如果是USB转串口设备会看到/dev/ttyUSB0如果是板载串口通常是/dev/ttyS0或/dev/ttyTHS0。我的驱动板通过USB转TTL模块连接到板子的USB口所以是ttyUSB0。然后是权限问题这是个容易踩的坑。普通用户默认没有权限访问串口sudo usermod -aG dialout $USER执行完需要重新登录否则串口依然打不开。3.2 底盘驱动节点发布odom和接收cmd_vel底盘驱动不能只写一个死循环去读串口。规范做法是写一个ROS2节点订阅/cmd_vel话题获取速度指令解析后通过串口发给驱动板同时周期性地读取驱动板里的轮速编码器数据计算出机器人的里程计信息发布/odom话题和/tf坐标变换。我的驱动节点核心代码结构大概是这样的import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist from nav_msgs.msg import Odometry import serial class RobotBaseNode(Node): def __init__(self): super().__init__(robot_base_node) self.serial_port serial.Serial(/dev/ttyUSB0, 115200, timeout0.1) self.cmd_sub self.create_subscription(Twist, /cmd_vel, self.cmd_callback, 10) self.odom_pub self.create_publisher(Odometry, /odom, 10) def cmd_callback(self, msg): left_speed msg.linear.x msg.angular.z * self.wheel_base / 2 right_speed msg.linear.x - msg.angular.z * self.wheel_base / 2 command fMOTOR {left_speed:.2f} {right_speed:.2f}\n self.serial_port.write(command.encode()) def publish_odom(self): # 读取编码器数据计算位置发布odom pass有个核心点时间戳。发布/odom时时间戳用node.get_clock().now().to_msg()而不是系统当前时间直接转因为ROS2的图要保证不同话题之间的时间同步乱给时间戳会导致后续融合定位算法出问题。3.3 TF树让每个传感器知道自己在哪传感器接入之前先把TF树建立起来不然后面所有算法都会报坐标找不到。我的机器人的TF树是map - odom - base_footprint - base_link - laser_link - imu_link - camera_link在launch文件里用robot_state_publisher发布静态变换node pkgrobot_state_publisher execrobot_state_publisher param namerobot_description value$(command cat $(find my_robot_description)/urdf/robot.urdf) / /node node pkgtf2_ros execstatic_transform_publisher param nametranslation value0 0 0.15/ param namerotation value0 0 0 1/ param nameframe_id valuebase_link/ param namechild_frame_id valuelaser_link/ /nodeTF树设计有个原则base_link是所有传感器坐标的根轮式里程计推算的是odom到base_link的变换激光雷达到车体中心是固定变换用静态TF发布即可。如果雷达装在车体中心偏前10厘米就是x0.1 y0 z0.15这些都是静态值一次性写进URDF里就行。4. 传感器接入与数据流打通4.1 激光雷达串口雷达的连接与校验我用的激光雷达是思岚A112米测距半径360度扫描对于室内机器人导航完全够用。A1通过串口输出接法很简单把雷达的TX/RX接到USB转TTL模块上再插到RDK X5的USB口。雷达驱动在ROS2里用现成的sllidar_ros2包sudo apt install ros-humble-sllidar ros2 launch sllidar_ros2 sllidar_a1_launch.py启动后检查话题数据ros2 topic echo /scan --once如果报错“Failed to open serial port”大概率是串口权限问题前面加的dialout用户组检查一下如果扫描出来数据全是0多半是波特率设置不对A1默认是115200检查驱动launch文件里的serial_baudrate参数。雷达数据接入后有一个非常关键的隐藏细节雷达扫描数据里的角度范围是0到360度但很多雷达由于物理安装原因0度方向并不对着车头正前方。你需要测量出雷达0度方向和车体正前方的夹角在后续建图时补偿这个角度偏移否则建出来的地图看起来是歪的。4.2 IMUI2C接口的校准与数据融合IMU我用的是BMI088通过I2C接口连接它提供三轴加速度和角速度。IMU对机器人导航的作用是补足轮式里程计在打滑场景下失效的问题轮子空转时里程计会认为机器人还在前进实际已经原地打滑IMU能帮算法识别这种状态。I2C设备的接入确认用i2cdetectsudo apt install i2c-tools sudo i2cdetect -y 2在I2C总线上看到设备地址出现在列表中说明IMU连接正常。IMU驱动在ROS2里可以用自定义的驱动包或者用bmi088_ros2包。启动后发布的数据在/imu/data_raw话题上。IMU数据需要进行静态校准尤其需要校准陀螺仪零偏。把机器人放在完全水平静止的桌面上采集一分钟的IMU角速度数据取平均这个值就是零偏后续需要在驱动代码里减去。这点不少文档没强调但直接用未校准的IMU数据做融合定位yaw角会缓慢漂移几分钟后偏到离谱。校准完IMU后建议用robot_localization包做轮式里程计和IMU的数据融合比单纯用里程计定位稳定得多。配置ekf_node时的关键参数是EkfNode: ros__parameters: frequency: 30.0 odom0: /odom imu0: /imu/data_raw odom0_config: [true, true, false, false, false, false, false, false, false, false, false, false, false, false, false] imu0_config: [false, false, false, true, true, true, false, false, false, false, false, true, false, false, false]odom0_config的含义是前三个true代表接收x、y、yaw速度数据后面代表其他速度/姿态分量不接收。IMU那边接收三个角速度和roll、pitch但不叠加线性加速度。按这个思路配置融合效果才不会互相打架。4.3 摄像头从采集到ROS2话题视觉传感器我用的是USB摄像头RDK X5支持UVC协议插上就能识别。通过usb_cam包发布图像话题sudo apt install ros-humble-usb-cam ros2 run usb_cam usb_cam_node_exe --ros-args -p video_device:/dev/video0 -p image_width:640 -p image_height:480图像分辨率不要调太高640x480足够算法用调高反而拖慢整个感知链路。摄像头画面用RViz2订阅/image_raw话题可以实时查看。5. BPU算法部署从ONNX到端侧推理5.1 模型准备与工具链安装这一步是整个RDK X5搭建流程里最有门槛的地方。我们要在BPU上跑一个YOLOv8s目标检测模型用来识别机器人前进方向上的障碍物。先在PC上训练或者下载一个预训练好的YOLOv8s模型导出为ONNX格式。导出时有两个关键参数需要注意opset11和dynamic_axes设置为固定尺寸BPU不支持的动态shape会导致转换失败。地瓜的模型转换工具链在ROMRDK工具链里安装方式官方文档说得很详细核心是hobot_model_encoder命令它负责把ONNX模型转换成BPU可执行的bin格式hobot_model_encoder -d yolov8s.onnx -o yolov8s.bin转换过程中有几个参数直接决定模型能不能高效跑在BPU上量化策略int8或fp16、输入分辨率、归一化参数。RDK X5的BPU对int8量化支持最好但直接转int8可能掉精度最好先用校准集做量化感知训练或者在转换工具里开启“混合量化”让关键层保持fp16其他层用int8。这个度需要根据实际场景测一下。5.2 推理节点hobot_dnn的使用模型转换完成后用hobot_dnn工具部署推理它相当于一个通用的DNN推理节点负责订阅图像话题、调用BPU推理、发布感知结果。用Python API的写法更灵活import numpy as np from hobot_dnn import pyeasy_dnn class YoloNode(Node): def __init__(self): super().__init__(yolo_node) self.model pyeasy_dnn.load(../model/yolov8s.bin) ...整个推理流程是订阅/image_raw话题 - 对图像做预处理resize到640x640、归一化、通道转换- 送入BPU推理 - 拿到输出tensor - 解析检测框和类别 - 发布vision_msgs/msg/Detection2DArray。图像预处理有个容易出错的地方RDK X5的BPU对输入数据的内存排布有要求通常是NHWC格式、RGB通道、归一化值范围0到1。如果你的模型训练时用的是BGR通道、0到255归一化那在Python里要先做转换不然模型输出会完全混乱。我的预处理核心代码img cv2.resize(img, (640, 640)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img img.astype(np.float32) / 255.0 img img.transpose(2, 0, 1) if model_input_channel_first else img判断模型的输入格式直接看转换工具生成的yaml描述文件就行里面对输入输出有完整定义。5.3 感知结果可视化与RViz2联动推理得到的目标框信息在RViz2里用Detection2DArray可视化比较麻烦我建议发布成visualization_msgs/msg/MarkerArray在RViz2里直接能显示3D框。核心是给每个检测结果生成一个长方体Marker放到相机坐标系对应的位置。要注意的是单目相机检测出的目标框是2D的没有深度信息不能直接生成有效3D框。我的做法是结合激光雷达的点云数据在图像上目标框中心对应的雷达距离值作为该目标的深度这样标出来的3D框在空间里就比较可信了。这个“2D框雷达深度”的融合办法在导航场景里非常实用。它会直接作为障碍物信息送入代价地图让导航算法知道前方几米处有障碍、这个障碍大概多大体积。单靠雷达点云判断障碍物很容易漏掉细小的目标比如桌腿、电线杆有了视觉先验再结合雷达测距准确率提升很多。6. Nav2建图与导航实测6.1 建图SLAM Toolbox跑通旋转扫描环境感知有了接下来就是把地图建起来。我用的是slam_toolbox它对二维激光SLAM在室内场景的表现比cartographer更稳定参数调起来也直观。启动命令ros2 launch slam_toolbox online_async_launch.py这里有个需要注意的地方slam_toolbox默认只订阅/scan话题作为输入并且要求坐标变换laser_link - base_link已经发布。我用rviz2控制机器人旋转一圈地图就开始逐步构建。建图时推进速度别太快雷达扫描周期是10Hz车体移动过快会导致帧间畸变地图会有明显的“重影”现象。建完地图后保存ros2 run nav2_map_server map_saver_cli -f my_map生成的map.pgm和map.yaml保存好后续导航直接加载。6.2 Nav2导航costmap配置与避障逻辑导航用Nav2全家桶这块的参数配置是ROS2机器人导航里最耗时间的活。核心是costmap的配置分global_costmap和local_costmap都包含几个layerstatic layer加载静态地图、obstacle layer订阅激光雷达数据实时添加障碍物、inflation layer做膨胀处理让机器人贴着障碍物边缘走。我的obstacle_layer配置obstacle_layer: plugin: nav2_costmap_2d::ObstacleLayer enabled: True observation_sources: scan scan: topic: /scan max_obstacle_height: 2.0 clearing: True marking: True关于动态障碍物普通costmap只能检测到雷达能扫到的障碍对于视觉识别到但雷达还没扫到的情况需要额外把视觉障碍信息作为一个单独的主题喂给obstacle layer。我写了一个桥接节点把YOLO检测到的目标框中心点结合雷达距离生成一个PointCloud2发布到/obstacles_vision然后在这个话题上再加一个observation source。Nav2的几个关键调参思路robot_radius对圆形底盘设为0.2米太小会导致规划路径贴上障碍物太大容易造成路径不可达。inflation_radius这个值决定路径和障碍物保持多远的“安全距离”室内紧凑空间设0.3~0.5大空间设0.6~0.8。planner_server默认的NavFn就行计算快且稳定。6.3 实测过程与常见问题整链路跑通后在RViz2里点击“2D Goal Pose”下发一个目标点让机器人自主规划并运动过去。整个过程分几个阶段全局规划器会先计算出从当前位置到目标点的全局路径然后局部规划器实时调整速度指令避让过程中新发现的障碍物底盘驱动节点把速度指令转成串口数据控制电机转动。实测中几次比较典型的失败案例第一次跑导航时机器人完全不动打开终端才发现在报错“No valid plan found”原因是我设置地图的时候map.yaml里的resolution参数和实际建图保存的不一致导致导航规划空间坐标系彻底乱了。第二次是机器人走了一条“贴墙又突然转向”的诡异路线排查发现是IMU和里程计融合的yaw角在缓慢漂移机器人认为自己已经转向到位实际还差角度。校准IMU零偏之后这个问题就消失了。第三次是激光雷达数据在导航过程中间歇性丢失过几秒又恢复排查下来是USB转TTL模块供电不稳雷达在电流波动时自我复位。换了一根带磁环屏蔽的USB线以及用独立电源给雷达供电问题彻底解决。7. 几个容易被问烂的坑位提前踩给你看RDK X5 ROS2这套组合本身不算复杂但把所有细节串起来确实有不少坑位值得提前知道。第一系统镜像升级要谨慎。地瓜发布的镜像迭代挺快不同版本之间设备树和默认配置有差异如果你用的是老版本镜像照着网上较新的教程去配置文件路径可能压根找不到对应文件。遇到这种情况先确认自己的镜像版本再决定要不要升级。第二串口权限问题反复出现。不仅驱动板串口需要dialout权限雷达串口、USB摄像头设备权限都可能涉及最好一劳永逸地把所有相关用户组加好。另外如果插了多个USB转串口设备/dev/ttyUSB0的编号可能漂移最好写一个udev规则根据设备ID固定映射到自定义名称。第三BPU模型转换时最容易犯的错是不看转换日志。每次转换都会输出各算子的支持情况和性能预估一眼就能看出哪个算子被跑在CPU上了。如果某个算子显示“not supported”尽量回到模型导出阶段把这个算子替换掉哪怕精度损失一点换来的推理速度提升非常明显。第四排查ROS2问题时要善用几个基础工具。话题有数据没数据ros2 topic hz /scan看频率节点之间没连通ros2 doctor做诊断坐标变换看不到ros2 run tf2_ros tf2_echo base_link laser_link。这些基础排查手段比盲目改代码高效得多。第五也是我觉得最重要的整套系统的实时性取决于最弱的那个环节。我刚开始只优化感知节点的推理速度模型从50ms优化到20ms但回头发现底盘驱动节点串口通信的响应间隔是100ms整个系统跟手的程度还是慢。后来排查发现是驱动节点用了阻塞式串口读加了超时和非阻塞处理之后整个控制链路流畅了很多。在机器人系统里算法快不代表系统快端到端的时延才是决定体验的关键指标。RDK X5这套板子加上ROS2生态组装一台功能完整的自主移动机器人已经不是门槛很高的事。硬件接口现成、ROS2环境预适配、BPU推理工具有现成的链路真正花时间的在于把每个环节的细节磨顺。这篇记录写到的内容基本覆盖了我从零到整链路跑通全过程遇到的主要问题和处理思路希望能给正在这条路上折腾的朋友省一些时间。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门