基于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库)(未完成-持续更新)相关推荐

  1. 通过电机编码器AB相输出确定电机转向

    AB相输出相差90度,即当A相"正跳变"时如果B相是高电平那么是"正转",反之是"反转" 图片: 正转 反转 #include <Ti ...

  2. stm32捕获占空比_【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置...

    现在我也只能说是电机入门,但是想要把电机作为终身事业,从有霍尔到无霍尔,从方波到正弦波,现在把其中的一些知识点分享出来,因为电机控制其实的资料比较难找的,前人栽树,后人乘凉,如果我有什么错误,在知乎上 ...

  3. 【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置

    已经做了半年的BLDC驱动器了,目前是做到了电流转速双闭环,期间遇到了很多很多问题,一个是资料难找,再加上公司要求使用CUBEMX,本身HAL库的资料也难找,难上加难啊,可能是用CUBEMX做出来的大 ...

  4. vue 雷达扫描_GitHub - suneildve/vueDataV: 基于Vue + Echarts 构建的数据可视化平台,酷炫大屏展示模板和组件库,持续更新各行各业实用模板和炫酷小组件。...

    前言 一个基于Vue前端框架和第三方图表库echarts构建的可视化大数据平台,通过vue项目构建.指令的灵活运用.组件封装.组件之间通信,使内部图表组件库可实现自由替换和组合. 项目中部分前端库采用 ...

  5. 移植Freemodbus到STM32(基于CubeMX,HAL库)-避坑篇

    具体Freemodbus移植到STM32步骤参考: STMC2CubeMX | STM32 HAL库移植FreeModbus详细步骤 基于STM32HAL库移植FreeModbus FreeModbu ...

  6. (学习)基于STM32的PWM控制直流电机转速(CubeMX+HAL库)

    使用到的各元件: 1.12V电源一个 2.单片机:STM32F103C8T6 3.直流电机4个 4.电机驱动模块:L298N 5.降压模块两个 6:杜邦线若干 对于直流电机的转动控制如下表 两边电平 ...

  7. 【基于Python】 - 人工智能机器学习深度学习数据分析 - 常见问题,常用的套路与操作(持续更新)

    20200221: 1.做分类问题的时候,给定你标签,你想知道每一类标签的出现频数,可以使用这个函数:np.bincount(). 如果想分析一下数据样本是否均衡的时候,可以考虑这种操作,代码十分简明 ...

  8. 正点原子STM32(基于HAL库)0

    目录 开发环境搭建与使用 常用开发工具简介 MDK 安装 仿真器驱动安装 CH340 USB 虚拟串口驱动安装 使用MDK5 编译例程 使用串口下载程序 使用DAP 下载与调试程序 使用DAP 下载程 ...

  9. 基于MSP430f5529 编码电机测速 接收脉冲数 PWM调速 CCS编译器 代码分析

    前言:2022年TI杯大学生电子设计竞赛,小车跟随行驶系统(C题)要求:设计一套小车跟随行驶系统,采用TI的MCU,由一辆领头小车和一辆跟随小车组成,要求小车具有循迹功能,且速度在0.3~1m/s可调 ...

最新文章

  1. P1276 校门外的树(增强版)(线段树)(校门三部曲)难度⭐⭐⭐
  2. 朱晔的互联网架构实践心得S1E2:屡试不爽的架构三马车
  3. 压力测试工具ab 及 centos下单独安装方法
  4. boost::geometry::append用法的测试程序
  5. UVA - 11732 strcmp() Anyone?左兄弟右儿子trie
  6. C#刷遍Leetcode面试题系列连载(2): No.38 - 报数
  7. Chrome谷歌浏览器新功能 删除主题更方便
  8. munin mysql_munin 监控 mysql 2种方法
  9. 知了堂学习笔记-CSS样式整理(一)
  10. Python数据类型解析(基础篇)
  11. vb.net 功能f8键事件_UG软件F8快捷键和笔记本电脑F8快捷键冲突的解决方法
  12. 转换azw3到epub
  13. oracle财务模块设置影响,Oracle 财务模块介绍.ppt
  14. css3永久放大动画,CSS3 简单的方形放大动画
  15. 淘宝自动回复机器人配置手册——利用旺旺分流针对性配置
  16. 怀旧服私聊显示服务器后缀,聊天窗口相关设置:有爱怀旧服聊天增强插件简易指南...
  17. HDU-4567-思维-Brilliant Programmers Show -13长沙邀请赛
  18. Fire (poj 2152 树形dp)
  19. 我只好去找了一根绳子系着它的脖子
  20. V2X-Hub,车路协同云控平台

热门文章

  1. 微信小程序-侧边栏-获取用户选中的值
  2. WebForm中UploadFile控件的使用案例
  3. 谈谈指纹浏览器的几个重要指纹参数
  4. 剑灵各西洛服务器位置,剑灵韩服西洛更新汇总详解 新任务界面篇
  5. 争辩地不要,悄悄地引导
  6. layui open传参_layer.open传值
  7. 前端工程师300道面试题整理
  8. 格林威治时间转UTC
  9. mysql无法在kvm虚拟机上_kvm常见故障及解决
  10. 24句经典哲理性语句