/** * @file joint.hpp * @brief 关节类 - 封装单个关节的所有功能 */ #pragma once #include #include #include "motor_base.hpp" #include "component/arm_kinematics/arm6dof.h" namespace arm { struct JointControlParams { float qmin; float qmax; float kp; float kd; }; // ============================================================================ // Joint 类 - 关节对象 // ============================================================================ class Joint { private: uint8_t id_; // 关节编号 IMotor* motor_; // 电机指针(多态) JointControlParams params_; // 关节控制参数 float q_offset_; // 零位偏移 const Joint* coupled_joint_; // 耦合源关节(J3 与 J2 耦合) // 状态 struct { float current_angle; float current_velocity; float current_torque; float target_angle; float feedforward_torque; // 前馈力矩(如重力补偿) bool online; } state_; public: // 构造函数 Joint(uint8_t id, IMotor* motor, const JointControlParams& params, float q_offset, float freq) : id_(id), motor_(motor), params_(params), q_offset_(q_offset), coupled_joint_(nullptr) { state_.current_angle = 0.0f; state_.current_velocity = 0.0f; state_.current_torque = 0.0f; state_.target_angle = 0.0f; state_.feedforward_torque = 0.0f; state_.online = false; } // 兼容构造:允许直接传入机械臂DH参数,但仅提取关节层需要的控制字段 Joint(uint8_t id, IMotor* motor, const Arm6dof_DHParams_t& dh_params, float q_offset, float freq) : Joint(id, motor, JointControlParams{dh_params.qmin, dh_params.qmax, 0.0f, 0.0f}, q_offset, freq) {} // 禁止拷贝(电机资源唯一) Joint(const Joint&) = delete; Joint& operator=(const Joint&) = delete; // Getters uint8_t GetId() const { return id_; } float GetCurrentAngle() const { return state_.current_angle; } float GetCurrentVelocity() const { return state_.current_velocity; } float GetTargetAngle() const { return state_.target_angle; } bool IsOnline() const { return state_.online; } const JointControlParams& GetParams() const { return params_; } float GetOffset() const { return q_offset_; } // Setters void SetOffset(float offset) { q_offset_ = offset; } /** * @brief 设置机械耦合源关节 * @param joint 耦合源关节指针(读取角度时减去其角度,写入时加回) * @note 用于关节间机械耦合补偿,如 J3 与 J2 耦合: * 实际J3角度 = 电机J3原始角度 - J2当前角度 */ void SetCoupledJoint(const Joint* joint) { coupled_joint_ = joint; } void SetTargetAngle(float target) { state_.target_angle = target; } void SetFeedforwardTorque(float torque) { state_.feedforward_torque = torque; } float GetFeedforwardTorque() const { return state_.feedforward_torque; } int8_t Register() { return motor_->Register(); } int8_t Enable() { return motor_->Enable(); } int8_t Update() { int8_t ret = motor_->Update(); float raw = motor_->GetAngle() - q_offset_; // 多圈关节(运动范围 > 2π,如 J1/J4/J6):直接透传多圈绝对值,不截断 // 单圈关节(运动范围 ≤ 2π,如 J2/J3/J5):归一化到 [-π, π] // 目的:消除 DM 电机 0~2π 单圈编码在过零点时的跳变 // 零点不变:raw=0 时不触发任何折叠 // 注意:j3 范围 [0,3]、j5 范围 [-1.75,1.75] 均在 [-π,π] 内, // 归一化后其实际运动段不会碰到 ±π 边界,计算安全 const bool multi_turn = (params_.qmax - params_.qmin) > 2.0f * M_PI; if (!multi_turn) { if (raw > M_PI) raw -= 2.0f * M_PI; if (raw < -M_PI) raw += 2.0f * M_PI; } // 机械耦合补偿:减去耦合源关节的当前角度以得到真实关节角度 // 例:J3 与 J2 耦合时,真实J3 = 电机J3原始角 - J2当前角 if (coupled_joint_) { raw -= coupled_joint_->GetCurrentAngle(); } state_.current_angle = raw; state_.current_velocity = motor_->GetVelocity(); state_.current_torque = motor_->GetTorque(); state_.online = motor_->IsOnline(); return ret; } int8_t Relax() { return motor_->Relax(); } // 位置控制 int8_t PositionControl(float target_angle, float dt) { // 检查限位 if (target_angle < params_.qmin || target_angle > params_.qmax) { return -1; } state_.target_angle = target_angle; // 总前馈力矩 = 重力补偿等前馈力矩 float total_feedforward = state_.feedforward_torque; // MIT控制参数:优先使用DH参数中配置的kp/kd,否则使用默认值 float kp = params_.kp; float kd = params_.kd; // 如果未配置(=0),使用默认值(按电机类型) if (kp <= 0.0f) kp = (id_ < 3) ? 10.0f : 50.0f; // LZ vs DM默认值 if (kd <= 0.0f) kd = (id_ < 3) ? 0.5f : 3.0f; // 机械耦合补偿:发送给电机的目标需加回耦合源关节的角度 float motor_target = target_angle; if (coupled_joint_) { motor_target += coupled_joint_->GetCurrentAngle(); } return motor_->PositionControl( motor_target, 0.0f, // 速度 kp, kd, // 刚度和阻尼 total_feedforward // 前馈力矩(重力补偿) ); } // 纯力矩控制 // @param torque: 输出力矩(N·m) // @return: 0=成功,-1=失败 int8_t TorqueControl(float torque) { state_.feedforward_torque = torque; // 存储当前前馈力矩 return motor_->PositionControl( state_.current_angle, // 保持当前位置 0.0f, // 速度 0.0f, 0.0f, // kp=0, kd=0(无刚度无阻尼) torque // 纯力矩 ); } // 检查是否到达目标 bool IsReached(float tolerance) const { return std::fabs(state_.target_angle - state_.current_angle) < tolerance; } }; } // namespace arm