cmvr-es/src/planner/joint_space_planner/include/toppra_bspline.h

227 lines
9.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <memory>
#include <vector>
#include <Eigen/Dense>
#include "planner/joint_space_planner/include/joint_space_planner.h"
#include <toppra/geometric_path/piecewise_poly_path.hpp>
#include <toppra/parametrizer/const_accel.hpp>
#include <toppra/parametrizer/spline.hpp>
namespace cmvr {
// 适配器ConstAccel
class ConstAccelTraj : public ITrajectory {
public:
explicit ConstAccelTraj(std::shared_ptr<toppra::parametrizer::ConstAccel> 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<toppra::parametrizer::ConstAccel> impl_;
};
// 适配器Spline
class SplineTraj : public ITrajectory {
public:
SplineTraj(const std::shared_ptr<toppra::PiecewisePolyPath> &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<std::vector<double> > &waypoints, TrajPtr &traj_out) override;
// 兼容旧 API可选转发为两点的统一入口
bool plan(const std::vector<double> &start_joints,
const std::vector<double> &goal_joints,
TrajPtr &traj_out) override;
std::vector<TrajSample> sampleTrajectory(const TrajPtr &traj, double dt) override;
bool writeTrajectoryCsv(const std::string &filename, const std::vector<TrajSample> &samples) override;
private:
// —— 几何路径统一分发 ——
std::shared_ptr<toppra::PiecewisePolyPath>
buildPathUnified(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S);
// 二点专用
std::shared_ptr<toppra::PiecewisePolyPath>
buildTwoPointPath(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1);
std::shared_ptr<toppra::PiecewisePolyPath>
buildLinearTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1);
std::shared_ptr<toppra::PiecewisePolyPath>
buildCubicHermiteTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1);
std::shared_ptr<toppra::PiecewisePolyPath>
buildQuinticRestToRestTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1);
std::shared_ptr<toppra::PiecewisePolyPath>
buildNaturalTwo(const Eigen::VectorXd &q0, const Eigen::VectorXd &q1);
// 多点
std::shared_ptr<toppra::PiecewisePolyPath>
buildLinearMulti(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S);
std::shared_ptr<toppra::PiecewisePolyPath>
buildCubicHermiteMulti(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S);
std::shared_ptr<toppra::PiecewisePolyPath>
buildQuinticC2Multi(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S);
std::shared_ptr<toppra::PiecewisePolyPath>
buildNaturalMulti(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S);
// —— 工具:限幅/参数/估计 ——
bool ensureLimitsSized(std::size_t DoF);
static void sanitizeVsq(toppra::Vector &v);
// centripetal 弦长alpha=0.5),生成严格递增 S
static std::vector<toppra::value_type>
makeS_centripetal(const std::vector<Eigen::VectorXd> &q) {
const size_t M = q.size();
std::vector<toppra::value_type> 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<toppra::value_type> makeS_equal(size_t M) {
std::vector<toppra::value_type> S(M);
for (size_t i = 0; i < M; ++i) S[i] = static_cast<toppra::value_type>(i);
return S;
}
// 或先用centripetal再整体归一化到跨度≈(M-1)并设置每段最小ds
static inline void normalize_and_floor_S(std::vector<toppra::value_type> &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;
}
// CatmullRomcentripetal估计结点几何速度 v端点=0
static std::vector<Eigen::VectorXd>
estimateVelsCatmull(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S) {
const size_t M = q.size();
const int DoF = static_cast<int>(q[0].size());
std::vector<Eigen::VectorXd> v(M, Eigen::VectorXd::Zero(DoF));
if (M <= 2) return v;
for (size_t i = 1; i + 1 < M; ++i) {
double ds0 = std::max<double>(S[i] - S[i - 1], 1e-12);
double ds1 = std::max<double>(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<Eigen::VectorXd> &v,
const std::vector<Eigen::VectorXd> &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<Eigen::VectorXd>
estimateAccelsSecondDiff(const std::vector<Eigen::VectorXd> &q,
const std::vector<toppra::value_type> &S) {
const size_t M = q.size();
const int DoF = static_cast<int>(q[0].size());
std::vector<Eigen::VectorXd> a(M, Eigen::VectorXd::Zero(DoF));
if (M <= 2) return a;
for (size_t i = 1; i + 1 < M; ++i) {
double h0 = std::max<double>(S[i] - S[i - 1], 1e-12); // 左间距
double h1 = std::max<double>(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<Eigen::VectorXd, 6> &c_tau, // c0..c5DoF维向量
double Sk, double ds,
std::array<Eigen::VectorXd, 6> &alpha // α0..α5DoF维向量
) {
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