Customer_controller/USER/dm_motor_drv.c

505 lines
16 KiB
C
Raw Permalink 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.

#include "dm_motor_drv.h"
#include "fdcan.h"
/**
************************************************************************
* @brief: dm4310_enable: 启用DM4310电机控制模式函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor: 指向motor_t结构的指针包含电机相关信息和控制参数
* @retval: void
* @details: 根据电机控制模式启用相应的模式通过CAN总线发送启用命令
* 支持的控制模式包括位置模式、位置速度控制模式和速度控制模式
************************************************************************
**/
void dm_motor_enable(hcan_t* hcan, motor_t *motor)
{
switch(motor->ctrl.mode)
{
case mit_mode:
enable_motor_mode(hcan, motor->id, MIT_MODE);
break;
case pos_mode:
enable_motor_mode(hcan, motor->id, POS_MODE);
break;
case spd_mode:
enable_motor_mode(hcan, motor->id, SPD_MODE);
break;
case psi_mode:
enable_motor_mode(hcan, motor->id, PSI_MODE);
break;
}
}
/**
************************************************************************
* @brief: dm4310_disable: 禁用DM4310电机控制模式函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor: 指向motor_t结构的指针包含电机相关信息和控制参数
* @retval: void
* @details: 根据电机控制模式禁用相应的模式通过CAN总线发送禁用命令
* 支持的控制模式包括位置模式、位置速度控制模式和速度控制模式
************************************************************************
**/
void dm_motor_disable(hcan_t* hcan, motor_t *motor)
{
switch(motor->ctrl.mode)
{
case mit_mode:
disable_motor_mode(hcan, motor->id, MIT_MODE);
break;
case pos_mode:
disable_motor_mode(hcan, motor->id, POS_MODE);
break;
case spd_mode:
disable_motor_mode(hcan, motor->id, SPD_MODE);
break;
case psi_mode:
disable_motor_mode(hcan, motor->id, PSI_MODE);
break;
}
dm_motor_clear_para(motor);
}
/**
************************************************************************
* @brief: dm4310_ctrl_send: 发送DM4310电机控制命令函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor: 指向motor_t结构的指针包含电机相关信息和控制参数
* @retval: void
* @details: 根据电机控制模式发送相应的命令到DM4310电机
* 支持的控制模式包括位置模式、位置速度控制模式和速度控制模式
************************************************************************
**/
void dm_motor_ctrl_send(hcan_t* hcan, motor_t *motor)
{
switch(motor->ctrl.mode)
{
case mit_mode:
mit_ctrl(hcan, motor, motor->id, motor->ctrl.pos_set, motor->ctrl.vel_set, motor->ctrl.kp_set, motor->ctrl.kd_set, motor->ctrl.tor_set);
break;
case pos_mode:
pos_ctrl(hcan, motor->id, motor->ctrl.pos_set, motor->ctrl.vel_set);
break;
case spd_mode:
spd_ctrl(hcan, motor->id, motor->ctrl.vel_set);
break;
case psi_mode:
psi_ctrl(hcan, motor->id,motor->ctrl.pos_set, motor->ctrl.vel_set, motor->ctrl.cur_set);
break;
}
}
/**
************************************************************************
* @brief: dm4310_clear: 清除DM4310电机控制参数函数
* @param[in]: motor: 指向motor_t结构的指针包含电机相关信息和控制参数
* @retval: void
* @details: 将DM4310电机的命令参数和控制参数清零包括位置、速度、
* 比例增益(KP)、微分增益(KD)和扭矩
************************************************************************
**/
void dm_motor_clear_para(motor_t *motor)
{
motor->ctrl.kd_set = 0;
motor->ctrl.kp_set = 0;
motor->ctrl.pos_set = 0;
motor->ctrl.vel_set = 0;
motor->ctrl.tor_set = 0;
motor->ctrl.cur_set = 0;
}
/**
************************************************************************
* @brief: dm4310_clear_err: 清除DM4310电机错误函数
* @param[in]: hcan: 指向CAN控制结构体的指针
* @param[in]: motor: 指向电机结构体的指针
* @retval: void
* @details: 根据电机的控制模式,调用对应模式的清除错误函数
************************************************************************
**/
void dm_motor_clear_err(hcan_t* hcan, motor_t *motor)
{
switch(motor->ctrl.mode)
{
case mit_mode:
clear_err(hcan, motor->id, MIT_MODE);
break;
case pos_mode:
clear_err(hcan, motor->id, POS_MODE);
break;
case spd_mode:
clear_err(hcan, motor->id, SPD_MODE);
break;
case psi_mode:
clear_err(hcan, motor->id, PSI_MODE);
break;
}
}
/**
************************************************************************
* @brief: dm4310_fbdata: 获取DM4310电机反馈数据函数
* @param[in]: motor: 指向motor_t结构的指针包含电机相关信息和反馈数据
* @param[in]: rx_data: 指向包含反馈数据的数组指针
* @retval: void
* @details: 从接收到的数据中提取DM4310电机的反馈信息包括电机ID、
* 状态、位置、速度、扭矩以及相关温度参数
************************************************************************
**/
void dm_motor_fbdata(motor_t *motor, uint8_t *rx_data)
{
motor->para.id = (rx_data[0])&0x0F;
motor->para.state = (rx_data[0])>>4;
motor->para.p_int=(rx_data[1]<<8)|rx_data[2];
motor->para.v_int=(rx_data[3]<<4)|(rx_data[4]>>4);
motor->para.t_int=((rx_data[4]&0xF)<<8)|rx_data[5];
motor->para.pos = uint_to_float(motor->para.p_int, -motor->tmp.PMAX, motor->tmp.PMAX, 16); // (-12.5,12.5)
motor->para.vel = uint_to_float(motor->para.v_int, -motor->tmp.VMAX, motor->tmp.VMAX, 12); // (-45.0,45.0)
motor->para.tor = uint_to_float(motor->para.t_int, -motor->tmp.TMAX, motor->tmp.TMAX, 12); // (-18.0,18.0)
motor->para.Tmos = (float)(rx_data[6]);
motor->para.Tcoil = (float)(rx_data[7]);
}
/**
************************************************************************
* @brief: float_to_uint: 浮点数转换为无符号整数函数
* @param[in]: x_float: 待转换的浮点数
* @param[in]: x_min: 范围最小值
* @param[in]: x_max: 范围最大值
* @param[in]: bits: 目标无符号整数的位数
* @retval: 无符号整数结果
* @details: 将给定的浮点数 x 在指定范围 [x_min, x_max] 内进行线性映射,映射结果为一个指定位数的无符号整数
************************************************************************
**/
int float_to_uint(float x_float, float x_min, float x_max, int bits)
{
/* Converts a float to an unsigned int, given range and number of bits */
float span = x_max - x_min;
float offset = x_min;
return (int) ((x_float-offset)*((float)((1<<bits)-1))/span);
}
/**
************************************************************************
* @brief: uint_to_float: 无符号整数转换为浮点数函数
* @param[in]: x_int: 待转换的无符号整数
* @param[in]: x_min: 范围最小值
* @param[in]: x_max: 范围最大值
* @param[in]: bits: 无符号整数的位数
* @retval: 浮点数结果
* @details: 将给定的无符号整数 x_int 在指定范围 [x_min, x_max] 内进行线性映射,映射结果为一个浮点数
************************************************************************
**/
float uint_to_float(int x_int, float x_min, float x_max, int bits)
{
/* converts unsigned int to float, given range and number of bits */
float span = x_max - x_min;
float offset = x_min;
return ((float)x_int)*span/((float)((1<<bits)-1)) + offset;
}
/**
************************************************************************
* @brief: enable_motor_mode: 启用电机模式函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: mode_id: 模式ID指定要开启的模式
* @retval: void
* @details: 通过CAN总线向特定电机发送启用特定模式的命令
************************************************************************
**/
void enable_motor_mode(hcan_t* hcan, uint16_t motor_id, uint16_t mode_id)
{
uint8_t data[8];
uint16_t id = motor_id + mode_id;
data[0] = 0xFF;
data[1] = 0xFF;
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = 0xFF;
data[5] = 0xFF;
data[6] = 0xFF;
data[7] = 0xFC;
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: disable_motor_mode: 禁用电机模式函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: mode_id: 模式ID指定要禁用的模式
* @retval: void
* @details: 通过CAN总线向特定电机发送禁用特定模式的命令
************************************************************************
**/
void disable_motor_mode(hcan_t* hcan, uint16_t motor_id, uint16_t mode_id)
{
uint8_t data[8];
uint16_t id = motor_id + mode_id;
data[0] = 0xFF;
data[1] = 0xFF;
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = 0xFF;
data[5] = 0xFF;
data[6] = 0xFF;
data[7] = 0xFD;
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: save_pos_zero: 保存位置零点函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: mode_id: 模式ID指定要保存位置零点的模式
* @retval: void
* @details: 通过CAN总线向特定电机发送保存位置零点的命令
************************************************************************
**/
void save_pos_zero(hcan_t* hcan, uint16_t motor_id, uint16_t mode_id)
{
uint8_t data[8];
uint16_t id = motor_id + mode_id;
data[0] = 0xFF;
data[1] = 0xFF;
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = 0xFF;
data[5] = 0xFF;
data[6] = 0xFF;
data[7] = 0xFE;
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: clear_err: 清除电机错误函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: mode_id: 模式ID指定要清除错误的模式
* @retval: void
* @details: 通过CAN总线向特定电机发送清除错误的命令。
************************************************************************
**/
void clear_err(hcan_t* hcan, uint16_t motor_id, uint16_t mode_id)
{
uint8_t data[8];
uint16_t id = motor_id + mode_id;
data[0] = 0xFF;
data[1] = 0xFF;
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = 0xFF;
data[5] = 0xFF;
data[6] = 0xFF;
data[7] = 0xFB;
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: mit_ctrl: MIT模式下的电机控制函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针用于指定CAN总线
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: pos: 位置给定值
* @param[in]: vel: 速度给定值
* @param[in]: kp: 位置比例系数
* @param[in]: kd: 位置微分系数
* @param[in]: torq: 转矩给定值
* @retval: void
* @details: 通过CAN总线向电机发送MIT模式下的控制帧。
************************************************************************
**/
void mit_ctrl(hcan_t* hcan, motor_t *motor, uint16_t motor_id, float pos, float vel,float kp, float kd, float tor)
{
uint8_t data[8];
uint16_t pos_tmp,vel_tmp,kp_tmp,kd_tmp,tor_tmp;
uint16_t id = motor_id + MIT_MODE;
pos_tmp = float_to_uint(pos, -motor->tmp.PMAX, motor->tmp.PMAX, 16);
vel_tmp = float_to_uint(vel, -motor->tmp.VMAX, motor->tmp.VMAX, 12);
tor_tmp = float_to_uint(tor, -motor->tmp.TMAX, motor->tmp.TMAX, 12);
kp_tmp = float_to_uint(kp, KP_MIN, KP_MAX, 12);
kd_tmp = float_to_uint(kd, KD_MIN, KD_MAX, 12);
data[0] = (pos_tmp >> 8);
data[1] = pos_tmp;
data[2] = (vel_tmp >> 4);
data[3] = ((vel_tmp&0xF)<<4)|(kp_tmp>>8);
data[4] = kp_tmp;
data[5] = (kd_tmp >> 4);
data[6] = ((kd_tmp&0xF)<<4)|(tor_tmp>>8);
data[7] = tor_tmp;
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: pos_speed_ctrl: 位置速度控制函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针用于指定CAN总线
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: vel: 速度给定值
* @retval: void
* @details: 通过CAN总线向电机发送位置速度控制命令
************************************************************************
**/
void pos_ctrl(hcan_t* hcan,uint16_t motor_id, float pos, float vel)
{
uint16_t id;
uint8_t *pbuf, *vbuf;
uint8_t data[8];
id = motor_id + POS_MODE;
pbuf=(uint8_t*)&pos;
vbuf=(uint8_t*)&vel;
data[0] = *pbuf;
data[1] = *(pbuf+1);
data[2] = *(pbuf+2);
data[3] = *(pbuf+3);
data[4] = *vbuf;
data[5] = *(vbuf+1);
data[6] = *(vbuf+2);
data[7] = *(vbuf+3);
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: speed_ctrl: 速度控制函数
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针用于指定CAN总线
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: vel: 速度给定值
* @retval: void
* @details: 通过CAN总线向电机发送速度控制命令
************************************************************************
**/
void spd_ctrl(hcan_t* hcan, uint16_t motor_id, float vel)
{
uint16_t id;
uint8_t *vbuf;
uint8_t data[4];
id = motor_id + SPD_MODE;
vbuf=(uint8_t*)&vel;
data[0] = *vbuf;
data[1] = *(vbuf+1);
data[2] = *(vbuf+2);
data[3] = *(vbuf+3);
fdcanx_send_data(hcan, id, data, 4);
}
/**
************************************************************************
* @brief: pos_speed_ctrl: 混控模式
* @param[in]: hcan: 指向CAN_HandleTypeDef结构的指针用于指定CAN总线
* @param[in]: motor_id: 电机ID指定目标电机
* @param[in]: pos: 位置给定值
* @param[in]: vel: 速度给定值
* @param[in]: i: 电流给定值
* @retval: void
* @details: 通过CAN总线向电机发送位置速度控制命令
************************************************************************
**/
void psi_ctrl(hcan_t* hcan, uint16_t motor_id, float pos, float vel, float cur)
{
uint16_t id;
uint8_t *pbuf, *vbuf, *ibuf;
uint8_t data[8];
uint16_t u16_vel = vel*100;
uint16_t u16_cur = cur*10000;
id = motor_id + PSI_MODE;
pbuf=(uint8_t*)&pos;
vbuf=(uint8_t*)&u16_vel;
ibuf=(uint8_t*)&u16_cur;
data[0] = *pbuf;
data[1] = *(pbuf+1);
data[2] = *(pbuf+2);
data[3] = *(pbuf+3);
data[4] = *vbuf;
data[5] = *(vbuf+1);
data[6] = *ibuf;
data[7] = *(ibuf+1);
fdcanx_send_data(hcan, id, data, 8);
}
/**
************************************************************************
* @brief: read_motor_data: 发送读取寄存器命令
* @param[in]: id: 电机can id
* @param[in]: rid: 寄存器地址
* @retval: void
* @details: 读取电机参数
************************************************************************
**/
void read_motor_data(uint16_t id, uint8_t rid)
{
uint8_t can_id_l = id & 0x0F;
uint8_t can_id_h = (id >> 4) & 0x0F;
uint8_t data[4] = {can_id_l, can_id_h, 0x33, rid};
fdcanx_send_data(&hfdcan1, 0x7FF, data, 4);
}
/**
************************************************************************
* @brief: read_motor_ctrl_fbdata: 发送读取电机反馈数据的命令
* @param[in]: id: 电机can id
* @retval: void
* @details: 读取电机控制反馈的数据
************************************************************************
**/
void read_motor_ctrl_fbdata(uint16_t id)
{
uint8_t can_id_l = id & 0x0F;
uint8_t can_id_h = (id >> 4) & 0x0F;
uint8_t data[4] = {can_id_l, can_id_h, 0xCC, 0x00};
fdcanx_send_data(&hfdcan1, 0x7FF, data, 4);
}
/**
************************************************************************
* @brief: write_motor_data: 发送写寄存器命令
* @param[in]: id: 电机can id
* @param[in]: rid: 寄存器地址
* @param[in]: d0-d3: 写入的数据
* @retval: void
* @details: 向寄存器写入数据
************************************************************************
**/
void write_motor_data(uint16_t id, uint8_t rid, uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
uint8_t can_id_l = id & 0x0F;
uint8_t can_id_h = (id >> 4) & 0x0F;
uint8_t data[8] = {can_id_l, can_id_h, 0x55, rid, d0, d1, d2, d3};
fdcanx_send_data(&hfdcan1, 0x7FF, data, 8);
}
/**
************************************************************************
* @brief: save_motor_data: 发送保存命令
* @param[in]: id: 电机can id
* @param[in]: rid: 寄存器地址
* @retval: void
* @details: 保存写入的电机参数
************************************************************************
**/
void save_motor_data(uint16_t id, uint8_t rid)
{
uint8_t can_id_l = id & 0x0F;
uint8_t can_id_h = (id >> 4) & 0x0F;
uint8_t data[4] = {can_id_l, can_id_h, 0xAA, 0x01};
fdcanx_send_data(&hfdcan1, 0x7FF, data, 4);
}