感知(Perception)回答的是机器人与物理世界之间的第一层问题:我周围有什么、它们在哪、长什么样、能不能走、能不能抓。上一页(04-06 视觉 SLAM)讲的是「我在哪、地图长什么样」,本页往下钻一层,讲「这些信息最初是怎么从传感器里被测量、被处理、被融合出来的」。
一台完整的人形机器人,通常在头部集中布置主传感器(视野与人眼对齐,兼顾环视),在躯干放 IMU,在脚底/关节放编码器与力传感器。典型清单如下:
| 传感器 | 典型安装位置 | 测量输出 | 在感知里的角色 |
|---|---|---|---|
| RGB-D 深度相机 | 头部(双眼位) | 彩色图 + 逐像素深度 | 近距离物体识别、抓取、室内建图的主力 |
| 3D 激光雷达 LiDAR | 头部/躯干顶部 | 三维点云(距离 + 角度) | 远距离、全天候避障与几何建图 |
| RGB 相机(单目/广角/鱼眼) | 头部、背部、手部 | 彩色图像 | 语义识别、目标检测、远程遥操作视角 |
| IMU(惯性测量单元) | 躯干(质心附近) | 三轴角速度 + 加速度 | 高频姿态、跌倒检测、与视觉/雷达融合 |
| 麦克风阵列 | 头部环形布置 | 多路音频 | 语音交互、声源定位(判断「谁在说话、在哪」) |
| 关节编码器 / 足底力传感器 | 全身关节、脚底 | 角度 / 力 | 本体感知(proprioception),与外部感知互补 |
相机是感知的地基。几乎所有视觉算法都假设相机可以用针孔模型(pinhole model)近似:三维空间点 P 通过光心投影到成像平面上。理解了内参、外参、畸变三件事,读任何视觉代码都不会再被矩阵吓住。
内参矩阵 K 把相机坐标系下的三维点投影到像素坐标:
外参描述相机本体在世界坐标系(或机器人基座坐标系)中的位置与朝向,是一个 [R | t] 变换:P_cam = R · P_world + t。其中 R 是 3×3 旋转矩阵, t 是 3×1 平移向量。对机器人而言,外参就是「相机装在头上哪个位置、朝哪看」——它把相机测量对齐到机器人坐标系,是后面激光-相机联合标定、手眼标定的核心对象。
| 类型 | 系数 | 成因与表现 |
|---|---|---|
| 径向畸变(Radial) | k1、k2、k3 | 镜片是曲面,光线离中心越远偏折越强;表现为「桶形」(广角)或「枕形」(长焦) |
| 切向畸变(Tangential) | p1、p2 | 镜片与成像平面装配不平行;表现为画面一侧被「拉伸」 |
工程上常用 Brown-Conrady 模型把两者写成一组多项式:dist = [k1, k2, p1, p2, k3]。做标定的目标就是解出这组系数,之后用 cv2.undistort 把图像「拉直」。
标定的经典方法是张正友标定法:用一张已知几何尺寸的平面标定板,从多个角度拍若干张图,通过「已知角点世界坐标 ↔ 检测到的角点像素坐标」这一堆对应关系,解出内参 K 和畸变系数。两张常见标定板:
ROS2 里最方便的是 camera_calibration 包的标定器;纯视觉则用 OpenCV。先跑标定器,再拿着板子多角度移动:
# ROS2 棋盘格标定(9x6 内角点,格子边长 0.025 m)
ros2 run camera_calibration cameracalibrator \
--size 9x6 --square 0.025 --k 4 --r 4 \
image:=/camera/image_raw
# OpenCV(Python)标定核心流程
import cv2, numpy as np
objp = np.zeros((9*6, 3), np.float32)
objp[:, :2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2) # 世界坐标角点
objpoints, imgpoints = [], [] # 逐图检测角点并 append
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-1], None, None)
# mtx = 内参 K;dist = 畸变 [k1,k2,p1,p2,k3]
普通 RGB 相机只能得到「每个像素是什么颜色」,不知道「每个像素有多远」。深度相机(RGB-D)额外输出一张深度图(depth map)——每个像素对应一个真实距离。得到深度有三条主流技术路线,各有优劣:
| 原理 | 怎么测距 | 优点 | 短板 | 代表型号 |
|---|---|---|---|---|
| 结构光(Structured Light) | 投射已知图案(散斑/条纹),图案形变反推深度 | 近距离精度高、成本低、帧率高 | 怕强阳光(图案被冲淡)、量程短、反光表面失效 | Kinect v1、RealSense SR300、Orbbec Astra |
| ToF(Time of Flight) | 发射调制红外光,测往返时间/相位差 | 深度均匀、抗环境光较好、无纹理依赖 | 多径干扰、边缘「飞点」、分辨率略低 | Azure Kinect、Orbbec Femto Bolt、RealSense L515 |
| 双目视差(Stereo) | 左右两相机视差 + 三角测距 | 被动测距、可室外、量程可调(靠基线) | 依赖纹理,白墙弱纹理失效;近距离精度受基线限制 | RealSense D435/D455、Orbbec Gemini 2/330、ZED 2i |
注:RealSense D435/D455 是「主动红外点阵投影 + 双目」的混合方案——红外点阵给弱纹理场景「人造纹理」,再由双目视差计算深度,因此室内弱纹理也能工作。
| 型号 | 厂商 | 原理 | 一句话定位 |
|---|---|---|---|
| D435 / D435i | Intel | 主动红外双目 | 机器人入门标配;D435i 内置 IMU,常作人形头部深度相机 |
| D455 | Intel | 主动红外双目 | D435 升级版:更长基线、更宽视场,中远距离精度更好 |
| L515 | Intel | ToF | 体积小、功耗低,近距高精度,适合桌面/近场操作 |
| Gemini 2 / 330 系列 | Orbbec | 双目 | 高性价比双目,330 系列为 2024 年新品,ROS2 支持好 |
| Femto Bolt | Orbbec | ToF | Azure Kinect 兼容形态,适合「Kinect 生态」迁移 |
| Femto Mega | Orbbec | ToF | 集成 NVIDIA 计算单元,端侧深度 + 推理一体 |
LiDAR(Light Detection and Ranging,激光雷达)主动发射激光脉冲,测量「光线飞出去再弹回来的时间」得到距离,再配上发射角度,拼出三维点云。它不依赖环境光照、测距远、精度高,是避障与几何建图的「硬通货」。
线数指垂直方向同时有多少条扫描线:单线只能扫一个平面(得到 2D 数据,用于平面建图/避障);多线(16/32/64/128 线)垂直堆叠多束激光,直接得到 3D 点云。线数越多、垂直分辨率越高,但点云数据量、功耗、价格也同步上涨。
| 线数 | 典型用途 | 数据量与算力需求 |
|---|---|---|
| 单线(2D) | 扫地机、AGV 平面避障、2D SLAM | 极低,嵌入式即可 |
| 16 线 | 轻量 3D 感知、低速移动机器人 | 较低,数十万点/秒 |
| 32 线 | 服务机器人、园区巡检 | 中等,~百万点/秒量级 |
| 64 线 | Robotaxi、重载移动平台 | 较高,需降采样处理 |
| 128 线 | L4 自动驾驶、高端科研平台 | 很高,百万级点/秒,强依赖 GPU |
| 厂商 | 代表产品线 | 结构 / 线数 | 定位 |
|---|---|---|---|
| 速腾聚创 RoboSense | RS-LiDAR-16、RS-Helios、RS-Ruby | 机械式;16 / 32 / 128 线 | 机器人到 Robotaxi 全覆盖,RS-Ruby 为 128 线高端 |
| 禾赛 Hesai | Pandar64 / Pandar128、QT128、AT128、XT16 / XT32 | Pandar 机械式、AT 转镜式、XT 机器人线 | Pandar128 为 128 线「机皇」;AT128 车规半固态;XT 面向机器人/工业 |
| 镭神智能 LeiShen | C16、C32、LS 系列、CH 混合固态 | 机械式 16 / 32 线 + 混合固态 | 国产高性价比,多用于 AGV/巡检/测绘 |
| 大疆览沃 Livox | Mid-40 / Mid-70、Mid-360、HAP | 棱镜非重复扫描(混合固态) | Mid-360 体积小、重量轻,是人形机器人头部常见选择 |
| 思岚 SLAMTEC | RPLIDAR A1/A2/A3、S 系列 | 单线 2D(三角/ToF) | 2D 建图避障的入门性价比之选 |
点云是 LiDAR 与深度相机的共同产物——一堆带坐标(x, y, z)的点,可能还带强度(intensity)、颜色(rgb)、法线(normal)等属性。处理点云,本质上是「在无序、稀疏、带噪声的离散点上,提取结构与语义」。
| 格式 | 来源 | 特点 |
|---|---|---|
| PCD(Point Cloud Data) | PCL 原生 | 头文件 + 数据体,支持 ASCII/二进制;字段可自定义(x/y/z/intensity/rgb) |
| PLY(Polygon File Format) | 斯坦福,通用 3D | 点 + 面,兼容性好,常用于扫描仪与网格软件 |
| sensor_msgs/PointCloud2 | ROS2 | 二进制消息,靠 fields/point_step/row_step 描述点布局,是 ROS2 感知的标准载体 |
ROS2 里点云在话题上以 sensor_msgs/msg/PointCloud2 传输,常用命令:
ros2 topic echo /points --field data # 看原始点云(数据量大,慎用)
ros2 topic hz /points # 看点云发布频率
ros2 run pcl_ros pointcloud_to_pcd input:=/points # 存成 .pcd 文件离线处理
处理原始点云的标准套路:先降采样 + 去噪,再分割地面,再对非地面点聚类,最后对每个簇提特征/框。用 Open3D(Python)串起来:
import open3d as o3d
import numpy as np
pcd = o3d.io.read_point_cloud("scene.pcd")
pcd = pcd.voxel_down_sample(voxel_size=0.05) # ① 体素降采样
pcd, _ = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0) # ② 统计滤波去噪
# ③ RANSAC 拟合平面(通常就是地面)
plane_model, inliers = pcd.segment_plane(distance_threshold=0.03,
ransac_n=3, num_iterations=1000)
[a, b, c, d] = plane_model
ground = pcd.select_by_index(inliers) # 地面点
obstacles = pcd.select_by_index(inliers, invert=True) # 非地面 = 障碍物
# ④ DBSCAN 聚类(把障碍物分成一个个物体)
labels = np.array(obstacles.cluster_dbscan(eps=0.3, min_points=10))
max_label = labels.max()
print(f"聚类出 {max_label + 1} 个物体")
对应的 PCL(C++)经典写法(思路完全一致):
#include <pcl/filters/voxel_grid.h>
#include <pcl/segmentation/sac_segmentation.h>
pcl::VoxelGrid<pcl::PointXYZ> vg;
vg.setInputCloud(cloud);
vg.setLeafSize(0.05f, 0.05f, 0.05f);
vg.filter(*cloud_filtered); // 体素降采样
pcl::SACSegmentation<pcl::PointXYZ> seg;
seg.setModelType(pcl::SACMODEL_PLANE); // RANSAC 平面
seg.setMethodType(pcl::SAC_RANSAC);
seg.setDistanceThreshold(0.03);
seg.setInputCloud(cloud_filtered);
seg.segment(*inliers, *coefficients); // 地面内点
| 算法 | 解决什么 | 一句话原理 |
|---|---|---|
| 体素降采样 VoxelGrid | 点太多、密度不均 | 把空间切成小立方体,每格用一个质心点代表 |
| 直通滤波 PassThrough | 只关心某范围 | 按 x/y/z 轴区间裁剪点 |
| 半径/统计滤波 | 孤立噪点 | 邻域点太少(半径)或偏离均值太远(统计)就删 |
| RANSAC 平面分割 | 找地面 | 随机抽 3 点拟平面,统计支持点数,迭代取最优 |
| 欧式聚类 / DBSCAN | 把点分成「物体」 | 距离小于阈值(eps)的点归为一簇 |
| 法线估计 | 表面朝向 | 邻域点做 PCA,最小特征值方向即法线 |
| BBox 提取 | 物体外包盒 | AABB 轴对齐框 / OBB 主轴方向框(惯性矩法) |
配准(Registration)求解两帧点云之间的刚体变换,让它们「对齐」。经典两招:
导航栈(本系列 11_Navigation2 实战)不直接消费原始点云,而是消费代价地图(costmap)。点云到代价地图的经典链路:
Nav2 里由 costmap_2d 的 obstacle 层(2D 投影)或 voxel 层(3D 体素,能识别「悬空物与低矮障碍」)订阅点云话题完成这一步;3D 建图则常用 octomap(八叉树)做可压缩、可更新的体素地图。
要把 LiDAR 点云与相机图像对齐,需要求解激光雷达 ↔ 相机之间的外参(R, t)。经典做法是拿一块有棋盘格/标定孔洞的标定板,在两种传感器里同时被观测:从图像里检测角点、从点云里检测标定板平面及其角点,再最小化「点云角点经外参投影到图像后与图像角点的重投影误差」。工程上常用 Autoware 标定工具 或手动 targetless(基于互信息)标定。
单传感器都有盲区:相机怕暗、怕逆光、缺精确尺度;LiDAR 没有颜色、分不清「红绿灯和广告牌」。融合的目标是用几何补语义、用语义补几何。
这是最直观的融合入门实验。利用相机内参 K 与外参 [R|t],把每个 3D 点投影到图像平面取颜色:
投影后,原本「只有几何」的点云变得可读:一眼就能看出哪里是人、哪里是墙,后续标注、调试、演示都清晰很多。反向也可以:把 2D 检测框的像素反投影到 3D,给目标框「量尺寸、定位姿」。
| 机型 | 已公开/拆解可见的传感器方案 | 备注 |
|---|---|---|
| 宇树 H1 | 头部 3D 激光雷达(Livox Mid-360 类)+ 深度相机(RealSense D435i 类)+ IMU(约) | H1 主打通用运动能力,头部集成 LiDAR + 深度相机 |
| 宇树 G1 | 头部 RealSense D435i 深度相机 + Livox Mid-360 激光雷达 + 麦克风/扬声器;主控 RK3588 / Jetson Orin NX(约,据拆解报告) | 感知方案与 H1 同源,成本更克制 |
| 智元 远征 A2 | 头部多相机 + 激光雷达(具体型号约/官方未公布) | 远征系列多款「均配备激光雷达」,强调交互 + 抓取 |
| 智元 灵犀 X1 | 开源平台,提供 RGB-D + 计算单元方案(具体以官方开源为准) | 面向开发者的低成本开源人形 |
| Figure 02 | 多路车载 RGB 相机(官方口径约 6 路)+ 车载 VLM(Helix);未公开 LiDAR 配置 | 强调端到端 VLA,视觉为主 |
注:以上传感器型号随批次与版本变动,「约」表示官方未逐项公布或仅见于第三方拆解,请以各厂商官方规格页为准。
一套最小可跑的 ROS2 感知链路,常用到这几个官方包:
| 包 / 节点 | 作用 |
|---|---|
| pcl_ros | PCL 与 ROS2 的桥:点云格式转换、滤波、分割、配准等节点 |
| depthimage_to_laserscan | 把深度图「压扁」成 2D 激光扫描,供 2D 导航/避障复用 |
| pointcloud_to_laserscan | 把 3D 点云压成 2D 激光扫描(取某一高度切片) |
| image_proc / image_pipeline | 图像去畸变、双目视差、深度注册等基础处理 |
| rtabmap | RGB-D/LiDAR 的 3D SLAM + 稠密建图(见 04-06) |
# 深度图 → 2D 激光扫描(把头部深度相机用于 2D 避障)
ros2 run depthimage_to_laserscan depthimage_to_laserscan_node \
--ros-args -r image:=/camera/depth/image_rect_raw \
-r scan:=/scan
# 点云 → 2D 激光(取机器人高度附近切片,用于 Nav2 局部代价地图)
ros2 run pointcloud_to_laserscan pointcloud_to_laserscan_node \
--ros-args -r cloud_in:=/points -r scan:=/scan_3d
# 观察数据流
ros2 topic list | grep -E "points|scan|image"
rviz2 # 添加 PointCloud2 / LaserScan / Image 显示
| 坑 | 现象 | 对策 |
|---|---|---|
| 点云带宽与帧率 | 128 线雷达每秒数百万点,PointCloud2 消息巨大,网络/CPU 被打爆 | 源头降采样、按需限频、只在必要时订阅原始点云;用 ros2 topic hz 监控 |
| 时间戳同步 | 相机与 LiDAR 帧对不上,融合结果「错位」 | 硬件同步触发(硬同步)或 message_filters 的 ApproximateTimeSynchronizer(软同步);校准各传感器时钟偏差 |
| 外参漂移 | 运行一段时间后,点云与图像逐渐「错开」 | 坚固一体化安装;启动自检;定期用标定板重标定或在线外参估计 |
| 回环与重定位 | 长时间行走累积漂移,回到原点认不出 | 引入回环检测(SLAM 侧,见 04-06);感知侧用场景指纹/视觉词袋做重定位 |
| 算力瓶颈与端侧推理 | YOLO + 点云分割吃满 GPU,整机卡顿、发热 | 模型量化/剪枝、TensorRT 部署、按需触发(靠近才推理)、把重活放到板载 Jetson Orin 等算力单元 |
官方文档与开源仓库见下方「参考来源」小节。学点云,最忌讳「只看不动手」——建议下载一个公开点云(如 KITTI、SemanticKITTI 或自己用 D435i 采一段),把第 5 节的流水线完整跑一遍,再谈进阶。
以下链接为官方文档 / 开源仓库 / 权威拆解报告,关键事实已通过联网检索核实(资料整理更新至 2026-08);标注「约」处为官方未逐项公布或仅见于第三方拆解。