/* 灵足电机驱动 灵足电机通信协议: - CAN 2.0通信接口,波特率1Mbps - 采用扩展帧格式(29位ID) - ID格式:Bit28~24(通信类型) + Bit23~8(数据区2) + Bit7~0(目标地址) */ /* Includes ----------------------------------------------------------------- */ #include "motor_lz.h" #include #include #include #include "bsp/can.h" #include "bsp/mm.h" #include "bsp/time.h" #include "component/user_math.h" /* Private define ----------------------------------------------------------- */ // 灵足电机协议参数 #define LZ_ANGLE_RANGE_RAD (12.57f) /* 角度范围 ±12.57 rad */ #define LZ_VELOCITY_RANGE_RAD_S (20.0f) /* 角速度范围 ±20 rad/s */ #define LZ_TORQUE_RANGE_NM (60.0f) /* 力矩范围 ±60 Nm */ #define LZ_KP_MAX (5000.0f) /* Kp最大值 */ #define LZ_KD_MAX (100.0f) /* Kd最大值 */ #define LZ_RAW_VALUE_MAX (65535) /* 16位原始值最大值 */ #define LZ_TEMP_SCALE (10.0f) /* 温度缩放因子 */ #define MOTOR_TX_BUF_SIZE (8) #define MOTOR_RX_BUF_SIZE (8) /* Private macro ------------------------------------------------------------ */ /* Private typedef ---------------------------------------------------------- */ /* Private variables -------------------------------------------------------- */ static MOTOR_LZ_CANManager_t *can_managers[BSP_CAN_NUM] = {NULL}; /* Private function prototypes ---------------------------------------------- */ static MOTOR_LZ_CANManager_t* MOTOR_LZ_GetCANManager(BSP_CAN_t can); static int8_t MOTOR_LZ_CreateCANManager(BSP_CAN_t can); static void MOTOR_LZ_Decode(MOTOR_LZ_t *motor, BSP_CAN_Message_t *msg); static uint32_t MOTOR_LZ_BuildExtID(MOTOR_LZ_CmdType_t cmd_type, uint16_t data2, uint8_t target_id); static uint16_t MOTOR_LZ_FloatToRaw(float value, float max_value); static float MOTOR_LZ_RawToFloat(uint16_t raw_value, float max_value); static int8_t MOTOR_LZ_SendExtFrame(BSP_CAN_t can, uint32_t ext_id, uint8_t *data, uint8_t dlc); static uint32_t MOTOR_LZ_IdParser(uint32_t original_id, BSP_CAN_FrameType_t frame_type); /* Private functions -------------------------------------------------------- */ /** * @brief 获取CAN管理器 */ static MOTOR_LZ_CANManager_t* MOTOR_LZ_GetCANManager(BSP_CAN_t can) { if (can >= BSP_CAN_NUM) return NULL; return can_managers[can]; } /** * @brief 创建CAN管理器 */ static int8_t MOTOR_LZ_CreateCANManager(BSP_CAN_t can) { if (can >= BSP_CAN_NUM) return DEVICE_ERR; if (can_managers[can] != NULL) return DEVICE_OK; can_managers[can] = (MOTOR_LZ_CANManager_t*)BSP_Malloc(sizeof(MOTOR_LZ_CANManager_t)); if (can_managers[can] == NULL) return DEVICE_ERR; memset(can_managers[can], 0, sizeof(MOTOR_LZ_CANManager_t)); can_managers[can]->can = can; return DEVICE_OK; } /** * @brief 构建扩展ID */ static uint32_t MOTOR_LZ_BuildExtID(MOTOR_LZ_CmdType_t cmd_type, uint16_t data2, uint8_t target_id) { uint32_t ext_id = 0; ext_id |= ((uint32_t)cmd_type & 0x1F) << 24; // Bit28~24: 通信类型 ext_id |= ((uint32_t)data2 & 0xFFFF) << 8; // Bit23~8: 数据区2 ext_id |= ((uint32_t)target_id & 0xFF); // Bit7~0: 目标地址 return ext_id; } /** * @brief 浮点值转换为原始值 */ static uint16_t MOTOR_LZ_FloatToRaw(float value, float max_value) { // 限制范围 if (value > max_value) value = max_value; if (value < -max_value) value = -max_value; // 转换为0~65535范围,对应-max_value~max_value return (uint16_t)((value + max_value) / (2.0f * max_value) * (float)LZ_RAW_VALUE_MAX); } /** * @brief 原始值转换为浮点值 */ static float MOTOR_LZ_RawToFloat(uint16_t raw_value, float max_value) { // 将0~65535范围转换为-max_value~max_value return ((float)raw_value / (float)LZ_RAW_VALUE_MAX) * (2.0f * max_value) - max_value; } /** * @brief 发送扩展帧 */ static int8_t MOTOR_LZ_SendExtFrame(BSP_CAN_t can, uint32_t ext_id, uint8_t *data, uint8_t dlc) { BSP_CAN_ExtDataFrame_t tx_frame; tx_frame.id = ext_id; tx_frame.dlc = dlc; if (data != NULL) { memcpy(tx_frame.data, data, dlc); } else { memset(tx_frame.data, 0, dlc); } return BSP_CAN_TransmitExtDataFrame(can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } /** * @brief 灵足电机ID解析器 * @param original_id 原始CAN ID(29位扩展帧) * @param frame_type 帧类型 * @return 解析后的ID(用于队列匹配) * * 灵足电机扩展ID格式: * Bit28~24: 通信类型 (0x1=运控控制, 0x2=反馈数据, 0x3=使能, 0x4=停止, 0x6=设零位) * Bit23~8: 数据区2 (根据通信类型而定) * Bit7~0: 目标地址 (目标电机CAN ID) */ static uint32_t MOTOR_LZ_IdParser(uint32_t original_id, BSP_CAN_FrameType_t frame_type) { // 只处理扩展数据帧 if (frame_type != BSP_CAN_FRAME_EXT_DATA) { return original_id; // 非扩展帧直接返回原始ID } // 解析扩展ID各个字段 uint8_t cmd_type = (original_id >> 24) & 0x1F; // Bit28~24: 通信类型 uint16_t data2 = (original_id >> 8) & 0xFFFF; // Bit23~8: 数据区2 uint8_t target_id = original_id & 0xFF; // Bit7~0: 目标地址 // 对于反馈数据帧,我们使用特殊的解析规则 if (cmd_type == MOTOR_LZ_CMD_FEEDBACK) { // 反馈数据的data2字段包含: // Bit8~15: 当前电机CAN ID // Bit16~21: 故障信息 // Bit22~23: 模式状态 uint8_t motor_can_id = data2 & 0xFF; // 返回格式化的ID,便于匹配 // 格式:0x02HHMMTT (02=反馈命令, HH=主机ID, MM=电机ID, TT=目标ID) return (0x02000000) | ((data2 & 0xFF00) << 8) | (motor_can_id << 8) | target_id; } // 对于其他命令类型,直接返回原始ID return original_id; } /** * @brief 解码灵足电机反馈数据 */ static void MOTOR_LZ_Decode(MOTOR_LZ_t *motor, BSP_CAN_Message_t *msg) { if (motor == NULL || msg == NULL) return; // 检查是否为反馈数据帧 (通信类型2) uint8_t cmd_type = (msg->parsed_id >> 24) & 0x1F; if (cmd_type != MOTOR_LZ_CMD_FEEDBACK) return; // 解析ID中的信息 uint16_t id_data2 = (msg->parsed_id >> 8) & 0xFFFF; uint8_t motor_can_id = id_data2 & 0xFF; // Bit8~15: 当前电机CAN ID uint8_t fault_info = (id_data2 >> 8) & 0x3F; // Bit16~21: 故障信息 uint8_t mode_state = (id_data2 >> 14) & 0x03; // Bit22~23: 模式状态 // 更新电机CAN ID motor->lz_feedback.motor_can_id = motor_can_id; // 解析故障信息 motor->lz_feedback.fault.under_voltage = (fault_info & 0x01) != 0; // bit16 motor->lz_feedback.fault.driver_fault = (fault_info & 0x02) != 0; // bit17 motor->lz_feedback.fault.over_temp = (fault_info & 0x04) != 0; // bit18 motor->lz_feedback.fault.encoder_fault = (fault_info & 0x08) != 0; // bit19 motor->lz_feedback.fault.stall_overload = (fault_info & 0x10) != 0; // bit20 motor->lz_feedback.fault.uncalibrated = (fault_info & 0x20) != 0; // bit21 // 解析模式状态 motor->lz_feedback.state = (MOTOR_LZ_State_t)mode_state; // 解析数据区 // Byte0~1: 当前角度 uint16_t raw_angle = (uint16_t)((msg->data[1] << 8) | msg->data[0]); motor->lz_feedback.current_angle = MOTOR_LZ_RawToFloat(raw_angle, LZ_ANGLE_RANGE_RAD); // Byte2~3: 当前角速度 uint16_t raw_velocity = (uint16_t)((msg->data[3] << 8) | msg->data[2]); motor->lz_feedback.current_velocity = MOTOR_LZ_RawToFloat(raw_velocity, LZ_VELOCITY_RANGE_RAD_S); // Byte4~5: 当前力矩 uint16_t raw_torque = (uint16_t)((msg->data[5] << 8) | msg->data[4]); motor->lz_feedback.current_torque = MOTOR_LZ_RawToFloat(raw_torque, LZ_TORQUE_RANGE_NM); // Byte6~7: 当前温度 (温度*10) uint16_t raw_temp = (uint16_t)((msg->data[7] << 8) | msg->data[6]); motor->lz_feedback.temperature = (float)raw_temp / LZ_TEMP_SCALE; // 更新通用电机反馈信息 motor->motor.feedback.rotor_abs_angle = motor->lz_feedback.current_angle; motor->motor.feedback.rotor_speed = motor->lz_feedback.current_velocity * 180.0f / M_PI * 6.0f; // 转换为RPM motor->motor.feedback.torque_current = motor->lz_feedback.current_torque; // 使用力矩作为电流反馈 motor->motor.feedback.temp = (int8_t)motor->lz_feedback.temperature; // 更新在线状态 motor->motor.header.online = true; motor->motor.header.last_online_time = BSP_TIME_Get(); } /* Exported functions ------------------------------------------------------- */ /** * @brief 初始化灵足电机驱动系统 * @return 设备状态码 */ int8_t MOTOR_LZ_Init(void) { // 注册灵足电机专用的ID解析器 return BSP_CAN_RegisterIdParser(MOTOR_LZ_IdParser) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } /** * @brief 反初始化灵足电机驱动系统 * @return 设备状态码 */ int8_t MOTOR_LZ_DeInit(void) { // 注销ID解析器 return BSP_CAN_UnregisterIdParser() == BSP_OK ? DEVICE_OK : DEVICE_ERR; } int8_t MOTOR_LZ_Register(MOTOR_LZ_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; if (MOTOR_LZ_CreateCANManager(param->can) != DEVICE_OK) return DEVICE_ERR; MOTOR_LZ_CANManager_t *manager = MOTOR_LZ_GetCANManager(param->can); if (manager == NULL) return DEVICE_ERR; // 检查是否已注册 for (int i = 0; i < manager->motor_count; i++) { if (manager->motors[i] && manager->motors[i]->param.motor_id == param->motor_id) { return DEVICE_ERR; // 已注册 } } // 检查数量 if (manager->motor_count >= MOTOR_LZ_MAX_MOTORS) return DEVICE_ERR; // 创建新电机实例 MOTOR_LZ_t *new_motor = (MOTOR_LZ_t*)BSP_Malloc(sizeof(MOTOR_LZ_t)); if (new_motor == NULL) return DEVICE_ERR; memcpy(&new_motor->param, param, sizeof(MOTOR_LZ_Param_t)); memset(&new_motor->motor, 0, sizeof(MOTOR_t)); memset(&new_motor->lz_feedback, 0, sizeof(MOTOR_LZ_Feedback_t)); memset(&new_motor->motion_param, 0, sizeof(MOTOR_LZ_MotionParam_t)); new_motor->motor.reverse = param->reverse; // 注册CAN接收ID - 使用解析后的反馈数据ID // 构建原始扩展ID uint32_t original_feedback_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_FEEDBACK, param->host_id, param->motor_id); // 通过ID解析器得到解析后的ID uint32_t parsed_feedback_id = MOTOR_LZ_IdParser(original_feedback_id, BSP_CAN_FRAME_EXT_DATA); if (BSP_CAN_RegisterId(param->can, parsed_feedback_id, 3) != BSP_OK) { BSP_Free(new_motor); return DEVICE_ERR; } manager->motors[manager->motor_count] = new_motor; manager->motor_count++; return DEVICE_OK; } int8_t MOTOR_LZ_Update(MOTOR_LZ_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; MOTOR_LZ_CANManager_t *manager = MOTOR_LZ_GetCANManager(param->can); if (manager == NULL) return DEVICE_ERR_NO_DEV; for (int i = 0; i < manager->motor_count; i++) { MOTOR_LZ_t *motor = manager->motors[i]; if (motor && motor->param.motor_id == param->motor_id) { // 获取反馈数据 - 使用解析后的ID uint32_t original_feedback_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_FEEDBACK, param->host_id, param->motor_id); uint32_t parsed_feedback_id = MOTOR_LZ_IdParser(original_feedback_id, BSP_CAN_FRAME_EXT_DATA); BSP_CAN_Message_t msg; while (BSP_CAN_GetMessage(param->can, parsed_feedback_id, &msg, 0) == BSP_OK) { MOTOR_LZ_Decode(motor, &msg); } return DEVICE_OK; } } return DEVICE_ERR_NO_DEV; } int8_t MOTOR_LZ_UpdateAll(void) { int8_t ret = DEVICE_OK; for (int can = 0; can < BSP_CAN_NUM; can++) { MOTOR_LZ_CANManager_t *manager = MOTOR_LZ_GetCANManager((BSP_CAN_t)can); if (manager == NULL) continue; for (int i = 0; i < manager->motor_count; i++) { MOTOR_LZ_t *motor = manager->motors[i]; if (motor) { if (MOTOR_LZ_Update(&motor->param) != DEVICE_OK) { ret = DEVICE_ERR; } } } } return ret; } int8_t MOTOR_LZ_MotionControl(MOTOR_LZ_Param_t *param, MOTOR_LZ_MotionParam_t *motion_param) { if (param == NULL || motion_param == NULL) return DEVICE_ERR_NULL; MOTOR_LZ_t *motor = MOTOR_LZ_GetMotor(param); if (motor == NULL) return DEVICE_ERR_NO_DEV; // 更新运控参数 memcpy(&motor->motion_param, motion_param, sizeof(MOTOR_LZ_MotionParam_t)); // 构建扩展ID uint32_t ext_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_MOTION, 0, param->motor_id); // 准备数据 uint8_t data[8]; // Byte0~1: 目标角度 uint16_t raw_angle = MOTOR_LZ_FloatToRaw(motion_param->target_angle, LZ_ANGLE_RANGE_RAD); data[0] = raw_angle & 0xFF; data[1] = (raw_angle >> 8) & 0xFF; // Byte2~3: 目标角速度 uint16_t raw_velocity = MOTOR_LZ_FloatToRaw(motion_param->target_velocity, LZ_VELOCITY_RANGE_RAD_S); data[2] = raw_velocity & 0xFF; data[3] = (raw_velocity >> 8) & 0xFF; // Byte4~5: Kp uint16_t raw_kp = MOTOR_LZ_FloatToRaw(motion_param->kp, LZ_KP_MAX); data[4] = raw_kp & 0xFF; data[5] = (raw_kp >> 8) & 0xFF; // Byte6~7: Kd uint16_t raw_kd = MOTOR_LZ_FloatToRaw(motion_param->kd, LZ_KD_MAX); data[6] = raw_kd & 0xFF; data[7] = (raw_kd >> 8) & 0xFF; return MOTOR_LZ_SendExtFrame(param->can, ext_id, data, 8); } int8_t MOTOR_LZ_Enable(MOTOR_LZ_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; // 构建扩展ID - 使能命令 uint32_t ext_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_ENABLE, param->host_id, param->motor_id); // 数据区清零 uint8_t data[8] = {0}; return MOTOR_LZ_SendExtFrame(param->can, ext_id, data, 8); } int8_t MOTOR_LZ_Disable(MOTOR_LZ_Param_t *param, bool clear_fault) { if (param == NULL) return DEVICE_ERR_NULL; // 构建扩展ID - 停止命令 uint32_t ext_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_DISABLE, param->host_id, param->motor_id); // 数据区 uint8_t data[8] = {0}; if (clear_fault) { data[0] = 1; // Byte[0]=1时清故障 } return MOTOR_LZ_SendExtFrame(param->can, ext_id, data, 8); } int8_t MOTOR_LZ_SetZero(MOTOR_LZ_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; // 构建扩展ID - 设置零位命令 uint32_t ext_id = MOTOR_LZ_BuildExtID(MOTOR_LZ_CMD_SET_ZERO, param->host_id, param->motor_id); // 数据区 - Byte[0]=1 uint8_t data[8] = {1, 0, 0, 0, 0, 0, 0, 0}; return MOTOR_LZ_SendExtFrame(param->can, ext_id, data, 8); } MOTOR_LZ_t* MOTOR_LZ_GetMotor(MOTOR_LZ_Param_t *param) { if (param == NULL) return NULL; MOTOR_LZ_CANManager_t *manager = MOTOR_LZ_GetCANManager(param->can); if (manager == NULL) return NULL; for (int i = 0; i < manager->motor_count; i++) { MOTOR_LZ_t *motor = manager->motors[i]; if (motor && motor->param.motor_id == param->motor_id) { return motor; } } return NULL; } int8_t MOTOR_LZ_Relax(MOTOR_LZ_Param_t *param) { return MOTOR_LZ_Disable(param, false); } int8_t MOTOR_LZ_Offline(MOTOR_LZ_Param_t *param) { MOTOR_LZ_t *motor = MOTOR_LZ_GetMotor(param); if (motor) { motor->motor.header.online = false; return DEVICE_OK; } return DEVICE_ERR_NO_DEV; }