小米微电机STM32 HAL库驱动教程

阅读: 评论:0

小米微电机STM32 HAL库驱动教程

小米微电机STM32 HAL库驱动教程

目录

一、相关资料

二、驱动代码

MI_motor_dev.h头文件:

MI_motor_dev.c源文件:

重定义can中断回调:

三、使用过程


一、相关资料

电机图纸、上位机、电机固件等可以找客服下载,这里给出使用说明书的分享链接(建议阅读)

文档链接:=2023 
提取码:2023

二、驱动代码

根据文档写出电机驱动文件如下(经测试可用):

MI_motor_dev.h头文件:

#ifndef MI_DEV_H
#define MI_DEV_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "pid_lib.h"//pid算法库,可以不要
#define P_MIN -12.5f
#define P_MAX 12.5f
#define V_MIN -30.0f
#define V_MAX 30.0f
#define KP_MIN 0.0f
#define KP_MAX 500.0f
#define KD_MIN 0.0f
#define KD_MAX 5.0f
#define T_MIN -12.0f
#define T_MAX 12.0ftypedef enum{OK                 = 0,//无故障BAT_LOW_ERR        = 1,//欠压故障OVER_CURRENT_ERR   = 2,//过流OVER_TEMP_ERR      = 3,//过温MAGNETIC_ERR       = 4,//磁编码故障HALL_ERR_ERR       = 5,//HALL编码故障NO_CALIBRATION_ERR = 6//未标定}motor_state_e;//电机状态(故障信息)typedef enum{RESET_MODE = 0,//Reset[模式]CALI_MODE  = 1,//Cali 模式[标定]RUN_MODE   = 2//Motor模式[运行]} motor_mode_e;//电机运行模式typedef struct{uint32_t motor_id : 8; // 只占8位uint32_t data : 16;uint32_t mode : 5;uint32_t res : 3;} EXT_ID_t; // 32位扩展ID解析结构体typedef struct{// 电机反馈int16_t angle_temp;int16_t speed_temp;int16_t torque_temp;int16_t temprature_temp;float angle; // 连续角float speed;float torque;float temprature;uint32_t last_update_time; // 编码器时间戳} Motor_fdb_t;                 // 电机编码器反馈结构体typedef struct{CAN_HandleTypeDef *phcan;motor_state_e motor_state;motor_mode_e  motor_mode;EXT_ID_t EXT_ID;uint8_t txdata[8];PID_t PID;Motor_fdb_t motor_fdb;} MI_Motor_t;/**********************Functions*************************8*/void MI_motor_get_ID(MI_Motor_t* hmotor);void MI_motor_init(MI_Motor_t* hmotor,CAN_HandleTypeDef *phcan);void MI_motor_enable(MI_Motor_t *hmotor, uint8_t id);void MI_motor_controlmode(MI_Motor_t* hmotor, float torque, float MechPosition , float speed , float kp , float kd);void MI_motor_stop(MI_Motor_t *hmotor);void MI_motor_setMechPosition2Zero(MI_Motor_t *hmotor);void MI_motor_changeID(MI_Motor_t* hmotor,uint8_t Now_ID,uint8_t Target_ID);void MIMotor_MotorDataDecode(uint32_t rx_EXT_id, uint8_t rxdata[]);extern MI_Motor_t MI_Motor;
#endif// #endif
#ifdef __cplusplus
}
#endif

MI_motor_dev.c源文件:

/**** @File:        MI_motor_dev.c* @Author:      本人不帅**/
/* Includes -------------------------------------------------------------------*/
#include "MI_motor_dev.h"
uint8_t MI_MASTERID = 1; //master id 发送指令时EXTID的bit8:15,反馈的bit0:7
uint8_t MI_fdbid = 0;//反馈ID,获取电机ID和识别码用
uint8_t MI_MCU_identifier[8];
MI_Motor_t MI_Motor;
/*** @brief  float转int,数据打包用* @param  x float数值* @param  x_min float数值的最小值* @param  x_max float数值的最大值* @param  bits  int的数据位数* @retval null*/
int float_to_uint(float x, float x_min, float x_max, int bits) {float span = x_max - x_min;float offset = x_min;if(x > x_max) x=x_max;else if(x < x_min) x= x_min;return (int) ((x-offset)*((float)((1<<bits)-1))/span);
}
/*** @brief  小米电机CAN通信发送* @param  hmotor 电机结构体* @retval null*/
CAN_TxHeaderTypeDef CAN_TxHeader_MI;
void MI_Motor_CanTx(MI_Motor_t* hmotor) {CAN_TxHeader_MI.DLC = 8;CAN_TxHeader_MI.IDE = CAN_ID_EXT;CAN_TxHeader_MI.RTR = CAN_RTR_DATA;CAN_TxHeader_MI.ExtId = *((uint32_t*)&(hmotor->EXT_ID));/*CAN_TxHeader_MI.ExtId = hmotor->_id<<24 | hmotor->EXT_ID.data << 8 |          hmotor->de << 5;*/uint32_t mailbox;/* Start the Transmission process */uint32_t ret = HAL_CAN_AddTxMessage(hmotor->phcan, &CAN_TxHeader_MI, hmotor->txdata, &mailbox);if (ret != HAL_OK) {/* Transmission request Error */while(1);}
}
/*** @brief  小米电机初始化* @param  hmotor 电机结构体* @param  phcan can总线句柄* @retval null*/
void MI_motor_init(MI_Motor_t* hmotor,CAN_HandleTypeDef *phcan)
{hmotor->phcan = phcan;
}
/*** @brief  小米电机使能* @param  hmotor 电机结构体* @param  id 电机id* @retval null*/
void MI_motor_enable(MI_Motor_t* hmotor,uint8_t id)
{hmotor->de = 3;hmotor->_id = id;hmotor->EXT_ID.data = MI_MASTERID;hmotor->s = 0;for(uint8_t i=0; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  获取设备ID (通信类型0),需在电机使能前使用* @param  hmotor 电机结构体* @retval null*/
void MI_motor_get_ID(MI_Motor_t* hmotor)
{hmotor->de = 0;hmotor->EXT_ID.data = 0;hmotor->_id = 0;hmotor->s = 0;for(uint8_t i=0; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  运控模式电机控制指令(通信类型1)* @param  hmotor 电机结构体* @param  motor_id 电机id* @param  master_id 主机id* @retval null*/
void MI_motor_controlmode(MI_Motor_t* hmotor, float torque, float MechPosition , float speed , float kp , float kd)
{hmotor->de = 1;hmotor->EXT_ID.data = float_to_uint(torque,T_MIN,T_MAX,16);hmotor->s = 0;hmotor->txdata[0]=float_to_uint(MechPosition,P_MIN,P_MAX,16)>>8;hmotor->txdata[1]=float_to_uint(MechPosition,P_MIN,P_MAX,16);hmotor->txdata[2]=float_to_uint(speed,V_MIN,V_MAX,16)>>8;hmotor->txdata[3]=float_to_uint(speed,V_MIN,V_MAX,16);hmotor->txdata[4]=float_to_uint(kp,KP_MIN,KP_MAX,16)>>8;hmotor->txdata[5]=float_to_uint(kp,KP_MIN,KP_MAX,16);hmotor->txdata[6]=float_to_uint(kd,KD_MIN,KD_MAX,16)>>8;hmotor->txdata[7]=float_to_uint(kd,KD_MIN,KD_MAX,16);MI_Motor_CanTx(hmotor);
}
/*** @brief  电机停止运行帧(通信类型4)* @param  hmotor 电机结构体* @retval null*/
void MI_motor_stop(MI_Motor_t* hmotor)
{hmotor->de = 4;hmotor->EXT_ID.data = MI_MASTERID;hmotor->s = 0;for(uint8_t i=0; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  设置电机机械零位(通信类型6)会把当前电机位置设为机械零位(掉电丢失)* @param  hmotor 电机结构体* @retval null*/
void MI_motor_setMechPosition2Zero(MI_Motor_t* hmotor)
{hmotor->de = 6;hmotor->EXT_ID.data = MI_MASTERID;hmotor->s = 0;hmotor->txdata[0]=1;for(uint8_t i=1; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  设置电机CAN_ID(通信类型7)更改当前电机CAN_ID , 立即生效,需在电机使能前使用* @param  hmotor 电机结构体* @param  Now_ID 电机现在的ID* @param  Target_ID 想要改成的电机ID* @retval null*/
void MI_motor_changeID(MI_Motor_t* hmotor,uint8_t Now_ID,uint8_t Target_ID)
{hmotor->de = 7;	hmotor->_id = Now_ID;hmotor->EXT_ID.data = Target_ID << 8 | MI_MASTERID;hmotor->s = 0;for(uint8_t i=0; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  单个参数读取(通信类型17)* @param  hmotor 电机结构体* @param  index 功能码* @retval null* @note   我用不着,所以没写反馈解码*/
void MI_motor_Read_One_Para(MI_Motor_t* hmotor,uint16_t index)
{hmotor->de = 17;hmotor->EXT_ID.data = MI_MASTERID;hmotor->s = 0;hmotor->txdata[0]=index;memcpy(&hmotor->txdata[0],&index,2);for(uint8_t i=2; i<8; i++){hmotor->txdata[i]=0;}MI_Motor_CanTx(hmotor);
}
/*** @brief  单个参数写入(通信类型18) (掉电丢失)* @param  hmotor 电机结构体* @param  index 功能码* @param  data[4] 参数数据缓冲* @retval null* @note   我用不着,所以没写反馈解码*/
void MI_motor_Write_One_Para(MI_Motor_t* hmotor, uint16_t index ,uint8_t data[4])
{hmotor->de = 0x12;hmotor->EXT_ID.data = MI_MASTERID;hmotor->s = 0;memcpy(&hmotor->txdata[0],&index,2);memcpy(&hmotor->txdata[4],data, 4);MI_Motor_CanTx(hmotor);
}
/*** @brief  单电机解码* @param  hmotor 电机结构体* @param  state_byte状态字节,扩展ID的bit8:23* @param  rxdata 数据缓冲区* @retval null*/
uint16_t decode_temp_mi = 0;
uint8_t nsvd = 0;
void MI_motor_decode(MI_Motor_t* hmotor,uint8_t state_byte,uint8_t rxdata[]) {nsvd = state_byte;if((state_byte&0xC0) == 0) {hmotor->motor_state = OK;} else {for(int i = 1; i < 7; i++) {if(state_byte&0x01) {hmotor->motor_state = i;}state_byte = state_byte>> 1;}}hmotor->motor_mode = state_byte;decode_temp_mi = (rxdata[0] << 8 | rxdata[1])^0x8000;hmotor->motor_fdb.angle_temp   = decode_temp_mi;decode_temp_mi = (rxdata[2] << 8 | rxdata[3])^0x8000;hmotor->motor_fdb.speed_temp   = decode_temp_mi;decode_temp_mi = (rxdata[4] << 8 | rxdata[5])^0x8000;hmotor->que_temp   = decode_temp_mi;decode_temp_mi = (rxdata[6] << 8 | rxdata[7]);hmotor->prature_temp  = decode_temp_mi;hmotor->motor_fdb.angle = (float)hmotor->motor_fdb.angle_temp/32768*4*3.1415926f;hmotor->motor_fdb.speed = (float)hmotor->motor_fdb.speed_temp/32768*30;hmotor->que = (float)hmotor->que_temp/32768*12.0f;hmotor->prature = (float)hmotor->prature_temp/10.0f;hmotor->motor_fdb.last_update_time = HAL_GetTick();
}
/*** @brief  小米电机解码* @param  rx_EXT_id 接收到的扩展ID* @param  rxdata 数据缓冲区* @retval null*/
EXT_ID_t EXT_ID_tmp;//扩展ID数据结构体
void MIMotor_MotorDataDecode(uint32_t rx_EXT_id,uint8_t rxdata[])
{   EXT_ID_tmp = *((EXT_ID_t*)(&rx_EXT_id));if(EXT_de == 0&&EXT__id == 0xFE) {MI_fdbid = EXT_ID_tmp.data;memcpy(MI_MCU_identifier,rxdata, 8);}if(EXT_de == 2) {uint8_t id = EXT_ID_tmp.data&0xFF;if(id == MI_Motor._id) {MI_motor_decode(&MI_Motor,(uint8_t)(EXT_ID_tmp.data>>8),rxdata);}}
}

重定义can中断回调:

/*** @brief      CAN总线数据接收回调函数* @param      phcan: 指向CAN句柄的指针* @retval     无*/
CAN_RxHeaderTypeDef Can_rxHeader;//放函数外面只是为了便于DEBUG,可以放回去
uint8_t Can_rxData[8];
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *phcan) {/* Get RX message */uint32_t ret = HAL_CAN_GetRxMessage(phcan, CAN_RX_FIFO0, &Can_rxHeader, Can_rxData);if (ret != HAL_OK) {/* Reception Error */}if(phcan==&hcan1){MIMotor_MotorDataDecode(Can_rxHeader.ExtId,Can_rxData);}
}

三、使用流程

小米电机使用可以分为以下几步:

1、获取电机当前ID,电机没有设置ID的拨码开关,也没有ID指示,需要通过CAN通讯查看ID。

使用

MI_motor_init(MI_Motor_t* hmotor,CAN_HandleTypeDef *phcan);//主要是初始化can,也可以加自己的初始化代码
MI_motor_get_ID(MI_Motor_t* hmotor);//获取ID指令

可以获取电机ID,反馈的ID存在变量MI_fdbid中,MCU唯一标识码存在在MI_MCU_identifier[8]中。执行此操作不要使用电机使能命令,即保证电机未使能,电机使能时会有声音

2、更改电机ID(执行此操作不要使用电机使能命令),如果不需要更改电机ID也可以跳过

MI_motor_init(MI_Motor_t* hmotor,CAN_HandleTypeDef *phcan);//主要是初始化can,也可以加自己的初始化代码
MI_motor_changeID(MI_Motor_t* hmotor,uint8_t Now_ID,uint8_t Target_ID);//更改ID

3、电机使能

MI_motor_init(MI_Motor_t* hmotor,CAN_HandleTypeDef *phcan);//主要是初始化can,也可以加自己的初始化代码
MI_motor_enable(MI_Motor_t* hmotor,uint8_t id);

4、使能之后就可以使用

MI_motor_controlmode(MI_Motor_t* hmotor, float torque, float MechPosition , float speed , float kp , float kd)

进行控制了。

5、可以使用一下函数关闭电机

void MI_motor_stop(MI_Motor_t* hmotor);

本文发布于:2024-01-31 15:14:45,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170668529029439.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:微电机   小米   教程   HAL
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23