项目档案 / 已完成底盘接入、首次地面运动与 LiDAR-SLAM 验证
NUC ROS2 室内机器人:从感知链路到第一次建图
基于 Intel NUC、Astra Pro、X2 激光雷达与麦克纳姆底盘,完成统一启动、速度接口、里程计和 LiDAR 初步建图的真实硬件验证。
- ROS2
- NUC
- 移动机器人
- SLAM
- 麦克纳姆底盘
这个项目的起点不是“做一个会听指令的小车”,而是先把室内移动机器人最基础、也最容易断开的几段链路接起来:传感器是否持续输出,速度指令能否安全到达底盘,编码器能否变成可用的里程计,以及雷达和车体坐标是否说的是同一种“前方”。
硬件由 Intel NUC、Orbbec Astra Pro RGB-D 相机、公模 X2 2D 激光雷达和四轮麦克纳姆底盘组成;软件环境为 Ubuntu 22.04 与 ROS2 Humble。当前成果不是一套已经可以自主导航的产品,而是一条已经过真实硬件、地面运动和初步建图验证的系统原型。
先建立两种互补的前方距离
Astra Pro 是第一条跑通的感知链路。相机能够持续发布彩色图、深度图、点云与 TF;深度图和彩色图的实际频率约为 30 Hz。基于深度图中央区域的有效值中位数,项目实现了 front_obstacle_distance,将“正前方有多远”发布为独立话题。
它适合快速建立 RGB-D 感知闭环,却不应被当作唯一安全来源。近距离桌面测试中,物体接近约 0.45 m 时,深度相机可能给出无效值;X2 雷达仍能提供连续测距。因此又将雷达扇区距离和深度相机结果合并为 obstacle_status:只要任一条可靠链路认为前方受阻,系统就保留阻塞状态。
这不是为了堆叠传感器数量,而是把它们的失效方式显式放进判断里。深度相机在近场可能失效,雷达则更适合作为近距离的兜底;两者给出相近读数时,也能作为安装和坐标是否正确的交叉检查。
从“雷达有数据”到“雷达在车体前方”
X2 雷达能够稳定发布 /scan。墙面距离测试曾得到约 1~4 mm 的误差量级,后续在整车启动中也确认了稳定的扫描覆盖。
真正容易遗漏的问题出在坐标约定:物理上朝前的扇区在原始扫描中对应约 180°,并不是通常假设的 0°。如果不修正,SLAM 和避障模块看到的“前方”会与车辆实际朝向相反。项目因此将 base_link → laser 的静态变换修正为绕 Z 轴旋转 180°,并把雷达、相机相对于车体中心的位置一并放入统一 TF 树。
这类改动不会让演示画面立刻变得更酷,却决定了后续数据能否组合。坐标一旦错位,单独看每个话题都像是正常的,整车运动却会在最难排查的地方失真。
最新的整车装配把这些关系落实为可启动的系统配置:以 base_link 为车体中心,雷达安装位为 (0.095, 0, 0.10) m,相机安装位为 (0.11, 0, 0.15) m;雷达保留 180° 的朝向修正。robot_bringup 会统一启动底盘驱动、Astra Pro、静态 TF、X2 雷达与障碍状态节点,并确认对外提供 /cmd_vel、/odom、/scan、/tf、/tf_static 和相机话题。当前统一启动将雷达电机默认保持关闭,只有显式传入 start_lidar:=true 才启动扫描;这避免了把“能启动”误写成“应当始终旋转”的安全策略。
底盘:把 /cmd_vel 变成可测量的运动
原底盘控制板的固件曾被完整备份,并通过 ST-Link 验证最小测试程序可从 Flash 启动。但 NUC 无法通过原板的 Type-C / CH340 通路建立可靠通信,继续猜测原协议的收益很低。项目没有把这条不可验证的路径包装成“已解决”,而是改用带四路编码器、板载速度闭环和串口反馈的新驱动板。
随后实现了 ROS2 底盘驱动节点。它订阅 /cmd_vel,把前进、横移和角速度分配为四个轮子的目标速度;从编码器反馈发布 /odom,并广播 odom → base_link。启动时还会以当前编码器计数归零基准,避免静止的小车继承上一次的里程。
控制节点同时保留两个边界:指令超时后发送零速度,退出时也主动停轮。对于真实底盘,这些行为比“能转起来”更重要——控制链路断开时,车辆必须回到明确的安全状态。
第一次落地验证:方向正确,但标定还没有结束
第一次地面测试使用低速、定时的固定指令,而不是直接追求速度。结果显示三种基本运动均符合预期:
- 以 0.05 m/s 前进 10 秒,里程计约为 0.488 m,实测约 0.50 m;
- 向左横移时方向正确,里程计约为 0.408 m,实测约为 0.38 m;
- 以 0.20 rad/s 原地左转 8 秒,里程计约为 90.8°,实测约为 87°,平移漂移约 4.6 mm。
这些数字说明底盘、轮序、编码器符号和麦克纳姆运动学已经能够共同工作;它们也说明当前里程计仍只是初始标定。前进、横移与转向误差不能被平均成一句“基本准确”,因为麦克纳姆轮在不同地面、负载和电量下会呈现不同的打滑特性。
在当前瓷砖地面上,重复 90° 转向试验得到约 1.033 的角速度修正系数。这个值被保留为可配置参数,而不是写死成普适结论;换到地毯、携带更多载荷或电池电压变化后,都需要重新测量。
把链路接到 SLAM,但不把它夸大成导航完成
在底盘运动与 TF 基础就绪后,项目接入了仅使用 2D 雷达的 slam_toolbox。启动后可获得 /map、/map_metadata 和 map → odom;首次原地扫描导出了一张 0.05 m 分辨率、153 × 109 栅格的地图。低速方形路径之后,地图扩展至 225 × 209 个栅格,已知空闲栅格约从 1008 增至 8243,占据栅格约从 76 增至 1152。这些变化是扫描与里程计共同参与建图的证据,而不是单纯保存了一张静态图像。
这证明雷达、里程计与坐标变换已经能共同参与建图。但目前雷达仍受到安装位置和车体遮挡影响,可用覆盖主要集中在前方扇区。因此它是一次 SLAM 集成验证,还不是“导航已经可用”的结论。项目还增加了局域网只读地图查看页,用来检查地图更新与存档,而不是把它当成控制入口。
当前阶段的边界
到目前为止,系统已经可以统一启动底盘、相机、雷达、静态 TF 和障碍状态链路;X2 雷达在整车启动中的扫描频率约为 16.6–17.1 Hz,局部传感器测试、首次地面行驶和初步建图都有可回看的验证结果。底盘的地面标定仍基于当前瓷砖地面和轻载状态,角速度修正、轮速上限与编码器尺度都不应脱离这些条件理解。
仍未完成的工作同样明确:
- 用更长距离和不同运动组合标定编码器里程计;
- 完成 NUC 供电转换与车载布线,再复核满载时的底盘与传感器状态;
- 改善雷达安装与可视覆盖,再评估建图质量;
- 建立可重复的停车、急停与低电压测试;
- 在稳定的里程计与地图基础上接入 Nav2;
- 最后才将本地语言模型产生的高层意图接到导航目标,而不是让模型直接控制电机。
这个顺序是刻意的。自然语言接口可以让演示更直观,却不能代替底盘、坐标与安全边界。先让系统准确知道自己在哪里、能否停下、传感器在看哪里,后续的导航和任务执行才有可靠基础。