#pragma once #include #include #include #include "planner/joint_space_planner/include/joint_space_planner.h" #include #include #include namespace cmvr { // 适配器:ConstAccel class ConstAccelTraj : public ITrajectory { public: explicit ConstAccelTraj(std::shared_ptr p); toppra::Bound timeInterval() const override; Eigen::VectorXd q(double t) const override; Eigen::VectorXd qd(double t) const override; Eigen::VectorXd qdd(double t) const override; private: std::shared_ptr impl_; }; // 适配器:Spline class SplineTraj : public ITrajectory { public: SplineTraj(const std::shared_ptr &path, const toppra::Vector &grid, const toppra::Vector &vsq); toppra::Bound timeInterval() const override; Eigen::VectorXd q(double t) const override; Eigen::VectorXd qd(double t) const override; Eigen::VectorXd qdd(double t) const override; private: toppra::parametrizer::Spline impl_; }; // 具体规划器:一次/三次/五次可切换;ConstAccel 校验失败自动回退 Spline class ToppraBSpline : public JointSpacePlanner { public: explicit ToppraBSpline(PathType type = PathType::Quintic); // 统一入口:两点/多点皆可 bool plan(const std::vector > &waypoints, TrajPtr &traj_out) override; // 兼容旧 API(可选):转发为两点的统一入口 bool plan(const std::vector &start_joints, const std::vector &goal_joints, TrajPtr &traj_out) override; std::vector sampleTrajectory(const TrajPtr &traj, double dt) override; bool writeTrajectoryCsv(const std::string &filename, const std::vector &samples) override; private: // —— 几何路径统一分发 —— std::shared_ptr buildPathUnified(const std::vector &q, const std::vector &S); // 二点专用 std::shared_ptr buildTwoPointPath(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1); std::shared_ptr buildLinearTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1); std::shared_ptr buildCubicHermiteTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1); std::shared_ptr buildQuinticRestToRestTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1); std::shared_ptr buildNaturalTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1); // 多点 std::shared_ptr buildLinearMulti(const std::vector &q, const std::vector &S); std::shared_ptr buildCubicHermiteMulti(const std::vector &q, const std::vector &S); std::shared_ptr buildQuinticC2Multi(const std::vector &q, const std::vector &S); std::shared_ptr buildNaturalMulti(const std::vector &q, const std::vector &S); // —— 工具:限幅/参数/估计 —— bool ensureLimitsSized(std::size_t DoF); static void sanitizeVsq(toppra::Vector &v); // centripetal 弦长(alpha=0.5),生成严格递增 S static std::vector makeS_centripetal(const std::vector &q) { const size_t M = q.size(); std::vector S(M, 0.0); auto chord = [](const Eigen::VectorXd &a, const Eigen::VectorXd &b) { double d = (a - b).norm(); return std::pow(std::max(d, 1e-16), 0.5); }; for (size_t i = 1; i < M; ++i) { S[i] = S[i - 1] + chord(q[i], q[i - 1]); if (S[i] <= S[i - 1]) S[i] = S[i - 1] + 1e-12; } return S; } // 等距参数(简单稳妥) static inline std::vector makeS_equal(size_t M) { std::vector S(M); for (size_t i = 0; i < M; ++i) S[i] = static_cast(i); return S; } // 或:先用centripetal,再整体归一化到跨度≈(M-1),并设置每段最小ds static inline void normalize_and_floor_S(std::vector &S, double ds_min = 0.2) { for (size_t i = 1; i < S.size(); ++i) S[i] -= S[0]; double L = S.back(); if (L > 0) for (auto &x: S) x *= (S.size() - 1) / L; for (size_t i = 1; i < S.size(); ++i) if (S[i] - S[i - 1] < ds_min) S[i] = S[i - 1] + ds_min; } // Catmull–Rom(centripetal)估计结点几何速度 v(端点=0) static std::vector estimateVelsCatmull(const std::vector &q, const std::vector &S) { const size_t M = q.size(); const int DoF = static_cast(q[0].size()); std::vector v(M, Eigen::VectorXd::Zero(DoF)); if (M <= 2) return v; for (size_t i = 1; i + 1 < M; ++i) { double ds0 = std::max(S[i] - S[i - 1], 1e-12); double ds1 = std::max(S[i + 1] - S[i], 1e-12); v[i] = ((q[i + 1] - q[i]) / ds1 * ds0 + (q[i] - q[i - 1]) / ds0 * ds1) / (ds0 + ds1); } return v; } // 对内点几何速度限幅,抑制过冲(k∈[0.5,1.0]) static void clampNodeVels(std::vector &v, const std::vector &q, double k = 1.0) { const size_t M = q.size(); if (M <= 2) return; for (size_t i = 1; i + 1 < M; ++i) { double d0 = (q[i] - q[i - 1]).norm(); double d1 = (q[i + 1] - q[i]).norm(); double d = std::max(std::min(d0, d1), 1e-12); double vmax = k * d; double n = v[i].norm(); if (n > vmax) v[i] *= (vmax / n); } } // 估计结点几何加速度 a(端点=0;中点二阶差分,按 s 尺度) static std::vector estimateAccelsSecondDiff(const std::vector &q, const std::vector &S) { const size_t M = q.size(); const int DoF = static_cast(q[0].size()); std::vector a(M, Eigen::VectorXd::Zero(DoF)); if (M <= 2) return a; for (size_t i = 1; i + 1 < M; ++i) { double h0 = std::max(S[i] - S[i - 1], 1e-12); // 左间距 double h1 = std::max(S[i + 1] - S[i], 1e-12); // 右间距 double denom = 0.5 * (h0 + h1); // 局部尺度 // 非均匀中心二阶差分(更精确): // a ≈ 2 * [ (q_{i+1}-q_i)/h1 - (q_i - q_{i-1})/h0 ] / (h0 + h1) a[i] = 2.0 * ((q[i + 1] - q[i]) / h1 - (q[i] - q[i - 1]) / h0) / (h0 + h1); } return a; } // τ→s 变元:把局部 Quintic(τ) 的系数 c_tau[0..5](τ^0..τ^5) // 变成全局 s 的系数 alpha[0..5](s^0..s^5),其中 τ = (s - S_k) / ds static inline void localQuinticToGlobalCoeffs( const std::array &c_tau, // c0..c5(DoF维向量) double Sk, double ds, std::array &alpha // α0..α5(DoF维向量) ) { static const double C[6][6] = { // binomial(n,m) {1, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0}, {1, 2, 1, 0, 0, 0}, {1, 3, 3, 1, 0, 0}, {1, 4, 6, 4, 1, 0}, {1, 5, 10, 10, 5, 1} }; const double eps = 1e-12; ds = std::max(ds, eps); for (int m = 0; m <= 5; ++m) alpha[m].setZero(c_tau[0].size()); // α_m = Σ_{n=m..5} c_n * C(n,m) * (-S_k)^{n-m} / ds^{n} for (int n = 0; n <= 5; ++n) { double invdsn = std::pow(ds, -n); for (int m = 0; m <= n; ++m) { double factor = C[n][m] * std::pow(-Sk, n - m) * invdsn; alpha[m].noalias() += factor * c_tau[n]; } } } }; } // namespace cmvr