arm/User/module/joint.hpp

198 lines
6.8 KiB
C++
Raw Permalink 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.

/**
* @file joint.hpp
* @brief 关节类 - 封装单个关节的所有功能
*/
#pragma once
#include <stdint.h>
#include <cmath>
#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