ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

松灵小车深度相机与激光雷达联合标定实战:基于Autoware的外参标定全流程

松灵小车深度相机与激光雷达联合标定实战:基于Autoware的外参标定全流程 前阵子给一台松灵SCOUT小车做深度相机与激光雷达的联合标定顺手把整套流程从硬件准备到外参落地理了一遍。说实话联合标定这个事在Autoware的感知链路里太容易被低估了很多人觉得装上驱动、跑通Autoware就算完事可等到做融合避障或者建图的时候相机图像里的障碍物和雷达点云里的障碍物对不上才知道外参这东西省不掉。这篇文章就把我在松灵小车上实际用Autoware生态完成联合标定的全过程写出来包括原理、实操步骤、核心代码思路以及我在现场踩过的坑给正在捣鼓传感器融合或者被标定折磨的朋友做个参考。1. 为什么深度相机和激光雷达需要联合标定1.1 两个传感器在“各说各话”激光雷达输出的是一堆以雷达自身为原点的三维点单位是米深度相机输出的则是一张张二维图像外加每个像素可选的深度值。雷达坐标系里一个点坐标是( x, y, z )到了相机图像里变成像素坐标( u, v )中间要经过投影变换而投影变换成立的前提是知道两个坐标系之间的旋转和平移关系。在实际整车上absolutely不止有这两个传感器还有车体底盘、IMU、GPS等。Autoware在做规划、控制、避障的时候默认所有数据都已经换算到车体坐标系base_link下了。如果相机和雷达没有标定图像里的障碍物框和雷达点云里的障碍物是两套坐标融合模块根本没法用。举个直观的例子小车前方1.5米处有个纸箱相机看到它在图像左上角某个位置雷达看到它在车体正前方略偏右1.5米如果不标定谁也不知道这两份信息描述的是同一个纸箱。1.2 Autoware到底管不管标定Autoware是开源的自动驾驶系统感知、定位、规划、控制模块都默认传感器已经完成内外参标定。它本身不会帮你去猜传感器装歪了多少度而是提供工具链去引导整个标定过程。在Autoware的生态里联合标定相关的工具常见的有两类一类是Autoware.AI时代就有的calibration_camera_lidar基于棋盘格检测做联合标定另一类是Autoware Universe里的autoware_camera_lidar_calibrator继续沿用“相机-雷达联合观察标定板”的思路只是把接口换到了ROS2。这篇主要讲ROS2/Autoware Universe的路线因为现在新项目用ROS2的比例明显更高而且松灵原厂也在往ROS2上靠。如果你的项目还在ROS1思路基本一致只是启动方式从roslaunch换成rosrun。1.3 标定到底在求什么一句话求外参。外参就是相机坐标系和雷达坐标系之间的变换关系包含一个3x3的旋转矩阵R和一个3x1的平移向量t。有了R和t雷达点云里的任意一点都可以转换到相机坐标系下再结合相机内参投影到图像上。可以把外参理解为两个人站在不同位置看同一栋楼如果想确认对方看到的窗户是不是同一扇必须先知道彼此的位置和脸的朝向。R就是朝向差t就是位置差。标定的过程就是通过两个传感器共同观察同一个参照物反推出这个位置差和朝向差。最终结果一般写成4x4齐次变换矩阵也可以拆成R和t输出到Autoware的tf树中。2. 标定前的准备从松灵小车到标定工具2.1 硬件安装与位置规划松灵SCOUT系列比如SCOUT MINI、SCOUT 2.0车顶是一块完整的安装板留了不少螺纹孔位装传感器比较方便。安装时我会先把相机和雷达的固定支架做好确保装上之后不会因为颠簸移位。标定完成后传感器哪怕偏了1毫米在10米处的误差也会被放大很多所以支架必须锁死。安装位置的数据最好记录一下相机装在车头哪个位置雷达装在哪个位置大致的高度、前后距离、朝向。这些粗值很有用后续标定工具做优化时如果初值离真实值太远容易陷入局部最优给一个靠谱的初值能省很多事。2.2 雷达IP修改与网络调试如果是速腾、Livox这类网络型雷达上电后第一件事是检查电脑能不能收到它的点云。Livox MID-360默认IP一般是192.168.1.1xx之类电脑网卡要配到同一网段比如192.168.1.50。这里有个松灵小车特别容易踩的坑底盘和感知系统会用不同网口一个口连底盘控制器一个口连雷达和相机。连雷达的那个网卡如果没配静态IP系统重启后IP变化雷达点云就会消失。用Livox Viewer2修改雷达IP的步骤大致是这样先把电脑网卡IP改成与雷达同一网段的静态地址打开Livox Viewer2扫描设备在设备列表里点设置把IP改成想要的地址保存后重启雷达。改完IP后再把主机网卡和雷达的IP关系在路由表里固定好避免拔插网线后失联。2.3 ROS2与Autoware标定工具的安装我这里用的环境是Ubuntu 22.04 ROS2 Humble Autoware Universe。如果还没装Autoware建议直接用官方镜像省去源码编译的很多麻烦。先确保ROS2基础环境能跑起来然后安装相机与雷达驱动。RealSense相机驱动可以直接用系统源里的包sudo apt install ros-humble-realsense2-cameraLivox驱动从官方仓库拉下来编译git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd livox_ros_driver2 colcon build source install/setup.bash标定工具autoware_camera_lidar_calibrator也建议单独拉一个工作空间编译git clone https://github.com/autowarefoundation/autoware_camera_lidar_calibrator.git cd autoware_camera_lidar_calibrator rosdep install -y --from-paths . --ignore-src colcon build编译过程中常见的问题是缺依赖用rosdep装一遍基本能解决。如果有包没被rosdep覆盖手工apt装也行。2.4 驱动启动与topic梳理启动相机ros2 launch realsense2_camera rs_launch.py depth_module.profile:1280x720x30启动雷达ros2 launch livox_ros_driver2 rviz_MID360.launch.py启动后用ros2 topic list确认关键话题都存在/camera/color/image_rawRGB图像/camera/color/camera_info相机内参/livox/lidar雷达点云还要用ros2 run tf2_tools view_frames看tf树确认有base_link、camera_link、livox_frame这几个关键坐标系。如果没有说明驱动里的静态tf没有发出来需要自己补一个粗略的外参作为初始值。3. 数据采集让两个传感器“看”到同一块板子3.1 标定板选择与摆放技巧棋盘格标定板是联合标定里最常用的参照物。尺寸建议尽量大A0或1.2米乘0.9米格子数量8x6或9x6都可以。关键是要用哑光磨砂材质不要用亮面覆膜否则激光一打上去会产生大量杂点。摆放板子的时候要让相机和雷达都能同时看到。雷达点云是稀疏的板子太远、角度太斜扫到的点数不够平面拟合质量就差相机视野一般比雷达窄板子太偏会跑到图像外面。我一般把板子放在0.8米到3米范围内左右各偏大概20到30度俯仰角度也稍微变一变。每个位置停几秒让两个传感器都吃到足够的帧。录制bag的命令ros2 bag record /camera/color/image_raw /camera/color/camera_info /livox/lidar /tf /tf_static这里不需要专门录深度相机的depth topic联合标定主要用RGB图像和雷达点云。深度相机的深度值在后续融合中会用到但标定过程中更依赖RGB图像里的棋盘格角点。3.2 时间同步检查录制之前最好先检查一下两个传感器的时间戳有没有对齐。简单方法是用rqt或者写个小脚本订阅两个话题打印最近一条消息的header.stamp看看时间差。如果时间差超过50毫秒标定板在两帧之间只要有轻微移动点云和图像里的板子位置就对不上标定结果一定偏。解决时间同步的办法有几个一是让两个驱动都用硬件时间戳RealSense和Livox都支持PTP或时钟同步二是录制时用--clock选项让bag统一时钟源三是采集时尽量保持机器人静止这样即使消息有几毫秒到几十毫秒的时间差板子位置变化也不大。实际最稳妥的做法是静态采集机器人完全不动用手移动板子到不同位置。4. 核心实战从点云与图像中求解外参4.1 原理棋盘格法向量如何约束外参联合标定最核心的思想是在某一帧中相机看到了棋盘格雷达也看到了棋盘格。相机图像通过角点检测和PnP求解可以算出棋盘格平面在相机坐标系下的位姿进而得到棋盘格平面的法向量n_cam。雷达点云通过裁剪和平面拟合可以算出同一平面在雷达坐标系下的法向量n_lidar。因为是同一块板旋转矩阵R要把n_lidar旋到n_camR * n_lidar n_cam一个平面法向量只能提供两个角度约束所以要多放几个位置采集多帧数据把所有帧的方程联立起来用最小二乘或者奇异值分解求解最优R。求得R之后再根据棋盘格中心点在不同传感器下的坐标差来求t。用生活类比来解释你站在A点伸出手指指向远处一个旗杆另一个人站在B点也指向同一个旗杆两个人的指向方向不同但都对着同一个目标。多换几个旗杆位置拿到足够多的指向数据就能反推出A和B之间的相对位置和朝向。4.2 用工具一把梭autoware_camera_lidar_calibrator实操工具用起来比手写算法省心很多。先把相机、雷达驱动跑起来再启动标定工具ros2 launch autoware_camera_lidar_calibrator calibrator.launch.xml \ camera:/camera/color/image_raw \ lidar:/livox/lidar打开的界面里左边是图像右边是点云。操作逻辑是逐帧处理在图像窗口里确认棋盘格角点检测是否成功然后调整点云裁剪框把棋盘格区域的点选中点击添加这一帧样本。重复这个动作采集10到20帧不同位置的数据然后点击标定按钮工具会跑优化并输出外参结果。官方工具的优势在于它把角点检测、平面拟合、非线性优化都封装好了并且会在界面上显示重投影误差。这个误差值是判断标定质量的关键指标越低越好。如果误差一直降不下来先别急着继续采帧回头检查是不是时间戳不对或者标定板太小。4.3 自己写脚本提取标定板平面并拟合法向量如果不想依赖现成工具或者想更深入理解原理自己写脚本也是可行的。两个核心步骤一是从雷达点云中提取标定板平面并求法向量二是从图像中求解棋盘格位姿得到法向量。点云部分我用Open3D来做平面拟合。首先从bag里读出一帧点云然后用ROI裁剪出标定板可能出现的位置再用RANSAC拟合平面。核心代码如下import numpy as np import open3d as o3d # 假设pcd是已转换到雷达坐标系的点云 pcd o3d.geometry.PointCloud() pcd.points o3d.utility.Vector3dVector(points) # 裁剪ROI只保留可能的标定板区域 bbox o3d.geometry.AxisAlignedBoundingBox( min_boundnp.array([-1.0, -1.0, -1.0]), max_boundnp.array([3.0, 3.0, 3.0]) ) pcd_cropped pcd.crop(bbox) # RANSAC平面拟合 plane_model, inliers pcd_cropped.segment_plane( distance_threshold0.02, ransac_n3, num_iterations1000 ) a, b, c, d plane_model normal np.array([a, b, c]) normal normal / np.linalg.norm(normal) centroid np.asarray(pcd_cropped.select_by_index(inliers).get_center())图像部分用OpenCV的棋盘格角点检测加solvePnPimport cv2 import numpy as np # 棋盘格参数 pattern_size (8, 6) square_size 0.108 # 格子边长单位米 # 角点检测 ret, corners cv2.findChessboardCorners(gray, pattern_size) if ret: # 生成棋盘格三维点坐标 objp np.zeros((np.prod(pattern_size), 3), np.float32) objp[:, :2] np.indices(pattern_size).T.reshape(-1, 2) * square_size # 相机内参 mtx np.load(camera_matrix.npy) dist np.load(dist_coeffs.npy) # 求解棋盘格位姿 ret, rvec, tvec cv2.solvePnP(objp, corners, mtx, dist) # 棋盘格平面法向量第三列旋转列向量 R, _ cv2.Rodrigues(rvec) normal R[:, 2]拿到每一帧的n_lidar和n_cam之后把所有帧的法向量拼起来构建方程组用最小二乘求R# 堆叠所有点的法向量 N_l np.hstack(n_lidar_list) # 3xN N_c np.hstack(n_cam_list) # 3xN # 用SVD求解 R * N_l N_c A N_l N_l.T B N_c N_l.T U, _, Vt np.linalg.svd(B.T A) R U Vt # 确保行列式为1避免反射变换 if np.linalg.det(R) 0: Vt[-1, :] * -1 R U Vt平移t的求解要复杂一些一般利用多个位置的棋盘格中心点建立线性方程求解。实际生产环境不建议完全自己写因为坑很多比如点云异常点、角点误检、法向量方向不一致等。我建议先用工具跑通再自己写代码去复现结果这样即使写错了也能对照。4.4 外参验证从图像重投影误差看标定质量标定完成不等于万事大吉必须验证。最直观的方法是重投影验证把雷达点云按照标定结果投影到图像上看看激光点是否落在图像中的标定板区域。# R和t是标定结果 points_cam (R points_lidar.T).T t.reshape(1, 3) uv (mtx points_cam.T).T uv uv[:, :2] / uv[:, 2:] # 画在图像上 for u, v in uv: if 0 u img.shape[1] and 0 v img.shape[0]: img cv2.circle(img, (int(u), int(v)), 2, (0, 0, 255), -1)在Rviz里也可以直接启动相机图像和点云叠加显示把点云topic的Fixed Frame设为camera_link然后调整点云的颜色和大小肉眼观察边缘是否对齐。这个检查一定要做建议近处、远处各放一次标定板如果近处对准远处偏说明旋转矩阵可能不够准如果远处对准近处偏可能是平移向量有问题。5. 松灵小车落地时的常见坑5.1 时间戳不同步导致标定板位置漂移这个坑我印象最深。第一次标定的时候相机和雷达消息时间差大约200毫秒采集过程中板子稍微动了一下结果标出来的外参平移量偏差了好几厘米。后来我重新采集全程把小车停在原地只动板子同时用工具打印两路话题的时间差确认都在20毫秒内结果一次通过。操作建议采集前一定先看时间戳差值。如果差值较大优先从驱动配置上解决如果解决不了就采用完全静态的采集方式把外部抖动降到最低。5.2 点云中找不到标定板雷达点云稀疏尤其在小角度、远距离情况下标定板上的点寥寥无几。常见原因包括标定板太小、反光太强、距离太远。黑色棋盘格会吸收大量激光能量点云里的板子看起来缺一块是正常的这时候可以借助反射率信息把强度过低或者过高的点过滤掉再用RANSAC拟合平面。我实际用下来的经验是标定板尺寸至少在1米乘0.8米以上位置放在雷达正前方1米到2.5米之间角度不要太极端。如果用的是Livox MID-360这类非重复扫描雷达点云相对密集效果会好一些如果是16线雷达就要更注意板子的放置角度。5.3 外参反复标不准甚至偏了几十厘米如果每次标定结果差异很大不要急着怀疑算法先查几个基础环节先确认相机内参是否准确。相机内参不准外参标定一定不准。RealSense出厂自带的内参一般够用但如果你换了镜头或者镜头被动过建议先用棋盘格重新标定相机内参。再确认传感器安装是否松动。松灵小车在越野场景下震动很厉害安装板上稍微有一点松动标定结果就跟着变。紧固完螺丝重启系统重新采集一遍数据再看结果。还要确认初值是否给得靠谱。Autoware工具和自写算法都需要一个初始外参。我的做法是先量出传感器在车上的大致安装位置输入作为初值再让工具去优化。初值离谱的话优化很容易掉进局部最优。5.4 常见问题速查表问题现象可能原因排查与解决点云和图像里板子位置对不上时间戳不同步检查消息时间戳开启硬件同步或静态采集点云中板子点数太少标定板太小/太远/反光换大板子放近一点用反射率过滤标定误差一直很大相机内参不准单独标定相机内参确认camera_info无误每次标定结果都不一样安装松动或初值不稳紧固支架固定初值重新采集雷达点云在Rviz里时有时无本机IP与雷达IP不在同一网段检查网卡静态IP用Livox Viewer2重新配对外参写入tf后Rviz显示异常tf树缺少静态变换检查tf树补充base_link到各传感器坐标系的变换室内标定效果好到室外就偏地面反光、多路径干扰换到空旷无强反光区域重新验证6. 标定质量对避障与建图的实际影响6.1 外参不准融合感知就是空中楼阁Autoware里做目标检测通常是相机出2D框雷达出3D点云然后在感知融合模块里把两类结果关联起来。外参标定不准相机输出“前方2米有障碍物”和雷达输出“前方2.2米有障碍物”就没法统一避障模块轻则忽远忽近重则直接把一个障碍物看成两个。建图也一样雷达建图本身依赖激光里程计和相机没有直接关系但如果后续要做激光相机融合建图或者要给点云上色外参不对就会看到彩色点云有重影有人管这个叫“建图飘”其实很大程度是标定没做好。松灵小车做园区巡检、物流配送这类任务时传感器安装高度低周围环境复杂外参不准带来的误差会被进一步放大。近处障碍物可能只差几厘米到了5米外的障碍物可能差出二三十厘米这在Autoware的规划模块里是不可接受的。6.2 上电后快速复查外参的习惯标定完成之后建议把复查流程固化下来。我现在的习惯是每次上电后先启动相机和雷达然后在车正前方1.5米处放一块标定板打开Rviz看看点云叠加图像是否对齐。如果明显偏移先用tf2_echo查一下当前外参有没有被覆盖再决定要不要重新标定。上电顺序也有讲究。相机驱动先起雷达驱动再起最后再启动Autoware相关节点。如果Autoware先启动某些静态tf可能会被驱动或者底盘节点重复发布导致标定结果被覆盖出现“明明标好了跑起来又歪了”的情况。6.3 后续扩展建议标定好的外参可以直接用在Autoware的感知管线里也可以在ROS2里结合Cartographer做激光雷达建图。建图的精度提升需要好的外参也需要好的里程计松灵小车的轮式里程计在平坦路面上够用遇到打滑就要靠IMU或者雷达里程计来纠正。另外如果你用的是RealSense这类深度相机联合标定完成后深度相机自带的点云和雷达点云也可以做进一步融合。这时候外参质量直接影响两个点云融合后的密度和精度建议在融合前用上文的重投影方式再验证一遍确认误差在可接受范围内。我个人在实际操作中的体会是联合标定本身的数学原理并不复杂真正耗时间的全在细节上尤其是时间同步、传感器安装牢固度、初始值合理性这三件事。把它们搞定标定基本一次过。最后再分享一个小技巧标定完成后把标定板放在车正前方1.5米处在Rviz里把点云叠加到图像上透明度调到50%看边缘对齐这个人工目检虽然是“土办法”但往往比看RMS误差数字更可靠。我现在已经把这一步加进松灵小车的日常上电检查流程里了。
返回列表