资讯详情

资讯详情

Autoware激光-相机联合标定实战:从环境配置到外参优化全流程

做感知融合的工程师应该都有过这种体验图像里明明看到一辆白色货车点云里对应的反射点却落在两米开外或者雷达的轮廓线叠在画面上怎么看都和实际物体错位。这个偏差的根源就是激光雷达坐标系和相机坐标系之间差了一个“外参”。把这个外参求准的过程就是激光-相机联合标定。今天这篇专门针对Autoware框架在Ubuntu 18.04环境下的激光-相机联合标定工具从安装依赖、启动节点、采集数据到求解落地完整跑一遍遇到的具体坑也会一并说清楚适合正在做传感器融合、刚接触Autoware或者准备给实车做标定的朋友参考。1. 为什么激光和相机要做联合标定两套传感器的对齐难题1.1 外参到底是什么相机看到的是由像素组成的二维图像激光雷达拿到的是带有三维坐标的点云两者各自独立工作的时候没什么问题可一旦要做目标级融合、传感器前融合或者生成训练真值就必须要回答一个问题点云里的某个点在图像里到底落在哪个像素位置。要回答这个问题光有相机内参还不够还必须知道激光雷达坐标系和相机坐标系之间的相对位置和姿态也就是外参。外参通常用一个4x4齐次变换矩阵表示包含旋转和平移两部分。旋转可以用欧拉角、旋转矩阵或者四元数表示Autoware的标定工具最终输出的是四元数加平移向量。这个矩阵的意义可以理解为把激光雷达坐标系下的一个三维点先旋转、再平移挪到相机坐标系下然后通过相机内参投影到图像平面。整个链路就是“激光点坐标→外参变换→相机坐标系→内参投影→像素坐标”。我不止一次看到刚入行的朋友认为相机装好、雷达装好两者坐标自然就对上了其实完全不是这么回事。传感器安装时的机械误差、打孔位置的偏差、支架形变都会让理论安装角与实际相差几度甚至十几度。几度的偏航角误差在50米外就能造成几米的横向偏差这对障碍物匹配、目标跟踪来说是致命的。1.2 标定不准的后果外参不准导致的典型问题大概是这几种。第一是融合目标错位。毫米波、激光和视觉分别检测出的目标明明指向同一个物体但就是因为坐标没对齐后融合算法会认为是两个不同的目标轻则出现双目标、重则造成误检。第二是投影信息错误比如把雷达检测到的正前方车辆点云投影到图像上结果落在旁边车道这在生成BEV特征或者做可视化的时侯非常明显。第三是测距和像素语义不匹配你拿图像上的车道线去关联雷达点会因为偏差把点云分到错误的语义区域直接影响下游规划决策的输入质量。所以联合标定不是“锦上添花”它是所有感知融合工作的前置条件。标定做得好不好直接决定了后续算法上线的下限。与其等整个系统跑起来之后在噪声里找问题不如一开始就把外参标准。1.3 为什么选Autoware自动驾驶开源框架里做激光-相机联合标定的工具其实不少比如Apollo的标定工具、lidar_camera_calibration、ACSC等。Autoware的优势在于它有一个相对完整的图形化标定界面整个流程都是点在按钮上完成的数据采集和结果保存都做了封装不需要自己写太多代码。对于实车站点标定来说这是非常高效的一条路径。另外Autoware 1.x系列在Ubuntu 18.04 ROS Melodic上运行非常成熟社区资料多遇到问题基本都能搜到答案。虽然Autoware.universe现在已经是全新的架构但很多存量系统、教学平台和实车改造项目用的还是1.x。这篇就以实际应用中接触最多的Autoware 1.14/1.15版本为例来讲。2. Ubuntu 18.04下Autoware标定工具的安装取舍源码编译与依赖陷阱2.1 版本与系统选型如果你是第一次在Ubuntu 18.04上装Autoware我建议认准Autoware 1.14以上版本配套ROS Melodic。1.12和更早的版本用的还是旧版catkin构建体系很多包编译时会遇到OpenCV和Qt版本兼容问题标定工具所在的autoware_camera_lidar_calibrator这个包也经历过多次重构越新的版本接口越干净。获取源码直接走官方git仓库git clone https://gitlab.com/autowarefoundation/autoware.ai/autoware.git cd autoware然后建议先安装rosdep依赖再执行官方脚本安装系统依赖rosdep update rosdep install -y --from-paths src --ignore-src --rosdistro melodic ./scripts/install_dep.sh这里有个很多人会跳过的点install_dep.sh里面包含了Qt、飞桨推理库、TensorRT等一大堆东西如果你只是为了做标定并不需要全部安装。装多了反而容易把系统环境搞乱尤其是OpenCV的版本冲突后面编译标定包时会非常痛苦。2.2 依赖安装的两个坑我在干净系统上编译时踩过两个印象深刻的坑。第一个坑是autoware_launcher这个包和Qt5的绑定问题。Autoware 1.14之后的runtime manager界面依赖autoware_launcher它需要找到合适的Qt5库。如果你系统里同时装了Anaconda或者别的Python发行版环境变量里的PKG_CONFIG_PATH或者LD_LIBRARY_PATH指向了非系统路径编译的时候经常会出现找不到Qt5Config.cmake之类的诡异错误。解决思路是编译前临时清空Anaconda相关路径用系统自带的Python和Qt环境。第二个坑是Ceres Solver版本。标定工具依赖Ceres做非线性优化Ubuntu 18.04的apt源里Ceres版本偏旧某些接口在编译时对不上。官方脚本会帮你安装依赖但如果你是手动装的建议直接源码编译最新稳定版Ceresgit clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver mkdir build cd build cmake .. make -j8 sudo make install2.3 编译完成后怎么验证依赖装完后执行下面的编译命令注意建议直接用colcon构建虽然是旧版Autoware但1.14以上已经支持./colcon build --cmake-args -DCMAKE_BUILD_TYPERelease全量编译时间很长机器性能一般的话可能要两三个小时。只做标定不需要等整个工作空间全部编译完可以单独编标定依赖的包./colcon build --packages-select autoware_camera_lidar_calibrator编完后验证是否成功先source环境然后用roslaunch启动标定工具的launch文件能打开图形界面基本就说明安装成功了source devel/setup.bash roslaunch autoware_camera_lidar_calibrator camera_lidar_calibration.launch如果启动后界面正常弹出并且可以在话题下拉框里看到消息列表说明环境没问题。接着就可以进入正式的标定流程了。3. 标定工具的核心工作流程棋盘格检测到外参优化的完整链路3.1 输入输出概览Autoware的激光-相机联合标定工具原理上并不复杂但理解它有助于你判断什么时候该相信结果、什么时候该重新采集。工具输入有两路一路是相机图像话题一般建议直接用原始图像不要用压缩话题另一路是激光雷达点云话题通常是一帧一帧的sensor_msgs/PointCloud2。工具内部会同步这两路消息并在界面上同时显示图像和经过ROI裁剪后的点云。输出则是一个YAML文件里面包含相机内参、畸变系数、图像分辨率以及最关键的外参变换矩阵。这个文件最终会被Autoware的许多模块读取比如points2image、lidar_euclidean_cluster_detect等。3.2 图像侧的棋盘格检测图像侧做的事情是自动检测棋盘格角点。工具里需要你填写棋盘格的内角点数量例如横排内角点7个、竖排内角点6个以及每个棋盘格方格的边长单位是米。OpenCV的findChessboardCorners会在图像中搜索满足行列数量关系的角点图案提取出亚像素精度的角点坐标。这里有一个很容易被忽略的细节棋盘格检测对图像质量要求很高如果阳光直射造成反光或者标定板表面有褶皱、污渍角点检测就会失败。工具界面上的图像窗口会实时显示检测结果如果格子被识别出来会叠加彩色角点标记。我在实际标定中遇到过一种情况棋盘格有一半被车身遮挡工具检测到的角点数量和设定不一致整个区域直接不响应。解决办法很简单调整标定板摆放位置让完整的棋盘格尽量在图像中间区域出现不要紧贴边缘。3.3 点云侧的平面提取与外参优化点云侧的逻辑可以大致概括为在标定板所在区域提取一个平面然后用这个平面和图像棋盘格角点建立约束迭代求解外参。工具界面上提供了一组滑块用来裁剪出包含标定板的点云ROI区域。这一操作的目的是把点云中棋盘格区域单独框出来减少背景点云的干扰。Autoware的实现会对ROI内的点云做平面拟合得到标定板平面的法向量和中心位置。然后结合图像侧提取的棋盘格角点通过非线性优化同时最小化两类误差一类是点云平面投影到图像后与图像检测到的棋盘格平面之间的偏差另一类是激光点云角点和图像角点之间的重投影误差。整个优化会在你点击“Calib”按钮后触发执行。工具内部依赖Ceres做优化优化变量通常就是激光雷达到相机的旋转和平移。这个过程不需要你手动计算但你需要知道优化的收敛质量严重依赖初始值。如果初始外参偏差过大比如安装角度差了几十度优化很可能收敛到局部极小值输出一个看起来合理但实际上错误的结果。3.4 关于相机内参的提醒这个工具解决的是外参问题它默认相机内参已经事先标定好。内参从哪里来通常是两个渠道一是相机驱动节点发布的camera_info话题里面带有内参矩阵和畸变系数二是工具保存的YAML文件里也会把当前相机话题的camera_info字段包含进去。如果你的相机完全没有内参建议先单独做一次相机内参标定棋盘格可以用同样的标定板也可以用标准的Camera Calibration工具。内参不准会直接影响外参求解的精度因为投影过程是“内参外参”一起作用的内参错了外参必然会被带偏。4. 实操从驱动启动到数据采集的全过程4.1 准备话题相机与激光雷达的驱动确认开始标定前先确认相机和雷达的话题是否都已经正常发布。相机这块如果是USB摄像头最简单的办法是直接用usb_camrosrun usb_cam usb_cam_node _video_device:/dev/video0确认话题rostopic list | grep image正常会看到/usb_cam/image_raw和/usb_cam/camera_info。建议先打开图像话题看一眼画面质量确认棋盘格纹理清晰、没有过度曝光。激光雷达这边以Velodyne VLP-16为例roslaunch velodyne_driver VLP16_points.launch确认点云话题rostopic list | grep pointsAutoware习惯使用的话题名是/points_raw。如果你的雷达话题名不是这个最省事的做法是加一行remap把/velodyne_points映射成/points_raw或者在工具界面直接选择实际话题名。工具本身支持任意话题名只是Autoware的许多内部节点默认听/points_raw。4.2 启动标定工具与参数填写确认话题没问题后启动标定工具roslaunch autoware_camera_lidar_calibrator camera_lidar_calibration.launch或者打开Runtime Manager在Sensing标签页下勾选calibration_camera_lidar。工具界面主要分为三块左上角是图像显示区左下角是点云显示区右边是参数配置面板。参数配置面板有几个关键项参数项含义建议值Camera Topic图像话题/usb_cam/image_rawPoints Topic点云话题/points_rawBoard Width棋盘格横向内角点数量7Board Height棋盘格纵向内角点数量6Board Size单个方格边长米0.108Image Topic相机话题旧版界面/usb_cam/image_raw参数填完后点击“Refresh”或者重新选择话题图像区和点云区应该都会有数据。如果点云没有显示就检查一下ROI裁剪滑块把裁剪范围调大。4.3 采集节奏距离、角度与帧数接下来就是整个流程里最影响结果质量的环节采集数据。先说标定板的选择。打印棋盘格时一定要用硬质板做底板KT板或者铝塑板都可以表面尽量平整。打印完成后用尺子量一下实际方格边长不要完全相信打印参数用卡尺量最准。因为指标书里假设一个方格是108毫米结果实际打印出来是102毫米这个误差会直接进入投影误差让标定结果系统性偏大。采集过程中的位置策略我这里说详细一点。在距离上3到8米是比较好用的区间太近了点云稀疏平面拟合噪声大太远了棋盘格在图像里占比太小角点检测不稳定。在角度上不要一直正对着放要交替采集正对、左右偏转30度到45度、上下俯仰角变化的姿态。这个思路是为了让外参解算在不同方向上都有约束避免出现某几个自由度求解退化。具体的操作节奏是摆好一个位置先在图像窗口里确认棋盘格被完整识别再在点云窗口里用滑块让点云中的棋盘格区域落在框内点一下“Capture”采集一帧。然后移动标定板换一个位置和姿态重复操作。整个过程建议采集15到20帧数据量太少会导致优化约束不足太多反而增加后期人工检查的时间。几个不要做的事也提一下。不要在标定过程中移动相机或雷达整个系统必须是静止的只动标定板。不要让行人或者车辆在背景里穿行点云ROI以外的干扰点会影响平面拟合的纯度。不要在有强风或者标定板抖动的情况下采集动态模糊对角点检测影响非常大。4.4 求解与保存采集完所有帧之后点击界面上的“Calib”按钮工具会执行优化求解。观察右侧的误差输出通常单位是像素数值越小越好。如果优化结果看起来合理就可以点击“Save”保存标定结果。输出文件是一个YAML文件默认保存路径可以自己指定。建议给文件起一个能区分传感器编号的名字比如front_camera_lidar.yaml这样后面批量标定多组传感器时不容易混淆。保存时确认文件内容里出现了完整的旋转四元数和平移向量而不是全零或者NaN。全零基本说明优化没跑起来往往是数据量不够或者ROI框选有问题。5. 求解出结果之后标定文件解读与投影验证5.1 标定结果yaml的字段含义标定保存下来的YAML文件大概长这样%YAML:1.0 header: frame_id: velodyne child_frame_id: camera transform: translation: x: 0.258 y: 0.014 z: -0.095 rotation: x: -0.002 y: 0.015 z: 0.512 w: 0.858 camera: camera_model: plumb_bob distortion_coefficients: k1: -0.382 k2: 0.174 p1: -0.0009 p2: 0.0007 k3: -0.061 distortion_model: plumb_bob intrinsic_matrix: fx: 927.14 fy: 923.78 cx: 643.2 cy: 371.6 resolution: height: 720 width: 1280transform部分就是激光雷达到相机的外参。这里要注意坐标变换方向文件里的frame_id是velodynechild_frame_id是camera意思是把点从velodyne坐标系变换到camera坐标系。后面如果要把这个外参用到其他节点里一定要搞清楚它定义的变换方向方向反了标定结果再准也没用。rotation用的是四元数表示想转成欧拉角或者旋转矩阵可以用ROS的tf工具或者Python的transforms3d库。平移向量的单位是米含义是相机坐标系原点相对于激光雷达坐标系原点的偏移。5.2 用可视化验证标定精度标定结果保存后强烈建议做一次投影验证眼见为实。最简单的验证方式是用rviz。启动rviz同时加载相机图像和点云话题然后给点云设置一个固定的坐标变换指向相机坐标系。如果外参正确点云的边缘和图像中的物体轮廓应该基本对齐。更直观的做法是把点云投影到图像上可以用Autoware自带的points2image节点也可以自己写一个小脚本读取YAML文件里的外参和内参把点云中的每个点变换并投影到图像坐标然后看投影点的位置和图像内容是否匹配。实际操作中我会重点关注几个位置标定板区域、车身的边线、路沿。这些位置有清晰的几何轮廓投影偏差比较容易肉眼观察。如果投影偏差在几个像素以内说明标定精度很好。如果偏差达到十几个像素甚至更多那基本可以判定标定过程有问题需要重新检查而不是硬着头皮继续用。5.3 常见误差形态与原因根据我自己的经验最终外参结果常见的误差形态可以归成三类。第一类是整体均匀偏移。投影出来的点云整体往左或者往右偏偏差在图像边缘处更明显。这种情况多半是标定板采集时覆盖的角度范围不够导致某个自由度约束不足。解决办法是回炉补采几个大角度偏转的数据。第二类是近处准确、远处发散。近距离物体投影贴合远处则出现明显偏差这通常是相机内参不准造成的尤其是焦距部分。内参的误差会随着深度放大。第三类是优化结果看着“很怪”输出一个旋转角明显不符合安装结构的值。这种情况大概率是初始值偏差过大优化陷入局部极小值。解决思路是尽量手动调整初始外参到接近真实值再重新采集求解。Autoware界面上没有直接填初始值的地方通常是在代码或launch参数里设置初始变换或者先用一个粗略的测量值初始化。6. 高频踩坑复盘从装环境到跑通全流程的问题清单6.1 安装与启动阶段这个阶段的问题主要集中在依赖和环境冲突上。rosdep install报错找不到依赖先确认/etc/ros/rosdep/sources.list.d/里的源配置没问题然后执行rosdep update再重试。编译时提示找不到OpenCV检查系统里是否安装了多个OpenCV版本如果因为Anaconda引入了新版本建议编译时显式指定-DOpenCV_DIR指向系统库路径。Runtime Manager打开后显示界面异常或者按钮灰化大概率是Qt环境问题试试换一个终端重新source环境变量或者检查QT_QPA_PLATFORM_PLUGIN_PATH环境变量是否被污染。标定工具启动后图像区黑屏先确认相机话题是否真的有数据在发可以用rqt_image_view排除相机自身的问题然后再回到工具界面重新选择话题。这些问题的共同排查思路是不要急着怀疑标定工具本身先用ROS原生的命令确认话题、图像、点云都正常再回到工具层面逐项核对。6.2 采集与求解阶段这个阶段遇到最多的问题是角点检测失败和优化结果不收敛。角点检测失败时先看图像里棋盘格是不是完整可见。我在室外标定时吃过一次亏标定板放在树荫和阳光交界处日光在板面上形成了一半亮一半暗的图案OpenCV怎么都提不出完整角点。后来把标定板挪到阴影均匀的区域问题立刻消失。另外图像分辨率如果特别低比如只有640x480棋盘格离得稍远角点检测就炸了这种情况下尽量用高分辨率相机或者把标定板放近一点。优化不收敛时除了前面说的初始值问题还有一个很容易被忽略的原因棋盘格尺寸填错。如果你填的格子边长为0.108米实际棋盘格边长只有0.09米优化的几何约束本身就是错的再好的算法也算不出正确外参。6.3 离线bag标定与时间同步实车环境不方便现场操作时可以考虑先录制rosbag然后离线播放用同样的工具做标定。录制时需要注意包含以下话题相机图像、camera_info、激光雷达点云、tf静态变换。播放时用rosbag play默认速度即可如果画面卡顿可以降到0.3倍速给标定工具足够的时间处理。还有一点容易被忽视时间同步。工具在同步图像和点云时如果两个传感器时间戳差得太多会出现点云和图像对不上的问题。实际标定中可以把相机和雷达都挂到同一台工控机上用同一个时钟源同步触发如果只能用ROS的软件时钟至少保证use_sim_time参数正确设置并且在回放bag时打开仿真时钟。rosparam set /use_sim_time true rosbag play --clock your_bag.bag离线标定结束后记得在真实系统上再做一次投影验证因为bag数据的时间同步和实车运行时的实际情况可能还有差异不能把离线结果想当然直接部署。回过头来看Autoware这套激光-相机联合标定工具并不复杂核心就三件事环境装好、数据采好、结果检好。环境问题只要按官方依赖走别被多Python环境干扰基本都能解决数据采集是真正考验耐心的环节位置、角度、光线、标定板材质都影响最终质量结果校验则是很多人偷懒跳过的一步但恰恰是这一步能帮你避免把错误外参带到下游。我个人在使用中最深的一点体会是标定不是一锤子买卖。传感器松动、支架微变形、拆装维修之后外参都可能发生改变建议每次上岗前花几分钟做一次快速投影检查发现偏差立刻重新标定。养成这个习惯之后能省掉后续排查融合对齐问题的大量时间。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →