stm32用pid控制编码电机

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,我还没调,哈哈,摆烂一天,明天继续!

  • 3
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuiStar_李什么恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值