/* Odrive电机驱动 */ /* Includes ----------------------------------------------------------------- */ #include "motor_odrive.h" #include #include #include "bsp/can.h" #include "bsp/mm.h" #include "bsp/time.h" #include "component/user_math.h" /* Private define ----------------------------------------------------------- */ /* Private macro ------------------------------------------------------------ */ /* Private typedef ---------------------------------------------------------- */ /* Private variables -------------------------------------------------------- */ static ODrive_CANManager_t *can_managers[BSP_CAN_NUM] = {NULL}; // 获取指定CAN总线的电机管理器指针 static ODrive_CANManager_t* MOTOR_GetCANManager(BSP_CAN_t can) { if (can >= BSP_CAN_NUM) return NULL; return can_managers[can]; } // 为指定CAN总线创建电机管理器 static int8_t MOTOR_CreateCANManager(BSP_CAN_t can) { if (can >= BSP_CAN_NUM) return DEVICE_ERR; if (can_managers[can] != NULL) return DEVICE_OK; can_managers[can] = (ODrive_CANManager_t*)BSP_Malloc(sizeof(ODrive_CANManager_t)); if (can_managers[can] == NULL) return DEVICE_ERR; memset(can_managers[can], 0, sizeof(ODrive_CANManager_t)); can_managers[can]->can = can; return DEVICE_OK; } // 解析CAN报文,更新电机反馈信息 static void Motor_Decode(ODrive_t *motor, BSP_CAN_Message_t *msg) { uint8_t axis_id = (msg->original_id >> 5) & 0x3F; // 提取电机号(0~63) uint8_t cmd_id = msg->original_id & 0x1F; // 提取命令 ID(低 5 位) motor->param.id = axis_id; // 保存电机 ID // 解析帧类型(数据帧或远程帧) if (msg->frame_type == BSP_CAN_FRAME_STD_DATA) { // 数据帧处理 switch (cmd_id) { case ODRIVE_HEARTBEAT_MESSAGE: // 0x001 ODrive心跳消息 // motor->motor.feedback.axis_error = (msg->data[0] | msg->data[1]<<8 | msg->data[2]<<16 | msg->data[3]<<24); // motor->motor.feedback.axis_state = msg->data[4]; // motor->motor.feedback.controller_status = msg->data[5]; break; case ENCODER_ESTIMATES: // 0x009 { uint32_t raw_pos = (msg->data[0] | msg->data[1]<<8 | msg->data[2]<<16 | msg->data[3]<<24); uint32_t raw_vel = (msg->data[4] | msg->data[5]<<8 | msg->data[6]<<16 | msg->data[7]<<24); memcpy(&motor->motor.feedback.rotor_abs_angle, &raw_pos, sizeof(float)); memcpy(&motor->motor.feedback.rotor_speed, &raw_vel, sizeof(float)); } break; case GET_ENCODER_COUNT: // 0x014 // motor->motor.feedback.encoder_shadow = (msg->data[0] | msg->data[1]<<8 | msg->data[2]<<16 | msg->data[3]<<24); // motor->motor.feedback.encoder_cpr = (msg->data[4] | msg->data[5]<<8 | msg->data[6]<<16 | msg->data[7]<<24); break; case GET_BUS_VOLTAGE_CURRENT: // 0x017 { uint32_t raw_vbus, raw_ibus; raw_vbus = (msg->data[0] | msg->data[1]<<8 | msg->data[2]<<16 | msg->data[3]<<24); raw_ibus = (msg->data[4] | msg->data[5]<<8 | msg->data[6]<<16 | msg->data[7]<<24); // memcpy(&motor->motor.feedback.bus_voltage, &raw_vbus, sizeof(float)); memcpy(&motor->motor.feedback.torque_current, &raw_ibus, sizeof(float)); } break; case GET_IQ: // 0x018 { uint32_t raw_iq_set, raw_iq_meas; raw_iq_set = (msg->data[0] | msg->data[1]<<8 | msg->data[2]<<16 | msg->data[3]<<24); raw_iq_meas = (msg->data[4] | msg->data[5]<<8 | msg->data[6]<<16 | msg->data[7]<<24); // memcpy(&motor->motor.feedback.iq_setpoint, &raw_iq_set, sizeof(float)); // memcpy(&motor->motor.feedback.iq_measured, &raw_iq_meas, sizeof(float)); } break; default: break; } } } /* Exported functions ------------------------------------------------------- */ // 注册一个新的电机实例到管理器 int8_t ODrive_Register(ODrive_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; if (MOTOR_CreateCANManager(param->can) != DEVICE_OK) return DEVICE_ERR; ODrive_CANManager_t *manager = MOTOR_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.id == param->id) { return DEVICE_ERR_INITED; } } // 检查数量 if (manager->motor_count >= ODRIVE_MAX_MOTORS) return DEVICE_ERR; // 创建新电机实例 ODrive_t *new_motor = (ODrive_t*)BSP_Malloc(sizeof(ODrive_t)); if (new_motor == NULL) return DEVICE_ERR; memcpy(&new_motor->param, param, sizeof(ODrive_Param_t)); memset(&new_motor->motor, 0, sizeof(MOTOR_t)); new_motor->motor.reverse = param->reverse; // 注册CAN接收ID if (BSP_CAN_RegisterId(param->can, param->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 ODrive_Update(ODrive_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; ODrive_CANManager_t *manager = MOTOR_GetCANManager(param->can); if (manager == NULL) return DEVICE_ERR_NO_DEV; for (int i = 0; i < manager->motor_count; i++) { ODrive_t *motor = manager->motors[i]; if (motor && motor->param.id == param->id) { BSP_CAN_Message_t rx_msg; if (BSP_CAN_GetMessage(param->can, param->id, &rx_msg, BSP_CAN_TIMEOUT_IMMEDIATE) != BSP_OK) { uint64_t now_time = BSP_TIME_Get(); if (now_time - motor->motor.header.last_online_time > 1000) { motor->motor.header.online = false; return DEVICE_ERR_NO_DEV; } return DEVICE_ERR; } motor->motor.header.online = true; motor->motor.header.last_online_time = BSP_TIME_Get(); Motor_Decode(motor, &rx_msg); return DEVICE_OK; } } return DEVICE_ERR_NO_DEV; } // 更新所有CAN总线下所有电机的反馈数据 int8_t ODrive_UpdateAll(void) { int8_t ret = DEVICE_OK; for (int can = 0; can < BSP_CAN_NUM; can++) { ODrive_CANManager_t *manager = MOTOR_GetCANManager((BSP_CAN_t)can); if (manager == NULL) continue; for (int i = 0; i < manager->motor_count; i++) { ODrive_t *motor = manager->motors[i]; if (motor != NULL) { if (ODrive_Update(&motor->param) != DEVICE_OK) { ret = DEVICE_ERR; } } } } return ret; } // 获取指定参数对应的电机实例指针 ODrive_t* ODrive_GetMotor(ODrive_Param_t *param) { if (param == NULL) return NULL; ODrive_CANManager_t *manager = MOTOR_GetCANManager(param->can); if (manager == NULL) return NULL; for (int i = 0; i < manager->motor_count; i++) { ODrive_t *motor = manager->motors[i]; if (motor && motor->param.id == param->id) { return motor; } } return NULL; } // 设置指定电机的输出值 int8_t ODrive_SetOutput(ODrive_Param_t *param, float value) { if (param == NULL) return DEVICE_ERR_NULL; // 如果电机反转标志为 true,则反向值 if (param->reverse) { value = -value; } BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id; uint8_t *pVal = (uint8_t *)&value; // 选择命令 ID 和数据打包方式 switch (param->mode) { case POSITION_CONTROL: { command_id = SET_INPUT_POS; float pos = value; int16_t vel_ff = 0; // 可扩展为参数传入 0就行 int16_t torque_ff = 0; // 可扩展为参数传入 0就行 uint8_t *pPos = (uint8_t *)&pos; uint8_t *pVel = (uint8_t *)&vel_ff; uint8_t *pTor = (uint8_t *)&torque_ff; memcpy(&tx_frame.data[0], pPos, 4); memcpy(&tx_frame.data[4], pVel, 2); memcpy(&tx_frame.data[6], pTor, 2); tx_frame.dlc = 8; break; } case VELOCITY_CONTROL: { command_id = SET_INPUT_VEL; float vel = value; float torque_ff = 0.0f; // 可扩展为参数传入 uint8_t *pVel = (uint8_t *)&vel; uint8_t *pTor = (uint8_t *)&torque_ff; memcpy(&tx_frame.data[0], pVel, 4); memcpy(&tx_frame.data[4], pTor, 4); tx_frame.dlc = 8; break; } case TORQUE_CONTROL: { command_id = SET_INPUT_TORQUE; memcpy(&tx_frame.data[0], pVal, 4); tx_frame.dlc = 4; break; } case VOLTAGE_CONTROL: default: return DEVICE_ERR; // 暂不支持电压模式 } // 组装 CAN ID(标准帧) tx_frame.id = (param->id << 5) | command_id; // 标准数据帧 return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } // 设置加速度和减速度 int8_t ODrive_SetAccel(ODrive_Param_t *param, float accel, float decel) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id = SET_TRAJ_ACCEL_LIMITS; uint8_t *pAccel = (uint8_t *)&accel; uint8_t *pDecel = (uint8_t *)&decel; memcpy(&tx_frame.data[0], pAccel, 4); memcpy(&tx_frame.data[4], pDecel, 4); tx_frame.dlc = 8; tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } // 获取位置和速度反馈 int8_t ODrive_RequestEncoderEstimates(ODrive_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id = ENCODER_ESTIMATES; // 请求编码器估计值命令 uint8_t zero_data[8] = {0}; // 发送全 0 数据(ODrive 协议要求) memcpy(tx_frame.data, zero_data, 8); tx_frame.dlc = 8; tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } // 设置轴请求状态(一般用来重启 ODrive 的某个轴) // ODrive_SetAxisRequestedState(odrive_axis[0], CLOSED_LOOP_CONTROL); int8_t ODrive_SetAxisRequestedState(ODrive_Param_t *param, Axis_State state) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id = SET_AXIS_REQUESTED_STATE; // 将 state 转为 4 字节 memcpy(tx_frame.data, &state, 4); memset(&tx_frame.data[4], 0, 4); tx_frame.dlc = 4; // 组装 CAN ID tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } // 清除错误 int8_t ODrive_ClearErrors(ODrive_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id = CLEAR_ERRORS; memset(tx_frame.data, 0, 8); tx_frame.dlc = 0; tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } // 重启 ODrive int8_t ODrive_Reboot(ODrive_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id = REBOOT_ODRIVE; memset(tx_frame.data, 0, 8); tx_frame.dlc = 0; tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; }