From Bits to the Physical World

A Full-Stack Robotics Guide for AI and Software Developers

01The Big Picture

What Is a Robot, Really?The Full-Stack Map of RoboticsWho's Who in the Industry?

02Hardware

SensorsActuatorsCompute Platforms

03Operating System

ROS 2DDS Deep Dive

04Algorithms

SLAMNav2MoveIt 2PerceptionBehavior Trees

05Simulation & Training

Why Simulation?NVIDIA Isaac Sim

06AI Meets Robotics

Reinforcement LearningImitation LearningFoundation Models

07Toolchain

Visualization & DebuggingDev Environment & DevOps

08The Harsh Reality of Deployment

Real-Robot DeploymentReliability EngineeringFleet Management

09Industry Reality

Business ModelsChina vs. GlobalCareer Advice

Part 8: The Harsh Reality of Deployment · From lab to real world

Chapter 21

真机部署 - 仿真里完美,现实里崩溃

你有没有在 Google Maps 的街景模式里“走”过一段路?画面清晰,街道干净,视角随意切换。然后你真的去了那个地方 - 地上有施工围挡,路边停着三辆共享单车挡住人行道,太阳正好照在你脸上什么都看不见。街景里的世界和你站在那里感受到的世界,是两个东西。

仿真和真机的关系也是这样。Isaac Sim 里的地面是完美平面,光照是均匀的,传感器返回的数据干净得像教科书插图。你的 Nav2 导航跑得行云流水,MoveIt 抓取一次成功。然后你把代码刷到真机上,机器人启动三秒后撞上了桌腿。

这不是你代码写得烂。这是 Sim-to-Real Gap - 仿真到真实世界之间那条看不见的裂缝。这一章讲的就是怎么过这条裂缝,以及过裂缝时最容易掉进去的那几个坑。

常见翻车点

先列一个“真机部署翻车排行榜”,按我见过的频率排序:

地面不平导致里程计漂移。 仿真里地面是一个完美的平面,轮式里程计(wheel odometry)算出来的距离和方向非常准。真实世界里,仓库地面有坡度、有接缝、有地砖高低差。轮子在不平整的地面上会打滑,里程计就开始漂移 - 机器人以为自己走了 3 米直线,实际上歪了 15 度还多走了半米。累积几分钟后,它在自己的 costmap 上的位置和现实中的位置可以差出一米以上。AMCL 可以纠正一部分,但如果漂移太快,粒子滤波也追不上。

光照变化导致感知失效。 仿真里的光照是你手动设的,可以是“室内均匀照明”也可以是“模拟阳光”,但它不会突然变。真实仓库里,叉车开过来大灯一照,你的相机画面直接过曝;下午三点阳光从天窗斜射进来,地上一半阴影一半高光,YOLO 模型对同一个货架的检测结果完全不一样。纯视觉 SLAM(比如 ORB-SLAM3)在光照剧变时特别脆弱 - 特征点匹配直接失败,定位丢失。

传感器标定不准。 这个后面会专门讲。简单说:你的相机和 LiDAR 装在机器人上,它们各自有自己的坐标系。如果你没有精确地告诉系统“相机在 LiDAR 的哪个方向、偏了多少角度”,那融合出来的数据就是错的 - 相机看到的物体位置和 LiDAR 测出的位置对不上。在仿真里这些坐标关系是精确定义的,但真机上,传感器安装总有误差。

网络延迟和通信丢包。 仿真里所有节点跑在同一台机器上,topic 消息基本是零延迟送达。真机上,感知模型可能跑在 Jetson 上,决策可能跑在另一台工控机上,还有个远程监控终端通过 Wi-Fi 连着。Wi-Fi 一抖,传感器数据延迟 200ms 到达规划模块,机器人就是拿着 200ms 前的信息在做决策 - 足够它撞上一个正在移动的人了。

这四个问题不是独立的,它们会叠加。地面不平导致机器人晃动,晃动导致相机画面模糊,模糊导致视觉定位漂移,漂移导致 costmap 错位,然后导航就崩了。这就是为什么仿真里 100% 成功率的任务,到真机上可能只有 60%。

标定:那些”调参永远调不好”的 bug,根子在这里

你有没有遇到过这种情况:Nav2 参数怎么调都不对,机器人总是往左偏 5 厘米;或者传感器融合之后,相机看到的障碍物位置和 LiDAR 测出来的总是差半个身位。你花了一整天调 controller gain 和 costmap 参数,但问题纹丝不动。

这种”参数调不掉的系统性偏差”,十有八九是标定(Calibration)没做好。标定出了问题,后面所有算法的输入都是歪的 - 不是随机噪声(那可以滤),而是固定方向的错误。你在下游拼命调参,就像试图用方向盘去纠正一辆四轮定位没做好的车 - 不是不能开,但永远别扭。

标定本质上在回答一个问题:这些传感器各自的坐标系之间,到底是什么空间关系? 根据你要对齐的东西不同,分几种情况。

相机内参 - 相机镜头有畸变,直线在画面边缘会变弯(广角镜头尤其明显)。不校正的话,画面边缘的物体定位误差会很大。做法很成熟:拿一张棋盘格标定板,从不同角度拍十几张照片,用 OpenCV 的 calibrateCamera 或者 ROS 2 的 camera_calibration 包自动算出来。这是标定里最不容易出错的一步,但有个坑:标定板要真的平(别用褶皱的 A4 纸),换分辨率或 FOV 之后要重新做。

相机-LiDAR 外参 - 机器人上同时有相机和 LiDAR,你想融合它们的数据(比如给点云上色、用图像语义标注点云中的物体),就需要知道两个传感器之间精确的平移和旋转关系。通常用 Autoware 的 extrinsic_calibration 工具 或 MATLAB Lidar Toolbox 来解一个 4x4 变换矩阵,写进 TF 树。这里最大的坑不是标定流程本身,而是物理刚性 - 我遇到过标定时完美、跑两天后融合开始偏的情况,查了半天发现是固定 LiDAR 的螺丝松了半圈。所以标定不是一次性的事,你需要定期验证(最简单的方法:把点云投影到图像上,看边缘是否对齐)。

手眼标定 - 如果你做的是抓取任务,相机多半装在机械臂末端(eye-in-hand),跟着手一起动。你需要标定相机相对于手臂末端法兰的固定变换。OpenCV 4.x 有 calibrateHandEye 函数,输入是多组手臂位姿 + 相机观测到的标定板位姿。如果你不做操作(manipulation),这部分可以跳过。做的话,注意两个容易踩的坑:一是采集姿态要够多样(不能光平移不旋转),二是手臂的 URDF 本身要准 - 如果关节零位有偏移,正运动学算出来的末端位姿就是错的,手眼标定的输入就是错的,根子坏了后面全白搭。

标定的核心教训是:它不性感,但跳过它的代价是后面每一步都在为它买单。

参数调优的实战流程

标定解决了”坐标系是否对齐”的问题 - 好消息是根子正了。坏消息是你还有一大堆运行时参数要调 - Nav2 的 inflation radius、MPPI controller 的速度限制、感知模型的置信度阈值、recovery behavior 的触发条件,等等。

新手最常犯的错误是把参数调优当成一次性工作:“部署之前调好参数,然后就不用管了。” 现实是,参数调优是一个持续的循环:部署 - 观察 - 诊断 - 调参 - 再部署。这个循环你可能要转几十圈。

第一轮:先让它活着

第一次上真机,不要追求任何性能指标。目标只有一个 - 机器人能动、不撞东西、不急停。

把所有速度参数调到很低(线速度 0.1-0.2 m/s,角速度 0.3 rad/s),inflation radius 调大一点(宁可机器人绕路也不要擦墙),感知模型的置信度阈值调高(宁可漏检也不要误检导致急停)。这个阶段你不是在“调参”,你是在确认系统的基础链路是通的:传感器数据→感知→定位→规划→控制→执行器,这条链上每个环节都没有断。

用 rosbag 录下这个阶段的所有数据。每一次真机测试都要录 bag,这是你事后分析的唯一素材。

第二轮:找瓶颈参数

系统能跑了之后,开始逐步放开参数。这时候最重要的不是“把所有参数都调一遍”,而是识别出 最敏感的 2-3 个参数 优先调。

怎么找?靠观察。在 Foxglove 或 RViz2 里同时打开 costmap 可视化、规划路径可视化、机器人实际轨迹,看哪里出问题:

  • 如果机器人在空旷地方频繁减速或绕路 → inflation radius 太大
  • 如果机器人贴着障碍物走或者偶尔蹭到 → inflation radius 太小或传感器数据有延迟
  • 如果路径规划成功但跟踪效果差(机器人走的弧线和规划的不一致)→ controller 参数需要调(MPPI 的 iteration count、温度参数)
  • 如果机器人频繁触发 recovery behavior → 要看是定位漂了还是 costmap 里有“幽灵障碍物”(清除超时参数太长)

第三轮:压力测试

参数调得差不多了,开始搞破坏。让人故意挡路、把灯关了再开、在地上放一些奇怪的障碍物(透明的、黑色的、反光的)、让机器人连续跑 2 小时看有没有内存泄漏或者性能衰减。

这个阶段你会发现一堆在“正常条件”下永远不会出现的问题。这些问题才是部署到客户现场后会真正出现的。

一个反直觉的经验

很多参数的最优值不是一个固定数字,而是取决于环境。同一台机器人,在开阔的仓库通道里和在狭窄的货架之间,最优的 inflation radius 是不同的。如果你的场景里两种地形都有,你要么用 Nav2 的自适应参数功能(比如根据区域切换不同的 planner 配置),要么找一个两边都凑合能用的折中值。

实际生产部署中,参数配置通常不是一套,而是多套 - 不同楼层、不同时段(白天有人 vs 夜间无人)、不同任务类型(快速搬运 vs 精确抓取)用不同的参数组。管理这些参数组、确保它们的版本可追溯,这本身就是一个工程问题。

真机部署没有”调完”的那一天。仿真做广度(跑 100 个场景确认没有回归),真机做深度(在最接近客户现场的环境里做精细调优)。两者配合的团队,过 Sim-to-Real Gap 的速度比只靠其中一边的团队快得多。

← Previous20. Dev Environment & DevOpsToolchainNext→22. Reliability Engineering