我是靠谱客的博主 淡然项链,这篇文章主要介绍基于STM32F103C6T6的AB相霍尔编码电机的PID转速调节(CubeMx-HAL库)(未完成-持续更新),现在分享给大家,希望可以做个参考。

基于STM32F103C6T6的AB相霍尔编码电机的PID转速调节(CubeMx-HAL库)(未完成-持续更新)

主要是记录一下,以后忘了再来看看,也记录记录自己做过的东西

首先是硬件电路图,一下是驱动板的硬件电路图(来自于实验室的某大佬比赛开的BTN驱动 再说一遍不是我开的)图省事直接拿过来用了,到程序调的差不多了我会开一版新的驱动和主控。
以前自己也开了一套MOS的H桥有刷驱动,但是自己手贱,明明知道自己设计的是12V的驱动,偏就直接要怼24V的大疆电池,依稀记得大一的时候,一个大二学长开的主控,也是被我怼的24V,还有不多几天就电赛了,学长是连夜修啊,惭愧。

来看看硬件的原理图
在这里插入图片描述
此处电机用的是AB相霍尔编码电机如下
请添加图片描述
然后就是接线,电机上都写的清楚,我也就不细说了

之后就是CubeMx的配置,时钟树如下
在这里插入图片描述
先是PWM输出口,一共开俩一个控制正转一个控制反转,我配置的PWM频率是1KHz就差不多,满占空比的CCR值是999,然后根据原理图做出以下配置。
至于PWM频率的计算,公式是这个 PWMf = TIMf/(ARR+1)*(PSC+1)
在这里插入图片描述
然后就是AB相编码器的配置,刚开始不知道芯片自带解算,可以直接读到电机旋转方向和计数值,用的中断触发然后判断另一相的状态,以此获取正反转和计数值,CubeMx是可以直接配置AB相编码器的啊,然后具体配置如下,当时为啥选8191为溢出值,啊这个没啥关系,一般我们采样间隔时间越长他的电机编码器的计数值就越大,让计数值不要超过这个溢出值就行。
在这里插入图片描述
然后就是串口啊,串口配置默认就行,后面调PID的三个初始化值会用到串口,实验室的大佬写了上位机的调参软件(对就是上面开驱动这个大佬),开了DMA
在这里插入图片描述
DMA
在这里插入图片描述
中断
在这里插入图片描述
关掉CubeMx默认生成的回调函数(大佬怎么说就怎么做,毕竟是人家写的上位机,不用调一次参,下载一遍程序是真的香)
在这里插入图片描述
然后是CAN这个CAN我是准备与主控连接的,主控通过CAN发送目标值,由驱动板进行PID调节。
此处CAN的频率为1MHz,为啥选1MHz,当时是希望兼容Robomaster的程序的(没错画电路板的那个大佬又写了Robomatser的整套程序)
在这里插入图片描述
CAN开一个接收中断用于处理主机发送过来的速度目标值
在这里插入图片描述
然后开个Freertos嗯,大佬说没有Freertos不好玩,开!
都是默认,也没有再添加线程,在程序里自己写添加线程
在这里插入图片描述
然后配置,导出工程
在这里插入图片描述
在这里插入图片描述
之后就是软件代码编写
首先移植大佬的调参器线程,嗯,也没有经过大佬同意我就不放调参器线程函数了
之后就是电机编码器的软件代码

MotorBoard_Encoder.c

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MotorBoard_PID.c * @brief : MotorBoard_PID program body * @author : Lesterbor * @time : 2021-09-14 ****************************************************************************** * @attention : 此处的电机获取速度值 写在了freertos的默认线程中 * * * ****************************************************************************** */ /* USER CODE END Header */ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "MotorBoard_Encoder.h" #include "stdio.h" #include "tim.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ signed short Speed = 0; /* USER CODE END PT */ /* Function definition -------------------------------------------------------*/ /* USER CODE BEGIN FD */ /** * @Function name : MotorBoard_Encoder_Init * @Introduce : 编码电机的PID调节初始化 * @Return : Null */ void MotorBoard_Encoder_Init(void){ HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); } /** * @Function name : MotorBoard_Encoder_Getspeed * @Introduce : 获取编码器的值 * @Return : 电机编码器值 */ unsigned short MotorBoard_Encoder_GetSpeed(void){ return __HAL_TIM_GET_COUNTER(&htim2); } /** * @Function name : MotorBoard_Encoder_SetZero * @Introduce : 编码器清零 * @Return : NULL */ void MotorBoard_Encoder_SetZero(void){ __HAL_TIM_SET_COUNTER(&htim2,0); } /* USER CODE END FD */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

MotorBoard_Encoder.h

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MotorBoard_Encoder.h * @brief : Header for MotorBoard_Encoder.c file. * This file provides code for the configuration * of the MotorBoard_Encoder instances * @author : Lesterbor ****************************************************************************** * @attention * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __MOTORBOARD_ENCODER_H_ #define __MOTORBOARD_ENCODER_H_ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "main.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ /* USER CODE END PT */ /* Exported functions prototypes ---------------------------------------------*/ /* USER CODE BEGIN EFP */ void MotorBoard_Encoder_Init(void); unsigned short MotorBoard_Encoder_GetSpeed(void); void MotorBoard_Encoder_SetZero(void); /* USER CODE END EFP */ #endif /* __MOTORBOARD_ENCODER_H_ */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

编码器的定时获取我放在了CubeMx生成的默认线程中一下是代码,当然啊,这个速度变量Speed是entern到这个文件中的,在MotorBoard_Encoder.c中我定义了一下
不知道for里面的这个三目运算符能不能看懂,在实际调试过程中发现,电机正转的时候计数值确实是向上计数的,但是反转的时候计数值是向下计数的,比如我电机现在的转速是+30 计数值就是30,但是你的电机转速是-30你的计数值就是8162也就是8192-30,所以我们在这加了一个判断语句,当计数值大于我溢出值的一半时我就减,当然我在MotorBoard_Encoder.c文件中定义了一个函数就是获取当前电机的旋转方向的,你也可以根据那个来判断是不是需要减掉计数值,嗯就是这样,如果你感觉你的电机速度值太小了,你可以稍微把采样时间调的大一点。每次取过计数值之后你需要吧计数器清空,也就是程序中的MotorBoard_Encoder_SetZero();这条语句,具体的定义在MotorBoard_Encoder.c文件中。
FreeRTOS.c

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ MotorBoard_Encoder_Init(); for(;;) { Speed = MotorBoard_Encoder_GetSpeed()>4096?(MotorBoard_Encoder_GetSpeed()-8192):MotorBoard_Encoder_GetSpeed(); MotorBoard_Encoder_SetZero(); osDelay(30); } /* USER CODE END StartDefaultTask */ }

然后就是PID部分了,这部分是参考了网络自己写了一下,也加了一个低通滤波
MotorBoard_PID.c

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MotorBoard_PID.c * @brief : MotorBoard_PID program body * @author : Lesterbor * @time : 2021-09-14 ****************************************************************************** * @attention : 包含低通滤波 * * * ****************************************************************************** */ /* USER CODE END Header */ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "MotorBoard_PID.h" #include "stdio.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ pid_t PID_Motor; lowpass_t LWF_Motor; float ControlSpeed = 0; /* USER CODE END PT */ /* Function definition -------------------------------------------------------*/ /* USER CODE BEGIN FD */ /** * @Function name : MotorBoard_CAN_Init * @Introduce : 编码电机的PID调节初始化 * @Return : Null */ void MotorBoard_PID_Init(float Kp,float Ki,float Kd){ PID_Motor.SetValue= 0.0; //设定的转速目标值 PID_Motor.ActualValue= 0.0; //实际转速值 PID_Motor.err= 0.0; //当前实际转速值与理想转速值的偏差 PID_Motor.err_last=0.0; //上一次的偏差 PID_Motor.integral= 0.0; //积分值 PID_Motor.Kp= Kp; //比例系数 PID_Motor.Ki= Ki; //积分系数 PID_Motor.Kd= Kd; //微分系数 } /** * @Function name : MotorBoard_PID_realize * @Introduce : 编码电机的PID调节 * @Return : 调节结果值 */ float MotorBoard_PID_Realize( float Target, float Input){ PID_Motor.SetValue = Target; //目标值传入 PID_Motor.ActualValue = Input; //实际值传入 PID_Motor.err = PID_Motor.SetValue - PID_Motor.ActualValue; //计算偏差 PID_Motor.integral += PID_Motor.err; //积分求和 PID_Motor.result = PID_Motor.Kp * PID_Motor.err + PID_Motor.Ki * PID_Motor.integral + PID_Motor.Kd * ( PID_Motor.err - PID_Motor.err_last);//位置式公式 PID_Motor.err_last = PID_Motor.err; //留住上一次误差 return PID_Motor.result; } /** * @Function name : MotorBoard_LWF_Init * @Introduce : 一阶低通滤波初始化 * @Return : NULL */ void MotorBoard_LWF_Init(void){ LWF_Motor.Result_Last = 0; } /** * @Function name : MotorBoard_LWF_Realize * @Introduce : 一阶低通滤波控制 * @Return : 本次滤波结果=(1-a)*本次采样值+a*上次滤波结果 * 滞后程度取决于a值的大小 * a float型变量 取值范围为0-1 */ signed short MotorBoard_LWF_Realize(signed short Value,float a){ LWF_Motor.Result= (1-a)*Value + a*LWF_Motor.Result_Last; LWF_Motor.Result_Last = LWF_Motor.Result; return LWF_Motor.Result; } /* USER CODE END FD */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

MotorBoard_PID.h

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MotorBoard_PID.h * @brief : Header for MotorBoard_PID.c file. * This file provides code for the configuration * of the MotorBoard_PID instances * @author : Lesterbor ****************************************************************************** * @attention * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __MOTORBOARD_PID_H_ #define __MOTORBOARD_PID_H_ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "main.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ //PID调节变量定义 typedef struct{ float SetValue; //定义设定值 float ActualValue; //定义实际值 float err; //定义偏差值 float err_last; //定义上一个偏差值 float Kp,Ki,Kd; //定义比例、积分、微分系数 float result; //pid计算结果 float voltage; //定义转速值(控制执行器的变量) float integral; //定义积分值 }pid_t; //一阶低通滤波变量定义 typedef struct { signed short ActualValue; //定义实际值 float a; //滞后程度 signed short Result_Last; //定义上一个结果 signed short Result; //滤波计算结果 }lowpass_t; /* USER CODE END PT */ /* Exported functions prototypes ---------------------------------------------*/ /* USER CODE BEGIN EFP */ void MotorBoard_PID_Init(float Kp,float Ki,float Kd); //PID初始化 float MotorBoard_PID_Realize(float v,float v_r); //PID控制 void MotorBoard_LWF_Init(void); //一阶低通滤波初始化 signed short MotorBoard_LWF_Realize(signed short Value,float a); //一阶低通滤波 /* USER CODE END EFP */ #endif /* __MOTORBOARD_PID_H_ */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

之后再创建主线程所有的业务代码都在这里,至于CAN嘛,等我先把PID调完再说吧,先就不放CAN的代码了,下面程序中的Debugger数组就是大佬写的调参器变量,当程序烧录进去之后,在上位机改变对应变量的值,程序内部自己会改变,而那个DebuggerLine则会在上位机上显示一条曲线。
MainThread.c

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MainThread.c * @brief : MainThread program body * @author : Lesterbor * @time : 2021-09-14 ****************************************************************************** * @attention * * * ****************************************************************************** */ /* USER CODE END Header */ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "MainThread.h" #include "MotorBoard_CAN.h" #include "MotorBoard_PID.h" #include "MotorBoard_Encoder.h" #include "DebuggerThread.h" #include "tim.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ extern signed short Speed; extern unsigned int ID; //本机ID 来自于CAN extern signed short MotorBoard_CAN_Output; //来自于CAN extern float ControlSpeed; /* USER CODE END PT */ /* Function definition -------------------------------------------------------*/ /* USER CODE BEGIN FD */ /** * @Function name MainTask * @Introduce 主线程函数 * @Return Null */ void MainTask(void *argument){ unsigned char TxData[8] = {0}; HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); for(;;){ //MotorBoard_LWF_Realize在PID控制的C文件中 功能是低通滤波 MotorBoard_PID_Init(Debugger[0],Debugger[1],Debugger[2]); ControlSpeed = MotorBoard_PID_Realize(Debugger[3],MotorBoard_LWF_Realize(Speed,Debugger[5])); DebuggerLine[0] = Speed; Debugger[4] = Speed; if(ControlSpeed> 0){ __HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_2,ControlSpeed); __HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0); }else{ __HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_2,0); __HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,-ControlSpeed); } osDelay(5); } } /** * @brief 主控制线程初始化 * @retval None */ void MainThread_Init(void){ const osThreadAttr_t MainTask_attributes = {"MainTask",0,0,0,0,256,(osPriority_t) osPriorityNormal}; osThreadNew(MainTask, NULL, &MainTask_attributes);//创建主线程 } /* USER CODE END FD */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

上面主线程函数中的MainThread_Init(void)需要在主函数中添加初始化一下,不然程序不会进入自己定义的这个线程
MainThread.h

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : MainThread.h * @brief : Header for MainThread.c file. * This file provides code for the configuration * of the MainThread instances * @author : Lesterbor ****************************************************************************** * @attention * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __MAINTHREAD_H_ #define __MAINTHREAD_H_ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "main.h" #include "cmsis_os.h" #include "FreeRTOS.h" #include "task.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PT */ /* USER CODE END PT */ /* Exported functions prototypes ---------------------------------------------*/ /* USER CODE BEGIN EFP */ void MainThread_Init(void); /* USER CODE END EFP */ #endif /* __MAINTHREAD_H_ */ /************************ (C) CopyRight Lesterbor ******END OF FILE******/

目前代码也就写到了这里,PID还没有调完,总是不太对,实在不行的话就移植一下大佬的PID程序,嗯,先调一调看吧

最后

以上就是淡然项链最近收集整理的关于基于STM32F103C6T6的AB相霍尔编码电机的PID转速调节(CubeMx-HAL库)(未完成-持续更新)的全部内容,更多相关基于STM32F103C6T6内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部