/* VESC电机驱动 */ /* Includes ----------------------------------------------------------------- */ #include "motor_vesc.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 -------------------------------------------------------- */ /************************************** * 限幅函数 **************************************/ void assert_param_duty(float *duty){ // 如果 duty 是 -1.0 ~ 1.0,则最大值用 wtrcfg_VESC_COMMAND_DUTY_MAX / 100 float max_duty = wtrcfg_VESC_COMMAND_DUTY_MAX / 100.0f; if (fabsf(*duty) > max_duty) { *duty = (*duty > 0) ? max_duty : -max_duty; } } void assert_param_current(float *current){ if( fabsf(*current) > wtrcfg_VESC_COMMAND_CURRENT_MAX ) *current = *current > 0 ? wtrcfg_VESC_COMMAND_CURRENT_MAX : - wtrcfg_VESC_COMMAND_CURRENT_MAX ; } void assert_param_rpm(float *rpm){ if( fabsf(*rpm) > wtrcfg_VESC_COMMAND_ERPM_MAX ) *rpm = *rpm > 0 ? wtrcfg_VESC_COMMAND_ERPM_MAX : - wtrcfg_VESC_COMMAND_ERPM_MAX ; } void assert_param_pos(float *pos){ if( fabsf(*pos) > wtrcfg_VESC_COMMAND_POS_MAX ) *pos = *pos > 0 ? wtrcfg_VESC_COMMAND_POS_MAX : - wtrcfg_VESC_COMMAND_POS_MAX ; } static VESC_CANManager_t *can_managers[BSP_CAN_NUM] = {NULL}; // 获取指定CAN总线的电机管理器指针 static VESC_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] = (VESC_CANManager_t*)BSP_Malloc(sizeof(VESC_CANManager_t)); if (can_managers[can] == NULL) return DEVICE_ERR; memset(can_managers[can], 0, sizeof(VESC_CANManager_t)); can_managers[can]->can = can; return DEVICE_OK; } // 解析CAN报文,更新电机反馈信息 static void Motor_VESC_Decode(VESC_t *motor, BSP_CAN_Message_t *msg) { if (motor == NULL || msg == NULL) return; motor->motor.feedback.rotor_speed = ((int32_t)msg->data[0] << 24) | ((int32_t)msg->data[1] << 16) | ((int32_t)msg->data[2] << 8) | ((int32_t)msg->data[3]); // torque_current: 低 2 字节 (data[4], data[5]) int16_t raw_current = (int16_t)((msg->data[5] << 8) | msg->data[4]); motor->motor.feedback.torque_current = raw_current / 1000.0f; // 从 0.1A -> A // duty_cycle: 低 2 字节 (data[6], data[7]) int16_t raw_duty = (int16_t)((msg->data[7] << 8) | msg->data[6]); //motor->motor.feedback.duty_cycle = raw_duty / 1000.0f; // 从千分之一 -> (-1.0 ~ 1.0) } /* Exported functions ------------------------------------------------------- */ // 注册一个新的电机实例到管理器 int8_t VESC_Register(VESC_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; if (MOTOR_CreateCANManager(param->can) != DEVICE_OK) return DEVICE_ERR; VESC_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 >= VESC_MAX_MOTORS) return DEVICE_ERR; // 创建新电机实例 VESC_t *new_motor = (VESC_t*)BSP_Malloc(sizeof(VESC_t)); if (new_motor == NULL) return DEVICE_ERR; memcpy(&new_motor->param, param, sizeof(VESC_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 VESC_Update(VESC_Param_t *param) { if (param == NULL) return DEVICE_ERR_NULL; VESC_CANManager_t *manager = MOTOR_GetCANManager(param->can); if (manager == NULL) return DEVICE_ERR_NO_DEV; VESC_t *motor = NULL; for (int i = 0; i < manager->motor_count; i++) { if (manager->motors[i] && manager->motors[i]->param.id == param->id) { motor = manager->motors[i]; break; } } if (motor == NULL) return DEVICE_ERR_NO_DEV; // 根据电机 ID 获取对应扩展帧 ID uint32_t ext_id = 0; switch (param->id) { case VESC_1: ext_id = CAN_VESC5065_M1_MSG1; break; case VESC_2: ext_id = CAN_VESC5065_M2_MSG1; break; case VESC_4: ext_id = CAN_VESC5065_M3_MSG1; break; default: return DEVICE_ERR_NO_DEV; } BSP_CAN_Message_t rx_msg; if (BSP_CAN_GetMessage(param->can, ext_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_VESC_Decode(motor, &rx_msg); return DEVICE_OK; } // 更新所有CAN总线下所有电机的反馈数据 int8_t VESC_UpdateAll(void) { int8_t ret = DEVICE_OK; for (int can = 0; can < BSP_CAN_NUM; can++) { VESC_CANManager_t *manager = MOTOR_GetCANManager((BSP_CAN_t)can); if (manager == NULL) continue; for (int i = 0; i < manager->motor_count; i++) { VESC_t *motor = manager->motors[i]; if (motor != NULL) { if (VESC_Update(&motor->param) != DEVICE_OK) { ret = DEVICE_ERR; } } } } return ret; } // 获取指定参数对应的电机实例指针 VESC_t* VESC_GetMotor(VESC_Param_t *param) { if (param == NULL) return NULL; VESC_CANManager_t *manager = MOTOR_GetCANManager(param->can); if (manager == NULL) return NULL; for (int i = 0; i < manager->motor_count; i++) { VESC_t *motor = manager->motors[i]; if (motor && motor->param.id == param->id) { return motor; } } return NULL; } // 设置指定电机的输出值 int8_t VESC_SetOutput(VESC_Param_t *param, float value) { if (param == NULL) return DEVICE_ERR_NULL; BSP_CAN_StdDataFrame_t tx_frame; uint16_t command_id; if (param->reverse) { value = -value; } switch (param->mode) { case DUTY_CONTROL: { assert_param_duty(&value); // 调用你现有的限幅函数 command_id = CAN_PACKET_SET_DUTY; int32_t duty_val = (int32_t)(value * 1e5f); // duty 放大 1e5 memcpy(&tx_frame.data[0], &duty_val, 4); tx_frame.dlc = 4; break; } case RPM_CONTROL: { assert_param_rpm(&value); command_id = CAN_PACKET_SET_RPM; int32_t rpm_val = (int32_t)value; memcpy(&tx_frame.data[0], &rpm_val, 4); tx_frame.dlc = 4; break; } case CURRENT_CONTROL: { assert_param_current(&value); command_id = CAN_PACKET_SET_CURRENT; int32_t cur_val = (int32_t)(value * 1e3f); // A -> mA (0-50A) memcpy(&tx_frame.data[0], &cur_val, 4); tx_frame.dlc = 4; break; } case POSITION_CONTROL: { assert_param_pos(&value); command_id = CAN_PACKET_SET_POS; memcpy(&tx_frame.data[0], &value, 4); tx_frame.dlc = 4; break; } default: return DEVICE_ERR; } tx_frame.id = (param->id << 5) | command_id; return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } int8_t VESC_Relax(VESC_Param_t *param) { return VESC_SetOutput(param, 0.0f); } int8_t VESC_Offine(VESC_Param_t *param) { VESC_t *motor = VESC_GetMotor(param); if (motor) { motor->motor.header.online = false; return DEVICE_OK; } return DEVICE_ERR_NO_DEV; }