草庐IT

stm32用pid控制编码电机

GuiStar_李什么恩 2023-10-09 原文

stm32硬件PID控制编码电机


stm32的定时器具有读取正交编码器的功能(所谓正交,就是波形相位互余的一对信号),其具体配置在之前的博客中我已经封装过函数了,没看过的朋友可以点击这里,位置式PID的封装函数也写过了,在这里。本文将以这些代码为例子,来写一个控制编码电机的代码。


首先,给出控制电机的代码,原理很简单,就是输出比较而已。

GuiStar_Motor.h:

#ifndef __GUISTAR_MOTOR_H__
#define __GUISTAR_MOTOR_H__

#include "stm32f10x.h"                  // Device header
#include "GuiStar_TIM.h"
#include "IO.h"

//电机的PWM选择TIM2通道1(A0),电机的正负极如下:
#define INA				PAout(1)
#define INA_Port 		GPIOA
#define INA_Pin  		GPIO_Pin_1

#define INB				PAout(2)
#define INB_Port 		GPIOA
#define INB_Pin  		GPIO_Pin_2

void GuiStar_Motor_Init(void);
void GuiStar_Motor_SetSpeed(int Speed);

#endif

GuiStar_Motor.c:

#include "GuiStar_Motor.h"

/**
  * @brief  电机初始化
  * @param  无
  * @retval 无
  */
void GuiStar_Motor_Init(void)
{
	IO_Init(INA_Port,INA_Pin,GPIO_Mode_Out_PP);
	IO_Init(INB_Port,INB_Pin,GPIO_Mode_Out_PP);
	Encoder_Init(TIM3);
	GuiStar_PWM_Init(TIM2,1,1,7200,0);
}

/**
  * @brief  设置电机速度
  * @param  Speed 电机速度,范围-7200~7200,正数正转,负数反转
  * @retval 无
  */
void GuiStar_Motor_SetSpeed(int Speed)
{
	if(Speed>0)
	{
		INA=1;
		INB=0;
		TIM_SetCompare1(TIM2,Speed);
	}
	else if(Speed==0)
	{
		INA=0;
		INB=0;
		TIM_SetCompare1(TIM2,0);
	}
	else if(Speed<0)
	{
		INA=0;
		INB=1;
		TIM_SetCompare1(TIM2,-Speed);
	}
}


接下来是重点,PID控制的.c和.h文件:

GuiStar_Control.h:

#ifndef __GUISTAR_CONTROL_H__
#define __GUISTAR_CONTROL_H__

#include "GuiStar_TIM.h"
#include "GuiStar_Motor.h"
#include "GuiStar_PID.h"

//PID调参宏
#define GuiStar_P 0
#define GuiStar_I 0
#define GuiStar_D 0

void GuiStar_StartControl(void);//启动PID控制
void GuiStar_SetEncoderSpeed(int Encoder_Speed_Value);//设置编码电机的预期值

#endif

GuiStar_Control.c:

#include "GuiStar_Control.h"

void GuiStar_PID_Control_IRQHandler(void);//PID中断函数声明
GuiStar_PIDTypedef GuiStar_PID;//PID调参结构体声明
int PWM_Speed=0;//电机的PWM数值(是GuiStar_Motor_SetSpeed的实参)
int Task_Encoder_Speed=0;//电机的编码器预期速度,范围-200~200


/**
  * @brief  (1)开启定时器中断,每隔10mspid控制一次电机
			(2)设置TIM4中断函数为PID中断函数
			(3)PID调参
  * @param 	
  * @retval 
  */
void GuiStar_StartControl(void)
{
	GuiStar_TIM(TIM4,7200,100,1,1);//设置TIM410ms中断
	GuiStar_TIM_SetTIM4IRQHandler(GuiStar_PID_Control_IRQHandler);//设置TIM4中断函数为PID_Control_IRQHandler
	GuiStar_Motor_Init();//电机初始化
	
	//PID参数设置
	GuiStar_PID.KP=GuiStar_P;
	GuiStar_PID.KI=GuiStar_I;
	GuiStar_PID.KD=GuiStar_D;
}

/**
  * @brief  设置本文件中的Task_Encoder_Speed变量(它是编码器速度的目标值)
  * @param  Encoder_Speed_Value 取值范围-200~200
  * @retval 无
  */
void GuiStar_SetEncoderSpeed(int Encoder_Speed_Value)
{
	Task_Encoder_Speed=Encoder_Speed_Value;
}

/**
  * @brief  读取CNT此时的值,并清零CNT,此函数将在10ms中断函数中调用,则
			它的值表示10ms内编码器的总次数,是反应速度大小的量
  * @param  无
  * @retval 编码器此时的值
  */
static int16_t GuiStar_GetMotor_Encoder_Speed(void)
{
	return Encoder_GetSpeed(TIM3);
}

/**
  * @brief  限幅PWM_Speed的值在合理的范围(-7200~7200)
  * @param  无
  * @retval 无
  */
static void GuiStar_Limit_PWM_Speed()
{
	if(PWM_Speed<-7200) PWM_Speed=-7200;
	else if(PWM_Speed>7200) PWM_Speed=7200;
}

/**
  * @brief  PID10ms中断函数,计算出本次控制应该输出的Speed变量,将变量限幅之后,以此变量来控制电机
  * @param  无
  * @retval 无
  */
void GuiStar_PID_Control_IRQHandler(void)
{
	PWM_Speed=GuiStar_P_PID1(GuiStar_GetMotor_Encoder_Speed(), Task_Encoder_Speed, &GuiStar_PID);//PID控制
	GuiStar_Limit_PWM_Speed();//速度限幅
	GuiStar_Motor_SetSpeed(PWM_Speed);//按本次的控制结果控制电机
}

PID控制总结:

需要做五件事:
第一,完成电机,相关定时器,引脚,编码器接口等的初始化工作
第二,在中断函数中输出本次控制的值
第三,对本次控制的值进行限幅
第四,将限幅之后的值交给执行函数去执行控制电机
第五,PID调参

其中,PID调参是重中之重,不难发现,我写的代码pid三个参数都还是0,我还没调,哈哈,摆烂一天,明天继续!

有关stm32用pid控制编码电机的更多相关文章

  1. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  2. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  3. Ruby Readline 在向上箭头上使控制台崩溃 - 2

    当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby​​安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少

  4. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  5. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  8. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  9. ruby-on-rails - 在 Rails 控制台中使用 asset_path - 2

    在我的Character模型中,我添加了:字符.rbbefore_savedoself.profile_picture_url=asset_path('icon.png')end但是,对于数据库中已存在的所有角色,它们的profile_picture_url为nil。因此,我想进入控制台并遍历所有这些并进行设置。在我试过的控制台中:Character.find_eachdo|c|c.profile_picture_url=asset_path('icon.png')end但这给出了错误:NoMethodError:undefinedmethod`asset_path'formain:O

  10. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

随机推荐