当前位置:   article > 正文

小米电机CyberGear--STM32控制:绝对零点设置及位置模式正弦运动_小米电机运控模式

小米电机运控模式

本文参考了小米电机CyberGear STM32HAL 使用指南_小米电机瞬时电流串口指令-CSDN博客(没有关注提供代码中VOFA+通信内容),借助HAL库仅控制单个小米电机。可以实现小米电机绝对零点的设置,以及在位置模式下的正弦运动(运控模式经测试页是可行的),并向电脑反馈电机信息。

CyberGear官方提供的文档:小米企业网盘 -- 分享文件 (mioffice.cn),提取码QDD1,包含说明书,固件包,电机三维图,上位机软件

注意:笔者在使用之前对CAN无了解,仅对串口传输有较充分的认识,调试CyberGear前搞清楚扩展帧和数据区后,根据官方说明书4.2章节以及参考博客,可以顺利对电机开发。

1.硬件

硬石的板子Stm32F407(含CAN接口),电源使用学生电源24V,电机接口使用网购的XT30PB(2+2)带线(不到20元),使用了板上的1个串口(通过仿真器与电脑通信)和CAN接口。

具体连接:通过仿真器TX\RX(板上USB接电脑同样可行,设置好对应串口即可)和板上一串口的RX\TX相连,电机引出线连到板上CAN口。

2.机械限位

SW2022绘制(低版本无法打开),3D打印制作,运动范围为60度。

结构中白色部分是一个120度的运动范围,对应可以做±60的运动。

注意:左图红色部分,电机自带的背面三颗螺钉无法拆卸

具体结构分享至网盘链接:https://pan.baidu.com/s/1mzTPC6rWjv7DBBEoDq2fhQ 
提取码:1234 

3.cubeMX设置

芯片选择其他初始设置在此不赘述,仅介绍关键内容

1)时钟

STM32F407芯片,时钟如下

2)CAN

电机默认波特率1Mbps,需要根据芯片时钟对CAN参数设置,笔者直接借助GPT,要求其根据上述时钟,分析产生1Mbps的波特率,设置如下

使能接收中断,具体是RX0还是RX1,要根据自己的板子确定,可参考他人博客。

3)板子与电脑串口通信(仅电脑接收板子传输的数据)

我使用仿真器的RX接口和32板的USART1与电脑连接;直接对应串口USB与电脑接也是可以

UART4异步通信,波特率115200,接收DMA;

4)TIM2

每隔10ms发送电机信息到电脑,不一定要定时器,也可以每次收到反馈之后,立刻把此次接收的数据传输给电脑

5)NVIC

4.控制程序

1)cybergear与电机交互部分,通信协议

xiaomi_driver.h,存储其定义的一些参数,cybergear.h直接引用即可

  1. #ifndef _XIAOMI_DRIVER_H_
  2. #define _XIAOMI_DRIVER_H_
  3. #include "main.h"
  4. typedef enum {
  5. RunMode_idx = 0x7005,
  6. IqRef_idx = 0x7006,
  7. SpdRef_idx = 0x700A,
  8. LimitTorque_idx = 0x700B,
  9. CurKp_idx = 0x7010,
  10. CurKi_idx = 0x7011,
  11. CurFiltGain_idx = 0x7014,
  12. LocRef_idx = 0x7016,
  13. LimitSpd_idx = 0x7017,
  14. LimitCur_idx = 0x7018,
  15. MechPos_idx = 0x7019,
  16. IqFilt_idx = 0x701A,
  17. MechVel_idx = 0x701B,
  18. Vbus_idx = 0x701C,
  19. Rotation_idx = 0x701D,
  20. LocKp_idx = 0x701E,
  21. SpdKp_idx = 0x7020,
  22. SpdKi_idx = 0x7020
  23. } ControlTable;
  24. typedef enum {
  25. RunMode_Typ = 's',
  26. IqRef_Typ = 'f',
  27. SpdRef_Typ = 'f',
  28. LimitTorque_Typ = 'f',
  29. CurKp_Typ = 'f',
  30. CurKi_Typ = 'f',
  31. CurFiltGain_Typ = 'f',
  32. LocRef_Typ = 'f',
  33. LimitSpd_Typ = 'f',
  34. LimitCur_Typ = 'f',
  35. MechPos_Typ = 'f',
  36. IqFilt_Typ = 'f',
  37. MechVel_Typ = 'f',
  38. Vbus_Typ = 'f',
  39. Rotation_Typ = 's',
  40. LocKp_Typ = 'f',
  41. SpdKp_Typ = 'f',
  42. SpdKi_Typ = 'f'
  43. } ControlTableType;
  44. //控制参数最值,谨慎更改
  45. #define P_MIN -12.5f
  46. #define P_MAX 12.5f
  47. #define V_MIN -30.0f
  48. #define V_MAX 30.0f
  49. #define KP_MIN 0.0f
  50. #define KP_MAX 500.0f
  51. #define KD_MIN 0.0f
  52. #define KD_MAX 5.0f
  53. #define T_MIN -12.0f
  54. #define T_MAX 12.0f
  55. #define MAX_P 720
  56. #define MIN_P -720
  57. //控制命令宏定义
  58. #define Communication_Type_GetID 0x00 //获取设备的ID和64位MCU唯一标识符
  59. #define Communication_Type_MotionControl 0x01 //用来向主机发送控制指令
  60. #define Communication_Type_MotorRequest 0x02 //用来向主机反馈电机运行状态
  61. #define Communication_Type_MotorEnable 0x03 //电机使能运行
  62. #define Communication_Type_MotorStop 0x04 //电机停止运行
  63. #define Communication_Type_SetPosZero 0x06 //设置电机机械零位
  64. #define Communication_Type_CanID 0x07 //更改当前电机CAN_ID
  65. #define Communication_Type_Control_Mode 0x12
  66. #define Communication_Type_GetSingleParameter 0x11 //读取单个参数
  67. #define Communication_Type_SetSingleParameter 0x12 //设定单个参数
  68. #define Communication_Type_ErrorFeedback 0x15
  69. enum CONTROL_MODE //控制模式定义
  70. {
  71. Motion_mode = 0,//运控模式
  72. Position_mode, //位置模式
  73. Velcity_mode, //位置模式
  74. Current_mode //电流模式
  75. };
  76. enum ERROR_TAG //错误回传对照
  77. {
  78. OK = 0,//无故障
  79. BAT_LOW_ERR = 1,//欠压故障
  80. OVER_CURRENT_ERR = 2,//过流
  81. OVER_TEMP_ERR = 3,//过温
  82. MAGNETIC_ERR = 4,//磁编码故障
  83. HALL_ERR_ERR = 5,//HALL编码故障
  84. NO_CALIBRATION_ERR = 6//未标定
  85. };
  86. #endif

cybergear.h,协议部分(含设置电机等),暂未提供电脑接收数据相关设置(后续补充)。

注:修正了参考博客中设置电机零位中的错误,参考电机说明书内容

  1. #ifndef __CYBERGEAR_H
  2. #define __CYBERGEAR_H
  3. #include "main.h"
  4. #include "can.h"
  5. #include "xiaomi_driver.h"
  6. #include "pc_communication.h"
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. extern volatile float motor_info[4];
  11. //主机CANID设置
  12. #define Master_CAN_ID 0x00 //主机ID
  13. //参数读取宏定义
  14. #define Gain_Angle 720/32767.0
  15. #define Bias_Angle 0x8000
  16. #define Gain_Speed 30/32767.0
  17. #define Bias_Speed 0x8000
  18. #define Gain_Torque 12/32767.0
  19. #define Bias_Torque 0x8000
  20. #define Temp_Gain 0.1
  21. #define Motor_Error 0x00
  22. #define Motor_OK 0X01
  23. typedef enum
  24. {
  25. Unit_Default,
  26. Unit_Deg=1,
  27. Unit_RPM=1,
  28. Unit_mA=1
  29. }Unit;
  30. typedef struct{
  31. volatile float freq;
  32. volatile float amp;//角度值
  33. volatile float delay;
  34. volatile float offset;
  35. volatile float downRatio;
  36. } SinMotion;
  37. typedef struct{ //小米电机结构体
  38. uint8_t CAN_ID; //CAN ID
  39. uint8_t MCU_ID; //MCU唯一标识符[后8位,共64位]
  40. float des_cur;
  41. float des_vel;
  42. float des_pos;
  43. float pre_cur;
  44. float pre_vel;
  45. float pre_pos;
  46. float pre_tor;
  47. float pre_temperature;
  48. uint8_t error_code;
  49. //零位选择通过Init_CyberZero()设置
  50. float ini_tor;
  51. float ini_vel;
  52. float ini_pos;
  53. float ini_kp, sin_kp;
  54. float ini_kd, sin_kd;
  55. //最大限制
  56. float max_tor;
  57. float max_pos;
  58. float max_vel;
  59. float tor_threshold;
  60. float zero_pos;
  61. SinMotion MotionPara;
  62. }Cyber_Motor;
  63. extern Cyber_Motor Cyber;
  64. /*****************************初始化*****************************/
  65. void Init_Cyber(Cyber_Motor *Motor, uint8_t Can_Id);
  66. void Start_Cyber(Cyber_Motor *Motor);
  67. void Stop_Cyber(Cyber_Motor *Motor, uint8_t clear_error);
  68. /*****************************设置电机参数*****************************/
  69. void Set_Cyber_Mode(Cyber_Motor *Motor, uint8_t Mode);
  70. void Set_Cyber_ZeroPos(Cyber_Motor *Motor);
  71. void Set_Cyber_Pos(Cyber_Motor *Motor, float value);//仅位置模式, value单位为Deg
  72. void Set_Cyber_limitSp(Cyber_Motor *Motor, float value);//同时设置电机结构体中的max_spd, value单位为RPM
  73. void Set_Cyber_limitTor(Cyber_Motor *Motor, float value);//同时设置电机结构体中的max_tor, value单位为Nm
  74. void Set_Cyber_RotNum(Cyber_Motor *Motor, float value);//设置电机当前圈数
  75. void Read_Cyber_Pos(Cyber_Motor *Motor);//获得反馈,发送位置可以时刻获得位置,这个呢
  76. /*****************************运动控制模式*****************************/
  77. void Cyber_ControlMode(Cyber_Motor *Motor,float tor, float vel_rads, float pos_rad, float kp, float kd);//仅运控模式
  78. /*****************************反馈帧处理回调函数 负责接回传信息 *****************************/
  79. void request_motor_feedback(Cyber_Motor *Motor);
  80. void Motor_Data_Handler(Cyber_Motor *Motor,uint8_t DataFrame[8],uint32_t IDFrame);
  81. /*****************************暂时没用,电机参数读取设置*****************************/
  82. void Check_Cyber(uint8_t ID);
  83. void set_CANID_cybergear(Cyber_Motor *Motor, uint8_t CAN_ID);
  84. void Set_Cyber_Cur(Cyber_Motor *Motor, float Current);
  85. uint32_t Get_Motor_ID(uint32_t CAN_ID_Frame);
  86. /*****************************电机协议*****************************/
  87. float uint16_to_float(uint16_t x,float x_min,float x_max,int bits);
  88. int float_to_uint(float x, float x_min, float x_max, int bits);
  89. void Set_Cyber_Parameter(Cyber_Motor *Motor,uint16_t Index,float Value,char Value_type);
  90. void Set_Cyber_Parameter(Cyber_Motor *Motor,uint16_t Index,float Value,char Value_type);
  91. void Read_Cyber_Parameter(Cyber_Motor *Motor,uint16_t Index);
  92. #ifdef __cplusplus
  93. }
  94. #endif
  95. #endif

cybergear.c

  1. #include "main.h"
  2. #include "can.h"
  3. #include "cybergear.h"
  4. #include "math.h"
  5. Cyber_Motor Cyber;//小米电机定义
  6. CAN_RxHeaderTypeDef rxMsg;//发送接收结构体
  7. CAN_TxHeaderTypeDef txMsg;//发送配置结构体
  8. uint8_t rx_data[8]; //接收数据
  9. uint32_t Motor_Can_ID; //接收数据电机ID
  10. uint8_t byte[4]; //转换临时数据
  11. uint32_t send_mail_box = {0};//NONE
  12. #define can_txd() HAL_CAN_AddTxMessage(&hcan1, &txMsg, tx_data, &send_mail_box)//CAN发送宏定义
  13. const float pi = 3.14159265358979323846f;
  14. /***************************************初始化**************************************/
  15. //@brief 小米电机初始化参数
  16. void Init_Cyber(Cyber_Motor *Motor,uint8_t Can_Id)
  17. {
  18. txMsg.StdId = 0; //配置CAN发送:标准帧清零
  19. txMsg.ExtId = 0; //配置CAN发送:扩展帧清零
  20. txMsg.IDE = CAN_ID_EXT; //配置CAN发送:扩展帧
  21. txMsg.RTR = CAN_RTR_DATA; //配置CAN发送:数据帧
  22. txMsg.DLC = 0x08; //配置CAN发送:数据长度
  23. Motor->CAN_ID=Can_Id; //ID设置
  24. }
  25. //@brief 使能电机
  26. void Start_Cyber(Cyber_Motor *Motor)
  27. {
  28. uint8_t tx_data[8] = {0};
  29. txMsg.ExtId = Communication_Type_MotorEnable<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  30. can_txd();
  31. }
  32. //@brief 停止电机
  33. void Stop_Cyber(Cyber_Motor *Motor,uint8_t clear_error)
  34. {
  35. uint8_t tx_data[8]={0};
  36. tx_data[0]=clear_error;//清除错误位设置 clear_error=1时清除故障
  37. txMsg.ExtId = Communication_Type_MotorStop<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  38. can_txd();
  39. }
  40. /*****************************设置电机参数*****************************/
  41. //@brief 设置电机模式(必须停止时调整!)
  42. void Set_Cyber_Mode(Cyber_Motor *Motor,uint8_t Mode)
  43. {
  44. Set_Cyber_Parameter(Motor,RunMode_idx,Mode,'s');
  45. }
  46. //@brief 设置电机位置,单位弧度;补充value为角度时的内容
  47. void Set_Cyber_Pos(Cyber_Motor *Motor, float value)
  48. {
  49. float pos = value * pi / 180;
  50. Set_Cyber_Parameter(Motor, LocRef_idx, pos, 'f');
  51. Motor->des_pos = value;
  52. }
  53. //@brief 设置电机当前位置为零点
  54. void Set_Cyber_ZeroPos(Cyber_Motor *Motor)
  55. {
  56. uint8_t tx_data[8]={0};
  57. tx_data[0]=1;
  58. txMsg.ExtId = Communication_Type_SetPosZero<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  59. can_txd();
  60. }
  61. //@brief 设置电机运动限速,单位弧度/s
  62. void Set_Cyber_limitSp(Cyber_Motor *Motor, float value) {
  63. Set_Cyber_Parameter(Motor, LimitSpd_idx, value, 'f');
  64. Motor->max_vel = value;
  65. }
  66. //@brief 设置电机运动最大扭矩,单位Nm
  67. void Set_Cyber_limitTor(Cyber_Motor *Motor, float value)
  68. {
  69. Set_Cyber_Parameter(Motor, LimitTorque_idx, value, 'f');
  70. Motor->max_tor = value;
  71. }
  72. //@brief 设置电机当前圈数
  73. void Set_Cyber_RotNum(Cyber_Motor *Motor, float value)
  74. {
  75. Set_Cyber_Parameter(Motor, Rotation_idx, value, 'f');
  76. //Motor->max_tor = value;
  77. }
  78. void Read_Cyber_Pos(Cyber_Motor *Motor)
  79. {
  80. Read_Cyber_Parameter(Motor, LocRef_idx);
  81. }
  82. /***************************************反馈帧处理回调函数 负责接回传信息 ***************************************/
  83. //反馈电机信息
  84. void request_motor_feedback(Cyber_Motor *Motor)
  85. {
  86. uint8_t tx_data[8]={0};
  87. txMsg.ExtId = Communication_Type_MotorRequest<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  88. can_txd();
  89. }
  90. /**
  91. * @brief 电机回复帧数据处理函数
  92. * @param[in] Motor:对应控制电机结构体
  93. * @param[in] DataFrame:数据帧
  94. * @param[in] IDFrame:扩展ID帧
  95. * @retval None
  96. */
  97. void Motor_Data_Handler(Cyber_Motor *Motor,uint8_t DataFrame[8],uint32_t IDFrame)
  98. {
  99. Motor->pre_pos=uint16_to_float(DataFrame[0]<<8|DataFrame[1],MIN_P,MAX_P,16);//DataFrame[0]<<8|DataFrame[1]低8位和高8位合并
  100. Motor->pre_vel=uint16_to_float(DataFrame[2]<<8|DataFrame[3],V_MIN,V_MAX,16);
  101. Motor->pre_tor=uint16_to_float(DataFrame[4]<<8|DataFrame[5],T_MIN,T_MAX,16);
  102. Motor->pre_temperature=(DataFrame[6]<<8|DataFrame[7])*Temp_Gain;
  103. Motor->error_code=(IDFrame&0x1F0000)>>16;
  104. }
  105. /***************************************电机信息接受和发送**************************************/
  106. /**
  107. * @brief hal库CAN回调函数,接收电机数据
  108. * @param[in] hcan:CAN句柄指针
  109. * @retval none
  110. */
  111. void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
  112. {
  113. HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &rxMsg, rx_data);//接收数据
  114. Motor_Data_Handler(&Cyber,rx_data,rxMsg.ExtId);
  115. }
  116. //@brief 小米运控模式指令
  117. void Cyber_ControlMode(Cyber_Motor *Motor,float tor, float vel_rpm, float pos_deg, float kp, float kd)
  118. {
  119. float pos_rad = pos_deg * pi / 180;
  120. float vel_rads = vel_rpm * 30 / pi;
  121. uint8_t tx_data[8];//发送数据初始化
  122. //装填发送数据
  123. tx_data[0]=float_to_uint(pos_rad,P_MIN,P_MAX,16)>>8;
  124. tx_data[1]=float_to_uint(pos_rad,P_MIN,P_MAX,16);
  125. tx_data[2]=float_to_uint(vel_rads,V_MIN,V_MAX,16)>>8;
  126. tx_data[3]=float_to_uint(vel_rads,V_MIN,V_MAX,16);
  127. tx_data[4]=float_to_uint(kp,KP_MIN,KP_MAX,16)>>8;
  128. tx_data[5]=float_to_uint(kp,KP_MIN,KP_MAX,16);
  129. tx_data[6]=float_to_uint(kd,KD_MIN,KD_MAX,16)>>8;
  130. tx_data[7]=float_to_uint(kd,KD_MIN,KD_MAX,16);
  131. txMsg.ExtId = Communication_Type_MotionControl<<24|float_to_uint(tor,T_MIN,T_MAX,16)<<8|Motor->CAN_ID;//装填扩展帧数据
  132. can_txd();
  133. }
  134. /***************************************暂时不用***************************************/
  135. //@brief 设置电机CANID
  136. void set_CANID_cybergear(Cyber_Motor *Motor,uint8_t CAN_ID)
  137. {
  138. uint8_t tx_data[8]={0};
  139. txMsg.ExtId = Communication_Type_CanID<<24|CAN_ID<<16|Master_CAN_ID<<8|Motor->CAN_ID;
  140. Motor->CAN_ID = CAN_ID;//将新的ID导入电机结构体
  141. can_txd();
  142. }
  143. //@brief 电流控制模式下设置电流
  144. void Set_Cyber_Cur(Cyber_Motor *Motor,float Current)
  145. {
  146. Set_Cyber_Parameter(Motor,IqRef_idx,Current,'f');
  147. }
  148. /**
  149. * @brief 提取电机回复帧扩展ID中的电机CANID
  150. * @param[in] CAN_ID_Frame:电机回复帧中的扩展CANID
  151. * @retval 电机CANID
  152. */
  153. uint32_t Get_Motor_ID(uint32_t CAN_ID_Frame)
  154. {
  155. return (CAN_ID_Frame&0xFFFF)>>8;
  156. }
  157. //@brief 小米电机ID检查
  158. void Check_cyber(uint8_t ID)
  159. {
  160. uint8_t tx_data[8] = {0};
  161. txMsg.ExtId = Communication_Type_GetID<<24|Master_CAN_ID<<8|ID;
  162. can_txd();
  163. }
  164. /***************************************电机内部协议***************************************/
  165. /**
  166. * @brief 浮点数转4字节函数
  167. * @param[in] f:浮点数
  168. * @retval 4字节数组
  169. * @description : IEEE 754 协议
  170. */
  171. uint8_t* Float_to_Byte(float f)
  172. {
  173. unsigned long longdata = 0;
  174. longdata = *(unsigned long*)&f;
  175. byte[0] = (longdata & 0xFF000000) >> 24;
  176. byte[1] = (longdata & 0x00FF0000) >> 16;
  177. byte[2] = (longdata & 0x0000FF00) >> 8;
  178. byte[3] = (longdata & 0x000000FF);
  179. return byte;
  180. }
  181. /**
  182. * @brief 小米电机回文16位数据转浮点
  183. * @param[in] x:16位回文
  184. * @param[in] x_min:对应参数下限
  185. * @param[in] x_max:对应参数上限
  186. * @param[in] bits:参数位数
  187. * @retval 返回浮点值
  188. */
  189. float uint16_to_float(uint16_t x,float x_min,float x_max,int bits)
  190. {
  191. uint32_t span = (1 << bits) - 1;
  192. float offset = x_max - x_min;
  193. return offset * x / span + x_min;
  194. }
  195. /**
  196. * @brief 小米电机发送浮点转16位数据
  197. * @param[in] x:浮点
  198. * @param[in] x_min:对应参数下限
  199. * @param[in] x_max:对应参数上限
  200. * @param[in] bits:参数位数
  201. * @retval 返回浮点值
  202. */
  203. int float_to_uint(float x, float x_min, float x_max, int bits)
  204. {
  205. float span = x_max - x_min;
  206. float offset = x_min;
  207. if(x > x_max) x=x_max;
  208. else if(x < x_min) x= x_min;
  209. return (int) ((x-offset)*((float)((1<<bits)-1))/span);
  210. }
  211. /**
  212. * @brief 写入电机参数
  213. * @param[in] Motor:对应控制电机结构体
  214. * @param[in] Index:写入参数对应地址
  215. * @param[in] Value:写入参数值
  216. * @param[in] Value_type:写入参数数据类型
  217. * @retval none
  218. */
  219. void Set_Cyber_Parameter(Cyber_Motor *Motor,uint16_t Index,float Value,char Value_type)
  220. {
  221. uint8_t tx_data[8]= {0};
  222. txMsg.ExtId = Communication_Type_SetSingleParameter<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  223. memcpy(&tx_data[0],&Index,2);
  224. if(Value_type == 'f')
  225. {
  226. memcpy(&tx_data[4], &Value, sizeof(Value));
  227. }
  228. else if(Value_type == 's')
  229. {
  230. tx_data[4]=(uint8_t)Value;
  231. }
  232. can_txd();
  233. HAL_Delay(1);
  234. }
  235. /**
  236. * @brief 读取电机参数
  237. * @param[in] Motor:对应控制电机结构体
  238. * @param[in] Index:写入参数对应地址
  239. * @param[in] Value:写入参数值
  240. * @param[in] Value_type:写入参数数据类型
  241. * @retval none
  242. */
  243. void Read_Cyber_Parameter(Cyber_Motor *Motor,uint16_t Index)
  244. {
  245. uint8_t tx_data[8]= {0};
  246. txMsg.ExtId = Communication_Type_GetSingleParameter<<24|Master_CAN_ID<<8|Motor->CAN_ID;
  247. tx_data[0]=Index;
  248. tx_data[1]=Index>>8;
  249. can_txd();
  250. }

2)具体控制完成零点设置以及位置模式下的正弦运动

注:修改模式为运控模式,并将set_cyber_pos修改为cybergear.h/c中的cyber_controlMode同样可以实现正弦运动函数;

cybermotor.h

  1. #ifndef __CYBERMOTOR_H
  2. #define __CYBERMOTOR_H
  3. #include "cybergear.h"
  4. #include <math.h>
  5. //该文件应该包括 绝对零点设置;正弦运动设置;
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*****************************获取期望零位*****************************/
  10. void Init_CyberZero(Cyber_Motor *Motor);
  11. void Init_Sin(Cyber_Motor *Motor);
  12. void Setting_AbsoluteZero(Cyber_Motor *Motor);
  13. void Motion_CyberSin(Cyber_Motor *Motor);
  14. #ifdef __cplusplus
  15. }
  16. #endif
  17. #endif

cybermotor.cpp

  1. #include "cybermotor.h"
  2. const float pi = 3.14159265358979323846f;
  3. //@brief 绝对零点设置,包括电机初始化,运控模式达到极限值;
  4. void Setting_AbsoluteZero(Cyber_Motor *Motor)
  5. {
  6. Init_Cyber(Motor, 0x7F);
  7. //设置当前位置为0位
  8. Init_CyberZero(Motor);//初始化电机结构体,即运控模式的参数Cyber_ControlMode
  9. Set_Cyber_Mode(Motor,Position_mode);
  10. //Set_Cyber_RotNum(Motor, 0);
  11. Start_Cyber(Motor);//使能电机
  12. Set_Cyber_RotNum(Motor, 0);
  13. Set_Cyber_ZeroPos(Motor);
  14. Set_Cyber_limitSp(Motor,1);
  15. Set_Cyber_limitTor(Motor,0.2);
  16. HAL_Delay(100);
  17. Set_Cyber_Pos(Motor, 10);
  18. HAL_Delay(100);
  19. Set_Cyber_Pos(Motor, 20);
  20. HAL_Delay(100);
  21. Set_Cyber_Pos(Motor, 40);
  22. HAL_Delay(100);
  23. Set_Cyber_Pos(Motor, 130);
  24. HAL_Delay(100);
  25. while (1)
  26. {
  27. //Set_Cyber_Pos(Motor, 30);
  28. Set_Cyber_RotNum(Motor, 0);
  29. // 检查力矩和速度
  30. if (Motor->pre_vel < 0.01)
  31. {
  32. Set_Cyber_ZeroPos(Motor);
  33. Set_Cyber_limitSp(Motor,6);
  34. Set_Cyber_Pos(Motor, -60);
  35. HAL_Delay(3000);
  36. //Set_Cyber_ZeroPos(Motor);
  37. //break;
  38. Motion_CyberSin(Motor);
  39. }
  40. }
  41. }
  42. // 控制电机正弦运动的函数
  43. void Motion_CyberSin(Cyber_Motor *Motor)
  44. {
  45. Init_Sin(Motor);
  46. uint32_t current_time;
  47. float position;
  48. //HAL_Delay(1000);
  49. float period = 1/Motor->MotionPara.freq;
  50. //float periodPositive = period * Motor->downRatio;
  51. //float periodNegative = period - periodPositive;
  52. // Init_Cyber(Motor, 0x7F);
  53. // Set_Cyber_ZeroPos(Motor);
  54. Set_Cyber_limitSp(Motor, 5);
  55. // 循环持续指定的时间
  56. while(1)
  57. {
  58. //float amp_rad = Motor->MotionPara.amp * pi/180;
  59. current_time = HAL_GetTick(); // 更新当前时间
  60. position = Motor->MotionPara.amp * sinf(2 * pi * Motor->MotionPara.freq * (current_time / 1000.0f))-60;
  61. Motor->des_pos = position / pi * 180;
  62. Set_Cyber_Pos(Motor, position);
  63. // 添加延时来控制更新频率
  64. HAL_Delay(3);
  65. }
  66. }
  67. /*****************************零位初始化*****************************/
  68. void Init_CyberZero(Cyber_Motor *Motor)
  69. {
  70. Motor->ini_tor=0.1;
  71. Motor->ini_vel=0;
  72. Motor->ini_pos=120;
  73. Motor->ini_kp=0.8;
  74. Motor->ini_kd=0.3;
  75. Motor->tor_threshold=0.15;
  76. }
  77. /*****************************实际驱动函数*****************************/
  78. void Init_Sin(Cyber_Motor *Motor)
  79. {
  80. Motor->sin_kp = 3;
  81. Motor->sin_kd = 0.5;
  82. Motor->MotionPara.amp=20;//角度值
  83. Motor->MotionPara.freq=3;
  84. Motor->MotionPara.delay=0;
  85. Motor->MotionPara.offset=0;
  86. Motor->MotionPara.downRatio=0.5;//上下扑动的duration相同
  87. }

3)pc_communication.h/c,发送当前位置和电流或其他数据到PC

在定时器回调函数中调用curve_Display函数实现发送;使用VOFA+(一个上位机软件,类似串口助手)的FireWater显示数据,通过curve_Display实现向电脑端的发送,不使用curveDisplay,直接printf也是可以的

pc_communication.h

  1. #ifndef __PCCOM_H
  2. #define __PCCOM_H
  3. #include "stm32f4xx_hal.h" // 根据你的STM32系列调整,如stm32f1xx_hal.h
  4. #include "dma.h" // 包含 DMA 初始化和配置的头文件
  5. #include <string.h> // 用于 strlen 函数
  6. #include <stdarg.h> // 用于可变参数函数
  7. #include <stdio.h>
  8. #include "usart.h"
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. void PC_Communication(UART_HandleTypeDef* huart, const char* format, ...);
  13. void curve_Display(float a, float b, float c, float d);
  14. #ifdef __cplusplus
  15. }
  16. #endif
  17. #endif

pc_communication.c

  1. #include "pc_communication.h"
  2. volatile float motor_info[5];//不能设置为uint_8,必须要和实际的Motor结构体的一致,否则无法发送
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. void PC_Communication(UART_HandleTypeDef* huart, const char* format, ...) {
  7. static char buffer[1000];
  8. va_list args;
  9. va_start(args, format);
  10. vsnprintf(buffer, sizeof(buffer), format, args);
  11. va_end(args);
  12. HAL_UART_Transmit_DMA(huart, (uint8_t*)buffer, strlen(buffer));
  13. }
  14. void curve_Display(float a, float b, float c, float d)
  15. {
  16. PC_Communication(&huart1, "d: %.2f, %.2f, %.2f, %.2f\r\n", a, b, c, d);
  17. }
  18. #ifdef __cplusplus
  19. |
  20. #endif

4)定时器回调函数,补充在tim.c最下面

  1. /**
  2. * @brief hal库TIM回调函数,发送数据到电脑
  3. * @param[in] hcan:TIM句柄指针
  4. * @retval none
  5. */
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  7. {
  8. if (htim->Instance == TIM2) // 检查是哪个定时器产生了中断
  9. {
  10. motor_info[0] = Cyber.des_pos;
  11. motor_info[1] = Cyber.pre_pos;
  12. motor_info[2] = Cyber.pre_vel;
  13. motor_info[3] = Cyber.pre_tor;
  14. //motor_info[4] = Cyber.pre_temperature;
  15. //printf("Desired Position: %f\n", motor_info[0]);
  16. //printf("Present Position: %f\n", motor_info[1]);
  17. //printf("Present Velocity: %f\n", motor_info[2]);
  18. //printf("Present Current: %f\n", motor_info[3]);
  19. curve_Display(motor_info[0],motor_info[1],motor_info[2],motor_info[3]);
  20. }
  21. }

每隔10ms,向电机反馈电机的数据

注意:根据说明书,发送一次,只能在发送的时刻瞬间收到一次电机反馈。

例如,如果仅单次发送设置位置1rad,仅在发送的瞬间反馈一次位置命令。如果想要获取电机的运动曲线,必须在while中发送才能绘制相关运动曲线图。

5.绝对零点实现方式解释

1 具体实现在CyberMotor.h/cpp中Setting_AbsoluteZero:

设置运动模式->使能电机->设置当前位置为零点->设置位置模式限速/扭矩->设置位置->进入循环

循环中:设置电机圈数(目的,获取电机反馈(参考说明书,获取通信类型2的反馈),进而获取电机的位置速度扭矩信息)->判断当前速度大小是否小于一个很小的值->如果小于说明电机达到限位,即进入if条件句中->设置当前位置为零点->调整电机限速/扭矩->回到我需要正弦运动的位置(-60的位置)->delay等待达到实际位置(可以修改一下判断是否达到当前位置,通过反馈,而不是delay)->正弦运动函数

2. 遇到的一些问题

使能电机,并设置一个目标位置后,电机会先顺逆运动(方向每一次都不一样)1s多,才会按实际要求运动。因为此,笔者以为每次的位置模式启动后,正角度对应的不是固定顺时针/逆时针;实际是对应的。

可能原因:

1)初始Kp,Kd设置不当; 2)本身传感器可能存在误差; 3)电机本身控制算法中存在误差修正或者启动过程中的初始调整

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/894612
推荐阅读
相关标签
  

闽ICP备14008679号