转弯扫掠校验
这一页解决什么问题
车在转弯时,车身扫过的不是一个圆,而是一个圆环:内侧后轮走小圆,外侧前角走大圆,两者之差就是这个弯至少要多宽的通道。轴距越长、前悬越长,这个环就越宽,窄路掉头、地下车库转弯、限宽门通过这些场景都会卡在这上面。
平时只能靠「打满方向盘试一下」,或者靠经验估。本页给出一个纯几何、纯标准库的实现:输入车辆几何参数和转弯半径,直接算出内轮差、外摆、所需通道宽度,并用四条断言判断这个弯能不能过。
本页原来的内容只有一条参考链接。下面的实现是在同一主题下补的:不依赖 CARLA、不需要 GPU、不需要显示器,一条命令在终端里出结果,方便在没有仿真环境的机器上做回归。
自主实现:turning_sweep_check
目录结构
src/ground/turning_sweep_check/
├── CMakeLists.txt
├── package.xml
├── README.md
├── config/turning_sweep_check.yaml # 13 个参数默认值
├── launch/main.launch # 13 个带 doc 的 arg
└── scripts/
├── main.py # roslaunch 的入口
├── turning_core.py # 纯几何计算(不 import rospy)
└── turning_node.py # ROS 收发放这里
tests/test_turning_sweep_check_local.py
核心计算全部放在 turning_core.py,不 import rospy、不读参数服务器,因此可以脱离 ROS 单独测试;节点只负责取参数、打印、发话题。
公式表
一律以后轴中心到转弯中心的距离 R 为基准(单位:米)。L 轴距,b 轮距,fo 前悬,ro 后悬:
| 量 | 公式 | 默认值下(R = 8.0) |
|---|---|---|
| 内后轮半径 | R - b/2 |
7.230 |
| 外后轮半径 | R + b/2 |
8.770 |
| 内前轮半径 | hypot(R - b/2, L) |
7.718 |
| 外前轮半径 | hypot(R + b/2, L) |
9.176 |
| 外前角半径 | hypot(R + b/2, L + fo) |
9.480 |
| 内后角半径 | hypot(R - b/2, ro) |
7.280 |
| 扫掠宽度(所需通道) | max(所有半径) - min(所有半径) |
2.250 |
| 内轮差 | 内前轮半径 - 内后轮半径 |
0.488 |
| 外摆 | 外前角半径 - 外前轮半径 |
0.304 |
| 最小可行半径 | L / tan(最大前轮转角) |
4.404 |
车身所有点到转弯中心的距离都在「内圈 ~ 外圈」之间,所以扫掠宽度就是车身实际占用的环形通道宽度,与画法、采样密度无关,是解析解而不是估算。
四条断言
| 断言 | 判据 | 不过时的含义 |
|---|---|---|
| 转弯可行性 | R >= L / tan(最大转角) |
方向盘打满也拐不过这个弯 |
| 通道宽度 | 扫掠宽度 <= channel_width |
路/库位不够宽,会压线或剐蹭 |
| 内轮差 | 内轮差 <= max_inner_diff |
轴距太大,内后轮会切进内角 |
| 内侧余量 | 内圈半径 >= inner_clearance |
内侧贴着墙/护栏,没有安全余量 |
四条都过才是 PASSED。
参数表
| 参数 | 默认 | 说明 |
|---|---|---|
vehicle/wheelbase |
2.70 | 轴距 |
vehicle/track |
1.54 | 轮距 |
vehicle/front_overhang |
0.90 | 前悬 |
vehicle/rear_overhang |
0.85 | 后悬 |
vehicle/width |
1.80 | 车宽(含后视镜时填更大值) |
vehicle/max_steer |
0.55 | 最大前轮转角(rad,约 31.5°) |
turning/radius |
8.0 | 后轴中心转弯半径 |
check/channel_width |
6.0 | 通道可用宽度 |
check/inner_clearance |
0.30 | 内侧最小余量 |
check/max_inner_diff |
1.00 | 内轮差上限 |
rate/publish_hz |
1.0 | 报告重发频率 |
topic/report |
/turning/sweep |
报告话题(std_msgs/String) |
topic/ring |
/turning/ring |
字符图话题(std_msgs/String) |
话题表
| 话题 | 类型 | 方向 | 说明 |
|---|---|---|---|
/turning/sweep |
std_msgs/String |
发布(latched) | 完整报告,含四条断言与结论 |
/turning/ring |
std_msgs/String |
发布(latched) | 扫掠圆环的字符图 |
运行
cd ~/catkin_ws7
source /opt/ros/melodic/setup.bash
source devel/setup.bash
roslaunch turning_sweep_check main.launch
默认参数(R = 8.0,通道 6.0 m)的实际输出:
转弯扫掠校验(内置几何计算,不依赖 CARLA)
车辆:轴距 2.70 m,轮距 1.54 m,车长 4.45 m,车宽 1.80 m,最大转角 0.550 rad
转弯:后轴中心半径 8.000 m,等效前轮转角 0.325 rad
半径:内后轮 7.230 / 外后轮 8.770 / 内前轮 7.718 / 外前轮 9.176
扫掠:内圈 7.230 m,外圈 9.480 m,需要通道宽度 2.250 m
其他:内轮差 0.488 m,外摆 0.304 m,最小可行半径 4.404 m
断言:4 通过 / 0 失败(共 4 条)
[PASS] 转弯可行性 后轴半径 8.000 m,最小可行 4.404 m
[PASS] 通道宽度 需要 2.250 m,通道 6.000 m
[PASS] 内轮差 内轮差 0.488 m,上限 1.000 m
[PASS] 内侧余量 内侧最小半径 7.230 m,要求 >= 0.300 m
结论:PASSED
后面的字符图把圆环画出来:# 是内圈之内(车身永远进不去的区域),. 是扫掠区(车身会扫过的地方),空白是外圈之外。也就是说. 的环宽就是所需通道宽度。
............
........................
................................
................####................
...........##################...........
.........##########################.........
.........##############################.........
........##################################........
........####################################........
........######################################........
.......########################################.......
.......##########################################.......
反例
# 通道只有 2.0 m,比需要的 2.25 m 窄
roslaunch turning_sweep_check main.launch channel_width:=2.0
# 半径 4.0 m,比最小可行半径 4.404 m 还小
roslaunch turning_sweep_check main.launch turn_radius:=4.0
第一条只会让「通道宽度」这一条失败,第二条只会让「转弯可行性」失败 —— 每条断言互相独立,失败信息直接指出是哪个量不够、差多少。
离线测试
cd <仓库根目录>
python3 tests/test_turning_sweep_check_local.py
只用标准库,不需要 ROS、不需要 CARLA、不需要显示器;同时兼容 Python 2.7 与 3.x(Melodic 与 Noetic 都能直接跑)。期望看到:
通过 204 项,失败 0 项
全部通过
也可以交给 pytest(每个分组都会被包装成真正会失败的 test_*):
python3 -m pytest tests/test_turning_sweep_check_local.py -q
与已有模块的关系
| 模块 | 关注点 | 与本模块的区别 |
|---|---|---|
carla_parking_lot |
在 CARLA 里画车位 | 需要 CARLA;本模块只算几何 |
reverse_parking_planner |
倒车入库的轨迹 | 算「怎么开进去」;本模块算「转过去占多宽」 |
twist_to_control |
速度指令 → 转角 | 算执行量;本模块算执行量的几何后果 |
| 本模块 | 转弯扫掠包络 | 纯几何、纯终端输出,用于窄路/限宽/车库通过性判断 |
常见问题
为什么内圈取的是「内后轮」而不是「内后角」?
默认参数下内后角 = hypot(7.23, 0.85) = 7.280,比内后轮 7.230 大,所以最小值仍是内后轮。后悬很长时内后角会更靠内,代码取的是所有半径的最小值,不写死。
为什么 Melodic 上会看到 UnicodeEncodeError?
Python 2.7 里 rosgraph 的日志格式化会对非 ASCII unicode 调 str(),直接炸。本模块所有日志都先编码成 byte str 再交给 rospy.loginfo(见 turning_node.py 的 _log()),所以中文日志在 Melodic 上安全。
转弯半径填的是哪个半径?
填后轴中心到转弯中心的距离。真车上常说的「最小转弯半径」通常按外侧车身算,可以用本模块的 radii_at_limit() 对比:默认参数下,后轴中心 4.404 m 对应外前角 9.480 m 量级的占用,两者不要混用。
大模型声明
使用大模型辅助代码编写、测试编写与文档整理,提交内容由本人负责。