mpc_solver.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #pragma once
  2. #include <geometry_msgs/PoseStamped.h>
  3. #include <nav_msgs/Path.h>
  4. #include <ros/ros.h>
  5. #include "mpc/arc_spline.hpp"
  6. #include <deque>
  7. #include "mpc/iosqp.hpp"
  8. #include <algorithm>
  9. namespace mpc_car
  10. {
  11. static constexpr int n = 4; // 四种状态:x y phi v
  12. static constexpr int m = 2; // 两个输入: a delta
  13. typedef Eigen::Matrix<double, n, n> MatrixA;
  14. typedef Eigen::Matrix<double, n, m> MatrixB;
  15. typedef Eigen::Vector4d VectorG;
  16. typedef Eigen::Vector4d VectorX;
  17. typedef Eigen::Vector2d VectorU;
  18. class MpcCar
  19. {
  20. private:
  21. ros::NodeHandle nh_;
  22. arc_spline::ArcSpline s_; // 参考的轨迹
  23. double wheel_base_; // 车辆轴距
  24. double dt_; // 采样时间
  25. double rho_; // 原始代价函数中的权重系数
  26. double rhoN_; // 原始代价函数中的权重系数
  27. double v_max_; // 速度最大值
  28. double a_max_; // 加速度最大值
  29. double delta_max_; // 最大转向角
  30. double ddelta_max_; // 最大转向角变化速度
  31. double delay_; // 延迟时间
  32. double desired_v_; // 规划速度
  33. double Desired_v_; // 期望速度
  34. int N_; // 向前采样的次数
  35. int run_times_ = 1;
  36. // arc_spline::ArcSpline s_; // 参考的轨迹
  37. osqp::IOSQP qpSolver_;
  38. std::vector<VectorX> predictState_; // 预测的状态(根据QP求解后得到的控制输入,计算出来的预测状态)
  39. std::vector<VectorU> predictInput_; // QP 求解后的决策变量(控制输入)
  40. std::deque<VectorU> historyInput_; // 历史输入,用来帮忙计算延迟状态的!
  41. int history_length_; // 历史输入的长度
  42. VectorX x0_observe_; // 观测到的状态
  43. // x_{k+1} = Ad * x_{k} + Bd * u_k + gd
  44. MatrixA Ad_;
  45. MatrixB Bd_;
  46. VectorG gd_;
  47. /**
  48. * osqp interface: QP求解器要求的形式如下,往下面矩阵填内容的时候必须填成下面形式
  49. *
  50. * minimize 0.5 x^T P_ x + q_^T x
  51. * subject to l_ <= A_ x <= u_
  52. *
  53. * OSQP(Operator Splitting Quadratic Program)是一个用于解决凸二次规划问题的求解器。
  54. * 它是一个高性能的、开源的数值优化工具,旨在有效地解决大规模稀疏凸二次规划问题。
  55. **/
  56. // 最后喂给QP求解器的矩阵
  57. Eigen::SparseMatrix<double> P_; // (2 * N_, 2 * N_) 最终 代价函数二次项的权重矩阵
  58. Eigen::SparseMatrix<double> q_; // (2 * N_, 1) 最终 代价函数一次项的权重矩阵
  59. Eigen::SparseMatrix<double> A_; // (4 * N_, 2 * N_) 最终 这是什么矩阵?
  60. Eigen::SparseMatrix<double> l_; // (4 * N_, 1) 最终 约束下边界矩阵
  61. Eigen::SparseMatrix<double> u_; // (4 * N_, 1) 最终 约束上边界矩阵
  62. /*
  63. A_ 和 l_、u_ 的行数是相同的,但是列数不同
  64. 然后,最终的代价函数和约束,都转换成以 控制输入 u 为自变量 的式子
  65. 所以,上面的 l_ <= A_ x <= u_ 应该是 l_ <= A_ * x <= u_
  66. 其中, x 是各个采样状态的控制输入,尺寸应该是:(2 * N_, 1) 这样一乘,不等式的尺寸就对上了
  67. 即: l_(4 * N_, 1) <= A_(4 * N_, 2 * N_) * (2 * N_, 1) <= u_(4 * N_, 1)
  68. */
  69. /* * 系统状态的约束
  70. * / x1 \
  71. * | x2 |
  72. * lx_ <= Cx_ | x3 | <= ux_
  73. * | ... |
  74. * \ xN /
  75. * */
  76. // p, v constrains // 状态约束
  77. Eigen::SparseMatrix<double> Cx_; // (1 * N_, 4 * N_) 状态约束的权重系数矩阵?
  78. Eigen::SparseMatrix<double> lx_; // (1 * N_, 1) 状态约束的下边界矩阵
  79. Eigen::SparseMatrix<double> ux_; // (1 * N_, 1) 状态约束的上边界矩阵
  80. /* * 系统控制输入约束
  81. * / u0 \
  82. * | u1 |
  83. * lu_ <= Cu_ | u2 | <= uu_
  84. * | ... |
  85. * \ uN-1 /
  86. * */
  87. // a delta vs constrains // 控制约束?
  88. Eigen::SparseMatrix<double> Cu_; // (3 * N_, 2 * N_) 状态约束的权重系数矩阵?
  89. Eigen::SparseMatrix<double> lu_; // (3 * N_, 1) 控制输入约束下边界矩阵
  90. Eigen::SparseMatrix<double> uu_; // (3 * N_, 1) 控制输入约束上边界矩阵
  91. Eigen::SparseMatrix<double> Qx_; // (4 * N_, 4 * N_) 原始代价函数的权重系数矩阵
  92. void linearization(const double &phi, const double &v, const double &delta)
  93. {
  94. // x_{k+1} = Ad * x_{k} + Bd * u_k + gd
  95. // TODO: set values to Ad_, Bd_, gd_
  96. Ad_ << 0, 0, -v * sin(phi), cos(phi),
  97. 0, 0, v * cos(phi), sin(phi),
  98. 0, 0, 0, tan(delta) / wheel_base_,
  99. 0, 0, 0, 0;
  100. Bd_ << 0, 0,
  101. 0, 0,
  102. 0, v / (wheel_base_ * pow(cos(delta), 2)),
  103. 1, 0;
  104. gd_ << v * phi * sin(phi),
  105. -v * phi * cos(phi),
  106. -v * delta / (wheel_base_ * pow(cos(delta), 2)),
  107. 0;
  108. // 离散化处理
  109. Ad_ = MatrixA::Identity() + dt_ * Ad_;
  110. Bd_ = dt_ * Bd_;
  111. gd_ = dt_ * gd_;
  112. return;
  113. }
  114. void calLinPoint(const double &s0, double &phi, double &v, double &delta, arc_spline::ArcSpline &s_)
  115. {
  116. Eigen::Vector2d dxy = s_(s0, 1);
  117. Eigen::Vector2d ddxy = s_(s0, 2);
  118. double dx = dxy.x();
  119. double dy = dxy.y();
  120. double ddx = ddxy.x();
  121. double ddy = ddxy.y();
  122. double dphi = (ddy * dx - dy * ddx) / (dx * dx + dy * dy);
  123. phi = atan2(dy, dx);
  124. v = desired_v_;
  125. delta = atan2(wheel_base_ * dphi, 1.0);
  126. }
  127. inline VectorX diff(const VectorX &state,
  128. const VectorU &input) const
  129. { // 根据控制输入和当前状态,返回下一步的状态
  130. VectorX ds;
  131. double phi = state(2);
  132. double v = state(3);
  133. double a = input(0);
  134. double delta = input(1);
  135. ds(0) = v * cos(phi);
  136. ds(1) = v * sin(phi);
  137. ds(2) = v / wheel_base_ * tan(delta);
  138. ds(3) = a;
  139. return ds;
  140. }
  141. inline void step(VectorX &state, const VectorU &input, const double dt) const
  142. {
  143. // Runge–Kutta
  144. VectorX k1 = diff(state, input);
  145. VectorX k2 = diff(state + k1 * dt / 2, input);
  146. VectorX k3 = diff(state + k2 * dt / 2, input);
  147. VectorX k4 = diff(state + k3 * dt, input);
  148. state = state + (k1 + k2 * 2 + k3 * 2 + k4) * dt / 6;
  149. }
  150. /*
  151. 计算四个中间变量(k1, k2, k3, k4),它们基于当前和预测的状态使用diff函数来估计状态的变化率。
  152. k1: 当前状态的变化率。
  153. k2: 在dt/2时间后,使用k1预测的中间状态的变化率。
  154. k3: 同样在dt/2时间后,使用k2预测的另一个中间状态的变化率。
  155. k4: 在dt时间后,使用k3预测的状态的变化率。
  156. 最后,根据这四个变化率的加权平均,更新当前状态。这里使用的加权平均方法确保了更新的准确性和稳定性。
  157. */
  158. VectorX compensateDelay(const VectorX &x0)
  159. { // 补偿延迟
  160. VectorX x0_delay = x0; // 现在观测到的状态
  161. // TODO: compensate delay
  162. double dt = 1e-3;
  163. for (double t = delay_; t > 0; t = t - dt)
  164. { // t 是越来越小的,
  165. int i = std::ceil(t / dt_); // 向上取整
  166. VectorU input = historyInput_[history_length_ - i]; // !!! 用来模拟延迟的!!!
  167. step(x0_delay, input, dt);
  168. }
  169. return x0_delay; // 根据历史的输入,和当前观测到的状态,估算出这次计算出来的控制信号对应的状态
  170. // x(t+tao) 只于当前状态和过去 tao 时间的输入有关,与当前输入无关
  171. // 当前观测的状态是 x0
  172. // 延时的时长是 tao
  173. // 预测下一个状态 x0_delay 就得根据 tao 时刻前到 现在 的输入信号来计算了
  174. }
  175. public:
  176. MpcCar() {}
  177. void initialize()
  178. {
  179. std::cout << "mpc car initialize !!" << std::endl;
  180. ros::param::get("/trajectory_tracker/planning_params/desired_v_", desired_v_);
  181. // desired_v_ = 0;
  182. ros::param::get("/trajectory_tracker/planning_params/wheel_base_", wheel_base_); // 这个变量名该一下,跟Hybird A* 的统一
  183. ros::param::get("/trajectory_tracker/planning_params/dt_", dt_);
  184. ros::param::get("/trajectory_tracker/planning_params/rho_", rho_);
  185. ros::param::get("/trajectory_tracker/planning_params/N_", N_);
  186. ros::param::get("/trajectory_tracker/planning_params/rhoN_", rhoN_);
  187. ros::param::get("/trajectory_tracker/planning_params/v_max_", v_max_);
  188. ros::param::get("/trajectory_tracker/planning_params/a_max_", a_max_);
  189. ros::param::get("/trajectory_tracker/planning_params/steering_angle_", delta_max_);
  190. ros::param::get("/trajectory_tracker/planning_params/ddelta_max_", ddelta_max_);
  191. ros::param::get("/trajectory_tracker/planning_params/delay_", delay_);
  192. delta_max_ = delta_max_ * 3.141592 / 180; // 转换成弧度制
  193. ddelta_max_ = ddelta_max_ * 3.141592 / 180;
  194. history_length_ = std::ceil(delay_ / dt_); // 用来帮忙计算delay mpc的
  195. // TODO: set initial value of Ad, Bd, gd
  196. Ad_.setIdentity(); // Ad for instance
  197. // set size of sparse matrices
  198. P_.resize(m * N_, m * N_);
  199. q_.resize(m * N_, 1);
  200. Qx_.resize(n * N_, n * N_);
  201. int n_cons = 4; // v a delta ddelta
  202. A_.resize(n_cons * N_, m * N_);
  203. l_.resize(n_cons * N_, 1);
  204. u_.resize(n_cons * N_, 1);
  205. // v constrains
  206. Cx_.resize(1 * N_, n * N_);
  207. lx_.resize(1 * N_, 1);
  208. ux_.resize(1 * N_, 1);
  209. // a delta constrains
  210. Cu_.resize(3 * N_, m * N_); // 稀疏矩阵,默认是全0
  211. lu_.resize(3 * N_, 1);
  212. uu_.resize(3 * N_, 1);
  213. // stage cost // 设置权重系数
  214. Qx_.setIdentity(); // 正常的所有状态的权重系数都是 1
  215. for (int i = 1; i <= N_; ++i)
  216. { // 四种状态:x y phi v
  217. Qx_.coeffRef(i * n - 2, i * n - 2) = 1; // 车辆朝向代价权重系数 // 这里的权重系数改成自己写的吧
  218. Qx_.coeffRef(i * n - 1, i * n - 1) = 1; // 车辆速度代价权重系数
  219. Qx_.coeffRef(i * n - 1, i * n - 1) = 0.5;
  220. Qx_.coeffRef(i * n - 1, i * n - 1) = 0.8;
  221. // 这里将速度的权重设置成0,说明在代价函数中不考虑速度,即不管算出来的速度跟期望速度差多少,都不会增加代价值
  222. // 在算不同状态的时候,都是通过期望速度来计算的,如果权重不设置成0,那么优化出来的速度会尽量网期望速度上靠
  223. // 设置成0,感觉效果不是很好,0.5的时候就感觉一般,试试1 1效果还不错喔! 但是不能总调高这个,因为位置跟踪也是很重要的
  224. }
  225. // Qx_.coeffRef(N_ * n - 4, N_ * n - 4) = rhoN_;
  226. // Qx_.coeffRef(N_ * n - 3, N_ * n - 3) = rhoN_;
  227. // Qx_.coeffRef(N_ * n - 2, N_ * n - 2) = rhoN_ * rho_;
  228. // set lower and upper boundaries 设置约束边界
  229. for (int i = 0; i < N_; ++i)
  230. {
  231. // TODO: set stage constraints of inputs (a, delta, ddelta) 控制输入的约束
  232. // -a_max <= a <= a_max for instance:
  233. Cu_.coeffRef(i * 3 + 0, i * m + 0) = 1; // 跟下面的 Cx_ 同理
  234. lu_.coeffRef(i * 3 + 0, 0) = -a_max_;
  235. uu_.coeffRef(i * 3 + 0, 0) = a_max_;
  236. // Cu_.coeffRef(i * 3 + 1, i * m + 0) = 1; 原来代码的列索引是跟上面的一样的,感觉是有问题的,应该改成下面这行这样,编译运行也是正常能跑的。。
  237. Cu_.coeffRef(i * 3 + 1, i * m + 1) = 1; // 乘出来的控制输入项是: delta 跟下面的 delta_max 也对应上了
  238. lu_.coeffRef(i * 3 + 1, 0) = -delta_max_;
  239. uu_.coeffRef(i * 3 + 1, 0) = delta_max_;
  240. if (i > 0)
  241. {
  242. Cu_.coeffRef(i * 3 + 2, (i - 1) * m + 1) = -1;
  243. // 这个项乘出来是: -delta_{i - 1} + delta_{i} 两个状态间的转向角度变化差异,和下面的 dt * ddelta_max_ 也对应上了
  244. }
  245. Cu_.coeffRef(i * 3 + 2, i * m + 1) = 1;
  246. lu_.coeffRef(i * 3 + 2, 0) = -dt_ * ddelta_max_;
  247. uu_.coeffRef(i * 3 + 2, 0) = dt_ * ddelta_max_;
  248. // TODO: set stage constraints of states (v) // 状态的约束(主要是速度最大最小值的约束)
  249. // -v_max <= v <= v_max
  250. Cx_.coeffRef(i, i * n + 3) = 1; // 权重系数矩阵
  251. // 稀疏矩阵,不给定初值默认元素是0,然后这里给定每行对应状态的第4个元素是1,其他元素都是0,就意味着屏蔽状态的前3个元素
  252. // 状态向量:x y phi v
  253. lx_.coeffRef(i, 0) = -v_max_; // 下边界约束
  254. ux_.coeffRef(i, 0) = v_max_; // 上边界约束
  255. }
  256. // set predict mats size
  257. predictState_.resize(N_);
  258. predictInput_.resize(N_);
  259. for (int i = 0; i < N_; ++i)
  260. {
  261. predictInput_[i].setZero();
  262. }
  263. for (int i = 0; i < history_length_; ++i)
  264. {
  265. historyInput_.emplace_back(0, 0);
  266. }
  267. std::cout << "mpc car initialize finish !!" << std::endl;
  268. }
  269. Eigen::Vector2d solveQP(const VectorX &x0_observe, const nav_msgs::Path &local_plan, bool teb_run_falg)
  270. {
  271. // 速度规划方面,只需要在这里改 desired_v_ 就好了? 看看代价函数
  272. // std::cout << "MPC runtimes = " << run_times_++ << std::endl;
  273. // desired_v_ = std::min(desired_v_ + 0.2 * 1/15, 1.0);
  274. x0_observe_ = x0_observe; // 当前时刻机器人的状态
  275. historyInput_.pop_front();
  276. historyInput_.push_back(predictInput_.front());
  277. // 求解初值,用上一次的求解结果,弹出第一个控制量,并且在最后家一个控制量
  278. std::vector<double> track_points_x, track_points_y;
  279. track_points_x.clear();
  280. track_points_y.clear();
  281. for (int i = 0; i < local_plan.poses.size(); i++)
  282. {
  283. track_points_x.push_back(local_plan.poses[i].pose.position.x);
  284. track_points_y.push_back(local_plan.poses[i].pose.position.y);
  285. }
  286. if (teb_run_falg == true)
  287. s_.setWayPoints(track_points_x, track_points_y); // 根据轨迹点,求解出对应的:关于 t 的参数方程 x(t) y(t), 关于弧长 s 的参数方程 x(s), y(s) // 这里可以优化吧,没调用TEB算法的话,不用重新setWayPoints
  288. lu_.coeffRef(2, 0) = -delta_max_; // 第一组控制输入的转向角下界(运行到这里的时候lu_.coeffRef(2, 0) 和 uu_.coeffRef(2, 0) 不是构造函数中给定的值,很奇怪,但不深究了,这里再重新赋一次值
  289. uu_.coeffRef(2, 0) = delta_max_;
  290. VectorX x0 = compensateDelay(x0_observe_); // 延迟补偿
  291. // 他这里的延迟补偿,只是根据当前观测到的状态x0_observe_ 和 设定的延迟时间 delay_ 和 历史控制信号输入 计算出 delay_ 秒前的状态?
  292. // set BB, AA, gg
  293. Eigen::MatrixXd BB, AA, gg;
  294. BB.setZero(n * N_, m * N_);
  295. AA.setZero(n * N_, n);
  296. gg.setZero(n * N_, 1);
  297. double s0 = s_.findS(x0.head(2));
  298. double phi, v, delta;
  299. double last_phi = x0(2);
  300. Eigen::SparseMatrix<double> qx;
  301. qx.resize(n * N_, 1);
  302. for (int i = 0; i < N_; ++i)
  303. {
  304. calLinPoint(s0, phi, v, delta, s_); // 根据弧长 s0, 计算出对应轨迹点的 车辆朝向 phi 后轮速度 v 转向输入 delta
  305. if (phi - last_phi > M_PI)
  306. {
  307. phi -= 2 * M_PI;
  308. }
  309. else if (phi - last_phi < -M_PI)
  310. {
  311. phi += 2 * M_PI;
  312. }
  313. last_phi = phi;
  314. linearization(phi, v, delta); // 线性化 + 离散化 生成对应的 Ac Bc gc
  315. // calculate big state-space matrices
  316. /* * BB AA
  317. * x1 / B 0 ... 0 \ / A \
  318. * x2 | AB B ... 0 | | A2 |
  319. * x3 = | A^2B AB ... 0 |u + | ... |x0 + gg
  320. * ... | ... ... ... 0 | | ... |
  321. * xN \A^(n-1 )B ... ... B / \ A^N /
  322. *
  323. * X = BB * U + AA * x0 + gg
  324. * */
  325. if (i == 0)
  326. {
  327. BB.block(0, 0, n, m) = Bd_;
  328. AA.block(0, 0, n, n) = Ad_;
  329. gg.block(0, 0, n, 1) = gd_;
  330. }
  331. else
  332. {
  333. // TODO: set BB AA gg
  334. BB.block(n * i, m * i, n, m) = Bd_;
  335. for (int j = i - 1; j >= 0; j--)
  336. {
  337. BB.block(n * i, m * j, n, m) = Ad_ * BB.block(n * (i - 1), m * j, n, m);
  338. }
  339. AA.block(n * i, 0, n, n) = Ad_ * AA.block(n * (i - 1), 0, n, n);
  340. gg.block(n * i, 0, n, 1) = Ad_ * gg.block(n * (i - 1), 0, n, 1) + gd_;
  341. }
  342. // TODO: set qx
  343. Eigen::Vector2d xy = s_(s0); // reference (x_r, y_r)
  344. // s_(s0) 返回的是在轨迹的s0弧长处的 x 和 y 坐标系
  345. // cost function should be represented as follows:
  346. /* *
  347. * / x1 \T / x1 \ / x1 \
  348. * | x2 | | x2 | | x2 |
  349. * J = 0.5 | x3 | Qx_ | x3 | + qx^T | x3 | + const.
  350. * | ... | | ... | | ... |
  351. * \ xN / \ xN / \ xN /
  352. * Qx_ 是关于系统状态的二次项, qx 是关于系统的线性项
  353. * */
  354. // 原始代价函数的一次项权重矩阵
  355. qx.coeffRef(n * i, 0) = -Qx_.coeffRef(n * i, n * i) * xy(0);
  356. qx.coeffRef(n * i + 1, 0) = -Qx_.coeffRef(n * i + 1, n * i + 1) * xy(1);
  357. qx.coeffRef(n * i + 2, 0) = -Qx_.coeffRef(n * i + 2, n * i + 2) * phi;
  358. qx.coeffRef(n * i + 3, 0) = 0;
  359. s0 += desired_v_ * dt_; // 轨迹的弧长索引往前进一步
  360. s0 = s0 < s_.arcL() ? s0 : s_.arcL();
  361. }
  362. Eigen::SparseMatrix<double> BB_sparse = BB.sparseView();
  363. Eigen::SparseMatrix<double> AA_sparse = AA.sparseView();
  364. Eigen::SparseMatrix<double> gg_sparse = gg.sparseView();
  365. Eigen::SparseMatrix<double> x0_sparse = x0.sparseView();
  366. // state constrants propogate to input constraints using "X = BB * U + AA * x0 + gg"
  367. /* *
  368. * / x1 \ / u0 \
  369. * | x2 | | u1 |
  370. * lx_ <= Cx_ | x3 | <= ux_ ==> lx <= Cx | u2 | <= ux
  371. * | ... | | ... |
  372. * \ xN / \ uN-1 /
  373. * ! ! !
  374. * */
  375. // 把状态约束转换成控制输入的约束
  376. Eigen::SparseMatrix<double> Cx = Cx_ * BB_sparse;
  377. Eigen::SparseMatrix<double> lx = lx_ - Cx_ * AA_sparse * x0_sparse - Cx_ * gg_sparse;
  378. Eigen::SparseMatrix<double> ux = ux_ - Cx_ * AA_sparse * x0_sparse - Cx_ * gg_sparse;
  379. /* * / Cx \ / lx \ / ux \
  380. * A_ = \ Cu_ /, l_ = \ lu_ /, u_ = \ uu_ /
  381. * */
  382. // 将转换后的状态约束 和 控制约束合并起来
  383. Eigen::SparseMatrix<double> A_T = A_.transpose();
  384. A_T.middleCols(0, Cx.rows()) = Cx.transpose();
  385. A_T.middleCols(Cx.rows(), Cu_.rows()) = Cu_.transpose();
  386. A_ = A_T.transpose();
  387. for (int i = 0; i < lx.rows(); ++i)
  388. {
  389. l_.coeffRef(i, 0) = lx.coeff(i, 0);
  390. u_.coeffRef(i, 0) = ux.coeff(i, 0);
  391. }
  392. for (int i = 0; i < lu_.rows(); ++i)
  393. {
  394. l_.coeffRef(i + lx.rows(), 0) = lu_.coeff(i, 0);
  395. u_.coeffRef(i + lx.rows(), 0) = uu_.coeff(i, 0);
  396. }
  397. Eigen::SparseMatrix<double> BBT_sparse = BB_sparse.transpose();
  398. P_ = BBT_sparse * Qx_ * BB_sparse;
  399. q_ = BBT_sparse * Qx_.transpose() * (AA_sparse * x0_sparse + gg_sparse) + BBT_sparse * qx;
  400. // osqp
  401. Eigen::VectorXd q_d = q_.toDense(); // toDense() 函数,它们分别被转换为密集向量
  402. Eigen::VectorXd l_d = l_.toDense();
  403. Eigen::VectorXd u_d = u_.toDense();
  404. /**
  405. * osqp interface: QP求解器要求的形式如下,往下面矩阵填内容的时候必须填成下面形式
  406. *
  407. * minimize 0.5 x^T P_ x + q_^T x
  408. * subject to l_ <= A_ x <= u_
  409. *
  410. * OSQP(Operator Splitting Quadratic Program)一个用于解决凸二次规划问题的求解器
  411. * 一个高性能、开源的数值优化工具,旨在有效地解决大规模稀疏凸二次规划问题。
  412. **/
  413. qpSolver_.setMats(P_, q_d, A_, l_d, u_d);
  414. qpSolver_.solve();
  415. int ret = qpSolver_.getStatus();
  416. if (ret != 1)
  417. {
  418. ROS_ERROR("fail to solve QP!");
  419. return Eigen::Vector2d::Zero();
  420. }
  421. Eigen::VectorXd sol = qpSolver_.getPrimalSol();
  422. Eigen::MatrixXd solMat = Eigen::Map<const Eigen::MatrixXd>(sol.data(), m, N_);
  423. Eigen::VectorXd solState = BB * sol + AA * x0 + gg;
  424. Eigen::MatrixXd predictMat = Eigen::Map<const Eigen::MatrixXd>(solState.data(), n, N_);
  425. for (int i = 0; i < N_; ++i)
  426. {
  427. predictInput_[i] = solMat.col(i);
  428. predictState_[i] = predictMat.col(i);
  429. }
  430. return predictInput_.front();
  431. }
  432. };
  433. }