#ifndef ROBOT_H #define ROBOT_H #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" class Robot { private: KDL::Chain kinematicChain; KDL::ChainFkSolverPos_recursive *fkSolver; KDL::ChainIkSolverVel_pinv *ikVelSolver; KDL::ChainIkSolverPos_NR_JL *ikSolverNR; KDL::ChainIkSolverPos_LMA *ikSolverLMA; bool m_initialized; KDL::JntArray jointLowerLimits; KDL::JntArray jointUpperLimits; std::vector activeJointNames; bool m_hasJointLimits; // 记录 joint 名称到 child link UUID 的映射,便于前端回写对象姿态。 std::unordered_map jointChildLinkUuidMap; // 内部工具方法。 double quaternionAngleDifference(const double q1[4], const double q2[4]); int calculateAutoSteps(const double startPose[7], const double endPose[7], int minSteps, int maxSteps, double positionResolution, double orientationResolution); bool parseJointChildLinkUuidsFromUrdf(const std::string &urdfString); // 自动收集 KDL Tree 中没有子节点的末端 link 名称。 std::vector collectLeafSegmentNames(const KDL::Tree &tree) const; // 自动选择可用于正逆运动学的 6 轴串联链,避免固定依赖 base/tool0 命名。 bool selectKinematicChain(const KDL::Tree &tree, KDL::Chain &selectedChain) const; // 从 URDF 中提取当前运动学链的关节上下限。 bool parseJointLimitsFromUrdf(const std::string &urdfString); // 检查关节数组是否处于 URDF 定义的上下限范围内。 bool validateJointLimits(const double joints[6], const std::string &context) const; // 检查关节向量是否处于 URDF 定义的上下限范围内。 bool validateJointLimits(const std::vector &joints, const std::string &context) const; public: /** * @brief 默认构造函数。 */ Robot(); /** * @brief 使用 URDF 字符串直接初始化机器人。 * @param urdfString URDF 格式字符串。 */ explicit Robot(const std::string &urdfString); /** * @brief 释放运动学求解器资源。 */ ~Robot(); int numberOfJoints; /** * @brief 根据 URDF 字符串初始化机器人运动学链。 * @param urdfString URDF 格式字符串。 * @return 初始化成功返回 true,否则返回 false。 */ bool initRobot(const std::string &urdfString); /** * @brief 根据关节序号获取 child link UUID。 * @param jointIndex 关节序号,从 1 开始。 * @return 找到时返回对应 UUID,未找到返回空字符串。 */ std::string getJointUuidByIndex(int jointIndex) const; /** * @brief 根据关节序号生成标准关节名称。 * @param jointIndex 关节序号,从 1 开始。 * @return 如 `joint_1`、`joint_2` 这样的关节名称。 */ static std::string getJointNameByIndex(int jointIndex); /** * @brief 获取当前已解析到的全部关节序号列表。 * @return 已排序且去重后的关节序号集合。 */ std::vector getAvailableJointIndices() const; /** * @brief 兼容多种命名格式查找关节 UUID。 * @param jointIndex 关节序号,从 1 开始。 * @return 找到时返回 UUID,未找到返回空字符串。 */ std::string findJointUuidByAnyFormat(int jointIndex) const; /** * @brief 对姿态序列做逆解,自动进行轨迹插补。 */ json inversePoseStr(const std::string &pose_str, const std::string &q_init_str); /** * @brief 对两点姿态按指定步数插补后做逆解。 */ json inversePoseStr2PSteps(const std::string &pose_str, const std::string &q_init_str, const std::int32_t steps); /** * @brief 直接对输入姿态点做逆解,不做相邻点插补。 */ json inversePoseStrNoDifference(const std::string &pose_str, const std::string &q_init_str); /** * @brief 解析姿态字符串,格式为 `x,y,z,qx,qy,qz,qw;...`。 */ std::vector> parsePoseString(const std::string &pose_str); /** * @brief 解析关节列表字符串,格式为 `j1,j2,j3,j4,j5,j6;...`。 */ std::vector> parseJointListString(const std::string &pose_str); std::unordered_map getJointChildLinkUuidMap() const { return jointChildLinkUuidMap; } std::string getJointChildLinkUuid(const std::string &jointName) const; std::vector parseJointString(const std::string &joint_str); /** * @brief 计算所有关节位姿,并按前端需要的 objStates 格式组织数据。 */ json kinematicsForwardAllJointsList(std::vector joints); /** * @brief 批量计算多帧关节正解,输出 OPERATION 结构。 */ json handleKinematicsForwardAllJoints(const std::string &joints_str); /** * @brief 兼容旧格式的全部关节正解输出。 */ json handleKinematicsForwardAllJoints_objStates(const std::string &joints_str); /** * @brief 判断机器人是否已初始化。 * @return 已初始化返回 true。 */ bool isInitialized() const { return m_initialized; } /** * @brief 使用 NR 求解器计算逆运动学。 * @param pose 目标位姿,格式为 `[x, y, z, qx, qy, qz, qw]`。 * @param iniJ 初始关节角,格式为 `[j1, ..., j6]`。 * @param resultJoints 输出关节角结果。 * @return 求解成功返回 true,否则返回 false。 */ bool calculateIK_NR(const double pose[7], const double iniJ[6], double resultJoints[6]); /** * @brief 使用 LMA 求解器计算逆运动学。 * @param pose 目标位姿,格式为 `[x, y, z, qx, qy, qz, qw]`。 * @param iniJ 初始关节角,格式为 `[j1, ..., j6]`。 * @param resultJoints 输出关节角结果。 * @param eps 迭代收敛精度。 * @param maxiter 最大迭代次数。 * @param eps_joints 关节收敛阈值。 * @return 求解成功返回 true,否则返回 false。 */ bool calculateIK_LMA(const double pose[7], const double iniJ[6], double resultJoints[6], double eps = 1e-8, int maxiter = 3000, double eps_joints = 1e-12); /** * @brief 计算 TCP 的正运动学结果。 * @param joints 输入关节角,格式为 `[j1, ..., j6]`。 * @param tcpPose 输出 TCP 位姿,格式为 `[x, y, z, qx, qy, qz, qw]`。 * @return 计算成功返回 true,否则返回 false。 */ bool calculateFK_TCP(const double joints[6], double tcpPose[7]); /** * @brief 计算每个关节节点的正运动学结果。 * @param joints 输入关节角,格式为 `[j1, ..., j6]`。 * @param jointPoses 输出全部关节位姿,共 6 组,每组 7 个值。 * @return 计算成功返回 true,否则返回 false。 */ bool calculateFK_AllJointsforwardKinematics(const double joints[6], double jointPoses[42]); bool forwardKinematics(const double joints[6], double jointPoses[42]); /** * @brief 获取当前 KDL 运动学链。 */ const KDL::Chain &getKinematicChain() const { return kinematicChain; } /** * @brief 获取机器人关节数量。 */ int getNumberOfJoints() const { return kinematicChain.getNrOfJoints(); } /** * @brief 生成姿态轨迹,输出为固定数组。 * @param pose1 起点位姿。 * @param pose2 终点位姿。 * @param outputPoses 输出轨迹数组。 * @param npoint 轨迹点数量,传 0 表示自动计算。 * @return 实际生成的轨迹点数量,失败返回 -1。 */ int trajectoryPlanning(const double pose1[7], const double pose2[7], double outputPoses[][7], int npoint = 0); /** * @brief 生成姿态轨迹,输出为二维向量。 * @param pose1 起点位姿。 * @param pose2 终点位姿。 * @param outputPoses 输出轨迹点集合。 * @param npoint 轨迹点数量,传 0 表示自动计算。 * @return 实际生成的轨迹点数量,失败返回 -1。 */ int trajectoryPlanning(const double pose1[7], const double pose2[7], std::vector> &outputPoses, int npoint = 0); /** * @brief 使用 `std::vector` 形式输入位姿生成轨迹。 * @param pose1 起点位姿。 * @param pose2 终点位姿。 * @param outputPoses 输出轨迹点集合。 * @param npoint 轨迹点数量,传 0 表示自动计算。 * @return 实际生成的轨迹点数量,失败返回 -1。 */ int trajectoryPlanning(const std::vector &pose1, const std::vector &pose2, std::vector> &outputPoses, int npoint = 0); int calculateAutoSteps(const std::vector &startPose, const std::vector &endPose, int minSteps, int maxSteps, double positionResolution, double orientationResolution); double quaternionAngleDifference(const std::vector &q1, const std::vector &q2); /** * @brief 使用 LMA 求解器计算逆解,输入为数组。 */ std::vector inverse(const double pose[7], const double iniJ[6], double eps = 1e-8, int maxiter = 3000, double eps_joints = 1e-12); /** * @brief 使用 LMA 求解器计算逆解,输入为向量。 */ std::vector inverse(const std::vector &pose, const std::vector &iniJ, double eps = 1e-8, int maxiter = 3000, double eps_joints = 1e-12); /** * @brief 使用默认零位初值计算逆解,输入为数组。 */ std::vector inverse(const double pose[7], double eps = 1e-8, int maxiter = 3000, double eps_joints = 1e-12); /** * @brief 使用默认零位初值计算逆解,输入为向量。 */ std::vector inverse(const std::vector &pose, double eps = 1e-8, int maxiter = 3000, double eps_joints = 1e-12); }; #endif // ROBOT_H