// // Created by xtkuang on 2025/7/8. // #ifndef ROBOT_H #define ROBOT_H #pragma once #include #include #include #include #include #include #include #include #include #include #include "inertial.h" #include "joint.h" #include "link.h" #include "state.h" #include "utils/math/liegroup.h" #include "utils/math/qp_solver.h" namespace cmvr::dyn { /********************************************************** * FORWARD DECLARATION **********************************************************/ // template class Robot; class Link; class Joint; /********************************************************** * MOBILE BASE **********************************************************/ enum class MobileBaseType { None, // Differential, // Mecanum // }; struct MobileBase { MobileBaseType type{MobileBaseType::None}; math::SE3::MatrixType T; // front = x-axis std::vector joints; std::vector params; }; struct MobileBaseDifferential : public MobileBase { unsigned int right_wheel_idx{}; unsigned int left_wheel_idx{}; double wheel_base{0.}; double wheel_radius{0.}; }; struct MobileBaseMecanum : public MobileBase { unsigned int fr_wheel_idx{}; unsigned int fl_wheel_idx{}; unsigned int rr_wheel_idx{}; unsigned int rl_wheel_idx{}; double L_x{0.}; double L_y{0.}; double wheel_radius{0.}; }; /********************************************************** * ROBOT **********************************************************/ struct RobotConfiguration { std::string name; std::shared_ptr base_link; std::shared_ptr mobile_base; }; template class Robot { public: template using ContainerType = typename std::conditional_t<(N > 0), std::array, std::vector >; struct Link_ { struct SubLink_ { std::shared_ptr link; Inertial::MatrixType J_wrt_p; math::SE3::MatrixType M_wrt_p; math::SE3::MatrixType M_wrt_base; }; std::vector links; Inertial::MatrixType J{Inertial::MatrixType::Zero()}; // Link_ inertial wrt base link math::SE3::MatrixType M{math::SE3::Identity()}; // Base link to Link_ frame Inertial::MatrixType I{Inertial::MatrixType::Zero()}; // Link_ inertial wrt Link_ frame int depth{0}; int parent_joint_idx{-1}; std::vector child_joint_idx{}; void SetBaseLink(const std::shared_ptr &link, const math::SE3::MatrixType &T) { // Rest link information links.clear(); J = Inertial::MatrixType::Zero(); M = T; AddLink(link, math::SE3::Identity()); } int AddLink(const std::shared_ptr &link, const math::SE3::MatrixType &M_wrt_p) { Inertial::MatrixType J_wrt_p = Inertial::Transform(M_wrt_p, link->I_); int idx = links.size(); SubLink_ l; l.link = link; l.J_wrt_p = J_wrt_p; l.M_wrt_p = M_wrt_p; l.M_wrt_base = M * M_wrt_p; links.push_back(l); I += J_wrt_p; J += Inertial::Transform(M, J_wrt_p); return idx; } }; struct Joint_ { std::shared_ptr joint{nullptr}; math::se3v::MatrixType S{math::se3v::MatrixType::Zero()}; // zero pose int parent_link_idx{}; int child_link_idx{}; }; struct LinkIdx_ { int link_idx; int sub_link_idx; }; explicit Robot(const RobotConfiguration &robot_configuration); std::shared_ptr GetBase(); std::vector GetLinkNames() const; std::vector GetJointNames() const; std::shared_ptr GetLink(const std::string &name) const; std::shared_ptr GetLink(std::shared_ptr> state, int index) const; LinkIdx_ GetLinkIdx(const std::string& name) const; template, typename JointContainer = std::vector > std::shared_ptr> MakeState(const LinkContainer &link_names, const JointContainer &joint_names); int GetDOF() const; int GetNumberOfJoints() const; void ComputeForwardKinematics(std::shared_ptr> state); void ComputeDiffForwardKinematics(std::shared_ptr> state); void Compute2ndDiffForwardKinematics(std::shared_ptr> state); void ComputeInverseDynamics(std::shared_ptr> state); Eigen::Vector ComputeGravityTerm(std::shared_ptr> state); Eigen::Matrix ComputeMassMatrix(std::shared_ptr> state); Eigen::Matrix ComputeReflectiveInertia(std::shared_ptr> state, unsigned int from, unsigned int to); math::SE3::MatrixType ComputeTransformation(std::shared_ptr> state, unsigned int from, unsigned int to); math::se3v::MatrixType ComputeBodyVelocity(std::shared_ptr> state, unsigned int from, unsigned int to); Eigen::Matrix ComputeSpaceJacobian(std::shared_ptr> state, unsigned int from, unsigned int to); Eigen::Matrix ComputeBodyJacobian(std::shared_ptr> state, unsigned int from, unsigned int to); double ComputeMass(std::shared_ptr> state, unsigned int target_link); Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr> state, unsigned int ref_link, unsigned int target_link); Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr> state, unsigned int ref_link, const std::vector &target_links); Eigen::Matrix ComputeCenterOfMassJacobian(std::shared_ptr> state, unsigned int ref_link, unsigned int target_link); Inertial::MatrixType ComputeTotalInertial(std::shared_ptr> state, unsigned int ref_link); Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr> state, unsigned int ref_link); Eigen::Matrix ComputeCenterOfMassJacobian(std::shared_ptr> state, unsigned int ref_link); std::vector DetectCollisionsOrNearestLinks(std::shared_ptr> state, int collision_threshold = 0); // TODO: ComputeBodyJacobianDot // TODO: ComputeBodyAcceleration // TODO: InverseDiffDynamics Eigen::Vector GetLimitQLower(const std::shared_ptr> &state); Eigen::Vector GetLimitQUpper(const std::shared_ptr> &state); Eigen::Vector GetLimitQdotLower(const std::shared_ptr> &state); Eigen::Vector GetLimitQdotUpper(const std::shared_ptr> &state); Eigen::Vector GetLimitQddotLower(const std::shared_ptr> &state); Eigen::Vector GetLimitQddotUpper(const std::shared_ptr> &state); Eigen::Vector GetLimitTorque(const std::shared_ptr> &state); Eigen::Vector GetJointProperty(const std::shared_ptr> &state, const std::function)> &getter); void ComputeMobilityInverseDiffKinematics(std::shared_ptr> state, // const Eigen::Vector2d &linear_velocity, // (m/s) double angular_velocity // (rad/s) ); void ComputeMobilityInverseDiffKinematics(std::shared_ptr> state, // const math::se2v::MatrixType &body_velocity // w, x, y ); math::se2v::MatrixType ComputeMobilityDiffKinematics( // std::shared_ptr> state // ); static int CountJoints(const std::shared_ptr &base_link, bool include_fixed=false); math::SE3::MatrixType GetLinkT(std::shared_ptr> state, const LinkIdx_ &idx); math::se3v::MatrixType GetLinkV(std::shared_ptr> state, const LinkIdx_ &idx); math::SE3::MatrixType GetJointT(std::shared_ptr> state, int joint_idx); math::se3v::MatrixType GetJointV(std::shared_ptr> state, int joint_idx); math::se3v::MatrixType GetJointVdot(std::shared_ptr> state, int joint_idx); math::SE3::MatrixType GetTransformation(std::shared_ptr> state, const LinkIdx_ &from, const LinkIdx_ &to); Eigen::Matrix GetSpaceJacobian(std::shared_ptr> state, const LinkIdx_ &from, const LinkIdx_ &to); Eigen::Matrix GetBodyJacobian(std::shared_ptr> state, const LinkIdx_ &from, const LinkIdx_ &to); protected: Robot() = default; void Build(const RobotConfiguration &rc); private: ContainerType links_; ContainerType joints_; std::unordered_map link_idx_; // link name to (parent idx, sub link idx) std::unordered_map joint_idx_; // joint name to joint idx size_t n_links_{}; size_t n_joints_{}; /** * MOBILE BASE */ std::shared_ptr mobile_base_; }; RobotConfiguration LoadRobotFromURDFData(const std::string &model, const std::string &base_link_name); RobotConfiguration LoadRobotFromURDF(const std::string &path, const std::string &base_link_name); inline std::string to_string(GeomType type) { switch (type) { case GeomType::kCapsule: return "capsule"; } return "unknown"; } } #include "robot.tpp" #endif //ROBOT_H