倒车雷达分级告警
这一页解决什么问题
倒车雷达的难点不在「测距」,而在「怎么叫」:
- 障碍物停在 0.5 m 的边界上来回晃,提示音会不会变成一串断续的尖叫?
- 草叶、井盖、坡道造成一帧假读数,会不会直接触发「停止」?
- 真靠近了,从读数到线到真正叫出来,晚了几帧?
- 四路通道里只有一路近,另外三路要不要也参与判定?
这一页给出一套可回归的答案:把四路测距的时序喂给一个带迟滞与帧数确认的状态机,输出五级告警,并用四条断言把上面四个问题变成可判定的检查。
级别与阈值
| 级别 | 名称 | 进入阈值(默认) | 退出阈值(默认) |
|---|---|---|---|
| 0 | 无 | > 2.00 m | — |
| 1 | 提示 | ≤ 2.00 m | > 2.20 m |
| 2 | 警告 | ≤ 1.50 m | > 1.70 m |
| 3 | 危险 | ≤ 1.00 m | > 1.20 m |
| 4 | 停止 | ≤ 0.50 m | > 0.70 m |
两个关键机制:
- 迟滞:退出阈值 = 进入阈值 +
exit_margin_m。级别越高区间越窄,所以在 0.70~1.20 m 之间晃动时级别会稳定在 3,而不是在 3 和 4 之间跳。 - 帧数确认:升级要连续
confirm_frames帧都到线;降级要连续release_frames帧都退出当前级别的退出阈值。单帧毛刺既不能触发升级,也不能抹掉正在生效的告警。
判定取四路通道里最近的一路,并记录是哪一路触发的。
四条断言
| 断言 | 判定方式 | 默认结果 |
|---|---|---|
| 分级准确 | 最高级别、末帧级别都等于「无迟滞时的即时级别」 | 4 / 0,通过 |
| 无抖动 | 切换次数 ≤ max_switches,且没有方向相反、间隔 < confirm_frames 的切换对 |
3 次 / 0 次振荡,通过 |
| 响应及时 | 最高级别的判定延迟 ≤ confirm_frames 帧 |
延迟 2 帧(上限 3),通过 |
| 覆盖全部通道 | 四路里进入过告警区间(≤ 2.00 m)的通道数 = 4 | 4 个,通过 |
参数
| 参数 | 默认 | 说明 |
|---|---|---|
alert/enter_info_m |
2.00 | 提示级进入阈值 |
alert/enter_warn_m |
1.50 | 警告级进入阈值 |
alert/enter_danger_m |
1.00 | 危险级进入阈值 |
alert/enter_stop_m |
0.50 | 停止级进入阈值 |
alert/exit_margin_m |
0.20 | 退出余量 |
alert/confirm_frames |
3 | 升级确认帧数 |
alert/release_frames |
3 | 降级确认帧数 |
alert/min_range_m |
0.15 | 量程下限 |
alert/max_range_m |
3.00 | 量程上限 |
alert/max_switches |
6 | 切换次数上限 |
rate/read_hz |
10.0 | 读数节拍 |
rate/publish_hz |
10.0 | 发布节拍 |
topic/level |
/rear_alert/level |
当前级别(Int32) |
topic/report |
/rear_alert/report |
文字报告(String) |
topic/levels |
/rear_alert/levels |
级别条带(String) |
topic/radar |
/rear_alert/radar |
四通道雷达条(String) |
话题
| 话题 | 类型 | 方向 | 说明 |
|---|---|---|---|
/rear_alert/level |
std_msgs/Int32 |
发布(latched) | 当前级别 0~4 |
/rear_alert/report |
std_msgs/String |
发布(latched) | 完整文字报告 |
/rear_alert/levels |
std_msgs/String |
发布(latched) | 级别随时间的字符条带 |
/rear_alert/radar |
std_msgs/String |
发布(latched) | 四通道距离条 |
运行
roslaunch ultrasonic_rear_alert main.launch
默认参数下的真实输出(节点跑完 23 帧后自己退出):
倒车雷达分级告警(四个后向通道,带迟滞)
进入阈值:2.00 / 1.50 / 1.00 / 0.50 m,退出余量 0.20 m,确认 3 帧 / 释放 3 帧
------------------------------------------------------------
帧数:23,时长:2.20 s
最高级别:4(停止),末帧级别:0(无)
级别切换:3 次
t=1.10 s -> 停止(通道 左后,0.36 m)
t=1.80 s -> 提示(通道 左后,1.90 m)
t=2.10 s -> 无(通道 左后,3.00 m)
断言:4 通过 / 0 失败(共 4 条)
[PASS] 分级准确 最高级别 4(期望 4),末帧级别 0(期望 0)
[PASS] 无抖动 切换 3 次(上限 6),3 帧内反复切换 0 次
[PASS] 响应及时 最高级别 4 在第 11 帧判定(原始第 9 帧),延迟 2 帧(上限 3)
[PASS] 覆盖全部通道 四个通道里进入过告警区间的有 4 个
结论:PASSED
两个反例
关掉帧数确认(confirm_frames:=1 release_frames:=1):切换次数从 3 涨到 8,超过上限,[FAIL] 无抖动:
帧数=23 时长=2.200 最高级别=4 末帧级别=0 切换=8 抖动=0
[FAIL] 无抖动 切换 8 次(上限 6),1 帧内反复切换 0 次
结论=FAILED
更迟钝(confirm_frames:=5):判定推迟到第 13 帧,延迟 4 帧(上限 5)仍然通过,但能明显看出「慢半拍」:
帧数=23 时长=2.200 最高级别=4 末帧级别=0 切换=3 抖动=0
[PASS] 响应及时 最高级别 4 在第 13 帧判定(原始第 9 帧),延迟 4 帧(上限 5)
结论=PASSED
离线测试
python3 tests/test_ultrasonic_rear_alert_local.py
只用标准库,不需要 ROS、不需要 CARLA、不需要显示器;同时兼容 Python 2.7 与 Python 3.x。
与已有模块的关系
| 模块 | 回答的问题 | 与本页的边界 |
|---|---|---|
reverse_parking_planner |
倒车入库该走什么轨迹 | 只管几何,不管告警 |
braking_distance_check |
从看见到停住要几米 | 只管纵向距离 |
turning_sweep_check |
转弯时车身扫过多宽 | 只管横向包络 |
twist_to_control |
速度指令 → 转角 | 只管执行量换算 |
ultrasonic_rear_alert |
距离在告警边界上来回时该怎么叫 | 只管分级、迟滞、帧数确认 |
常见问题
为什么障碍物退到 1.9 m 还显示「提示」? 提示级的退出阈值是 2.20 m,1.9 m 还没退出去。这是迟滞的设计,避免边界抖动。
一帧读到 2.90 m 为什么没把级别清掉?
降级要连续 release_frames 帧都退出去,单帧跳变会被吃掉。
为什么「覆盖全部通道」会失败? 它检查的是场景覆盖:读数里只有一路进过告警区间时判失败,提示换一个有代表性的场景。
Melodic 上日志报 UnicodeEncodeError?
Python 2.7 下 rospy 的日志格式化对非 ASCII unicode 会炸,节点里的日志统一走 _log() 转成 byte str。
本页内容由大模型辅助整理
本页的代码、测试与说明由作者与大模型协作完成,提交内容由作者负责。
服务调用:rosservice call /rear_alert/simulate
除了四路 latched 话题,节点还把「重算一次并给出报告」暴露成一个
std_srvs/Trigger 服务。它不依赖话题的历史值,调用一次就重跑整个判定过程,
把「重算后的四条断言是否全过」放进 success、把一行 ASCII 摘要放进 message:
$ rosservice call /rear_alert/simulate
success: True
message: max_level=4 final_level=0 switches=3 asserts=4/4 passed=True
message 只放 ASCII 摘要(max_level 最高级别、final_level 末帧级别、
switches 切换次数、asserts 通过条数、passed 总结论)。原因很实际:
rosservice call 会把中文转义成 \u5012\u8F66 这种形式,截图里根本没法读;
完整的中文报告仍然在终端日志与 /rear_alert/report 话题里。
参数改动后不必重启节点,改完 rosparam set 再调一次服务即可拿到新报告;
CI 或其它脚本也能以 success 为准做断言,不用解析文本。
把 alert/confirm_frames 设成 1 再调用,可以现场看到 success: False 与
[FAIL] 无抖动。