从几何地图到语义认知:机器人如何听懂“去找红色椅子”
机器人篇做到第004号来聊一个从建图走向任务时的真问题SLAM 把环境扫成图了自主导航也能跑了可你对着机器人说一句“去找红色椅子”它为什么还是听不懂这不是段子是很多人在跑通 SLAM 建图和导航之后都会撞上的墙。SLAM 给你的是几何答案——哪里能走、哪里有墙、我在哪里但“红色椅子”是人类语义需要把视觉识别、语义理解、空间定位和任务执行串成一条完整链路。这篇文章就围绕这条链路展开讲讲我从原理到真机实现踩过的坑以及一个可落地的小系统该怎么搭。先说一个关键判断如果你继续优化 SLAM 的精度、换更好的雷达、调更顺滑的建图参数这个问题大概率还是解决不了。因为问题不在“地图够不够精确”而在“地图里没有物体概念”。想知道“去找红色椅子”能不能变成机器人的行动我们得先把 SLAM 建出来的地图到底缺什么这件事聊透。1. 先重新审视SLAM 建出来的图到底只是一张“几何图”1.1 栅格地图、点云地图和“物体认知”是两码事最常见的 2D SLAM比如 Gmapping、Cartographer建出来的是占据栅格地图Occupancy Grid Map。你可以把这张图理解成一张“格子纸”每个格子存一个概率0 表示确定空闲100 表示确定有障碍-1 表示还不知道。导航规划器拿到这张图,只知道哪里可以走、哪里不能走至于这个障碍是一面墙、一个柜子还是一把椅子它完全不关心。3D 点云地图会好一些吗从视觉表现上点云地图确实能看出椅子的轮廓但对机器人来说那就是一堆带三维坐标的点没有类别标签、没有边界框、更没有任何颜色信息。激光雷达即使带反射强度也无法告诉你“这是红色的”普通 RGB 相机有颜色信息但得到的是像素矩阵不是“椅子”这个对象。我见过不少初学者把 Cartographer 或 Fast-LIO 跑得很漂亮办公室里一圈云图在 Rviz 里转起来非常有成就感然后开始给机器人下自然语言指令等待它“理解环境”。实际上机器人的存储系统里只有坐标和几何体没有一个叫“红色椅子”的实体。这就好比给了你一张城市的街道图但图上只画了马路和建筑轮廓没有标“哪个地方有咖啡店”然后让你去“买杯美式”——能走出门但到了目的地也不知道该进哪个门。1.2 “红色椅子”在传感器里到底意味着什么要回答“机器人怎么知道红色椅子”先得拆解人类说出这个词时包含了哪些信息。“红色椅子”至少包含三层内容类别信息它是一把椅子不是桌子或纸箱、属性信息它的颜色是红色可能还隐含可移动、可坐、位置信息在空间坐标系里有一个具体的 pose。这三层信息分别对应不同的感知能力。类别信息需要目标检测或分类模型比如基于深度学习的 YOLO、Detectron2、Grounding DINO颜色属性需要视觉颜色分析通常是 HSV 空间或 Lab 空间的阈值与判断位置信息则要能从图像坐标反推世界坐标这离不开相机标定、深度图像和 TF 坐标变换。而这些没有一样是传统 SLAM 建图环节会帮你做的。SLAM 的定位与建图本质是在估计传感器自身的运动轨迹和环境的空间结构。它给出的“椅子位置”最多是扫描到某个障碍物簇时的几何中心而不是语义对象。这也解释了为什么“SLAM 会用却执行不了语义指令”——因为从建图模型到对象认知之间存在一条明显的断层。1.3 再提升建图精度也补不上语义鸿沟有人觉得是不是我的地图分辨率太低导致椅子没被扫清楚不是。即使你把 2D 栅格地图分辨率做到 1 厘米椅腿之间的空隙可能都能体现出来但地图存储的数据结构里依然没有“Chair”字段。激光扫描到的是物体表面的反射点颜色是光学属性类别是推理产物。所以正确的思路不是改造 SLAM 前端去识别物体而是在建图之上叠加一个“语义层”。几何地图负责提供空间骨架和可通行性语义层负责把检测到的目标对象、属性和位姿记录下来。两者可以分开维护也可以组合使用。我后来选择的工程架构就是“底图跑 Nav2语义层跑对象数据库中间通过坐标变换和状态机衔接”。这个分层思路是理解整篇文章的基础。后面要说的所有方法几乎都是为了在不破坏 SLAM 稳定性的前提下给机器人补齐“理解红色椅子”的能力。2. 给机器人认识“红色椅子”我试过的三种路线2.1 路线 A离线人工标定先录一把“目标入库”最朴素的方法是我先带机器人找到那椅子人工告诉它“这个位置叫 red_chair_001”。具体操作就是把机器人开到椅子附近通过遥控器微调位姿然后记录当前机器人在 map 坐标系下的位置再输入一个标签保存到数据库里。这个方案简单到什么程度它甚至不需要深度学习也不需要相机只要机器人本身定位准确能在之后导航到记录点就行。仓库、工厂和很多固定场景的 AGV 到现在还是采用类似逻辑把“托盘”“充电桩”“工位”作为预置坐标写进系统本质上就是人工做了一次语义标注。优点是非常稳定、可预期缺点也非常明显如果椅子被移动了机器人不知道如果现场出现一把新的红色椅子它也不会自动认识如果用户换个说法“去找那把会客椅”你依然要重新标定。所以这条路适合“点位少、环境固定”的场景不适合做通用语义理解。但它给我提供了一个很清晰的启示所有复杂系统都至少要有一个“对象登记表”否则后续识别结果没地方放。2.2 路线 B在线目标检测把“当前看到的椅子”流式写入地图这是我在家用机器人项目上真正采用的做法。机器人运行时RGB-D 相机的每一帧图像都会经过目标检测模型识别出常见物体类别比如椅子、桌子、沙发、人。检测到椅子后再对检测框内的像素做颜色分析判断是不是红色。如果检测到“红色椅子”就把检测框对应的深度像素值读出来结合相机内参反投影成相机坐标系下的三维点再通过相机到机器人 base 再到 map 坐标系的变换得到这个物体在地图坐标系下的位置。这条信息会写进对象的临时数据库时间戳、置信度、位置一起存下来。在线检测最大的好处是机器人可以在自主探索或日常巡航过程中增量式地构建“语义物体列表”。哪怕没有专门去看椅子只要路过时扫到了它就会自己记录下来。之后“去找红色椅子”直接查对象数据库就能选出一个坐标不用重新扫描整个房间。当然在线检测也有不少坑。检测模型的推理速度、目标框抖动、深度图中的黑洞、相机外参误差都会直接影响语义坐标的准确性。后面我专门用几个小节讲这些坑。2.3 路线 C开放词汇模型让机器人认识“没见过的椅子”传统检测模型的问题是只能识别训练集里的类别。如果我的数据集里只有 “chair”用户说“去找红色椅子”模型能检测出椅子再靠颜色过滤解决但用户如果说“去找那个电竞椅”传统模型大概率无能为力除非你给数据集新增 “gaming_chair” 类别并重新训练。开放词汇检测模型则把这件事变成了“文本和图像的匹配问题”。你可以传入任意文本短语比如 “red chair”“gaming chair”“office chair with armrests”模型在当前图像中找对应区域。Detic、Grounding DINO、CLIP 这类模型的思路各不相同但都能让机器人对“新词”有一定泛化能力。在服务机器人的原型阶段这是很诱人的方案。代价也很明显模型体积大、对推理硬件要求高、延迟不稳定。我在 Jetson Orin Nano 上跑轻量级检测模型还能实时跑开放词汇模型就明显吃力。如果你也在做类似项目建议不要一上来就追求“什么都会认”的大模型先在固定类别加颜色属性这条路上跑通。跑通之后你把检测模块替换成开放词汇模型的难度并不高接口是相同的。为了帮助你快速决策我把三条路线放在一起对比路线识别新类别难度地图维护成本硬件要求适用环境A 离线人工标定重新标定低固定点位极低固定工位、仓储场景B 在线固定类别检测需扩展训练数据中需处理动态目标中普通 GPU/嵌入式即可家庭、办公室等常见物体C 开放词汇模型低文本即类别高高需要独立推理设备科研原型、高动态变化场景3. 一句“去找红色椅子”在系统里经历了怎样的拆解3.1 第一步语言拆解知道“想让我干什么”自然语言指令“去找红色椅子”表面看是一句话但系统内部要先把它转成一个结构化表达。我的做法是先做意图识别和槽位抽取。意图是“去某地找某物”槽位包括目标类别 椅子颜色属性 红色动作方式 移动到目标附近。如果用户说“去厨房找红色椅子”位置槽就多了一个“厨房”区域如果用户说“把这把红椅子推过来”动作就从“导航至附近”变成了“导航 操作”。在原型阶段不一定要上大语言模型。简单关键词模板匹配就能应付“去找红色椅子”这类句式先匹配动词“找”或“去”再匹配类别词再过滤颜色词。问题是这种匹配在真实对话中很脆弱“帮我看看客厅有没有红色椅子”“刚才那把椅子在哪”都不好处理。我现在的做法比较务实基础语义由轻量级 NLU 规则承担意图不清晰时交给大语言模型做一次上下文补全例如把“那把椅子”解析为“之前提到过的红色椅子”。对于固定命令式任务规则系统完全足够如果做聊天机器人或复杂人机交互再引入 LLM 也不迟。3.2 第二步目标绑定把“红色椅子”对应到地图里的一个对象语言层给出“类别椅子颜色红色”之后下一步是查询语义对象数据库。这个数据库里可能已经有三条记录客厅红色单人椅、书房的黑色转椅、阳台蓝色塑料椅。查询逻辑很直接筛选类别为椅子、颜色包含红色的记录。如果只有一条记录系统就直接选中如果有两条以上红色椅子就要用到“指代消解”和场景优先级。机器人当前在客厅客厅这条红椅置信度又高就优先选它如果机器人站在门口两条红椅都在不同方向那就得触发澄清用语音合成反问用户“你要找客厅那把还是卧室那把”这一步经常被忽略。很多人以为自然语言处理完了就直接导航实际上“找哪个目标”本身就是一个不确定性问题。我在最初实现时遇到过最尴尬的情况地图里早就记录了办公桌左侧有一把红色折叠椅但我后来把它挪到了阳台机器人执行旧指令时会固执地跑到办公桌旁边对着空气说“找到了”。所以语义对象不能只有名字和坐标还要有时间戳和“最近观测状态”。3.3 第三步行为编排导航只是任务里的一个动作“去找红色椅子”这个任务如果按传统导航框架理解就是给 move_base 一个目标点。但实际完整行为至少包括查询候选目标、确认是否能直接到达、发布导航目标、跟踪导航状态、到达后二次确认、返回任务结果。如果机器人在行进过程中迷路或被障碍挡住那么系统应该在超时后重新规划或者调整目标点如果到了目标点附近却没有在相机视野里发现红色椅子系统不应直接任务成功而是应该原地旋转一圈尝试再次检测。若始终找不到再向用户报告“目标可能不在预设位置”。我在代码实现里把这套逻辑写成了状态机。状态包括 IDLE、QUERYING、PLANNING、NAVIGATING、ARRIVED、CONFIRMING、REPORTING、ABORTED。每个状态都有进入条件和退出条件。别看这个状态机简单它把自然语言到最终行动的每个节点都变成了可测试、可追踪的动作。这也让我意识到“机器人知道你说什么”从来不只是算法问题还是任务编排问题。4. 一个可落地的例子在 ROS2 机器人上实现“去找红色椅子”4.1 我用到的硬件和软件栈先交代一下我跑通的这套配置方便你做参考。机器人底盘是差速轮式小车搭载了一块 Jetson Orin Nano 作为主控。建图用的传感器是 2D 激光雷达型号是 RPLIDAR A2负责运行 SLAM 构建 2D 栅格地图。识别红色椅子用的是 Intel RealSense D435i它是 RGB-D 相机能同时输出彩色图和深度图。ROS2 环境是 Humble导航栈用 Nav2。为什么没有直接上一套 3D 激光雷达做视觉语义原因很简单2D SLAM Nav2 在家庭场景已经足够稳定门槛低、材料多、调试成本小。视觉语义层完全由 RGB-D 相机补足不一定要和高精点云建图绑在一起。如果你已经有 Fast-LIO 或 LIO-SAM 建的点云地图可以把导航代价层换成 3D 的但针对“语义目标定位”的原理是一样的。4.2 视觉结果变成地图坐标的三个关键步骤要发布一个 Nav2 能接受的目标位姿我必须完成从“图像像素”到“map 坐标”的转换。整个过程分成三步。第一步在彩色图中检测椅子并判断颜色。检测模型输出目标框矩形框内像素做 HSV 颜色统计如果红色占比超过阈值就认为这个检测结果是“红色椅子”。这一步的输出是二维图像坐标比如目标框中心点 (u, v)。第二步从深度图读取目标中心位置的深度值。RGB-D 相机如果做了对齐彩色图和深度图的像素是一一对应的。深度值为 Z单位是米。结合相机内参可以用针孔模型反投影出相机坐标系下的三维坐标 X (u - cx) / fx * Z Y (v - cy) / fy * Z Z Z 这里的 cx、cy、fx、fy 是相机内参通常在相机标定或厂家出厂参数里能拿到。第三步把相机坐标系下的点变换到机器人 base 坐标系再变换到 map 坐标系。这一步依赖 TF 树我写了类似 transformPoint 的调用输入相机坐标系中的一个点查询 camera - base_link - map 的变换关系输出地图坐标点。重点提醒查询时一定要判断 transform 是否可用不要盲目缓存旧变换尤其在机器人刚启动、TF 树还没稳定的时候这一步特别容易出错。4.3 观察点要比目标点本身更重要工程上还有一个经验“去找红色椅子”的目标点最好选择“能清楚看到椅子的观察位置”而不是直接指向椅子的几何中心。为什么对于导航机器人来说最终目的是“找到并确认红色椅子”机器人需要站在一个合适的距离和角度让相机能看到它。我处理的方法是对目标物体坐标做一次“可视偏移”沿着物体朝向的反方向推出 1.2 米作为导航目标点。比如椅子面向客厅中央机器人就从椅子前方 1.2 米位置看过去。如果椅子紧贴墙角观察点就位于它的斜前方。用这个观察点导航到达后相机基本能正对目标二次检测的成功率高很多。如果没有这个观察点设计单纯导航到椅子坐标上机器人很可能会贴着椅子相机里只有红色椅背的局部纹理检测框极不稳定二次确认经常失败。后来我把观察点计算也放进对象数据库每次更新坐标时顺手存一个 suggested_view_pose问题就解决了。4.4 目标数据持久化不能让机器人每次“失忆”语义识别出的坐标如果只放在内存变量里机器人重启之后就全忘了。我在 map 目录下放了一个 JSON 数据库每条对象记录至少包含这些字段object_id、class_name、color、x、y、yaw、confidence、last_seen、view_x、view_y、view_yaw。启动时加载运行时更新退出时保存。值得强调的是对象数据库和 SLAM 的栅格地图是分开保存的。栅格地图负责静态环境的通行性对象数据库负责动态物体的语义位置。这样即便你优化了 SLAM 地图、重写了代价地图参数对象数据也可以保留。反过来如果目标物体移动了你只需要更新数据库中的坐标不需要重新建图。5. 真机调试最容易翻车的 5 个地方5.1 颜色识别在光照变化下非常脆弱我第一次真机测试时选了下午四点的客厅阳光从窗户斜射进来红色椅子的识别效果还行。到晚上开暖黄色吸顶灯后同一把红椅子在相机里变成了偏暗的橙红色HSV 的红色阈值直接失效。后来我把颜色判断从 RGB 改成了 HSV 空间并且把 Hue 范围放宽到 0~10 和 170~180 两个区间Sat 和 Value 做了自适应下限才算稳定一些。如果你觉得“红色”很好识别说明你还没在复杂光照下试过。经验是不要只依赖单个像素的颜色要看目标框内的颜色直方图甚至结合检测模型输出的类别置信度做加权。户外场景更麻烦自动白平衡会让同一种红色在不同时段产生完全不同的 RGB 值。加上相机白平衡锁定的思路可能比调阈值更实用。5.2 多把红色椅子在场时的选择策略客厅和餐厅各放一把红色椅子机器人站在过道中间查询结果返回两个候选。如果系统默默选择第一条记录用户看到机器人走向了客厅可能根本不是他想的那把。这里需要“澄清”或“主动猜测”。我的策略是如果候选有多个先看各候选是否在最近的语义地图中可见。可见且距离近的候选优先如果两个都在视野中我会让机器人播放语音“附近有两把红色椅子你要找哪一把”然后等待用户通过触摸屏选择或语音回复“左边那把”。语音交互一旦介入“左右”又要和机器人当前朝向绑定这又是一个新的语义对齐问题。所以更实用的做法是给每个语义目标记录一个语义别名“客厅红色单人椅”“阳台红色折叠椅”在澄清时直接列出用户很容易确认。5.3 相机外参没标定投影点会偏得离谱视觉检测结果转地图坐标误差来源里最容易被忽视的是相机到机器人底盘的外参。机器人底盘里相机的安装位置通常和激光雷达中心不重合如果使用默认值或者粗略量测你会发现检测出的物体坐标和实际位置差出二三十厘米很正常。我最初直接用尺子量相机安装位置填入 URDF误差在 5 厘米内导航到椅子附近没问题但当椅子靠近墙壁时偏差可能导致机器人尝试“穿墙”到墙的另一侧。后来我用标定板做了一次相机到 base_link 的外参标定把旋转和平移都精确到毫米级物体坐标的误差才降到可接受范围。你如果不想做太复杂的标定至少要在运行时通过 TF 工具确认相机坐标系和 base_link 的变换不是凭空拍脑袋写的。5.4 不要把检测到的物体直接画进代价地图很多人做完目标检测后会顺手把物体中心点标成代价地图里的障碍物因为这样机器人会绕开它。这个做法在静态物体上还行但椅子是会移动的。一旦你今天把它当作永久障碍写进 costmap明天椅子挪走了地图里却还留着“鬼影”导致机器人规划路径时莫名其妙绕一个圈子。我建议不要一上来就修改全局成本图。临时检测到的物体可以作为“动态物体列表”单独管理只在当前会话中有效。如果想让机器人避障可以在 local costmap 中传递一个瞬时障碍层如果目标是最终要去的位置那更不能把它设置成永久障碍否则导航规划会认为目标不可达。5.5 目标位置应该在导航结束后被再次确认和更新机器人到达观察点后应该再做一次完整的“确认循环”检测红色椅子、投影到地图坐标、和目标数据库中的历史坐标做比较。如果两次检测结果的距离误差大于阈值就以后者为准更新对象位置同时更新 last_seen 时间戳。这个机制在椅子被挪动过的情况下特别重要。旧坐标不仅会导致导航去错地方还会让用户觉得机器人“很蠢”。加上二次确认后机器人至少有机会发现位置变化然后进行修正。当然如果二次确认也找不到目标我就会触发重新搜索流程在原地旋转 360 度扫描常见物体并更新数据库仍然是找不到就上报用户处理。6. 从“跑通Demo”到“像点样子”语义层设计里的几条体会6.1 把地图和对象数据库分开是最重要的架构决策我在前面的实现中反复提到“对象数据库”这确实是总结下来最值得坚持的做法。几何地图是低动态层代表环境的固定结构语义对象库是高动态层记录物体标签、时间戳和置信度。二者通过坐标系统一但不直接耦合。这样做的好处是重定位、重新建图和语义对象更新互不拖累系统每个部分都能独立调试。如果你去看很多科研中的“语义 SLAM”论文会发现它们尝试把目标识别和地图估计融合到一个概率模型里理论上很优雅实践时却需要大量调参。对于普通机器人项目我更推荐先跑通“分离式语义地图”把对象数据库和 SLAM 图松耦合等系统稳定后再考虑深度融合。6.2 语义对象要带“生命周期”不能一直有效红色椅子今天在客厅明天可能在卧室后天可能被搬到阳台。如果对象数据库里每一条记录都是永久的时间一长机器人查询时会被大量过期信息干扰。我给对象记录增加了置信度和时间戳并设置一个有效周期。如果一件低频移动的物体超过三天没有被重新观测到它的查询优先级就会降低如果在线识别到同一物体出现在新位置就更新而不是新增。对于临时出现的目标比如用户带来的折叠椅则标记为 ephemeral任务结束后自动清理。这套机制虽然简单却让机器人对不同物体的“记忆稳定性”有了区分。6.3 想继续做深下一个重点不是更多模型而是目标重识别很多人觉得让机器人认识更多物体是下一步重点我反而觉得更有价值的是“目标重识别和长期更新”。机器人今天看到的那把红色椅子明天还能认出它是同一把吗如果两把完全相同的红色椅子出现过怎么保证不会把它们的身份搞混这些小问题会直接影响用户体验。“去找红色椅子”不只是找到任意一把红椅而是要找到用户心里想的那一把。解决目标重识别需要视觉特征嵌入、对象跟踪和时间一致性约束模型和工程复杂度都会上升。如果你也想做系列机器人项目我建议在一次导航任务跑得很顺之后优先花时间打磨这一步它会让你对“机器人到底知不知道自己在找什么”这件事有完全不同的理解。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →