基于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
/* 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
/* 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
/* 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
/* 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
/* 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
/* 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 来自于CANextern signed short MotorBoard_CAN_Output; //来自于CANextern 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
/* 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库)(未完成-持续更新)相关推荐
- 通过电机编码器AB相输出确定电机转向
AB相输出相差90度,即当A相"正跳变"时如果B相是高电平那么是"正转",反之是"反转" 图片: 正转 反转 #include <Ti ...
- stm32捕获占空比_【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置...
现在我也只能说是电机入门,但是想要把电机作为终身事业,从有霍尔到无霍尔,从方波到正弦波,现在把其中的一些知识点分享出来,因为电机控制其实的资料比较难找的,前人栽树,后人乘凉,如果我有什么错误,在知乎上 ...
- 【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置
已经做了半年的BLDC驱动器了,目前是做到了电流转速双闭环,期间遇到了很多很多问题,一个是资料难找,再加上公司要求使用CUBEMX,本身HAL库的资料也难找,难上加难啊,可能是用CUBEMX做出来的大 ...
- vue 雷达扫描_GitHub - suneildve/vueDataV: 基于Vue + Echarts 构建的数据可视化平台,酷炫大屏展示模板和组件库,持续更新各行各业实用模板和炫酷小组件。...
前言 一个基于Vue前端框架和第三方图表库echarts构建的可视化大数据平台,通过vue项目构建.指令的灵活运用.组件封装.组件之间通信,使内部图表组件库可实现自由替换和组合. 项目中部分前端库采用 ...
- 移植Freemodbus到STM32(基于CubeMX,HAL库)-避坑篇
具体Freemodbus移植到STM32步骤参考: STMC2CubeMX | STM32 HAL库移植FreeModbus详细步骤 基于STM32HAL库移植FreeModbus FreeModbu ...
- (学习)基于STM32的PWM控制直流电机转速(CubeMX+HAL库)
使用到的各元件: 1.12V电源一个 2.单片机:STM32F103C8T6 3.直流电机4个 4.电机驱动模块:L298N 5.降压模块两个 6:杜邦线若干 对于直流电机的转动控制如下表 两边电平 ...
- 【基于Python】 - 人工智能机器学习深度学习数据分析 - 常见问题,常用的套路与操作(持续更新)
20200221: 1.做分类问题的时候,给定你标签,你想知道每一类标签的出现频数,可以使用这个函数:np.bincount(). 如果想分析一下数据样本是否均衡的时候,可以考虑这种操作,代码十分简明 ...
- 正点原子STM32(基于HAL库)0
目录 开发环境搭建与使用 常用开发工具简介 MDK 安装 仿真器驱动安装 CH340 USB 虚拟串口驱动安装 使用MDK5 编译例程 使用串口下载程序 使用DAP 下载与调试程序 使用DAP 下载程 ...
- 基于MSP430f5529 编码电机测速 接收脉冲数 PWM调速 CCS编译器 代码分析
前言:2022年TI杯大学生电子设计竞赛,小车跟随行驶系统(C题)要求:设计一套小车跟随行驶系统,采用TI的MCU,由一辆领头小车和一辆跟随小车组成,要求小车具有循迹功能,且速度在0.3~1m/s可调 ...
最新文章
- P1276 校门外的树(增强版)(线段树)(校门三部曲)难度⭐⭐⭐
- 朱晔的互联网架构实践心得S1E2:屡试不爽的架构三马车
- 压力测试工具ab 及 centos下单独安装方法
- boost::geometry::append用法的测试程序
- UVA - 11732 strcmp() Anyone?左兄弟右儿子trie
- C#刷遍Leetcode面试题系列连载(2): No.38 - 报数
- Chrome谷歌浏览器新功能 删除主题更方便
- munin mysql_munin 监控 mysql 2种方法
- 知了堂学习笔记-CSS样式整理(一)
- Python数据类型解析(基础篇)
- vb.net 功能f8键事件_UG软件F8快捷键和笔记本电脑F8快捷键冲突的解决方法
- 转换azw3到epub
- oracle财务模块设置影响,Oracle 财务模块介绍.ppt
- css3永久放大动画,CSS3 简单的方形放大动画
- 淘宝自动回复机器人配置手册——利用旺旺分流针对性配置
- 怀旧服私聊显示服务器后缀,聊天窗口相关设置:有爱怀旧服聊天增强插件简易指南...
- HDU-4567-思维-Brilliant Programmers Show -13长沙邀请赛
- Fire (poj 2152 树形dp)
- 我只好去找了一根绳子系着它的脖子
- V2X-Hub,车路协同云控平台