0 专栏介绍
🔥课设、毕设、创新竞赛必备!🔥本专栏涉及更高阶的运动规划算法轨迹优化实战,包括:曲线生成、碰撞检测、安全走廊、优化建模(QP、SQP、NMPC、iLQR等)、轨迹优化(梯度法、曲线法等),每个算法都包含代码实现加深理解
🚀详情:运动规划实战进阶:轨迹优化篇
1 边界值问题建模
在轨迹优化 | 基于边界中间值问题(BIVP)的路径平滑求解器(附C++/Python仿真)中,我们介绍过边界中间值问题(Boundary Intermediate Value Problem, BIVP)的形式:
min ∫ t 0 t k v ( t ) T W v ( t ) + ρ ( t k − t 0 ) s.t. z [ r i − 1 ] ( i − 1 ) ( t i ) = z ^ i , 1 ⩽ i < k , r i ⩽ s z [ s − 1 ] ( s − 1 ) ( t 0 ) = z ^ 0 , z [ s − 1 ] ( s − 1 ) ( t k ) = z ^ k \begin{aligned} \min & \int_{t_0}^{t_k} \boldsymbol{v}(t)^T \boldsymbol{W} \boldsymbol{v}(t) + \rho(t_k - t_0) \\ \text{s.t.} & \ z_{[r_i-1]}^{(i-1)}(t_i) = \widehat{z}_i, \ 1 \leqslant i < k, \ r_i \leqslant s \\ & \ z_{[s-1]}^{(s-1)}(t_0) = \widehat{z}_0, \ z_{[s-1]}^{(s-1)}(t_k) = \widehat{z}_k \end{aligned} mins.t.∫t0tkv(t)TWv(t)+ρ(tk−t0) z[ri−1](i−1)(ti)=z i, 1⩽i<k, ri⩽s z[s−1](s−1)(t0)=z 0, z[s−1](s−1)(tk)=z k
其中定义 z [ s − 1 ] ( t ) ≜ ( z T , z ˙ T , ⋯ , z ( s − 1 ) T ) T z^{[s-1]}(t) \triangleq (z^T, \dot{z}^T, \cdots, z^{(s-1)^T})^T z[s−1](t)≜(zT,z˙T,⋯,z(s−1)T)T, v ( t ) ≜ z ( s ) ( t ) \boldsymbol{v}(t) \triangleq z^{(s)}(t) v(t)≜z(s)(t)
将BIVP的中间值约束移除将得到更特殊的边界值问题(Boundary Value Problem, BVP):
min z ( t ) , T ∫ t 0 T v ( t ) T W v ( t ) + ρ T s . t . z [ s − 1 ] ( 0 ) = z ˉ 0 , z [ s − 1 ] ( T ) = z ˉ T \underset{\boldsymbol{z}\left( t \right) ,T}{\min}\int_{t_0}^T{\boldsymbol{v}\left( t \right) ^T\boldsymbol{Wv}\left( t \right)}+\rho T\,\,\\\mathrm{s}.\mathrm{t}. \boldsymbol{z}^{\left[ s-1 \right]}\left( 0 \right) =\boldsymbol{\bar{z}}_0, \boldsymbol{z}^{\left[ s-1 \right]}\left( T \right) =\boldsymbol{\bar{z}}_T z(t),Tmin∫t0Tv(t)TWv(t)+ρTs.t.z[s−1](0)=zˉ0,z[s−1](T)=zˉT
其仍然满足BIVP的最优性原理,即最优解 z ∗ ( t ) : [ t 0 , t k ] → R n z^*(t): [t_0, t_k] \to \mathbb{R}^n z∗(t):[t0,tk]→Rn的充要条件为:
- z ∗ z^* z∗ 的第 i i i段轨迹是 2 s − 1 2s - 1 2s−1 次多项式;
- 边界条件与中间点条件成立;
- z ∗ z^* z∗ 在 t = t i t = t_i t=ti 处满足 r ˉ i − 1 \bar{r}_i - 1 rˉi−1 次连续可微,其中 r ˉ i = 2 s − r i \bar{r}_i = 2s - r_i rˉi=2s−ri;
所以最优解满足无中间值条件的约束方程
[ F 0 E k ] P 1 = [ D 0 D k ] \left[ \begin{array}{c} \boldsymbol{F}_0\\ \boldsymbol{E}_k\\\end{array} \right] \boldsymbol{P}_1=\left[ \begin{array}{c} \boldsymbol{D}_0\\ \boldsymbol{D}_k\\\end{array} \right] [F0Ek]P1=[D0Dk]
对于BVP问题来说,可以更进一步写出矩阵的结构。对于单个微分平坦维度有
d = A F ( T ) p \boldsymbol{d}=\boldsymbol{A}_F\left( T \right) \boldsymbol{p} d=AF(T)p
其中 p = [ p 0 p 1 ⋯ p n ] T ∈ R 2 s \boldsymbol{p}=\left[ \begin{matrix} p_0& p_1& \cdots& p_n\\\end{matrix} \right] ^T\in \mathbb{R} ^{2s} p=[p0p1⋯pn]T∈R2s, d = [ z 0 ⋯ z 0 ( s − 1 ) z T ⋯ z T ( s − 1 ) ] ∈ R 2 s \boldsymbol{d}=\left[ \begin{matrix} z_0& \cdots& z_{0}^{\left( s-1 \right)}& z_T& \cdots& z_{T}^{\left( s-1 \right)}\\\end{matrix} \right] \in \mathbb{R} ^{2s} d=[z0⋯z0(s−1)zT⋯zT(s−1)]∈R2s
A F ( t ) = [ E O F ( t ) G ( t ) ] \boldsymbol{A}_F\left( t \right) =\left[ \begin{matrix} \boldsymbol{E}& \boldsymbol{O}\\ \boldsymbol{F}\left( t \right)& \boldsymbol{G}\left( t \right)\\\end{matrix} \right] AF(t)=[EF(t)OG(t)]
各分块矩阵形式为
E i j = { ( i − 1 ) ! i f i = j 0 i f i ≠ j , F i j ( t ) = { ( j − 1 ) ! ( j − i ) ! t j − i i f i ⩽ j 0 i f i > j , G i j ( t ) = ( s + j − 1 ) ! ( s + j − i ) ! t s + j − i \begin{aligned}\boldsymbol{E}_{ij}&=\begin{cases} \left( i-1 \right) ! \ \ \ \ \mathrm{if} i=j\\ 0 \ \ \ \ \ \ \mathrm{if} i\ne j\\\end{cases}, \\ \boldsymbol{F}_{ij}\left( t \right) &=\begin{cases} \frac{\left( j-1 \right) !}{\left( j-i \right) !}t^{j-i}\,\,\ \ \ \ \ \mathrm{if}\ i\leqslant j\\ 0 \ \ \ \ \ \mathrm{if}\ i>j\\\end{cases}, \\\boldsymbol{G}_{ij}\left( t \right) &=\frac{\left( s+j-1 \right) !}{\left( s+j-i \right) !}t^{s+j-i}\end{aligned} EijFij(t)Gij(t)={(i−1)! ifi=j0 ifi=j,={(j−i)!(j−1)!tj−i if i⩽j0 if i>j,=(s+j−i)!(s+j−1)!ts+j−i
为了避免大规模矩阵求逆,在应用中也可以直接采用逆矩阵版本
p = A B ( T ) d \boldsymbol{p}=\boldsymbol{A}_B\left( T \right) \boldsymbol{d} p=AB(T)d
其中
A B ( t ) = [ U O V ( t ) W ( t ) ] \boldsymbol{A}_B\left( t \right) =\left[ \begin{matrix} \boldsymbol{U}& \boldsymbol{O}\\ \boldsymbol{V}\left( t \right)& \boldsymbol{W}\left( t \right)\\\end{matrix} \right] AB(t)=[UV(t)OW(t)]
各分块矩阵形式为
U i j = { 1 ( i − 1 ) ! i f i = j 0 i f i ≠ j , V i j ( t ) = ∑ k = 0 s − max { i , j } ( − 1 ) k ( s i + k ) ( 2 s − j − k − 1 s − 1 ) ( j − 1 ) ! ( − 1 ) i t s + i − j W i j ( t ) = ∑ k = 0 s − max { i , j } ( s − k − 1 i − 1 ) ( 2 s − j − k − 1 s − 1 ) ( j − 1 ) ! ( − 1 ) i + j t s + i − j \begin{aligned}\boldsymbol{U}_{ij}&=\begin{cases} \frac{1}{\left( i-1 \right) !}\,\, \mathrm{if} i=j\\ 0 \mathrm{if} i\ne j\\\end{cases}, \\\boldsymbol{V}_{ij}\left( t \right) &=\frac{\sum_{k=0}^{s-\max \left\{ i,j \right\}}{\left( -1 \right) ^k\left( \begin{array}{c} s\\ i+k\\\end{array} \right) \left( \begin{array}{c} 2s-j-k-1\\ s-1\\\end{array} \right)}}{\left( j-1 \right) !\left( -1 \right) ^it^{s+i-j}}\\\\\boldsymbol{W}_{ij}\left( t \right) &=\frac{\sum_{k=0}^{s-\max \left\{ i,j \right\}}{\left( \begin{array}{c} s-k-1\\ i-1\\\end{array} \right) \left( \begin{array}{c} 2s-j-k-1\\ s-1\\\end{array} \right)}}{\left( j-1 \right) !\left( -1 \right) ^{i+j}t^{s+i-j}}\end{aligned} UijVij(t)Wij(t)={(i−1)!1ifi=j0ifi=j,=(j−1)!(−1)its+i−j∑k=0s−max{i,j}(−1)k(si+k)(2s−j−k−1s−1)=(j−1)!(−1)i+jts+i−j∑k=0s−max{i,j}(s−k−1i−1)(2s−j−k−1s−1)
对平坦变量的各个维度应用上述公式即可求解BVP最优轨迹
2 算法仿真
2.1 ROS C++仿真
参考轨迹优化 | 基于边界中间值问题(BIVP)的路径平滑求解器(附C++/Python仿真)特化一个用于路径平滑的BIVP
求解器
struct WaypointProblem
{
static constexpr size_t problem_dim = 2; // x, y
static constexpr size_t boundary_order = 2; // position, velocity, accleration
static constexpr size_t intermediate_order = 0; // position
};
template <>
struct rmp::common::math::ProblemTraits<WaypointProblem>
{
static constexpr size_t problem_dim = WaypointProblem::problem_dim;
static constexpr size_t boundary_order = WaypointProblem::boundary_order;
static constexpr size_t intermediate_order = WaypointProblem::intermediate_order;
};
using Solver = rmp::common::math::BIVPSolver<WaypointProblem>;
接着根据路径点约束设置求解器参数并求解即可
bool BIVPOptimizer::optimize(const Points3d& waypoints)
{
solver_->reset();
setBoundaryConstraints(waypoints.front(), waypoints.back());
setIntermediateConstraints(waypoints);
setTimeAllocation(waypoints);
solution_ = std::move(solver_->solve());
return true;
}
2.2 Python仿真
核心代码如下所示:
def optimize(self, waypoints: List[Point3d]) -> None:
solver_params = SolverParameters(
problem_dim=2, # x, y
boundary_constraint_order=2, # position, velocity, accleration
intermediate_constraint_order=0, # position
)
self.solver = BIVPSolver(solver_params)
# boundary
start_boundary = [
SecondOrderBVPState(x=waypoints[0].x(), dx=0.0, ddx=0.0), # x
SecondOrderBVPState(x=waypoints[0].y(), dx=0.0, ddx=0.0), # y
]
goal_boundary = [
SecondOrderBVPState(x=waypoints[-1].x(), dx=0.0, ddx=0.0), # x
SecondOrderBVPState(x=waypoints[-1].y(), dx=0.0, ddx=0.0), # y
]
self.solver.setBoundaryConstraints(start_boundary, goal_boundary)
# intermediate
intermediate_constraints = []
for i in range(1, len(waypoints) - 1):
constraints = [ZeroOrderBVPState(x=waypoints[i].x()), ZeroOrderBVPState(x=waypoints[i].y())] # position
intermediate_constraints.append(constraints)
self.solver.setIntermediateConstraints(intermediate_constraints)
# time allocation
time_allocation = [self.duration_per_segment] * (len(waypoints) - 1)
self.solver.setTimeAllocation(time_allocation)
# solve
self.solution = self.solver.solve()
完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏: