当前位置:   article > 正文

Robomaster电控组小白的学习经验分享(一)——用大疆C型开发板控制GM6020电机转动到既定角度_大疆c板

大疆c板

88ab4432dec2153611cbbc8f98d96f0f

一、认识硬件

1、大疆C型开发板

        我们可以从Robomaster官网上下载C板的用户使用手册,在编写代码的时候用户开发手册往往非常重要。引脚配置、IO说明等信息都可以从用户手册上获得。

27a068cc327d411d9b2ff9f2cc98d881.png

2、GM6020电机

        GM6020的说明手册也可以从Robomaster的官网上下载,网址我会在下面给出。GM6020电机自带编码器,特点在于扭矩大,非常适合用来控制云台的航向和俯仰。

a46b311224c94c1d88295a2195ff34ce.png

       电机的ID切换可以通过电机底下的拨码开关来设置,拨码开关有bit0、bit2、bit3三位,符合二进制编码,详细可见电机使用说明书

2cf71f9ceeb2433c8c2e73a7cb74d832.png

b452ffa834dc45af970629b041e61bf7.png

3、网址

大疆C型开发板用户手册

GM6020使用说明书

二、代码编写

1、CubeMX配置

(1)开启高速和速度外部时钟

f1ad783d3f6d4fb89720bf62efba8b2b.png

2d93343d3ca4489696087eb98a8590e5.png

系统时钟设置为168MHz(最大为180MHz),设置为180MHz也是可以的

9be29282de3444dbb8243e89e864d1fd.png

 (2)debug设置成SW

9a3125520b1c48a790d75812aaed975b.png

 (3)打开CAN1外设

ff52b7e353ae49c3804f53797625f022.png

切记在打开CAN1外设时,cubeMX会自动帮你配置,但当我们翻阅C板的使用手册,会发现CAN1的Tx为PD1,Rx为PD0,因此要自己重新配置引脚(这一点很重要!!!!!),如下图

239ae45250374259b0e1c14fedd87293.png

e8a6df01d42b4ea6a03fe2626def6736.png

然后是配置CAN总线的传输速率,CAN总线接口最大支持1MHz的传输速率。我们可以将预分频器设置为7,BS1为2,BS2为3

BR=42000000/7/(1+2+3)=1000000Hz

其中42000000代表CAN1所挂载的APB1时钟的频率为42MHz

最后,不要忘了打开CAN1的接收(Rx0)中断

 (4)打开C板的红、绿、蓝指示灯,蓝灯引脚为PH10、绿灯PH11、红灯PH12,默认为高电平触发,所以初始状态设置为低电平。红绿蓝指示灯可以在调试的时候使用。

2、代码编写

bsp_can.h

在该头文件中,我们先创建用来储存电机信息的结构体motor_info_t,结构体内的内容也是参照6020电机的使用说明书,详细的大家可以自己去了解一下,如下两图

  1. #ifndef __BSP_CAN_H_
  2. #define __BSP_CAN_H_
  3. #include "main.h"
  4. #include "can.h"
  5. #include "stm32f4xx.h"
  6. typedef struct
  7. {
  8. uint16_t can_id;//电机ID
  9. int16_t set_voltage;//设定的电压值
  10. uint16_t rotor_angle;//机械角度
  11. int16_t rotor_speed;//转速
  12. int16_t torque_current;//扭矩电流
  13. uint8_t temp;//温度
  14. }moto_info_t;
  15. void can_filter_init(void);
  16. void set_GM6020_motor_voltage(CAN_HandleTypeDef* hcan,int16_t v1);
  17. #endif

bsp_can.c

  1. #include "bsp_can.h"
  2. moto_info_t motor_yaw_info;
  3. uint16_t can_cnt;
  4. void can_filter_init(void)//筛选器配置
  5. {
  6. CAN_FilterTypeDef can_filter_st;
  7. can_filter_st.FilterActivation = ENABLE;
  8. can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK;
  9. can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT;
  10. can_filter_st.FilterIdHigh = 0x0000;
  11. can_filter_st.FilterIdLow = 0x0000;
  12. can_filter_st.FilterMaskIdHigh = 0x0000;
  13. can_filter_st.FilterMaskIdLow = 0x0000;
  14. can_filter_st.FilterBank = 0;
  15. can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0;
  16. HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);
  17. HAL_CAN_Start(&hcan1);
  18. HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  19. can_filter_st.SlaveStartFilterBank = 14;
  20. can_filter_st.FilterBank = 14;
  21. HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);
  22. HAL_CAN_Start(&hcan1);
  23. HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  24. }
  25. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
  26. {
  27. CAN_RxHeaderTypeDef rx_header;
  28. uint8_t rx_data[8];
  29. if(hcan->Instance == CAN1)
  30. {
  31. HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data); //receive can data
  32. switch(rx_header.StdId)
  33. {
  34. case 0x205:
  35. {
  36. motor_yaw_info.rotor_angle = ((rx_data[0] << 8) | rx_data[1]);
  37. motor_yaw_info.rotor_speed = ((rx_data[2] << 8) | rx_data[3]);
  38. motor_yaw_info.torque_current = ((rx_data[4] << 8) | rx_data[5]);
  39. motor_yaw_info.temp = rx_data[6];
  40. break;
  41. }
  42. }
  43. }
  44. }
  45. void set_GM6020_motor_voltage(CAN_HandleTypeDef* hcan,int16_t v1)
  46. {
  47. CAN_TxHeaderTypeDef tx_header;
  48. uint8_t tx_data[8] = {0};
  49. tx_header.StdId = 0x1ff;
  50. tx_header.IDE = CAN_ID_STD;
  51. tx_header.RTR = CAN_RTR_DATA;
  52. tx_header.DLC = 8;
  53. tx_data[0] = (v1>>8)&0xff;
  54. tx_data[1] = (v1)&0xff;
  55. HAL_CAN_AddTxMessage(&hcan1, &tx_header, tx_data,(uint32_t*)CAN_TX_MAILBOX0);
  56. }

can_filter_init()为筛选器配置函数,筛选器模式为32位掩码模式,显码为0x0000,掩码也是0x00000,也就是说这个函数的掩码掩了一个寂寞,这串代码的作用在于它其实没什么作用,但是如果不配置就无法完成通信,没什么用但一定要有。其次该函数还有初始化can的功能,要将它放在main.c当中

HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)为CAN接收的中断回调函数,首先判断电机的ID值(0x205就是GM6020电机的ID1,详细可以参考官方手册),即识别是总线上的哪一个设备(电机)在发送信息,单片机接受来自该电机编码器的信息,如下图(机械角度、转速、转矩电流、温度)

set_GM6020_motor_voltage(CAN_HandleTypeDef* hcan,int16_t v1)为can的发送函数,首先识别数据的标识符是0x1FF(因为电机的ID是1,所以其数据帧的标识符为0x1FF),然后主控发送电压值给电机,驱动电机转动。而发送给ID1电机的电压值为数据帧的第1位和第二位(DATA[0]和DATA[1])

pid.h

该头文件中我们定义pid算法的结构体pid_struct_t

  1. #ifndef __PID_H_
  2. #define __PID_H_
  3. #include "main.h"
  4. #include "stm32f4xx.h"
  5. typedef struct _pid_struct_t
  6. {
  7. float kp;//比例
  8. float ki;//积分
  9. float kd;//微分
  10. float i_max;//积分限幅
  11. float out_max;//输出限幅
  12. float ref; // target value目标角度
  13. float fdb; // feedback value设定角度
  14. float err[2]; // error and last error差值
  15. float p_out;//比例输出
  16. float i_out;//积分输出
  17. float d_out;//微分输出
  18. float output;//pid总输出
  19. }pid_struct_t;
  20. void pid_init(pid_struct_t *pid,
  21. float kp,
  22. float ki,
  23. float kd,
  24. float i_max,
  25. float out_max);
  26. void gimbal_PID_init(void);
  27. float pid_calc(pid_struct_t *pid, float ref, float fdb);
  28. #endif

 pid.c

  1. #include "pid.h"
  2. pid_struct_t gimbal_yaw_speed_pid;
  3. pid_struct_t gimbal_yaw_angle_pid;
  4. void pid_init(pid_struct_t *pid,
  5. float kp,
  6. float ki,
  7. float kd,
  8. float i_max,
  9. float out_max)//PID初始化函数
  10. {
  11. pid->kp = kp;
  12. pid->ki = ki;
  13. pid->kd = kd;
  14. pid->i_max = i_max;
  15. pid->out_max = out_max;
  16. }
  17. float pid_calc(pid_struct_t *pid, float ref, float fdb)//PID运算函数
  18. {
  19. pid->ref = ref;
  20. pid->fdb = fdb;
  21. pid->err[1] = pid->err[0];
  22. pid->err[0] = pid->ref - pid->fdb;
  23. pid->p_out = pid->kp * pid->err[0];
  24. pid->i_out += pid->ki * pid->err[0];
  25. pid->d_out = pid->kd * (pid->err[0] - pid->err[1]);
  26. LIMIT_MIN_MAX(pid->i_out, -pid->i_max, pid->i_max);
  27. pid->output = pid->p_out + pid->i_out + pid->d_out;
  28. LIMIT_MIN_MAX(pid->output, -pid->out_max, pid->out_max);
  29. return pid->output;
  30. }
  31. void gimbal_PID_init()//角度环和速度环的PID初始化,只是初测出来的数据,具体还需要测试
  32. {
  33. pid_init(&gimbal_yaw_speed_pid, 30, 0, 0, 30000, 30000);//P=30,I=0,D=0
  34. pid_init(&gimbal_yaw_angle_pid, 400, 0, 0, 0, 320);//P=400,I=0,D=0
  35. }

该文件中我们运用双环PID控制电机的角度和转速,角度环为内环,计算出当前角度和我设定角度之间的差值;速度环为外环,如果检测出角度相差的值很大,就会输出一个大电压值,为使电机以更快的转速到达设定值,反之则输出小电压,小转速。

PID运算的逻辑图如下

 mian.c

  1. #include "main.h"
  2. #include "can.h"
  3. #include "dma.h"
  4. #include "usart.h"
  5. #include "gpio.h"
  6. #include "bsp_can.h"
  7. #include "pid.h"
  8. #include "bsp_dbus.h"
  9. int16_t led_cnt;
  10. int16_t text_speed = 0;
  11. int16_t target_yaw_speed;
  12. float target_yaw_angle = 0;
  13. float now_yaw_angle;
  14. extern moto_info_t motor_yaw_info;
  15. extern pid_struct_t gimbal_yaw_speed_pid;
  16. extern pid_struct_t gimbal_yaw_angle_pid;
  17. double msp(double x, double in_min, double in_max, double out_min, double out_max)//映射函数,将编码器的值(0~8191)转换为弧度制的角度值(-pi~pi)
  18. {
  19. return (x-in_min)*(out_max-out_min)/(in_max-in_min)+out_min;
  20. }
  21. int main(void)
  22. {
  23. HAL_Init();
  24. SystemClock_Config();
  25. MX_GPIO_Init();
  26. MX_DMA_Init();
  27. MX_CAN1_Init();
  28. MX_USART3_UART_Init();
  29. MX_USART1_UART_Init();
  30. can_filter_init();//can初始化
  31. gimbal_PID_init();//PID初始化
  32. while (1)
  33. {
  34. led_cnt ++;
  35. if (led_cnt == 250)
  36. {
  37. led_cnt = 0;
  38. HAL_GPIO_TogglePin(GPIOH,GPIO_PIN_11); //blink cycle 500ms
  39. }
  40. now_yaw_angle=msp(motor_yaw_info.rotor_angle,0,8191,-pi,pi);//计算当前的编码器角度值,运用msp函数将编码器的值映射为弧度制
  41. pid_calc(&gimbal_yaw_angle_pid,target_yaw_angle, now_yaw_angle);//角度环
  42. pid_calc(&gimbal_yaw_speed_pid,gimbal_yaw_angle_pid.output, motor_yaw_info.rotor_speed);//速度环
  43. set_GM6020_motor_voltage(&hcan1,gimbal_yaw_speed_pid.output);//can发送函数,发送经过PID计算的电压值
  44. HAL_Delay(40);
  45. }
  46. }

 三、结束语

本人亲测代码是有效,但还是有很多地方需要改善,自己今年是第一年参加robomaster比赛,还有很多需要学习的地方。写这篇博客的契机在于希望对自己这段时间的学习进行总结,也希望将自己的一些经验分享出来,如果上述有什么不对或者不完善的地方也恳请大家批评指正

代码也参考CSDN上很多好的文章,他们比我讲的更好

(6条消息) RoboMaster电机驱动_gm6020波特率_HouEna的博客-CSDN博客

(6条消息) 【RM_EE_Note】1 GM6020收发&简单的PID调试_gm6020控制角度_ScreepsJackeroo的博客-CSDN博客

代码可直接使用。能控制6020电机转动到既定的角度值。

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

闽ICP备14008679号