pointcloud_to_laserscan(三维地形点云转二维扫描)
pointcloud_to_laserscan(三维地形点云转二维扫描)
实车先看:哪些三维点会被画进二维地图
当前建图链为:
terrain_map_ext(odom系地形点)
→ pointcloud_to_laserscan(转到底盘系,筛选并投影)
→ obstacle_scan(base_footprint系二维扫描)
→ slam_toolbox(二维建图)
这个节点在整套 slam:=True 启动中使用。已有地图导航 slam:=False 不走这个入口;当前局部/全局代价地图直接使用地形点云,并非依靠这份二维扫描更新障碍。
扫描以 base_footprint 原点为中心,方向按底盘系表达。 输入虽来自MID360,却不是原始雷达点云,而是 terrain_map_ext;其中 intensity 已被改成相对估计地面的高差,单位m,不是雷达反射强度。
| 实车上看到的现象 | 先看哪些参数或条件 | 怎样理解 |
|---|---|---|
| 正常坡面被画成障碍 | 地形估计、min_intensity | 当前10 cm高差门槛可能接纳被误估成凸起/凹陷的坡点;降低门槛也会接纳更多小障碍和噪声 |
| 下坡较远处的点消失 | min_height、target_frame方向 | 这里重新要求底盘系z不低于-0.5 m;上游按距离放宽高度范围,并不保证能通过这里 |
| 高处横梁、悬空结构被画成墙 | max_height、max_intensity、上游地形筛选 | 通过筛选的点会压到二维平面;目前z上限6 m很宽,是否妨碍车辆通行需按实车包络判断 |
| 车旁小障碍没进入地图 | range_min、min_intensity 和上游输出 | 0.3 m内的点或高差不足10 cm的点会被删;本节点也不能恢复上游丢掉的点 |
| 小杆或障碍边缘漏掉 | angle_increment、点云密度 | 当前约0.5°一个角度格,每格只留最近合格点;分格更细不能补出原本没有的回波 |
| 以为扫描固定20 Hz,实际不是 | scan_time、输入点云周期 | 0.05 s只写入消息,发布由点云回调驱动,没有20 Hz发布定时器 |
| 有点云却没有扫描 | 下游订阅、坐标TF、字段 | 没人订阅扫描时不接点云;当前需要有效TF以及XYZ、intensity字段 |
参数
ros__parameters(ROS节点参数)
参数表
前13项对应当前实物 YAML;仿真仅 use_sim_time=True。另外列出源码默认的3项,明确TF等待与无回波编码的条件。
pointcloud_to_laserscan:
ros__parameters:
use_sim_time: False
target_frame: base_footprint
min_height: -0.5
max_height: 6.0
min_intensity: 0.1
max_intensity: 2.0
angle_min: -3.1415926 # 约 -π,-180°
angle_max: 3.1415926 # 约 +π,+180°
angle_increment: 0.00872665 # 约 π/360,0.5°
scan_time: 0.05
range_min: 0.3
range_max: 10.0
use_inf: true
原配置把 angle_min/max 的注释写成 ±π/2,与数值不符;当前数值对应约±π,扫描角域约360°,不是180°。
| 参数名 | 当前值 | 单位 | 实车处理建议 | 作用 | 调大效果 | 调小效果 | 生效条件/备注 |
|---|---|---|---|---|---|---|---|
use_sim_time | False;仿真 True | 不适用,布尔 | 上实物前必须核对并正确配置 | 控制节点与TF缓存的ROS时间 | 不适用 | 不适用 | 输出沿用输入点云时间戳,不重新按当前时间打点;应与上游和机械TF使用相同时间域 |
target_frame | base_footprint | 不适用,坐标系名称 | 上实物前必须核对并正确配置 | 先把点坐标转到此系,再按它的原点和轴投影 | 不适用 | 不适用 | 当前是底盘系虚拟扫描;不是只改frame_id;TF不可用时无法正常转换;空值保留输入系 |
min_height | -0.5 | m,目标系z下界 | 上实物前必须核对并正确配置 | 删除低于底盘原点下方0.5 m的点 | 下界上移,更多低处/下坡点被删 | 下界下移,保留更多低处点,也可能引入无关低层 | 固定高度窗口,不随距离扩大;不是相对局部地面的高差 |
max_height | 6.0 | m,目标系z上界 | 上实物前必须核对并正确配置 | 删除高于底盘原点上方6 m的点 | 保留更多高处点,悬空结构也可能进入二维图 | 更多高处点被删,也可能丢掉障碍的可见部分 | 不是整车高度;点还必须通过高差门槛与上游规则,调大不保证出现更多点 |
min_intensity | 0.1 | m,当前地形点的高差下界 | 实物运行时重点观察,有问题再针对性调整 | 只接纳相对估计地面高差至少10 cm的点 | 忽略更多小高差,可能减少坡面误判,也会漏低障碍 | 接纳更多低障碍,也更容易把地面噪声/坡面当障碍 | 当前输入不是反射强度;地形估计不准时不能只靠这项纠正 |
max_intensity | 2.0 | m,当前地形点的高差上界 | 通常保持当前值,不作为优先调试项 | 删除高差超过2 m的点 | 允许更多大高差点 | 更多大高差点被删 | 当前近场正常高差低于0.5 m、远场低于1 m,2 m通常不再额外裁剪;条件仍被执行 |
angle_min | -3.1415926 | rad,目标系平面方位角 | 通常保持当前值,不作为优先调试项 | 指定角域下界,当前约-180° | 下界提高,角域缩小 | 下界降低,角域扩大 | 与上界共同定义方位覆盖;不是雷达垂直视场或云台机械角 |
angle_max | 3.1415926 | rad,目标系平面方位角 | 通常保持当前值,不作为优先调试项 | 指定角域上界,当前约+180° | 上界提高,角域扩大 | 上界降低,角域缩小 | 当前近似整圈;需与下界、增量及数组边界共同核对 |
angle_increment | 0.00872665 | rad/角度格,约0.5° | 实物运行时重点观察,有问题再针对性调整 | 把方位角划分为离散格 | 格子更粗、项数减少,近邻方向更易合并 | 格子更细、项数增加,稀疏输入时空格更多 | 当前生成720项;不改变MID360采样密度或点云降采样;应为正数 |
scan_time | 0.05 | s,消息中的扫描间隔 | 上实物前必须核对并正确配置 | 给LaserScan.scan_time字段赋值 | 消息声明更长间隔,发布周期不变 | 消息声明更短间隔,发布周期不变 | 应与实际输入/输出扫描周期对应;不是固定20 Hz开关;time_increment另写死为0 |
range_min | 0.3 | m,目标系水平距离 | 上实物前必须核对并正确配置 | 删除虚拟中心0.3 m内的点 | 近处点删得更多,可能漏车旁障碍 | 保留更多近点,也可能带入自车回波 | 距离为sqrt(x²+y²),以base_footprint为中心;不是雷达三维斜距或完整自车掩膜 |
range_max | 10.0 | m,目标系水平距离 | 实物运行时重点观察,有问题再针对性调整 | 删除虚拟中心10 m外的点 | 接纳更远的已有点,也增加远处稀疏/噪声影响 | 截掉更多远处轮廓 | 不提高硬件量程;还受地形输出覆盖和下游扫描范围限制 |
use_inf | true | 不适用,布尔 | 根据实际功能需求开启或设置 | 为没有合格点的角度格选择无回波表示 | 不适用 | 不适用 | True写+∞;False写range_max+inf_epsilon;没有合格回波不等于确定空地 |
transform_tolerance | 0.01,源码默认;YAML未配置 | s,变换查询等待时间 | 通常保持当前值,不作为优先调试项 | 点云转换时等待所需TF | 可等待更久,也可能延后处理 | 更快放弃缺失变换 | 当前传给TF查询的timeout;不是时间戳偏移或点云同步误差容差;空target_frame时不用 |
queue_size | 硬件并发线程数,源码默认;YAML未配置 | 消息数,计数 | 通常保持当前值,不作为优先调试项 | 设置点云订阅及TF消息过滤队列深度 | 可暂存更多消息,可能增加积压 | 缓存更少,TF未就绪时更易丢消息 | 默认随机器而变;不是CPU工作线程数、发布频率或扫描点数 |
inf_epsilon | 1.0,源码默认;YAML未配置 | m,超出量程的附加值 | 当前运行不使用这个参数,暂不调整 | use_inf=False时生成无回波哨兵值 | 启用该分支后:哨兵值离range_max更远 | 启用该分支后:哨兵值更接近range_max | 当前use_inf=True,不参与结果;False时默认无回波为10+1=11 m;启用时宜保持正附加值,避免落入有效量程 |
参数详解
target_frame:扫描的中心和方向是底盘,不是云台或雷达
当前输入 terrain_map_ext 的点坐标在odom中;转换使用输入消息时间戳对应的 base_footprint←odom,随后以转换后的x、y、z筛选。输出 obstacle_scan.header.frame_id 为base_footprint,时间戳沿用输入。
平面角度以该系+x为0,绕+z逆时针为正;距离以该系原点计算。它与 fake_vel_transform 最终按云台系表达的速度指令是两条不同接口:这里处理测距轮廓,没有给底盘或云台下运动指令。
因此这是底盘原点上的虚拟二维扫描,不是MID360原点上的真实激光束。MID360与底盘有安装偏移,不能把range_min理解成“离雷达外壳0.3 m”。输入是累积地形结果,含不同时间、不同高度的点;同一角度格只留最近的合格点,也不重新验证从底盘虚拟中心到该点是否存在真实光路或遮挡。
正确的上游配准和机械TF应让独立云台yaw转动后的静态环境仍转换到底盘方向;不能对这份点再手工重复加一个云台角。MID360挂在gimbal_yaw、随yaw不随pitch转动,两条odom关节固定的机械约定继续适用。
base_footprint 这个名字不会自动把TF中的z、roll、pitch清零。当前sensor_scan_generation保留完整三维位姿,所以投影是该系的x-y平面;上坡时它是否真正与地面投影/预期水平面对应,需要核对参考系定义及上游姿态,不能仅凭名称判断。
若target_frame设空,源码不转换点,直接在输入系中计算。当前输入为odom,这就变成以odom原点和方向作虚拟中心;机器人移动后,它不等价于仍以底盘为中心投影。
min_height、max_height 与两项intensity:两把不同的尺
高度窗口看 z_base_footprint,即点相对底盘原点、沿底盘z轴的坐标;高差窗口看 intensity,即上游地形分析给出的“离估计地面多远”。它们单位都是m,但基准不同。
假设上游已保留这些点,其他条件也满足:
| 点在底盘系中的z | 上游给出的地形高差 | 本节点结果 |
|---|---|---|
| +0.2 m | 0.15 m | 两个窗口都通过,参与二维投影 |
| +0.2 m | 0.06 m | 高差不足0.1 m,被删 |
| -0.7 m | 0.2 m | 低于-0.5 m高度下界,被删,即使高差足够 |
所以远处下坡点即使通过扩展地形节点随距离放宽的窗口,仍可能在这里被固定下界删掉。上坡、下坡是否连续可见,要同时看target_frame的方向与高度窗口;disRatioZ 不会替本节点放宽范围。
min_intensity=0.1 把10 cm作为进入二维障碍轮廓的高差下限,不是说车辆能跨10 cm台阶。降低它可能看见更低障碍,也可能把正常地面或坡面误差画进地图;提高它会减少小高差轮廓,却可能漏掉对实车危险的低障碍。远场地形高差取绝对值,坡面较低一侧也可能过门槛;近场目前忽略负高差,4 m交接处的差异仍会传入扫描。
max_height=6.0 的窗口很宽。若高处横梁等点通过上游和高差筛选,就会被压到二维地图中,即使车本来能从下面通过也可能形成障碍轮廓。应该根据底盘、云台活动包络与悬空结构核对要保留的高度,不能把它当模型尺寸;同时也不能只调小上限而漏掉障碍唯一可见的部位。
当前正常地形输出近场高差低于0.5 m、远场低于1 m,因此max_intensity=2 m通常不额外删点;这不表示参数没被读取。若换输入、调整上游或出现其他标记点,效果会改变。高度与高差门槛使用“小于下界/大于上界则删除”,边界值可通过。
本地实现要求float类型的XYZ与intensity字段;没有intensity字段的点云不能直接套用。若接原始雷达点,intensity可能恢复为反射强度,这时0.1/2.0不再代表10 cm/2 m;不应仅换话题继续沿用当前解释。
angle_min、angle_max 与 angle_increment:整圈分成720格
当前角域约为-180°~+180°,增量约0.5°,源码生成720个距离项。角度是目标系中的 atan2(y,x),不是雷达垂直视场、安装倾角或云台机械yaw范围。
同一角度格内有多个合格点时,只保留水平距离最近的一个。例如,同方向2 m和5 m处各有点,扫描只留2 m;二维扫描不会同时表达它们的高度或多层结构。
0.5°在10 m处对应横向约8.7 cm,在1 m处约8.7 mm;这里只说明角度分格的几何尺度,不是定位精度,也不保证这么细的障碍都能看见。输入点云经过上游筛选与降采样,调小角增量不会增加实际回波。
源码先以 ceil((angle_max-angle_min)/angle_increment) 建数组,再计算下标。当前实现没有检查下标是否越界,而角度上界允许通过;当角域与增量恰好形成整数分格时,上界点存在越界路径。当前近似整圈设置得到720项,不能据此证明其他角度组合的边界安全;该缺口尚无运行触发记录。
range_min 与 range_max:底盘周围的水平圆环
当前保留0.3~10.0 m水平距离的点,按 sqrt(x²+y²) 计算,不含z。相同x、y而高度不同的点,只要过高度/高差窗口,测距数值就一样。
增大range_min可排掉更多近处回波,但也会漏掉车旁障碍;减小则可能带入车体、云台或其他自车点。0.3 m圆形门槛不是完整车辆轮廓,距底盘原点更远的自车回波仍可能留下,需要结合安装位置与真实车体观察。
增大range_max只允许更多已经存在的远点,不能让雷达看到更远,也不能恢复上游删点。当前slam_toolbox另配置min_laser_range=0.3、max_laser_range=10.0,两级范围应一起核对;下游参数用途另属建图参数块。
scan_time:时间字段,不是发布频率开关
LaserScan定义中scan_time表示扫描之间的时间间隔。这里没有测量实际间隔,只把参数0.05 s写入消息;输出由输入点云驱动,实际周期取决于地形点云、TF与计算过程。
time_increment 写死为0,表示没有逐束时间差;header.stamp 沿用输入点云时间。地形输入含历史点,不能把这个结果当成所有射线确实在同一时刻由物理二维雷达采集,也不能用scan_time代替运动补偿或修复上游点时间单位。
实际发布周期应按对应启动模式测量后核对。修改scan_time只会改字段,不会使10 Hz输入变成20 Hz扫描,也不会给各个角度格补出真实采样时间。
use_inf 与 inf_epsilon:无回波不等于确定空地
True先把每格距离设为+∞,再用最近合格点覆盖;某格没有合格点就保留∞。False则先设为range_max+inf_epsilon,当前默认组合是11 m,仍超出10 m有效量程。
“没有合格点”可以来自真实无回波,也可以来自缺数据、遮挡、上游删除、高度/高差过滤或角度格里没有样本;不能仅凭∞就判断这条方向安全。下游怎样处理无效/超量程值,应按对应扫描使用者的实现核对。
输出只填ranges,不填LaserScan.intensities。这里的两项intensity参数用于挑选输入点,并不把地形高差继续作为扫描强度发布。
默认TF参数与订阅条件
transform_tolerance=0.01 s 在当前代码中作为转换查询的等待超时;它不是点云和TF可以错开0.01秒的补偿量,也没有把消息时间戳前移/后移。TF消息过滤器按输入时间等待目标变换,queue_size控制其队列以及点云订阅深度。TF转换失败的回调直接返回,不用单位变换继续生成扫描。
节点只有在scan输出存在订阅者时才订阅cloud_in;最后一个扫描订阅者消失后,会取消点云订阅。输入和输出均使用SensorDataQoS;兼容的订阅QoS与有效TF是收到扫描的前提。全是被过滤的点时,仍可发布一帧全为无回波值的扫描,不能把“有扫描消息”视为障碍轮廓正确。
默认queue_size取硬件并发线程数,适合先沿用;若消息排队或TF等待导致丢点,再按实际数据率和负载核对,不把队列长度当成工作线程数。
启动来源与验证状态
| 启动方式 | 配置与输入输出来源 |
|---|---|
| 整套reality,slam=True | 实物nav2_params.yaml经slam_launch传入;cloud_in重映射为terrain_map_ext,scan为obstacle_scan;target_frame=base_footprint |
| 整套simulation,slam=True | 仿真nav2_params.yaml,13项中仅use_sim_time=True不同;同样的输入输出与目标系 |
| 整套slam=False | 进入已有地图定位流程,不启动这个转换节点 |
| 包内sample_pointcloud_to_laserscan_launch.py | 示例点云发布器与静态TF;目标系cloud、高度0~1 m、角域约±90°、scan_time=0.3333、距离0.45~4 m,未读取整套YAML |
15项自定义参数在构造时读取,没有动态参数更新回调;同名参数运行时改变不自动更新这些成员或重建TF过滤器。ROS标准use_sim_time由节点时钟处理。当前use_inf=True使inf_epsilon不参与输出,其他门槛仍按各自条件执行。
- 源码依据:
pointcloud_to_laserscan/src/pointcloud_to_laserscan_node.cpp;启动接线见pb2025_nav_bringup/launch/slam_launch.py,LaserScan字段定义见ROS2 sensor_msgs。 - 已有验证范围: 独立Point-LIO静止与短距离往返已有输出记录;该转换节点的二维扫描、建图轮廓、云台连续yaw和坡道投影尚未验证。
- 实物待核实: 底盘原点与投影平面、IMU/雷达/底盘转换、上下坡点是否被固定高度窗口截掉、低障碍与悬空结构的保留范围、自车回波、角度覆盖、实际扫描周期及无回波区域的下游处理。