带加减速及中途目标变更的一维运动轨迹解析求解技术问询
一维运动控制器解析解方案
问题背景
给定一维运动控制器的初始条件与参数:
- 初始状态:
x=0,v=0 - 运动参数:加速加速度
a_acc=50,减速加速度a_dec=30,最大速度v_max=40 - 运动规则:需从当前状态出发,先加速至
v_max(若可行),必要时巡航,最终减速至目标位置时速度为0;支持中途实时变更目标位置。
此前采用每帧离散积分(delta≈33ms)更新速度与位置,存在误差累积、速度曲线错误、过冲/漂移等问题,需改用解析解实现精准轨迹控制。
核心算法实现
1. 轨迹类型判断
先计算无巡航阶段时,从当前状态加速后再减速到0的总距离,与目标相对距离对比,判断轨迹类型:
定义变量
- 当前位置:
x_curr,当前速度:v_curr - 目标位置:
x_target,相对距离:D = x_target - x_curr(正负代表运动方向) - 取绝对值计算:
abs_D = |D|,加速加速度取方向值:a_acc_dir = a_acc * sign(D),减速加速度取反向值:a_dec_dir = -a_dec * sign(D)(保证减速是阻碍当前运动方向的加速度)
无巡航时的最大可行速度计算
若全程仅加速后减速到0,可达到的最大速度v_switch满足:
v_{switch} = \sqrt{\frac{2 \cdot a_{acc} \cdot a_{dec} \cdot abs\_D + a_{dec} \cdot v_{curr}^2}{a_{acc} + a_{dec}}}
轨迹类型判定
- 若
v_switch ≤ v_max:轨迹为加速→减速(无巡航阶段) - 若
v_switch > v_max:轨迹为加速→巡航→减速
2. 各阶段距离与时间计算
情况1:加速→减速(无巡航)
- 加速时间:
t_acc = (v_switch - v_curr) / a_acc_dir - 加速距离:
s_acc = v_curr * t_acc + 0.5 * a_acc_dir * t_acc² - 减速时间:
t_dec = v_switch / abs(a_dec_dir) - 减速距离:
s_dec = 0.5 * abs(a_dec_dir) * t_dec² - 总运动时间:
t_total = t_acc + t_dec
情况2:加速→巡航→减速
- 加速到
v_max的时间:t_acc = (v_max * sign(D) - v_curr) / a_acc_dir - 加速距离:
s_acc = v_curr * t_acc + 0.5 * a_acc_dir * t_acc² - 从
v_max减速到0的时间:t_dec = v_max / a_dec - 减速距离:
s_dec = 0.5 * a_dec * t_dec² - 巡航距离:
s_cruise = abs_D - s_acc - s_dec - 巡航时间:
t_cruise = s_cruise / v_max - 总运动时间:
t_total = t_acc + t_cruise + t_dec
3. 实时位置与速度计算
每帧根据轨迹启动后的累计时间t_elapsed,判断当前所处阶段,直接计算位置与速度:
# 伪代码示例 import math def get_current_state(t_elapsed, x_curr, v_curr, x_target, a_acc, a_dec, v_max): D = x_target - x_curr sign_D = 1 if D > 0 else -1 abs_D = abs(D) a_acc_dir = a_acc * sign_D a_dec_dir = -a_dec * sign_D # 计算无巡航时的切换速度 numerator = 2 * a_acc * a_dec * abs_D + a_dec * v_curr**2 v_switch = math.sqrt(numerator / (a_acc + a_dec)) if v_switch <= v_max: # 加速→减速阶段 t_acc = (v_switch - v_curr) / a_acc_dir s_acc = v_curr * t_acc + 0.5 * a_acc_dir * t_acc**2 if t_elapsed < t_acc: # 加速中 v = v_curr + a_acc_dir * t_elapsed x = x_curr + v_curr * t_elapsed + 0.5 * a_acc_dir * t_elapsed**2 else: # 减速中 t_in_dec = t_elapsed - t_acc v = v_switch + a_dec_dir * t_in_dec x = x_curr + s_acc + v_switch * t_in_dec + 0.5 * a_dec_dir * t_in_dec**2 else: # 加速→巡航→减速阶段 t_acc = (v_max * sign_D - v_curr) / a_acc_dir s_acc = v_curr * t_acc + 0.5 * a_acc_dir * t_acc**2 t_dec = v_max / a_dec s_dec = 0.5 * a_dec * t_dec**2 s_cruise = abs_D - s_acc - s_dec t_cruise = s_cruise / v_max t_cruise_end = t_acc + t_cruise if t_elapsed < t_acc: # 加速中 v = v_curr + a_acc_dir * t_elapsed x = x_curr + v_curr * t_elapsed + 0.5 * a_acc_dir * t_elapsed**2 elif t_elapsed < t_cruise_end: # 巡航中 v = v_max * sign_D x = x_curr + s_acc + v_max * (t_elapsed - t_acc) else: # 减速中 t_in_dec = t_elapsed - t_cruise_end v = v_max * sign_D + a_dec_dir * t_in_dec x = x_curr + s_acc + s_cruise + v_max * sign_D * t_in_dec + 0.5 * a_dec_dir * t_in_dec**2 return x, v
4. 目标变更处理
当目标位置实时变更时,立即执行以下操作:
- 记录当前的
x_curr、v_curr作为新的初始状态 - 重置轨迹累计时间
t_elapsed为0 - 以新的目标位置
x_new_target重新计算轨迹(重复上述轨迹判断、阶段计算流程)
标签
game-development physics-simulation kinematics motion-planning math
内容的提问来源于stack exchange,提问作者Spartak Aghababyan
相关产品推荐
相关产品推荐

