119 lines
4.9 KiB
C++
119 lines
4.9 KiB
C++
//
|
||
// Created by xtkuang on 2025/7/21.
|
||
//
|
||
|
||
#ifndef CMVR_ES_CARTESIAN_CONTROLLER_H
|
||
#define CMVR_ES_CARTESIAN_CONTROLLER_H
|
||
|
||
#pragma once
|
||
|
||
#include <Eigen/Core>
|
||
#include <Eigen/Dense>
|
||
#include <vector>
|
||
#include <string>
|
||
#include <memory>
|
||
#include <cmath>
|
||
#include <fcl/fcl.h>
|
||
#include <optional>
|
||
#include <unordered_map>
|
||
|
||
#include "utils/math/se3.h"
|
||
#include "utils/math/qp_solver.h"
|
||
#include "utils/dynamics/robot.h"
|
||
|
||
namespace cmvr::ctrl{
|
||
using cmvr::math::SE3;
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// Task & collision descriptions
|
||
// -----------------------------------------------------------------------------
|
||
struct PoseTarget {
|
||
std::string link_name; //!< link to be controlled
|
||
Eigen::Matrix4d T_target; //!< desired pose w.r.t *base_link*
|
||
double w_posrot = 0.5; // [0→pure pos, 1→pure rot]
|
||
double weight = 1.0; // task weight (0‑1 soft, 1 hard)
|
||
};
|
||
|
||
struct CollisionPair { std::string link_A, link_B; };
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// CartesianController declaration (implementation in .cpp)
|
||
// -----------------------------------------------------------------------------
|
||
template<int DOF>
|
||
class CartesianController {
|
||
public:
|
||
using RobotT = cmvr::dyn::Robot<DOF>;
|
||
using VecD = Eigen::Vector<double, DOF>;
|
||
using Mat6D = Eigen::Matrix<double, 6, DOF>;
|
||
|
||
enum class Mode { Position, Velocity, Torque };
|
||
|
||
CartesianController(std::shared_ptr<RobotT> robot, double dsafe = 0.05, double lambda = 1e-2);
|
||
/* ------------------------- configuration ----------------------------- */
|
||
void setCollisionPairs(const std::vector<CollisionPair>& pairs);
|
||
|
||
// Joint limits (size = DOF). Any value = std::nullopt → no limit.
|
||
void setPositionLimits(const std::vector<std::optional<double>>& q_min, const std::vector<std::optional<double>>& q_max);
|
||
void setVelocityLimits(const std::vector<std::optional<double>>& qd_max);
|
||
void setAccelerationLimits(const std::vector<std::optional<double>>& qdd_max);
|
||
|
||
/* --------------------------- main API -------------------------------- */
|
||
/**
|
||
* Compute joint command given Cartesian objectives.
|
||
* @param state current (mutable) robot state
|
||
* @param base reference frame (string)
|
||
* @param targets list of PoseTarget
|
||
* @param dt controller step [s]
|
||
* @param mode desired output type
|
||
* @param out_cmd filled with q / q̇ / τ
|
||
* @return true if IK converged (position) or soft OK (others)
|
||
*/
|
||
bool compute(
|
||
std::shared_ptr<cmvr::dyn::State<DOF>>& state,
|
||
const std::string& base_link,
|
||
const std::vector<PoseTarget>& targets,
|
||
double dt,
|
||
Mode mode,
|
||
VecD& out_cmd,
|
||
int max_iters = 60,
|
||
double tol = 1e-3,
|
||
double alpha_h = 10.0);
|
||
|
||
private:
|
||
/* -------- internal helpers (implemented in .cpp) --------------------- */
|
||
bool solveIK(std::shared_ptr<cmvr::dyn::State<DOF>>& state, const std::string& base, const std::vector<PoseTarget>& targets,
|
||
const VecD& q_init, VecD& q_out, int max_iters, double tol, double alpha_h) const;
|
||
|
||
bool distanceConstraint(const CollisionPair& cp, std::shared_ptr<cmvr::dyn::State<DOF>>& state,
|
||
const std::vector<std::shared_ptr<fcl::CollisionObjectd>>& objs,
|
||
double& h_out, Eigen::RowVectorXd& J_out) const;
|
||
|
||
inline void clampVec(VecD& v, const std::vector<std::optional<double>>& lo, const std::vector<std::optional<double>>& hi) const;
|
||
|
||
/* -------------------------- data ------------------------------------ */
|
||
std::shared_ptr<RobotT> robot_;
|
||
std::vector<CollisionPair> pairs_;
|
||
double d_safe_ = 0.05;
|
||
double lambda_ = 1e-2;
|
||
mutable math::QPSolver solver_;
|
||
|
||
// joint limits (optional)
|
||
std::vector<std::optional<double>> q_min_ = std::vector<std::optional<double>>(DOF);
|
||
std::vector<std::optional<double>> q_max_ = std::vector<std::optional<double>>(DOF);
|
||
std::vector<std::optional<double>> qd_max_ = std::vector<std::optional<double>>(DOF);
|
||
std::vector<std::optional<double>> qdd_max_= std::vector<std::optional<double>>(DOF);
|
||
|
||
// FCL reusable buffers
|
||
mutable fcl::DistanceRequestd dist_req_{};
|
||
mutable fcl::DistanceResultd dist_res_{};
|
||
};
|
||
}
|
||
|
||
// ------------------------------ explicit instantiation -----------------------
|
||
extern template class cmvr::ctrl::CartesianController<7>;
|
||
extern template class cmvr::ctrl::CartesianController<14>;
|
||
extern template class cmvr::ctrl::CartesianController<20>;
|
||
|
||
|
||
#endif //CMVR_ES_CARTESIAN_CONTROLLER_H
|