从 OpenClaw 语音控制到实验室巡逻路线:一次 ROS 2 导航闭环验证

从语音控制、地图保存到 Nav2 纯规划验证,记录一条实验室巡逻路线的安全闭环。

1. 记录目的

今天的工作不是单独验证某个 ROS 2 节点,而是把语音控制、地图、定位、路线标定和路径规划串成一条完整链路。

这次主要解决五个问题:

  1. OpenClaw 能否通过语音链路实际调用小车底盘?
  2. 当前实验室地图能否正确保存并重新加载?
  3. 小车在地图上的定位偏移究竟来自哪里?
  4. 人工采集的巡逻点是否位于可通行区域?
  5. 在不让车辆运动的情况下,能否证明整条路线可以被 Nav2 规划?

今天继续采用系统化排错方法:

记录现象
  -> 检查节点、话题和 TF
  -> 提取日志与数值证据
  -> 区分事实、推测和显示误解
  -> 选择影响范围最小的处理方式
  -> 进行静态验证、规划验证和退出验证

2. 今天处理的系统链路

今天涉及的功能可以分为四层:

语音输入
  -> ASR
  -> OpenClaw 决策
  -> ROS 2 动作服务
  -> 底盘控制

双雷达
  -> LaserScan 合并与过滤
  -> Cartographer / AMCL
  -> map 与 TF

人工驾驶
  -> 采集 map -> base_footprint
  -> 生成巡逻点
  -> 保存路线配置

路线配置
  -> Nav2 planner_server
  -> ComputePathToPose
  -> 纯规划验证

这种分层很重要。语音有回复不代表动作执行成功,地图能显示不代表定位准确,目标点位于白色区域也不代表两点之间一定能生成路径,博主建议每次执行操作结束时,去使用AI拉取后台日志,看看有没有板块报错,因为学习途中很多部分是无法完全可视化完成的,介于win转linux的同学,我建议还是采用我的方式去进行检验。

3. OpenClaw 语音控制验证

3.1 工作流程

当前语音控制链路可以概括为:

麦克风录音
  -> VAD 判断语音结束
  -> ASR 转写文字
  -> OpenClaw 生成回复和动作列表
  -> action_service 执行动作
  -> /cmd_vel 控制底盘
  -> TTS 播放回复

3.2 实际验证

测试“前进一米”后,车辆确实完成了约一米的前进动作。这说明 OpenClaw 不只是返回文本,它已经能够经过动作服务调用底盘。

但“能动”只是最低层验证。当前方案仍存在以下缺口:

  • 语音交互主要是单轮指令模式;
  • 缺少稳定的唤醒、工作和休眠状态机;
  • 缺少连续对话窗口;
  • 缺少单独的中途取消词;
  • 动作接口还没有严格限制为安全白名单。

因此,今天只证明了链路可用,没有把 OpenClaw 直接接入巡逻路线自动执行。

3.3 对休眠计时的认识

后续设计不能简单地从接收到语音后固定倒计时 30 秒。正确逻辑应当是:

唤醒
  -> 接收命令
  -> 执行任务
  -> 反馈结果
  -> 进入空闲状态
  -> 从空闲状态开始计算 30 秒

任务执行期间不应进入休眠倒计时。新命令、中途取消或任务反馈都应刷新会话状态。

4. 地图保存与版本验证

4.1 保存结果

本次地图保存到:

/home/jetson/.config/m3pro_openclaw/maps/20260805_203638/
├── patrol_map.yaml
└── patrol_map.pgm

地图参数:

尺寸:231 x 270
分辨率:0.05 m/pixel
原点:[-3.4, -2.66, 0]

地图文件版本标识:

YAML SHA-256:d3e2d7770b8bb5bf9fced298ba2120e5e0f0ea256bc6cd900e7996b58d0a8034
PGM  SHA-256:4e77c90fa1449e57e68ca8abcc148ffd03c0358aa7c2524815ffe93a180df16c

4.2 为什么不能只看文件存在

地图保存完成后进行了以下验证:

  1. map_saver_cli 返回成功状态;
  2. YAML 和 PGM 均存在且大小非零;
  3. YAML 包含图像路径、分辨率、原点和占用阈值;
  4. PGM 可以被识别为有效 Netpbm 图像;
  5. 使用临时 nav2_map_server 重新加载 YAML;
  6. 地图服务器能够进入 active
  7. 重新发布的尺寸和分辨率与原地图一致。

这次验证说明:文件存在只是第一层,能够重新加载并发布一致的 /map,才算地图真正可用。

5. 实验室巡逻路线标定

5.1 标定方法

小车从 home 出发,使用手柄依次到达三个巡逻停靠点,车辆停稳后采样:

map -> base_footprint

每个点连续读取多帧,使用稳定区间的中位值,而不是只记录单帧数据。

5.2 最终坐标

home
  x = -0.007 m
  y = -0.002 m
  yaw = -3.11 deg

lab_point_1
  x = 1.646 m
  y = -0.106 m
  yaw = 0.893 deg

lab_point_2
  x = 1.613 m
  y = 0.729 m
  yaw = 88.539 deg

lab_point_3
  x = 0.142 m
  y = 0.905 m
  yaw = 175.212 deg

最终路线为:

home -> lab_point_1 -> lab_point_2 -> lab_point_3 -> home

第四次停车位置经过确认就是返回后的 home,因此没有把它保存成重复的第四个巡逻点。

6. 一次典型的定位偏移排查

这是今天最值得记录的排错过程。

6.1 现象

车辆到达第一个点后,RViz 中看起来出现了偏移。画面中还能看到小车和一条很长的黄色连线,容易误以为小车模型、雷达或地图发生了错位。(当时博主在第一次位移发生偏移的时候,使用了很多方法去验证是否是控制器或者雷达问题,建议大家都在标定结束后复盘时利用AI去分析原因并做对比,使用控制变量法去排错是最便捷的,排错不要心急,很多时候可能是外部变化引起的暂时性问题)

6.2 运行状态

后台检查结果:

  • /scan 正常发布,频率约 7.15 Hz
  • 雷达坐标系和外参正常;
  • map -> base_footprint 连续存在;
  • AMCL、地图服务器和 RViz 均处于运行状态;
  • /cmd_vel 当时只有 joy_ctrl 一个发布者。

车辆从暂定 home 到第一个点的地图位移约为:

前进约 1.60 m
横向变化约 3.2 cm

这说明车辆并没有在地图坐标中产生明显横移。

6.3 日志与数值证据

底层里程计和 AMCL 之间存在明显差异:

odom 认为车辆偏航约 +12.3 deg
map -> odom 使用约 -12.2 deg 修正

AMCL 的位置协方差也一度升高,说明定位结果不够集中。

6.4 根因判断

问题包含两个部分:

第一,RViz 中的长黄线是 TF 显示的 odom -> base_footprint 父子坐标关系。车辆离开里程计原点后,连线自然变长。它不是第二个车辆位置,也不是雷达漂移。

第二,车辆返回实体 home 后,AMCL 最初给出的坐标与起点相差约 15 cm / 16.6 deg。车辆实际位置和朝向没有变化,因此不能把误差归因于人工摆放,而应继续检查定位是否及时更新。

6.5 处理决定

没有重新点击 2D Pose Estimate,也没有立刻修改厂商 AMCL 源码,而是调用静止更新服务:

ros2 service call /request_nomotion_update std_srvs/srv/Empty '{}'

这一操作不会驱动车辆,只要求 AMCL 在车辆静止时重新使用当前雷达数据更新粒子分布。

6.6 验证结果

静止更新后,定位从:

x = -0.089 m
y = 0.009 m
yaw = -14.4 deg

逐步收敛到:

x = -0.007 m
y = -0.002 m
yaw = -3.11 deg

这证明主要问题是 AMCL 更新滞后和里程计航向误差累积,而不是车辆实际返回位置错误。

这个案例再次说明:看到界面偏移后,不能直接拖动车模或重设初始位置。应该先比较 mapodombase_footprint 和雷达数据之间的关系。

7. 路线配置与静态安全检查

路线保存到:

/home/jetson/.config/m3pro_openclaw/routes/lab_patrol_route.yaml

本地保留:

D:\AutomataCar\lab_patrol_route.yaml

路线 SHA-256:

b2ee71deedfeb53d9592e78df172f9469f0a40e287a78ef55097704faba12dac

配置中明确设置:

require_confirmation: true
autonomous_execution_enabled: false

随后对地图栅格进行了静态检查:

  • home 最近障碍距离约 0.87 m
  • lab_point_1 最近障碍距离约 0.74 m
  • lab_point_2 最近障碍距离约 0.46 m
  • lab_point_3 最近障碍距离约 0.86 m
  • 四段直线路径均未穿过占用或未知栅格;
  • 整条路线最小静态余量约 0.47 m

点位安全和路径可规划是两个不同问题,因此还需要下一层 Nav2 验证。

8. Nav2 纯规划验证

8.1 为什么先做 dry-run

这里的 dry-run 指只启动路径规划器并计算路径,不启动控制器,不让车辆运动。

本次只启动:

planner_server
global_costmap

没有启动:

controller_server
bt_navigator
waypoint_follower

因此规划过程中不会出现新的 /cmd_vel 发布者。

8.2 参数问题

检查厂商参数时发现:

global_costmap:
  global_costmap:
    ros__parameters:
      use_sim_time: True

当前是实机环境,没有 /clock。直接使用该值可能导致代价地图时间不更新。

处理方式不是修改厂商 YAML,而是新增独立参数文件:

D:\AutomataCar\nav2_planner_dry_run.yaml

其中强制使用实机时间,并且只加载静态地图层和膨胀层。

8.3 规划结果

四段 ComputePathToPose 请求全部返回 SUCCEEDED

路段 路径长度 路径点数量 规划耗时
home -> point_1 1.666 m 66 2.222 ms
point_1 -> point_2 0.854 m 33 1.112 ms
point_2 -> point_3 1.498 m 59 0.878 ms
point_3 -> home 0.940 m 37 0.739 ms

最大首尾坐标误差约 1.7 cm,规划日志中没有 WARNERROR

验证过程中反复检查 /cmd_vel,始终只有:

joy_ctrl

纯规划结束后,临时规划器按以下顺序退出:

deactivate -> cleanup -> SIGTERM 专属进程组

退出后确认没有残留 planner_serverglobal_costmap 节点。

9. 断电前的安全收尾

车辆电量不足后,没有继续执行实车测试,而是停止本次标定启动的功能:

  • AMCL;
  • 地图服务器;
  • RViz;
  • EKF 和 TF;
  • 雷达合并与预处理;
  • 临时 Nav2 规划器。

停止时使用已经确认过的独立进程组,没有使用范围过大的 pkill,也没有误伤厂商底盘常驻节点。

这次再次验证了一个重要原则:机器人测试的结束条件不是“功能已经跑通”,而是“运动输出已经停止、临时节点已经退出、配置已经保存”。

10. 今天形成的认识

10.1 语音回复不等于动作链路完成

必须同时确认 ASR 文本、OpenClaw 动作列表、动作服务结果、/cmd_vel 发布者和车辆实际表现。

10.2 地图显示正常不等于定位可靠

地图、雷达点、RobotModel、TF 连线和 AMCL 粒子分别表示不同信息。必须先理解显示对象,再判断是否真的偏移。

10.3 物理事实优先于单次软件估计

车辆实体回到相同位置且朝向一致,而 AMCL 坐标不同,说明应该检查定位更新和里程计累积,不能先怀疑用户摆放错误。

10.4 先验证规划,再允许控制

目标点自由、线段自由和 Nav2 规划成功是逐层增强的证据。只有这些验证完成后,才适合进入低速实车测试。

10.5 尽量使用独立覆盖配置

发现厂商 use_sim_time 配置不适合当前实机时,使用独立 dry-run 参数文件,而不是直接修改厂商源码。这样更容易回滚,也更方便比较差异。

10.6 安全状态必须能被证明

“我没有发送运动命令”不够,还应检查 /cmd_vel 的实际发布者,并在退出后确认相关进程和节点消失。

11. 阶段结论

今天最大的进展不是让小车多运行了一个功能,而是建立了从语音意图到物理运动、从地图文件到路线规划的验证闭环。

这条链路可以概括为:

语音可识别
  != 动作可安全执行

地图可显示
  != 地图可重新加载

点位在自由区域
  != 路线一定可规划

路线可规划
  != 可以直接开放自动驾驶

目前已经证明:地图有效、定位问题可以通过数据链路解释、三个巡逻点可以组成闭环、Nav2 可以为四段路线生成路径,并且整个验证过程没有产生自主速度输出。

下一步才是低速实车验收,而不是直接让 OpenClaw 自动巡逻。

留言功能暂未开放