MRobot/assets/User_code/device/motor_vesc.c
2025-09-06 13:04:19 +08:00

249 lines
8.7 KiB
C
Raw 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.

/*
VESC电机驱动
*/
/* Includes ----------------------------------------------------------------- */
#include "motor_vesc.h"
#include <stdbool.h>
#include <string.h>
#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;
}