ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从阿克曼转向到jerk约束:自动泊车轨迹规划建模

从阿克曼转向到jerk约束:自动泊车轨迹规划建模

简介:面向备战MathorCup及高校数学建模竞赛的学生与指导教师,这份PDF文档围绕2022年C题“自动泊车问题”给出赛题解读与分析。内容结合阿克曼转向乘用车参数,梳理最小转弯半径、直线加速至20km/h所需距离及曲率变化限制,讨论垂直、平行与45°倾斜车位的泊车轨迹建模、碰撞约束、最优车位选择和动态占用下的路径仿真,并涉及控制点轨迹、速度与加速度平滑、算法复杂度等细节,强调安全、时效与轨迹平滑之间的权衡。资源包共1个PDF文件,大小约2.07MB,结构集中便于查阅和打印研读。已有1230人学习,可用于理解题意、搭建建模框架、核对模型假设与求解思路,也可作为赛前专题训练和论文写作的参考。

1. 自动泊车真正难的不是找车位,而是让方向盘来得及转

很多人拿到这道数学建模题的第一反应,是把它当成一道纯几何题:车长 4.9 米、宽 1.8 米,车位宽 2.5 米,尺寸一减就知道塞不塞得进去。但真把轨迹画出来才会发现,卡住规划的往往不是车位宽度,而是方向盘的最大转速——400°/s 经过 16:1 的传动比变成前轮 25°/s,在 20 km/h 车速下,曲率对路径长度的变化率被压在 0.037 m⁻² 以内。这意味着一辆车从直行切到满舵,必须实实在在跑完约 6.5 米。泊不入位不是因为车太大,而是把曲率当成可以瞬变的参数,最后规划出一条物理上根本执行不了的轨迹。这道题真正的分量,就在这里。

2. 阿克曼转向几何:方向盘打满 470° 之后,最小转弯半径为 4.97 米

阿克曼结构的前轮转向、后轮驱动,意味着前轮可以绕垂直轴转动,后轮则被牢牢固定在车身方向。这个看似朴素的机械约束,决定了整车所有可行轨迹的集合形状。想算出这辆车的机动极限,需要把方向盘转角、前轮转角、轴距、转弯半径这条链路一层层拆开。

2.1 16:1 的传动比把 470° 压缩成 29.375°

题目给出方向盘最大转角 470°、传动比 16:1。传动比在这里的作用是放大驾驶员的力矩、缩小转角,换算过来前轮最大转角 δ_max = 470/16 = 29.375°。这个数字不大,普通乘用车的前轮最大转角大多也在 30°~35° 区间,再大轮胎就会和轮拱打架。

提示:传动比是方向盘转角与前轮转角的比值,方向盘转 16° 前轮才转 1°,计算最小转弯半径时必须先做这一步换算,直接拿 470° 代入 tan 会得到完全错误的量级。

低速泊车场景下侧偏角可以忽略,车轮运动方向就近似等于车轮朝向,也就是所谓运动学自行车模型。因此后轴中心的速度方向始终沿车身纵轴,前轮中心的速度方向始终沿前轮朝向,这两条约束一确立,整车就只能绕着某个固定点做圆周运动。

2.2 控制点选后轴中心时,R = L / tan δ 是怎么推出来的

假设车辆以固定前轮转角 δ 做稳态圆周运动。后轴中心的速度沿车身纵轴,而圆周运动的瞬时转动中心(ICR)到该点的连线必须垂直于速度方向,所以 ICR 一定落在后轴的延长线上。同理,前轮处的速度沿前轮朝向,ICR 也一定落在过前轮中心、垂直于前轮朝向的那条直线上。两条垂线的交点就是唯一的 ICR。

设后轴中心到 ICR 的距离为 R。后轴到前轴的纵向距离是轴距 L = 2.8 m,前轮相对车身的偏转是 δ。在由“后轴中心—前轴中心—ICR”组成的直角三角形里,直角边 L 对的是角 δ,邻边是 R,于是 tan δ = L / R,也就是 R = L / tan δ。

import math L = 2.8 # 轴距,单位 m wheelbase_track = 1.7 # 轮间距,单位 m steer_wheel_max = 470.0 # 方向盘最大转角,单位 deg ratio = 16.0 # 方向盘与前轮转角传动比 steer_rate_wheel = 400.0 / ratio # 前轮最大角速度,deg/s delta_max = steer_wheel_max / ratio # 前轮最大转角,deg delta_max_rad = math.radians(delta_max) R_min = L / math.tan(delta_max_rad) # 后轴中心最小转弯半径 kappa_max = math.tan(delta_max_rad) / L # 最大曲率 # 若把控制点换成车身几何中心,半径要再做一次勾股 R_center = math.hypot(R_min, L / 2) print(f"前轮最大转角 = {delta_max:.3f} deg") print(f"前轮最大角速度 = {steer_rate_wheel:.3f} deg/s") print(f"最小转弯半径(后轴中心) = {R_min:.3f} m") print(f"最小转弯半径(车身中心) = {R_center:.3f} m") print(f"最大曲率 = {kappa_max:.4f} 1/m")

这段代码里R_min算出来是 4.974 m,kappa_max是 0.2010 m⁻¹。参数改动的影响很直观:轴距每增加 0.1 m,最小转弯半径大致同比例增加约 0.18 m;而前轮最大转角每多 1°,半径下降约 0.15 m,属于敏感度更高的那一项。

注意:题目在问题 1 里问的是“车辆最小转弯半径”,而问题 2 又明确规定控制点位于后轴中心。如果按车身几何中心计算,结果是 5.163 m,两者相差近 0.2 m。在狭窄车位里,这个差异足以让车尾压线。

还有一个常被忽略的量:车身外廓扫掠半径。车长 4.9 m、轴距 2.8 m,前后悬合计 2.1 m,即使按前后均分估算,外侧前角到 ICR 的距离也在 5.5 m 量级。垂直车位旁若只剩 5.2 m 的通道宽度,几何上就转不进去,这跟驾驶员技术无关。

2.3 曲率对弧长的变化率:一个被忽略但足以导致轨迹不可执行的约束

最小转弯半径回答的是“能不能转”,而问题 1 的第三问问的是“转得多快”,这才是自动泊车轨迹规划真正的硬性边界。

曲率 κ 与转向角的关系是 κ = tan δ / L。方向盘以 400°/s 转动时,前轮角速度 dδ/dt = 25°/s = 0.4363 rad/s。车辆同时以速度 v 前进,那么单位弧长上能获得多少曲率变化,就是链式法则的结果:

dκ/ds = (dκ/dδ) · (dδ/dt) / (ds/dt) = [1 / (L·cos²δ)] · (dδ/dt) / v

import math L = 2.8 d_delta_dt = math.radians(400.0 / 16.0) # 前轮角速度 rad/s v = 20.0 / 3.6 # 20 km/h 换算成 m/s for delta_deg in (0.0, 10.0, 20.0, 29.375): delta = math.radians(delta_deg) dk_ds = d_delta_dt / (L * math.cos(delta) ** 2 * v) print(f"delta={delta_deg:6.3f} deg -> dkappa/ds = {dk_ds:.5f} 1/m^2") # 从直行打到满舵需要走多长弧长 delta_max = math.radians(470.0 / 16.0) t_full = delta_max / d_delta_dt print(f"打满舵耗时 = {t_full:.3f} s, 对应弧长 = {t_full * v:.3f} m")

在 δ = 0 处 dκ/ds = 0.02805 m⁻²,在 δ = δ_max 处升到 0.03694 m⁻²,整体被限制在 0.028~0.037 m⁻² 这个窄区间内。更直观的算法是:前轮从 0 打到 29.375° 需要 1.175 s,20 km/h 下这 1.175 s 跑过 6.53 m。也就是说,曲率想从 0 变到 0.201 m⁻¹,至少要消耗 6.5 米的路程。

这条约束的杀伤力在于它对 v 成反比。车速翻倍,同样的方向盘转速能提供的 dκ/ds 就减半。所以高速行驶时轨迹必须更“直”,任何急弯在物理上都打不出来。规划器如果只约束曲率上限而不约束曲率变化率,输出的轨迹在纸面上完美,交给控制器却会因为转向执行器跟不上而直接漂移出去——这是自动泊车从仿真走向实车最常见的问题之一。

3. 加加速度约束:从静止加到 20 km/h 为什么不是 5.1 米而是 5.6 米

问题 1 的第二问看起来简单,但要答对,必须区分“加速度受限”和“加加速度受限”两种情形。前者是中学物理,后者才是真实车辆动力学的样子。

3.1 只考虑加速度约束时,5.14 米确实够了

如果加速度可以瞬间从 0 跳到 3.0 m/s²,那么从静止加速到 20 km/h(5.556 m/s)的位移就是匀加速公式 s = v² / (2a) = 5.556² / 6 = 5.144 m,耗时 1.852 s。这是理论下界,任何真实车辆都达不到,因为加速度的跳变意味着无穷大的冲击度。

3.2 叠加 jerk 约束后,加速度本身需要逐渐建立

题目要求加加速度不超过 20 m/s³。这意味着加速度从 0 爬到 3.0 m/s² 至少要花 t_j = 3.0 / 20 = 0.15 s。这 0.15 s 里速度并不是线性增长的,而是呈抛物线增长:v(t) = ½·J·t²,末速度 0.225 m/s,位移 J·t³/6 = 0.01125 m。

完整的加速过程被拆成三段:加速度爬坡、加速度保持、加速度回落。第三段的加速度从 3.0 掉回 0,jerk 为 −20 m/s³,速度再增加 0.225 m/s。

J = 20.0 # 最大加加速度 m/s^3 a_max = 3.0 # 最大油门加速度 m/s^2 v_target = 20.0 / 3.6 t_j = a_max / J # 加速度爬坡时间 v_j = 0.5 * J * t_j ** 2 # 爬坡段速度增量 s_j = J * t_j ** 3 / 6 # 爬坡段位移 # 中间匀速加速度段:补足剩余速度增量 v_mid_end = v_target - v_j dv_mid = v_mid_end - v_j t_mid = dv_mid / a_max s_mid = v_j * t_mid + 0.5 * a_max * t_mid ** 2 # 回落段:jerk = -J,初速 v_mid_end s_down = v_mid_end * t_j + 0.5 * a_max * t_j ** 2 - J * t_j ** 3 / 6 s_total = s_j + s_mid + s_down t_total = 2 * t_j + t_mid print(f"爬坡段: t={t_j:.3f}s, dv={v_j:.4f}m/s, ds={s_j:.5f}m") print(f"保持段: t={t_mid:.4f}s, ds={s_mid:.4f}m") print(f"回落段: ds={s_down:.4f}m") print(f"总位移 = {s_total:.4f} m, 总耗时 = {t_total:.4f} s") print(f"匀加速理论下界 = {v_target**2/(2*a_max):.4f} m")

输出是总位移 5.561 m、总耗时 2.002 s。和匀加速下界相比,多走了 0.417 m,多花了 0.15 s。这 0.417 米就是 jerk 约束的“税”——它不大,但在车位旁边只剩半米余量时,这半米足以决定成败。

换个角度理解:jerk 约束并不会显著拉长加速距离,因为 a_max = 3.0 m/s² 本身才是主要瓶颈。真正让 jerk 约束变得关键的是“变化”——起步、刹车、换挡、转弯的每一个过渡点。一段规划如果只保证加速度不超限、却在 t = 0 时刻把加速度从 0 直接设成 3.0,乘客会明确感到“被踹了一脚”,机械上则表现为悬架和传动系统的冲击载荷。

3.3 减速带、倒车限速与曲率限速把速度曲线变成分段拼接问题

单看直线加速只是一道热身题,真正进入问题 2 之后,速度曲线要同时服务四个约束源。

第一个是题目明写的:减速带前后 5 m 内车速不超过 10 km/h,全程前进不超过 20 km/h、倒车不超过 10 km/h。这些构成速度包络上的“凹槽”,规划器必须在到达减速带前把速度降到 2.778 m/s 以下,且减速过程本身也要满足 −6.0 m/s² 和 20 m/s³ 的 jerk 限制。

第二个是曲率限速。车辆过弯时的横向加速度 a_lat = v²·κ。若取一个让乘客不难受的横向加速度上限 1.0~1.5 m/s²,在满舵 κ = 0.201 m⁻¹ 时允许的车速只有 sqrt(1.0/0.201) ≈ 2.23 m/s,也就是 8 km/h。这个数字和题目给的倒车限速 10 km/h 刚好在同一个量级——并非巧合,低速泊车时限制车速的往往是横向舒适性,而不是动力或法规。

第三个是换挡点。前进与倒车之间速度必须过零,而在零点附近转向角还在变化,这就把整条速度曲线切成了若干段单调区间。

第四个是终点约束:泊车完成时速度、加速度、角速度都必须归零,且车头朝向要精确对齐车位箭头方向。这意味着最后一段减速必须精确落在车位中心线上,误差累积到终点就是压线。

把这四个约束叠起来,一条合格的泊车速度曲线实际是若干 S 型加减速段的拼接,每段内部 jerk 恒定,段与段之间加速度连续。手工推导费力且容易出错,工程上一般用数值积分或直接调用时间参数化算法(如 TOPP 系列)来求解,输入是几何路径,输出是每个采样时刻的 s、v、a、jerk。

4. 泊车轨迹规划:垂直、平行、斜列三种车位在构型空间里差在哪

问题 2 要求对 10 号垂直车位、82 号平行车位、31 号 45° 倾斜车位分别给出轨迹,并且输出每时刻的路径长度、朝向、速度、加速度、jerk、角速度、角加速度。这已经不是“画一条线”的问题,而是三维构型空间里的带约束搜索。

4.1 构型空间里的车被建模成 4.9×1.8 的矩形

规划的状态量最少需要三个:(x, y, θ),其中 (x, y) 是后轴中心坐标,θ 是车身朝向。这是所谓 SE(2) 构型空间,也是所有非完整约束车辆规划的标准舞台。

之所以必须带 θ,是因为车不是各向同性的点。同一组 (x, y) 配上不同 θ,车辆占据的物理区域完全不同。把车当成质点做规划,得到的路径往往在转弯时车尾扫进隔壁车位——这是建模题里最典型也最致命的一类错误。

车辆占地区域是一个以 (x, y) 为参考点、长 4.9 m、宽 1.8 m 的矩形,参考点位于后轴中心。给定 θ 之后,矩形的四个角点坐标可以解析写出。

import math CAR_LEN, CAR_WID = 4.9, 1.8 L = 2.8 REAR_OVERHANG = (CAR_LEN - L) / 2 # 按前后悬均分估算,约 1.05 m def footprint(x, y, theta): """返回后轴中心在 (x,y)、朝向 theta 时车身矩形的四个角点""" c, s = math.cos(theta), math.sin(theta) # 车身坐标系下的四个角(x 向前,y 向左) local = [ (-REAR_OVERHANG, CAR_WID / 2), ( L + REAR_OVERHANG, CAR_WID / 2), ( L + REAR_OVERHANG, -CAR_WID / 2), (-REAR_OVERHANG, -CAR_WID / 2), ] return [(x + lx * c - ly * s, y + lx * s + ly * c) for lx, ly in local]

theta用的是车身坐标系到世界坐标系的旋转,local里 x 分量按后悬、轴距、前悬划分,y 分量按车宽一半划分。前悬后悬按均分处理是题目没给具体数值时的合理假设,实际车辆通常前悬略短于后悬,做精细化分析时可以替换。

4.2 三种车位的几何差异,决定了完全不同的机动模式

垂直车位的进入角是 90°。车辆要么一把倒入(需要通道宽度约 6 m),要么先向前借位再倒。它的难点在于终点朝向必须与车位箭头一致,且车身两侧余量通常只有 0.3~0.4 m。

平行车位是三者中最考验几何的。车位长度一般只比车长多 0.6~1.0 m,车辆必须先把车尾倒进车位入口、以约 30°~45° 的进入角切入,再用第二段反向圆弧把车头摆正。这是典型的 Reeds-Shepp 曲线形态——两段相切圆弧加一段直线,且中间包含一次行驶方向切换。

45° 倾斜车位反而最“友好”。车辆沿车位轴线方向直入即可,需要的通道宽度和转弯角度都最小。这也是现实停车场里斜列车位通行效率更高的原因:进入角小,机动次数少,平均泊车时间短。

三种车位的差异,本质上是终点位姿约束与可用空间约束的不同组合。规划器要做的是在构型空间里找到一条从起点位姿到终点位姿、全程无碰撞、且满足曲率与曲率变化率约束的路径。

4.3 碰撞检测用分离轴判断 OBB 相交,别把车缩成圆

判断车辆是否与障碍物冲突,最省事的做法是把车近似成圆或者用中心点到障碍物的距离,但这会严重高估或低估占用。正确的做法是对两个有向包围盒(OBB)做分离轴测试。

原理不复杂:两个凸多边形不相交,当且仅当存在一条轴,使得两者在该轴上的投影区间不重叠。对两个矩形来说,候选轴只需要四条——每个矩形的两条边法向。

def project(poly, axis): dots = [p[0] * axis[0] + p[1] * axis[1] for p in poly] return min(dots), max(dots) def obb_intersect(poly_a, poly_b): """分离轴测试:任一轴上投影不重叠即判定不相交""" for poly in (poly_a, poly_b): n = len(poly) for i in range(n): x1, y1 = poly[i] x2, y2 = poly[(i + 1) % n] axis = (-(y2 - y1), x2 - x1) # 边的法向量 length = (axis[0] ** 2 + axis[1] ** 2) ** 0.5 if length < 1e-9: continue axis = (axis[0] / length, axis[1] / length) a_min, a_max = project(poly_a, axis) b_min, b_max = project(poly_b, axis) if a_max < b_min or b_max < a_min: return False # 找到分离轴 return True

project把多边形所有顶点投影到单位轴上取最小最大值,`

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进