背景:項目中需要用到可以低速轉動的電機,并且力矩需要滿足項目條件,因此這里選用小米電機(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);
}
```
下圖為說明書中速度模式指令順序

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)
2024-11-8 19:50 上傳
點擊文件名下載附件
程序
|