更新啦

This commit is contained in:
2025-08-09 04:42:11 +08:00
parent 62549172dd
commit e070e723aa
9 changed files with 719 additions and 242 deletions

View File

@@ -41,6 +41,7 @@ int8_t DR16_Restart(void);
int8_t DR16_StartDmaRecv(DR16_t *dr16);
bool DR16_WaitDmaCplt(uint32_t timeout);
#ifdef __cplusplus
}
#endif

View File

@@ -18,24 +18,32 @@
/* Exported functions ------------------------------------------------------- */
float MOTOR_GetRotorAbsAngle(const MOTOR_t *motor) {
if (motor == NULL) return DEVICE_ERR_NULL;
return motor->feedback.rotor_abs_angle;
if (motor->reverse) {
return -motor->feedback.rotor_abs_angle;
}else{
return motor->feedback.rotor_abs_angle;
}
}
float MOTOR_GetRotorSpeed(const MOTOR_t *motor) {
if (motor == NULL) return DEVICE_ERR_NULL;
return motor->feedback.rotor_speed;
if (motor->reverse) {
return -motor->feedback.rotor_speed;
}else{
return motor->feedback.rotor_speed;
}
}
float MOTOR_GetTorqueCurrent(const MOTOR_t *motor) {
if (motor == NULL) return DEVICE_ERR_NULL;
return motor->feedback.torque_current;
if (motor->reverse) {
return -motor->feedback.torque_current;
}else{
return motor->feedback.torque_current;
}
}
float MOTOR_GetTemp(const MOTOR_t *motor) {
if (motor == NULL) return DEVICE_ERR_NULL;
return motor->feedback.temp;
}
}

View File

@@ -19,7 +19,7 @@ typedef struct {
typedef struct {
DEVICE_Header_t header;
bool reverse; /* 是否反装 */
bool reverse; /* 是否反装 true表示反装 */
MOTOR_Feedback_t feedback;
} MOTOR_t;
@@ -29,7 +29,6 @@ float MOTOR_GetRotorSpeed(const MOTOR_t *motor);
float MOTOR_GetTorqueCurrent(const MOTOR_t *motor);
float MOTOR_GetTemp(const MOTOR_t *motor);
#ifdef __cplusplus
}
#endif

View File

@@ -2,62 +2,51 @@
CAN总线上的设备
将所有CAN总线上挂载的设备抽象成一个设备进行配置和控制
*/
/* Includes ----------------------------------------------------------------- */
#include "motor_rm.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 ----------------------------------------------------------- */
/* Motor id */
/* id feedback id control id */
/* 1-4 0x205 to 0x208 0x1ff */
/* 5-7 0x209 to 0x20B 0x2ff */
#define GM6020_FB_ID_BASE (0x205)
#define GM6020_CTRL_ID_BASE (0x1ff)
#define GM6020_CTRL_ID_EXTAND (0x2ff)
#define GM6020_FB_ID_BASE (0x205)
#define GM6020_CTRL_ID_BASE (0x1ff)
#define GM6020_CTRL_ID_EXTAND (0x2ff)
/* id feedback id control id */
/* 1-4 0x201 to 0x204 0x200 */
/* 5-8 0x205 to 0x208 0x1ff */
#define M3508_M2006_FB_ID_BASE (0x201)
#define M3508_M2006_FB_ID_BASE (0x201)
#define M3508_M2006_CTRL_ID_BASE (0x200)
#define M3508_M2006_CTRL_ID_EXTAND (0x1ff)
#define M3508_M2006_ID_SETTING_ID (0x700)
#define GM6020_MAX_ABS_LSB (30000)
#define M3508_MAX_ABS_LSB (16384)
#define M2006_MAX_ABS_LSB (10000)
#define GM6020_MAX_ABS_LSB (30000)
#define M3508_MAX_ABS_LSB (16384)
#define M2006_MAX_ABS_LSB (10000)
#define MOTOR_TX_BUF_SIZE (8)
#define MOTOR_RX_BUF_SIZE (8)
#define MOTOR_TX_BUF_SIZE (8)
#define MOTOR_RX_BUF_SIZE (8)
#define MOTOR_ENC_RES (8192) /* 电机编码器分辨率 */
#define MOTOR_CUR_RES (16384) /* 电机转矩电流分辨率 */
#define MOTOR_ENC_RES (8192) /* 电机编码器分辨率 */
#define MOTOR_CUR_RES (16384) /* 电机转矩电流分辨率 */
/* Private macro ------------------------------------------------------------ */
/* Private typedef ---------------------------------------------------------- */
/* Private variables -------------------------------------------------------- */
static MOTOR_RM_CANManager_t *can_managers[BSP_CAN_NUM] = {NULL};
/* Private function -------------------------------------------------------- */
static int8_t MOTOR_RM_GetLogicalIndex(uint16_t can_id, MOTOR_RM_Module_t module) {
switch (module) {
case MOTOR_M2006:
case MOTOR_M3508:
if (can_id >= M3508_M2006_FB_ID_BASE && can_id < M3508_M2006_FB_ID_BASE + 7) {
return can_id - M3508_M2006_FB_ID_BASE; // 返回1-8
return can_id - M3508_M2006_FB_ID_BASE;
}
break;
case MOTOR_GM6020:
if (can_id >= GM6020_FB_ID_BASE && can_id < GM6020_FB_ID_BASE + 6) {
return can_id - GM6020_FB_ID_BASE + 4; // 返回5-11
return can_id - GM6020_FB_ID_BASE + 4;
}
break;
default:
@@ -67,16 +56,12 @@ static int8_t MOTOR_RM_GetLogicalIndex(uint16_t can_id, MOTOR_RM_Module_t module
}
static int16_t MOTOR_RM_GetLSB(MOTOR_RM_Module_t module) {
switch (module) {
case MOTOR_M2006:
return M2006_MAX_ABS_LSB;
case MOTOR_M3508:
return M3508_MAX_ABS_LSB;
case MOTOR_GM6020:
return GM6020_MAX_ABS_LSB;
default:
return DEVICE_ERR;
}
switch (module) {
case MOTOR_M2006: return M2006_MAX_ABS_LSB;
case MOTOR_M3508: return M3508_MAX_ABS_LSB;
case MOTOR_GM6020: return GM6020_MAX_ABS_LSB;
default: return DEVICE_ERR;
}
}
static MOTOR_RM_CANManager_t* MOTOR_RM_GetCANManager(BSP_CAN_t can) {
@@ -87,24 +72,18 @@ static MOTOR_RM_CANManager_t* MOTOR_RM_GetCANManager(BSP_CAN_t can) {
static int8_t MOTOR_RM_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_RM_CANManager_t*)BSP_Malloc(sizeof(MOTOR_RM_CANManager_t));
if (can_managers[can] == NULL) return DEVICE_ERR;
memset(can_managers[can], 0, sizeof(MOTOR_RM_CANManager_t));
can_managers[can]->can = can;
return 0;
return DEVICE_OK;
}
static void Motor_RM_Decode(MOTOR_RM_t *motor, BSP_CAN_Message_t *msg) {
uint16_t raw_angle = (uint16_t)((msg->data[0] << 8) | msg->data[1]);
int16_t raw_current = (int16_t)((msg->data[4] << 8) | msg->data[5]);
motor->motor.feedback.rotor_abs_angle = raw_angle / (float)MOTOR_ENC_RES * M_2PI;
motor->motor.feedback.rotor_speed = (int16_t)((msg->data[2] << 8) | msg->data[3]);
// 根据电机类型选择正确的LSB
int16_t lsb = MOTOR_RM_GetLSB(motor->param.module);
motor->motor.feedback.torque_current = raw_current * lsb / (float)MOTOR_CUR_RES;
motor->motor.feedback.temp = msg->data[6];
@@ -112,76 +91,59 @@ static void Motor_RM_Decode(MOTOR_RM_t *motor, BSP_CAN_Message_t *msg) {
/* Exported functions ------------------------------------------------------- */
int8_t MOTOR_RM_Register(MOTOR_RM_Param_t *param) {
if (param == NULL) return DEVICE_ERR_NULL;
// 1. 检查并创建CAN管理器
if (MOTOR_RM_CreateCANManager(param->can) != DEVICE_OK) {
return DEVICE_ERR;
}
// 获取对应的CAN管理器
if (MOTOR_RM_CreateCANManager(param->can) != DEVICE_OK) return DEVICE_ERR;
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(param->can);
if (manager == NULL) return DEVICE_ERR;
// 2. 检查电机是否已注册
// 检查是否已注册
for (int i = 0; i < manager->motor_count; i++) {
if (manager->motors[i] != NULL &&
manager->motors[i]->param.id == param->id) {
return DEVICE_ERR_INITED; // 电机已存在
if (manager->motors[i] && manager->motors[i]->param.id == param->id) {
return DEVICE_ERR_INITED;
}
}
// 3. 检查是否还能添加更多电机
if (manager->motor_count >= MOTOR_RM_MAX_MOTORS) {
return DEVICE_ERR; // 电机数量已满
}
// 4. 创建新的电机实例
// 检查数量
if (manager->motor_count >= MOTOR_RM_MAX_MOTORS) return DEVICE_ERR;
// 创建新电机实例
MOTOR_RM_t *new_motor = (MOTOR_RM_t*)BSP_Malloc(sizeof(MOTOR_RM_t));
if (new_motor == NULL) return DEVICE_ERR;
// 5. 初始化电机参数
memcpy(&new_motor->param, param, sizeof(MOTOR_RM_Param_t));
memset(&new_motor->motor, 0, sizeof(MOTOR_t));
new_motor->motor.reverse = param->reverse;
// 6. 注册CAN接收ID直接使用实际CAN ID
// 注册CAN接收ID
if (BSP_CAN_RegisterId(param->can, param->id, 3) != BSP_OK) {
BSP_Free(new_motor);
return DEVICE_ERR;
}
// 7. 将电机添加到管理器中
manager->motors[manager->motor_count] = new_motor;
manager->motor_count++;
return DEVICE_OK;
}
int8_t MOTOR_RM_Update(BSP_CAN_t can, uint16_t id) {
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(can);
int8_t MOTOR_RM_Update(MOTOR_RM_Param_t *param) {
if (param == NULL) return DEVICE_ERR_NULL;
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(param->can);
if (manager == NULL) return DEVICE_ERR_NO_DEV;
for (int i = 0; i < manager->motor_count; i++) {
MOTOR_RM_t *motor = manager->motors[i];
if (motor != NULL && motor->param.id == id) {
if (motor && motor->param.id == param->id) {
BSP_CAN_Message_t rx_msg;
if (BSP_CAN_GetMessage(can, id, &rx_msg, BSP_CAN_TIMEOUT_IMMEDIATE) != BSP_OK) {
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_NO_DEV;
}
return DEVICE_ERR; // 没有新数据但电机在线
return DEVICE_ERR;
}
// 解码接收到的消息
motor->motor.header.online = true;
motor->motor.header.last_online_time = BSP_TIME_Get();
Motor_RM_Decode(motor, &rx_msg);
return DEVICE_OK; // 成功更新
return DEVICE_OK;
}
}
return DEVICE_ERR_NO_DEV; // 未找到对应电机
return DEVICE_ERR_NO_DEV;
}
int8_t MOTOR_RM_UpdateAll(void) {
@@ -189,11 +151,10 @@ int8_t MOTOR_RM_UpdateAll(void) {
for (int can = 0; can < BSP_CAN_NUM; can++) {
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager((BSP_CAN_t)can);
if (manager == NULL) continue;
for (int i = 0; i < manager->motor_count; i++) {
MOTOR_RM_t *motor = manager->motors[i];
if (motor != NULL) {
if (MOTOR_RM_Update((BSP_CAN_t)can, motor->param.id) != DEVICE_OK) {
if (MOTOR_RM_Update(&motor->param) != DEVICE_OK) {
ret = DEVICE_ERR;
}
}
@@ -202,33 +163,29 @@ int8_t MOTOR_RM_UpdateAll(void) {
return ret;
}
int8_t MOTOR_RM_SetOutput(BSP_CAN_t can, uint16_t id, float value) {
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(can);
int8_t MOTOR_RM_SetOutput(MOTOR_RM_Param_t *param, float value) {
if (param == NULL) return DEVICE_ERR_NULL;
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(param->can);
if (manager == NULL) return DEVICE_ERR_NO_DEV;
if (value > 1.0f) value = 1.0f;
if (value < -1.0f) value = -1.0f;
MOTOR_RM_t *motor = MOTOR_RM_GetMotor(can, id);
MOTOR_RM_t *motor = MOTOR_RM_GetMotor(param);
if (motor == NULL) return DEVICE_ERR_NO_DEV;
int8_t logical_index = MOTOR_RM_GetLogicalIndex(id, motor->param.module);
int8_t logical_index = MOTOR_RM_GetLogicalIndex(param->id, param->module);
if (logical_index < 0) return DEVICE_ERR;
MOTOR_RM_MsgOutput_t *output_msg = &manager->output_msg;
int16_t output_value = (int16_t)(value * (float)MOTOR_RM_GetLSB(motor->param.module));
int16_t output_value = (int16_t)(value * (float)MOTOR_RM_GetLSB(param->module));
output_msg->output[logical_index] = output_value;
return DEVICE_OK;
}
int8_t MOTOR_RM_Ctrl(BSP_CAN_t can, uint16_t id) {
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(can);
int8_t MOTOR_RM_Ctrl(MOTOR_RM_Param_t *param) {
if (param == NULL) return DEVICE_ERR_NULL;
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(param->can);
if (manager == NULL) return DEVICE_ERR_NO_DEV;
MOTOR_RM_MsgOutput_t *output_msg = &manager->output_msg;
BSP_CAN_StdDataFrame_t tx_frame;
uint16_t id = param->id;
switch (id) {
case M3508_M2006_FB_ID_BASE:
case M3508_M2006_FB_ID_BASE+1:
@@ -236,14 +193,10 @@ int8_t MOTOR_RM_Ctrl(BSP_CAN_t can, uint16_t id) {
case M3508_M2006_FB_ID_BASE+3:
tx_frame.id = M3508_M2006_CTRL_ID_BASE;
tx_frame.dlc = MOTOR_TX_BUF_SIZE;
tx_frame.data[0] = (uint8_t)((output_msg->output[0] >> 8) & 0xFF);
tx_frame.data[1] = (uint8_t)(output_msg->output[0] & 0xFF);
tx_frame.data[2] = (uint8_t)((output_msg->output[1] >> 8) & 0xFF);
tx_frame.data[3] = (uint8_t)(output_msg->output[1] & 0xFF);
tx_frame.data[4] = (uint8_t)((output_msg->output[2] >> 8) & 0xFF);
tx_frame.data[5] = (uint8_t)(output_msg->output[2] & 0xFF);
tx_frame.data[6] = (uint8_t)((output_msg->output[3] >> 8) & 0xFF);
tx_frame.data[7] = (uint8_t)(output_msg->output[3] & 0xFF);
for (int i = 0; i < 4; i++) {
tx_frame.data[i*2] = (uint8_t)((output_msg->output[i] >> 8) & 0xFF);
tx_frame.data[i*2+1] = (uint8_t)(output_msg->output[i] & 0xFF);
}
break;
case M3508_M2006_FB_ID_BASE+4:
case M3508_M2006_FB_ID_BASE+5:
@@ -251,59 +204,49 @@ int8_t MOTOR_RM_Ctrl(BSP_CAN_t can, uint16_t id) {
case M3508_M2006_FB_ID_BASE+7:
tx_frame.id = M3508_M2006_CTRL_ID_EXTAND;
tx_frame.dlc = MOTOR_TX_BUF_SIZE;
tx_frame.data[0] = (uint8_t)((output_msg->output[4] >> 8) & 0xFF);
tx_frame.data[1] = (uint8_t)(output_msg->output[4] & 0xFF);
tx_frame.data[2] = (uint8_t)((output_msg->output[5] >> 8) & 0xFF);
tx_frame.data[3] = (uint8_t)(output_msg->output[5] & 0xFF);
tx_frame.data[4] = (uint8_t)((output_msg->output[6] >> 8) & 0xFF);
tx_frame.data[5] = (uint8_t)(output_msg->output[6] & 0xFF);
tx_frame.data[6] = (uint8_t)((output_msg->output[7] >> 8) & 0xFF);
tx_frame.data[7] = (uint8_t)(output_msg->output[7] & 0xFF);
for (int i = 4; i < 8; i++) {
tx_frame.data[(i-4)*2] = (uint8_t)((output_msg->output[i] >> 8) & 0xFF);
tx_frame.data[(i-4)*2+1] = (uint8_t)(output_msg->output[i] & 0xFF);
}
break;
case GM6020_FB_ID_BASE+4:
case GM6020_FB_ID_BASE+5:
case GM6020_FB_ID_BASE+6:
tx_frame.id = GM6020_CTRL_ID_EXTAND;
tx_frame.dlc = MOTOR_TX_BUF_SIZE;
tx_frame.data[0] = (uint8_t)((output_msg->output[8] >> 8) & 0xFF);
tx_frame.data[1] = (uint8_t)(output_msg->output[8] & 0xFF);
tx_frame.data[2] = (uint8_t)((output_msg->output[9] >> 8) & 0xFF);
tx_frame.data[3] = (uint8_t)(output_msg->output[9] & 0xFF);
tx_frame.data[4] = (uint8_t)((output_msg->output[10] >> 8) & 0xFF);
tx_frame.data[5] = (uint8_t)(output_msg->output[10] & 0xFF);
for (int i = 8; i < 11; i++) {
tx_frame.data[(i-8)*2] = (uint8_t)((output_msg->output[i] >> 8) & 0xFF);
tx_frame.data[(i-8)*2+1] = (uint8_t)(output_msg->output[i] & 0xFF);
}
tx_frame.data[6] = 0;
tx_frame.data[7] = 0;
break;
default:
return DEVICE_ERR; // 不支持的控制ID
return DEVICE_ERR;
}
return BSP_CAN_TransmitStdDataFrame(can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR;
return BSP_CAN_TransmitStdDataFrame(param->can, &tx_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR;
}
MOTOR_RM_t* MOTOR_RM_GetMotor(BSP_CAN_t can, uint16_t id) {
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(can);
MOTOR_RM_t* MOTOR_RM_GetMotor(MOTOR_RM_Param_t *param) {
if (param == NULL) return NULL;
MOTOR_RM_CANManager_t *manager = MOTOR_RM_GetCANManager(param->can);
if (manager == NULL) return NULL;
for (int i = 0; i < manager->motor_count; i++) {
MOTOR_RM_t *motor = manager->motors[i];
if (motor != NULL && motor->param.id == id) {
if (motor && motor->param.id == param->id) {
return motor;
}
}
return NULL;
}
int8_t MOTOR_RM_Relax(BSP_CAN_t can, uint16_t id) {
int8_t ret = MOTOR_RM_SetOutput(can, id, 0.0f);
if (ret != DEVICE_OK) return ret;
return DEVICE_OK;
int8_t MOTOR_RM_Relax(MOTOR_RM_Param_t *param) {
return MOTOR_RM_SetOutput(param, 0.0f);
}
int8_t MOTOR_RM_Offine(BSP_CAN_t can, uint16_t id) {
MOTOR_RM_t *motor = MOTOR_RM_GetMotor(can, id);
if (motor != NULL) {
int8_t MOTOR_RM_Offine(MOTOR_RM_Param_t *param) {
MOTOR_RM_t *motor = MOTOR_RM_GetMotor(param);
if (motor) {
motor->motor.header.online = false;
return DEVICE_OK;
}

View File

@@ -10,7 +10,7 @@ extern "C" {
#include "bsp/can.h"
/* Exported constants ------------------------------------------------------- */
#define MOTOR_RM_MAX_MOTORS 11 /* 最大电机数量 */
#define MOTOR_RM_MAX_MOTORS 11
/* Exported macro ----------------------------------------------------------- */
/* Exported types ----------------------------------------------------------- */
@@ -37,91 +37,87 @@ typedef union {
int16_t gm6020_id20B;
} named;
} MOTOR_RM_MsgOutput_t;
/*注册电机时候每个电机需要的参数*/
/*每个电机需要的参数*/
typedef struct {
BSP_CAN_t can;
uint16_t id; // 实际CAN ID如0x201, 0x205等
uint16_t id;
MOTOR_RM_Module_t module;
bool reverse;
} MOTOR_RM_Param_t;
/*电机实例*/
typedef struct MOTOR_RM_t {
MOTOR_RM_Param_t param;
MOTOR_t motor;
} MOTOR_RM_t;
/*CAN管理器管理一个CAN总线上所有的电机*/
typedef struct {
BSP_CAN_t can;
MOTOR_RM_MsgOutput_t output_msg;
MOTOR_RM_t *motors[MOTOR_RM_MAX_MOTORS]; // 最多15个电机
MOTOR_RM_t *motors[MOTOR_RM_MAX_MOTORS];
uint8_t motor_count;
} MOTOR_RM_CANManager_t;
/* Exported functions prototypes -------------------------------------------- */
/**
* @brief 注册一个RM电机
* @param param 电机参数
* @return 0 成功,其他值失败
* @return
*/
int8_t MOTOR_RM_Register(MOTOR_RM_Param_t *param);
/**
* @brief 更新单个电机数据
* @param can CAN通道
* @param id 电机实际CAN ID
* @return 0 成功,其他值失败
* @brief 更新指定电机数据
* @param param 电机参数
* @return
*/
int8_t MOTOR_RM_Update(BSP_CAN_t can, uint16_t id);
int8_t MOTOR_RM_Update(MOTOR_RM_Param_t *param);
/**
* @brief 更新所有注册了的电机数据
* @return 0 成功,其他值失败
* @brief 设置一个电机的输出
* @param param 电机参数
* @param value 输出值,范围[-1.0, 1.0]
* @return
*/
int8_t MOTOR_RM_UpdateAll(void);
int8_t MOTOR_RM_SetOutput(MOTOR_RM_Param_t *param, float value);
/**
* @brief 设置电机输出值
* @param can CAN通道
* @param id 电机实际CAN ID
* @param value 输出值(归一化,-1.0到1.0
* @return 0 成功,其他值失败
* @brief 发送控制命令到电机注意一个CAN可以控制多个电机所以只需要发送一次即可
* @param param 电机参数
* @return
*/
int8_t MOTOR_RM_SetOutput(BSP_CAN_t can, uint16_t id, float value);
int8_t MOTOR_RM_Ctrl(MOTOR_RM_Param_t *param);
/**
* @brief 发送电机控制命令
* @param can CAN通道
* @param ctrl_id 控制帧ID0x200, 0x1ff, 0x2ff
* @return 0 成功,其他值失败
* @brief 获取指定电机的实例指针
* @param param 电机参数
* @return
*/
int8_t MOTOR_RM_Ctrl(BSP_CAN_t can, uint16_t ctrl_id);
/**
* @brief 获取电机实例
* @param can CAN通道
* @param id 电机实际CAN ID
* @return 电机实例指针失败返回NULL
*/
MOTOR_RM_t* MOTOR_RM_GetMotor(BSP_CAN_t can, uint16_t id);
MOTOR_RM_t* MOTOR_RM_GetMotor(MOTOR_RM_Param_t *param);
/**
* @brief 使电机松弛设置输出为0
* @param can CAN通道
* @param id 电机实际CAN ID
* @return 0 成功,其他值失败
* @param param
* @return
*/
int8_t MOTOR_RM_Relax(BSP_CAN_t can, uint16_t id);
int8_t MOTOR_RM_Relax(MOTOR_RM_Param_t *param);
/**
* @brief 使电机离线(输出为0并标记为不在线
* @param can CAN通道
* @param id 电机实际CAN ID
* @return 0 成功,其他值失败
* @brief 使电机离线(设置在线状态为false
* @param param
* @return
*/
int8_t MOTOR_RM_Offine(BSP_CAN_t can, uint16_t id);
int8_t MOTOR_RM_Offine(MOTOR_RM_Param_t *param);
/**
* @brief
* @param
* @return
*/
int8_t MOTOR_RM_UpdateAll(void);
#ifdef __cplusplus
}