找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1229|回复: 0
收起左侧

STM32单片机控制小米电机

[复制链接]
ID:861056 发表于 2024-11-8 10:00 | 显示全部楼层 |阅读模式
背景:项目中需要用到可以低速转动的电机,并且力矩需要满足项目条件,因此这里选用小米电机(CyberGear 微电机)。

本实验硬件条件:单片机,STM32F103RET6、CAN通讯芯片。

注:PCB由自己设计绘制,在设计中单片机本身的时钟频率无法与高频率CAN同步,因此需要增加8M晶振。

## 原理图设计

下图为单片机主电路图



下图为CAN通讯电路图



## 控制程序设计

控制程序都封装在.c文件中了

## 小米电机ID检查,通信类型为0

```c
/*—————————————————————————————————————————————————————————————————————————————————*/
/** @brief          小米电机ID检查,通信类型为0
  * @param[in]      id:  控制电机CAN_ID【出厂默认0x7F】
  **/
void check_cybergear(uint8_t ID)
{
    uint8_t tx_data[8] = {0};//没有数据
                //扩展ID的组合,依旧是3个部分
    txMsg.ExtId = Communication_Type_GetID<<24|Master_CAN_ID<<8|ID;
        MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令        
}
```

### 小米运控模式指令,通信类型:1

```C
/*——————————————————————————————————————————————————————————————————————————————————*/
/** @brief          小米运控模式指令,通信类型:1
  * @param[in]      Motor:  目标电机结构体
  * @param[in]      torque: 力矩设置[-12,12] N*M
  * @param[in]      MechPosition: 位置设置[-12.5,12.5] rad
  * @param[in]      speed: 速度设置[-30,30] rpm
  * @param[in]      kp: 比例参数设置
  * @param[in]      kd: 微分参数设置
  * @retval         none
  **/
void motor_controlmode(MI_Motor *Motor,float torque, float MechPosition, float speed, float kp, float kd)
{   
    uint8_t tx_data[8]={0};//发送数据初始化
    //装填发送数据
          //将目标角度转化为16位2进制数,对应字节0~1,假设是0x1234
    tx_data[0]=float_to_uint(MechPosition,P_MIN,P_MAX,16)>>8;  //取得是高位的结果,即0x12
    tx_data[1]=float_to_uint(MechPosition,P_MIN,P_MAX,16);  //取得是低位的结果,即0x34
          //将目标速度转化为16位2进制数,对应字节2~3
    tx_data[2]=float_to_uint(speed,V_MIN,V_MAX,16)>>8;  
    tx_data[3]=float_to_uint(speed,V_MIN,V_MAX,16);  
          //目标KP
    tx_data[4]=float_to_uint(kp,KP_MIN,KP_MAX,16)>>8;  
    tx_data[5]=float_to_uint(kp,KP_MIN,KP_MAX,16);  
          //目标KD
    tx_data[6]=float_to_uint(kd,KD_MIN,KD_MAX,16)>>8;  
    tx_data[7]=float_to_uint(kd,KD_MIN,KD_MAX,16);
        
    txMsg.ExtId = Communication_Type_MotionControl<<24|float_to_uint(torque,T_MIN,T_MAX,16)<<8|Motor->CAN_ID;//装填扩展帧数据
    MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令        
}
```

### 电机反馈数据,通信类型2

```C
/*——————————————————————————————————————————————————————————————————————————————————————*/
/** @brief         电机反馈数据,通信类型2
  * @param[in]     信息存放的地址
  * @retval         none
  */
void Rx_Fifo0_Msg(MI_Motor *Motor)
{
                if (MyCAN_ReceiveFlag())//判断是否接收到报文信息
                {
                        uint32_t RxID;
      uint8_t RxLength;
      uint8_t RxData[8];
                        //接收信息放到对应的接收报文之中
                        MyCAN_Receive(&RxID, &RxLength, RxData);
                  Motor->CAN_ID=(RxID&0xFFFF)>>8;//获取接收数据的ID:保留低16位,其余全变成零,再右移8位,则获得了bit8~bit15的canid
      Motor->Angle=uint16_to_float(RxData[0]<<8|RxData[1],MIN_P,MAX_P,16);//将字节0~1转化位浮点数,即为当前角度
                  Motor->Speed=uint16_to_float(RxData[2]<<8|RxData[3],V_MIN,V_MAX,16);//将字节2~3转化位浮点数,即为当前速度                        
                  Motor->Torque=uint16_to_float(RxData[4]<<8|RxData[5],T_MIN,T_MAX,16);//将字节4~5转化位浮点数,即为当前角度                                
                  Motor->Temp=(RxData[6]<<8|RxData[7])*Temp_Gain;//将字节4~5转化为当前温度        
                  Motor->error_code=(RxID&0x1F0000)>>16;        
                }
}
```

### 使能电机,通信类型为3

```C
/*****************************使能电机,通信类型为3*******************************
  * @brief          使能小米电机
  * @param[in]      Motor:对应控制电机结构体   
  * @retval         none
  *****************************************************/
void start_cybergear(MI_Motor *Motor)
{
    uint8_t tx_data[8] = {0};
    txMsg.ExtId = Communication_Type_MotorEnable<<24|Master_CAN_ID<<8|Motor->CAN_ID;
    MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令        
}
```

### 电机停止运行,通信类型为4

```C
/************************电机停止运行,通信类型为4********************************
  * @brief          停止电机
  * @param[in]      Motor:对应控制电机结构体   
  * @param[in]      clear_error:清除错误位(0 不清除 1清除)
  * @retval         None
  *******************************************************************************/
void stop_cybergear(MI_Motor *Motor,uint8_t clear_error)
{
        uint8_t tx_data[8]={0};
        tx_data[0]=clear_error;//清除错误位设置
        txMsg.ExtId = Communication_Type_MotorStop<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令        
}
```

### 小米电机初始化

```C
/**
  * @brief          小米电机初始化
  * @param[in]      Motor:  电机结构体
  * @param[in]      Can_Id: 小米电机ID(默认0x7F)
  * @param[in]      Motor_Num: 电机编号
  * @param[in]      mode: 电机工作模式(0.运动模式Motion_mode 1. 位置模式Position_mode 2. 速度模式Speed_mode 3. 电流模式Current_mode)
  * @retval         none
  */
void init_cybergear(MI_Motor *Motor,uint8_t Can_Id, uint8_t mode)
{
    txMsg.StdId = 0;            //配置CAN发送:标准帧清零
    txMsg.ExtId = 0;            //配置CAN发送:扩展帧清零     
    txMsg.IDE = CAN_ID_EXT;     //配置CAN发送:扩展帧
    txMsg.RTR = CAN_RTR_DATA;   //配置CAN发送:数据帧
    txMsg.DLC = 0x08;           //配置CAN发送:数据长度

                Motor->CAN_ID=Can_Id;       //ID设置
                set_mode_cybergear(Motor,mode);//设置电机模式
                start_cybergear(Motor);        //使能电机
}
```

### 单个参数读取,通信类型17

```C
/*************************单个参数读取,通信类型17******************
*@brief         电机参数读取
*@param[in]     ID,电机的ID号
*/
void check_param_cybergear(MI_Motor *Motor, uint8_t index)
{
  uint8_t tx_data[8]={0};
  txMsg.ExtId = Communication_Type_GetSingleParameter<<24|Master_CAN_ID<<8|Motor->CAN_ID;//装填扩展帧数据
  tx_data[0]=index>>8;//高8位
  tx_data[1]=index;//低8位
  MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令        
}
```

### 对应说明书的单个参数写入,通信类型为18

```C
/******************对应说明书的单个参数写入,通信类型为18*************
  * @brief          写入电机参数
  * @param[in]      Motor:对应控制电机结构体
  * @param[in]      Index:写入参数对应地址
  * @param[in]      Value:写入参数值
  * @param[in]      Value_type:写入参数数据类型,可以对照字节数进行区分
  * @retval         none
  */
static void Set_Motor_Parameter(MI_Motor *Motor,uint16_t Index,float Value,char Value_type)
{
        uint8_t tx_data[8]={0};//写入的数据
        //扩展ID,包括三个部分:通信类型、主ID、电机ID
        txMsg.ExtId = Communication_Type_SetSingleParameter<<24|Master_CAN_ID<<8|Motor->CAN_ID;
        //参见说明书的通信类型18里面,Index的相关应用方法,Index共
        tx_data[0]=Index;      //高8位
        tx_data[1]=Index>>8;   //低8位
        tx_data[2]=0x00;
        tx_data[3]=0x00;
        //如果参数类型为浮点型,则对应的数据所占字节数为4,对应的数据需要转化为8个字节
        if(Value_type == 'f'){
                Float_to_Byte(Value);//将数值转化为4个byte 作为返回值
                tx_data[4]=byte[3];//高8位
                tx_data[5]=byte[2];
                tx_data[6]=byte[1];
                tx_data[7]=byte[0];//低8位               
        }
        //如果参数类型为uint8,只有一个字节
        else if(Value_type == 's'){
                tx_data[4]=(uint8_t)Value;
                tx_data[5]=0x00;
                tx_data[6]=0x00;
                tx_data[7]=0x00;                                
        }
        //can_txd();
  MyCAN_Transmit(txMsg.ExtId,txMsg.DLC,tx_data);//写入指令
}
```

### 小米速度模式指令

此代码根据电机说明书中给出的速度模式通讯顺序编写

```C
/*——————————————————————————————————————————————————————————————————————————————————*/
/** @brief          小米速度模式指令,通信类型:2
  * @param[in]      Motor:  目标电机结构体
  * @param[in]      CurValue: 电流设置[0,23] A
  * @param[in]      SpeedValue: 速度设置[-30,30] rad
  * @retval         none
  **/
void motor_speedmode(MI_Motor *Motor, float CurValue, float SpeedValue)
{   
                //设置limit_cur参数(最大电流指令)
                Set_Motor_Parameter(Motor,Limit_Cur,CurValue,'f');
                DelayMs(10);
                //设置spd_ref参数(转速模式转速指令)
                Set_Motor_Parameter(Motor,Spd_Ref,SpeedValue,'f');
                DelayMs(10);
}
```

下图为说明书中速度模式指令顺序

![image-20241021172242942](assets/image-20241021172242942.png)

main函数中根据此顺序进行小米电机初始化,然后设置速度模式,使能电机,写入单个参数limit_cur(最大电流),然后写入单个参数spd_ref(最大速度)。即可让电机按照速度模式转动。

下面为main函数:

```C
MI_Motor Cyber;
uint8_t Motor_ID=0x01; //电机ID,初始状态默认为0x7F,这里调整为0x01
uint8_t Mode = Speed_mode;//电机工作模式(0.运动模式Motion_mode 1. 位置模式Position_mode 2. 速度模式Speed_mode 3. 电流模式Current_mode)
uint32_t id;

/*
************************************************************
*        函数名称:        Hardware_Init
*
*        函数功能:        硬件初始化
************************************************************
*/
void Hardware_Init(void)
{
        
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        //中断控制器分组设置

        Delay_Init();                                                                        //systick初始化
        
        uart1_init(115200);                                                        //串口1
        uart2_init(115200);                                                        //串口2
        
        LED_Init();
        MyCAN_Init();
        
}

/*
************************************************************
*        函数名称:        main
*
*        函数功能:        
************************************************************
*/
int main(void)
{
        Hardware_Init();                                //初始化外围硬件
        DelayMs(1000);

        //以下用于调用程序验证相应的通信数据是否准确
        init_cybergear(&Cyber, 0X01, Mode);//初始化电机
        //*校验用的内容
  check_cybergear(Cyber.CAN_ID);//小米电机ID检查,通信类型为0
        //电机运控模式
//        motor_controlmode(&Cyber, 0, 0, 1, 0, 0.5);
        //电机速度模式
        motor_speedmode(&Cyber,23,1);
        
        while(1)
        {
                LED_STA();
//                MyCAN_Transmit(0X555, 8 ,AA);
                DelayMs(10);
        }
}

原理图: 无
仿真: 无
代码: STM32控制小米电机.7z (198.2 KB, 下载次数: 3)
回复

使用道具 举报

无效楼层,该帖已经被删除
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表