转弯扫掠校验

这一页解决什么问题

车在转弯时,车身扫过的不是一个圆,而是一个圆环:内侧后轮走小圆,外侧前角走大圆,两者之差就是这个弯至少要多宽的通道。轴距越长、前悬越长,这个环就越宽,窄路掉头、地下车库转弯、限宽门通过这些场景都会卡在这上面。

平时只能靠「打满方向盘试一下」,或者靠经验估。本页给出一个纯几何、纯标准库的实现:输入车辆几何参数和转弯半径,直接算出内轮差、外摆、所需通道宽度,并用四条断言判断这个弯能不能过。

本页原来的内容只有一条参考链接。下面的实现是在同一主题下补的:不依赖 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 量级的占用,两者不要混用。

大模型声明

使用大模型辅助代码编写、测试编写与文档整理,提交内容由本人负责。