轨迹优化 | 基于边界值问题(BVP)的无约束路径平滑(附ROS C++/Python仿真)
目录
- 0 专栏介绍
- 1 边界值问题建模
- 2 算法仿真
- 2.1 ROS C++仿真
- 2.2 Python仿真
0 专栏介绍
🔥课设、毕设、创新竞赛必备!🔥本专栏涉及更高阶的运动规划算法轨迹优化实战,包括:曲线生成、碰撞检测、安全走廊、优化建模(QP、SQP、NMPC、iLQR等)、轨迹优化(梯度法、曲线法等),每个算法都包含代码实现加深理解
🚀详情:运动规划实战进阶:轨迹优化篇
1 边界值问题建模
在轨迹优化 | 基于边界中间值问题(BIVP)的路径平滑求解器(附C++/Python仿真)中,我们介绍过边界中间值问题(Boundary Intermediate Value Problem, BIVP)的形式:
min∫t0tkv(t)TWv(t)+ρ(tk−t0)s.t.z[ri−1](i−1)(ti)=z^i,1⩽i<k,ri⩽sz[s−1](s−1)(t0)=z^0,z[s−1](s−1)(tk)=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)=zi, 1⩽i<k, ri⩽s z[s−1](s−1)(t0)=z0, z[s−1](s−1)(tk)=zk
其中定义z[s−1](t)≜(zT,z˙T,⋯,z(s−1)T)Tz^{[s-1]}(t) \triangleq (z^T, \dot{z}^T, \cdots, z^{(s-1)^T})^Tz[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):
minz(t),T∫t0Tv(t)TWv(t)+ρTs.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}}_Tz(t),Tmin∫t0Tv(t)TWv(t)+ρTs.t.z[s−1](0)=zˉ0,z[s−1](T)=zˉT
其仍然满足BIVP的最优性原理,即最优解z∗(t):[t0,tk]→Rnz^*(t): [t_0, t_k] \to \mathbb{R}^nz∗(t):[t0,tk]→Rn的充要条件为:
- z∗z^*z∗ 的第iii段轨迹是 2s−12s - 12s−1 次多项式;
- 边界条件与中间点条件成立;
- z∗z^*z∗ 在 t=tit = t_it=ti 处满足 rˉi−1\bar{r}_i - 1rˉi−1 次连续可微,其中 rˉi=2s−ri\bar{r}_i = 2s - r_irˉi=2s−ri;
所以最优解满足无中间值条件的约束方程
[F0Ek]P1=[D0Dk]\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=AF(T)p\boldsymbol{d}=\boldsymbol{A}_F\left( T \right) \boldsymbol{p}d=AF(T)p
其中p=[p0p1⋯pn]T∈R2s\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=[z0⋯z0(s−1)zT⋯zT(s−1)]∈R2s\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
AF(t)=[EOF(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)]
各分块矩阵形式为
Eij={(i−1)!ifi=j0ifi≠j,Fij(t)={(j−1)!(j−i)!tj−iifi⩽j0ifi>j,Gij(t)=(s+j−1)!(s+j−i)!ts+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=AB(T)d\boldsymbol{p}=\boldsymbol{A}_B\left( T \right) \boldsymbol{d}p=AB(T)d
其中
AB(t)=[UOV(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)]
各分块矩阵形式为
Uij={1(i−1)!ifi=j0ifi≠j,Vij(t)=∑k=0s−max{i,j}(−1)k(si+k)(2s−j−k−1s−1)(j−1)!(−1)its+i−jWij(t)=∑k=0s−max{i,j}(s−k−1i−1)(2s−j−k−1s−1)(j−1)!(−1)i+jts+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, ystatic constexpr size_t boundary_order = 2; // position, velocity, acclerationstatic 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, yboundary_constraint_order=2, # position, velocity, acclerationintermediate_constraint_order=0, # position)self.solver = BIVPSolver(solver_params)# boundarystart_boundary = [SecondOrderBVPState(x=waypoints[0].x(), dx=0.0, ddx=0.0), # xSecondOrderBVPState(x=waypoints[0].y(), dx=0.0, ddx=0.0), # y]goal_boundary = [SecondOrderBVPState(x=waypoints[-1].x(), dx=0.0, ddx=0.0), # xSecondOrderBVPState(x=waypoints[-1].y(), dx=0.0, ddx=0.0), # y]self.solver.setBoundaryConstraints(start_boundary, goal_boundary)# intermediateintermediate_constraints = []for i in range(1, len(waypoints) - 1):constraints = [ZeroOrderBVPState(x=waypoints[i].x()), ZeroOrderBVPState(x=waypoints[i].y())] # positionintermediate_constraints.append(constraints)self.solver.setIntermediateConstraints(intermediate_constraints)# time allocationtime_allocation = [self.duration_per_segment] * (len(waypoints) - 1)self.solver.setTimeAllocation(time_allocation)# solveself.solution = self.solver.solve()
完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏:
- 《ROS从入门到精通》
- 《Pytorch深度学习实战》
- 《机器学习强基计划》
- 《运动规划实战精讲》
- …