|
一、前言
最近接觸到一個(gè)項(xiàng)目需要用到小米電機(jī),本來是想用STM32進(jìn)行控制,但是必須得使用Arduino進(jìn)行開發(fā),于是嘗試了一下。小米電機(jī)是基于CAN通訊的,但恰好Arduino不帶CAN通訊協(xié)議,于是難度上了一個(gè)檔次。在查閱了相關(guān)資料后,偶然間看到B站某位大佬的視頻,得到了啟發(fā),在此感謝這位大佬,并成功實(shí)現(xiàn)了目標(biāo)功能,鏈接如下:www.bilibili.com/video/BV1P64y1p7hx/
二、準(zhǔn)備
硬件:
1、MCP2515 SPI2CAN轉(zhuǎn)換器 *1
2、小米微電機(jī) *1
3、電機(jī)轉(zhuǎn)接頭 *1
4、Arduino Nano *1
5、轉(zhuǎn)接線 *若干
6、usb to can轉(zhuǎn)換頭
知識儲備:
1、掌握Arduino開發(fā),能讀懂程序
2、了解CAN協(xié)議
3、了解小米微電機(jī)相關(guān)參數(shù),電機(jī)運(yùn)轉(zhuǎn)方式
三、接線及庫的準(zhǔn)備
參考一篇文章的CAN協(xié)議進(jìn)行接線,鏈接如下:gitcodecom/autowp/arduino-mcp2515/overview?utm_source=csdn_github_accelerator&isLogin=1
注意,小米電機(jī)供電為24V,電流在額定電流左右即可。具體相關(guān)參數(shù)在小米電機(jī)手冊中查看。CAN通訊線最好雙絞。
并下載相關(guān)庫函數(shù),導(dǎo)入我們的library文件夾中
CAN庫需要我們另外下載,下載渠道很多,這里貼一個(gè)下載鏈接:githubcom/sandeepmistry/arduino-CAN
四、電機(jī)ID使用usb2can轉(zhuǎn)換頭連接電腦,并進(jìn)行如下設(shè)置:
五、運(yùn)行代碼xm_motor.cpp
- #include "xm_motor.h"
- #include <Arduino.h>
- MCP2515 mcp2515(10);
- struct can_frame canMsg;
- uint32_t ExtId; //定義can擴(kuò)展id
- uint8_t rx_data[8]; //接收數(shù)據(jù)
- uint32_t Motor_Can_ID; //接收數(shù)據(jù)電機(jī)ID
- static uint8_t byte_ls[4]; //轉(zhuǎn)換臨時(shí)數(shù)據(jù)
- uint8_t tx_data[8]; //can寫入的數(shù)據(jù)
-
- int filter(int queue[], char n) //數(shù)值過濾
- {
- int sum = 0;
- byte i;
- int maxsz = queue[0]; //尋找最大值
- int minsz = queue[0]; //尋找最小值
- for (i = 0; i < n; i++) {
- if (maxsz < queue[i]) { maxsz = queue[i]; } //尋找最大值和最小值
- if (minsz > queue[i]) { minsz = queue[i]; }
- }
-
- for (i = 0; i < n; i++) {
- sum += queue[i];
- }
- sum = sum - maxsz - minsz; //去除最大值和最小值
- return (sum / (n - 2));
- } //數(shù)值過濾
- int check(byte ao_port, byte n) //采樣
- {
-
- int check_date[n]; //定義采樣數(shù)組
- for (byte i = 0; i < n; ++i) {
- check_date[i] = analogRead(ao_port); //獲得指定傳感器數(shù)據(jù)
- }
-
- int vvvv = filter(check_date, n);
- return vvvv;
-
- } //采樣
- void xm_can_start() {
-
- mcp2515.reset();
- mcp2515.setBitrate(CAN_1000KBPS, MCP_8MHZ);
- mcp2515.setNormalMode();
- delay(4);
- }
- static uint8_t* Float_to_Byte(float f) //float分解成四個(gè)byte數(shù)據(jù)
- {
- unsigned long longdata = 0;
- longdata = *(unsigned long*)&f;
- byte_ls[0] = (longdata & 0xFF000000) >> 24;
- byte_ls[1] = (longdata & 0x00FF0000) >> 16;
- byte_ls[2] = (longdata & 0x0000FF00) >> 8;
- byte_ls[3] = (longdata & 0x000000FF);
- return byte_ls;
- }
- static float uint16_to_float(uint16_t x, float x_min, float x_max, int bits) //把uint 16位數(shù)據(jù)變成浮點(diǎn)數(shù) 用在接受數(shù)據(jù)的處理上
- {
- uint32_t span = (1 << bits) - 1;
- float offset = x_max - x_min;
- return offset * x / span + x_min;
- }
- static int float_to_uint(float x, float x_min, float x_max, int bits) //把浮點(diǎn)數(shù)轉(zhuǎn)換成uint_16 用在位置 扭矩 上面
- {
- 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);
- }
- void exid_count(uint8_t Communication_Type, uint16_t msid, uint8_t can_id) //計(jì)算擴(kuò)展ExtId,Communication_Type通信類型,msid主canid,
- {
- uint8_t msid_l = msid;
- uint8_t msid_h = msid >> 8;
- uint32_t di_data = ((0xFFFFFFFF & Communication_Type) << 24) | 0x00FFFFFF; //求出高32位
- uint32_t di_datab = ((0xFFFFFFFF & msid_h) << 16) | 0xFF00FFFF; //求出高32位
- uint32_t di_datac = ((0xFFFFFFFF & msid_l) << 8) | 0xFFFF00FF; //求出高32位
- uint32_t di_datad = (0xFFFFFFFF & can_id) | 0xFFFFFF00; //求出高32位
- ExtId = (di_data & di_datab & di_datac & di_datad);
- } //計(jì)算擴(kuò)展ExtId,Communication_Type通信類型,msid主canid,
-
- void data_count_dcs(uint16_t Index, float Value, char Value_type) {
- //計(jì)算can在 單參數(shù)寫入,通信類型 12下發(fā)送的8位數(shù)據(jù),Index 是命令類型0: 運(yùn)控模式1: 位置模式2: 速度模式3: 電流模式Value是0 值,Value_type是數(shù)據(jù)類型,浮點(diǎn)數(shù)用f非浮點(diǎn)用s
- //速度數(shù)值要 注明浮點(diǎn)數(shù) f ,
- //寫入扭矩 n
-
-
- canMsg.data[0] = Index;
- canMsg.data[1] = Index >> 8;
- canMsg.data[2] = 0x00;
- canMsg.data[3] = 0x00;
- if (Value_type == 'f') {
- Float_to_Byte(Value);
- canMsg.data[4] = byte_ls[3];
- canMsg.data[5] = byte_ls[2];
- canMsg.data[6] = byte_ls[1];
- canMsg.data[7] = byte_ls[0];
- } else if (Value_type == 's') {
- canMsg.data[4] = (uint8_t)Value;
- canMsg.data[5] = 0x00;
- canMsg.data[6] = 0x00;
- canMsg.data[7] = 0x00;
- }
- } //計(jì)算can在 單參數(shù)寫入,通信類型 12下發(fā)送的8位數(shù)據(jù),Index 是命令類型Value是值,Value_type是數(shù)據(jù)類型,浮點(diǎn)數(shù)用f非浮點(diǎn)用s
- void data_count_zero() //can數(shù)據(jù)置零
- {
- canMsg.data[0] = 0x00;
- canMsg.data[1] = 0x00;
- canMsg.data[2] = 0x00;
- canMsg.data[3] = 0x00;
- canMsg.data[4] = 0x00;
- canMsg.data[5] = 0x00;
- canMsg.data[6] = 0x00;
- canMsg.data[7] = 0x00;
- } //can數(shù)據(jù)置零
-
- void motor_enable(uint8_t id = 1) //電機(jī)使能 電機(jī)canid
- {
- exid_count(3, Master_CAN_ID, id);
- canMsg.can_id = ExtId | CAN_EFF_FLAG;
- canMsg.can_dlc = 8;
- data_count_zero();
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- } //電機(jī)使能 電機(jī)canid
- void motor_mode(uint8_t id, char type) //電機(jī)運(yùn)行模式 電機(jī)canid 模式值1位置模式2速度模式 3 電流模式0運(yùn)控模式
- {
- exid_count(0x12, Master_CAN_ID, CanID);
- canMsg.can_id = ExtId | CAN_EFF_FLAG; //ExtId 0x12000001
- canMsg.can_dlc = 8;
- data_count_dcs(0x7005, type, 's');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- }
-
- void motor_speed_value(uint8_t id, float speed_ref) { //設(shè)置速度模式下的參數(shù)轉(zhuǎn)速
- exid_count(0x12, Master_CAN_ID, CanID);
- canMsg.can_id = ExtId | CAN_EFF_FLAG; //ExtId 0x12000001
- canMsg.can_dlc = 8;
- data_count_dcs(0x700A, speed_ref, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- }
-
- void motor_pos_zero(uint8_t id = 1) //位置置0
- {
- exid_count(6, Master_CAN_ID, id);
- canMsg.can_id = ExtId | CAN_EFF_FLAG;
- canMsg.can_dlc = 8;
- data_count_zero();
- canMsg.data[0] = 1;
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
-
- } //位置置0
- void motor_pos_value(uint8_t id, float speed_ref) { //設(shè)置位置模式下的位置
- exid_count(0x12, Master_CAN_ID, CanID);
- canMsg.can_id = ExtId | CAN_EFF_FLAG; //ExtId 0x12000001
- canMsg.can_dlc = 8;
- data_count_dcs(0x7016, speed_ref, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- }
-
- void motor_pow_value(uint8_t id, float torque, float limit_cur, float kp = 1, float ki = 0.0158) { //設(shè)置速度 電流限制,kp,kd
- exid_count(0x12, Master_CAN_ID, CanID);
- canMsg.can_id = ExtId | CAN_EFF_FLAG; //ExtId 0x12000001
- canMsg.can_dlc = 8;
- data_count_dcs(0x7017, torque, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- data_count_dcs(0x7018, limit_cur, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- data_count_dcs(0x7010, kp, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- data_count_dcs(0x7011, ki, 'f');
- mcp2515.sendMessage(MCP2515::TXB1, &canMsg);
- delay(4);
- }</font></font></font>
復(fù)制代碼 xm_motor.h
- #include "Arduino.h"
- #include <SPI.h>
- #include "mcp2515.h"
-
- #define pi 3.14159265359f
- #define Communication_Type_MotorEnable 0x03
- #define Master_CAN_ID 0x00
- #define CanID 0x01
- #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.0f
- #define MAX_P 720
- #define MIN_P -720
-
- #define Communication_Type_GetID 0x00 //獲取設(shè)備的ID和64位MCU唯一標(biāo)識符
- #define Communication_Type_MotionControl 0x01 //用來向主機(jī)發(fā)送控制指令
- #define Communication_Type_MotorRequest 0x02 //用來向主機(jī)反饋電機(jī)運(yùn)行狀態(tài)
- #define Communication_Type_MotorEnable 0x03 //電機(jī)使能運(yùn)行
- #define Communication_Type_MotorStop 0x04 //電機(jī)停止運(yùn)行
- #define Communication_Type_SetPosZero 0x06 //設(shè)置電機(jī)機(jī)械零位
- #define Communication_Type_CanID 0x07 //更改當(dāng)前電機(jī)CAN_ID
- #define Communication_Type_Control_Mode 0x12
- #define Communication_Type_GetSingleParameter 0x11 //讀取單個(gè)參數(shù)
- #define Communication_Type_SetSingleParameter 0x12 //設(shè)定單個(gè)參數(shù)
- #define Communication_Type_ErrorFeedback 0x15 //故障反饋幀
- //參數(shù)讀取宏定義
- #define Run_mode 0x7005
- #define Iq_Ref 0x7006
- #define Spd_Ref 0x700A
- #define Limit_Torque 0x700B
- #define Cur_Kp 0x7010
- #define Cur_Ki 0x7011
- #define Cur_Filt_Gain 0x7014
- #define Loc_Ref 0x7016
- #define Limit_Spd 0x7017
- #define Limit_Cur 0x7018
- #define Gain_Angle 720/32767.0
- #define Bias_Angle 0x8000
- #define Gain_Speed 30/32767.0
- #define Bias_Speed 0x8000
- #define Gain_Torque 12/32767.0
- #define Bias_Torque 0x8000
- #define Temp_Gain 0.1
-
- #define Motor_Error 0x00
- #define Motor_OK 0X01
- enum CONTROL_MODE //控制模式定義
- {
- Motion_mode = 0,//運(yùn)控模式
- Position_mode, //位置模式
- Speed_mode, //速度模式
- Current_mode //電流模式
- };
- enum ERROR_TAG //錯(cuò)誤回傳對照
- {
- 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//未標(biāo)定
- };
- typedef struct{ //小米電機(jī)結(jié)構(gòu)體
- uint8_t CAN_ID; //CAN ID
- uint8_t MCU_ID; //MCU唯一標(biāo)識符【后8位,共64位】
- float Angle; //回傳角度
- float Speed; //回傳速度
- float Torque; //回傳力矩
- float Temp; //回傳溫度
-
- uint16_t set_current;
- uint16_t set_speed;
- uint16_t set_position;
-
- uint8_t error_code;
-
- float Angle_Bias;
-
- }MI_Motor;
- extern MI_Motor mi_motor;//預(yù)先定義1個(gè)小米電機(jī)
-
- void xm_can_start();
- void motor_enable( uint8_t id=1 ) ;
- void motor_mode( uint8_t id ,char type );
- void motor_speed_value( uint8_t id ,float speed_ref );//-30rad-30rad
- void motor_yk( uint8_t id ,float torque, float MechPosition, float speed, float kp, float kd );
- void motor_pos_zero( uint8_t id=1 ); //位置置0
- void motor_pos_value( uint8_t id ,float speed_ref );
- void motor_pow_value( uint8_t id , float torque,float limit_cur ,float kp,float kd );
-
- int filter(int queue[], char n) ; //數(shù)值過濾
- int check(byte ao_port, byte n); //獲取ad口電壓</font></font></font>
復(fù)制代碼
main.ino
- #include "xm_motor.h"
- String comdata = ""; //藍(lán)牙字符
- void setup() {
- while (!Serial)
- ;
- Serial.begin(115200);
-
- xm_can_start(); //初始化can設(shè)置
- motor_enable(1); //使能id 1電機(jī)
- motor_pos_zero(1); //位置置0
- motor_mode(1, 1); //電機(jī)運(yùn)行模式 電機(jī)canid 模式值 1位置模式2速度模式 3 電流模式0運(yùn)控模式
- motor_pow_value(1, 30, 20, 0.2, 0.13); //uint8_t id , float torque 位置模式速度限制 ,float limit_cur ,float kp=0.8,float ki=0.13 id 速度 電流限制,kp,kd 速度 0~30rad/s 6.28rad 等于1圈 電流最大23A
- Serial.println("Example: Write to CAN");
- }
- void loop() {
-
- int speed_value = 100;
- int speed_valueb = map(speed_value, 0, 1023, 0, 30); //前進(jìn)模擬量
- float bb = (float)speed_value;
- bb = bb / 163.9423;
- if (bb > 6.2) { bb = 6.2; }
- motor_pos_value(1, bb); //電機(jī)位置模式賦值,id,位置角度rad 2派=360度。
-
- delay(20);
- }
復(fù)制代碼
在main.ino中更改loop里speed_value的值即可更改角度,在0-1023范圍內(nèi)進(jìn)行更改。
|
評分
-
查看全部評分
|