STM32控制两路直流电机_2

在上一篇博客中讲述了怎样使用STM32输出两路PWM波控制电机转动和使用定时器的编码器模块功能读取电机编码器的信息以获得电机的实时转速。
本篇博客内容包括:控制电机的转向,读取编码器数值,以及速度PID控制的编程方法。
(1)控制电机转向
由于我们使用的是TB6612芯片来驱动电机的运行,根据上一篇博客中所讲的控制方法可以编写一下代码实现对小车运动的控制:

/*
启动电机
*/
void motorStart(uint16_t pwma, uint16_t pwmb )
{
  GPIO_ResetBits(GPIOE,GPIO_Pin_7);
	GPIO_SetBits(GPIOE,GPIO_Pin_8);
	GPIO_ResetBits(GPIOE,GPIO_Pin_14);
	GPIO_SetBits(GPIOE,GPIO_Pin_13);
	GPIO_SetBits(GPIOE,GPIO_Pin_10);
	TIM1->CCR1 = pwma;
	TIM1->CCR2 = pwmb;
	TIM_Cmd(TIM1, ENABLE);
}

/*
停止电机运行
*/
void motorStop(void)
{
    GPIO_ResetBits(GPIOE,GPIO_Pin_10);
}

/*
控制小车前进
*/
void motorForward(void)
{
	  GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	
	  GPIO_SetBits(GPIOE,GPIO_Pin_7);
	  GPIO_ResetBits(GPIOE,GPIO_Pin_8);
		GPIO_ResetBits(GPIOE,GPIO_Pin_13);
	  GPIO_SetBits(GPIOE,GPIO_Pin_14);
	
	  GPIO_SetBits(GPIOE,GPIO_Pin_10);
}


/*
控制小车后退
*/
void motorBackward(void)
{
	 GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	
   	GPIO_ResetBits(GPIOE,GPIO_Pin_7);
	  GPIO_SetBits(GPIOE,GPIO_Pin_8);
	  GPIO_SetBits(GPIOE,GPIO_Pin_13);
	  GPIO_ResetBits(GPIOE,GPIO_Pin_14);
	
	  GPIO_SetBits(GPIOE,GPIO_Pin_10);
}


/*
控制小车左转
*/
void motorTurnLeft(void)
{
	GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	
	GPIO_SetBits(GPIOE,GPIO_Pin_7);
	GPIO_ResetBits(GPIOE,GPIO_Pin_8);
	GPIO_SetBits(GPIOE,GPIO_Pin_13);
	GPIO_ResetBits(GPIOE,GPIO_Pin_14);
	
	GPIO_SetBits(GPIOE,GPIO_Pin_10);
}


/*
控制小车右转
*/
void motorTurnRight(void)
{
	GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	
	GPIO_ResetBits(GPIOE,GPIO_Pin_7);
	GPIO_SetBits(GPIOE,GPIO_Pin_8);
	GPIO_ResetBits(GPIOE,GPIO_Pin_13);
	GPIO_SetBits(GPIOE,GPIO_Pin_14);
	
	GPIO_SetBits(GPIOE,GPIO_Pin_10);
}

(2)读取编码器的数值
已知车轮每转一圈编码器的计数值(本项目中轮子转一圈,编码器的计数值输出为1560),通过定时读取电机编码器的计数值,采用以下公式可以获取这段时间内电机的转速:
V m o t o r = 编码器计数值 定时器周期 V_{motor}=\frac{编码器计数值}{定时器周期} Vmotor=定时器周期编码器计数值

获取编码器计数值程序设计如下:

/*
获取编码器计数值,获取后的计数值存储在结构体motorInfo中
参数 x=3表示读取定时器3的计数值
     x=4表示读取定时器4的计数值
*/
extern MotorInfo     motorInfo;
void read_encoder(uint8_t x)
{
    switch(x)
		{
			case 3:
						 if(TIM3->CNT>=32678)
							 motorInfo.leftCnt=65535-TIM3->CNT;
						 else
							 motorInfo.leftCnt=TIM3->CNT;
					   TIM3->CNT=0;
						 break;
			case 4:
				     if(TIM4->CNT>=32678)
			          motorInfo.rightCnt=65535-TIM4->CNT;
		         else
		            motorInfo.rightCnt=TIM4->CNT;
						 TIM4->CNT=0;
						 break;
		} 
}

值得注意的是,每次读取完定时器的计数值之后都要把计数值清零,这样才能可靠地保证数据采集的正确性。

(3)小车速度的PID控制
根据上一篇博客中的控制框图,我们在此对小车两轮的速度分别加以控制,控制算法选择常用的数字式增量PID算法。
电机控制框图
本PID控制器的输入是每个车轮的期望速度与实际速度的偏差,输出为电机PWM占空比的增量值。增量式PID控制算法可表示如下:
Δ p w m = K p ∗ ( e r r − e r r 1 ) + K i ∗ e r r + K d ∗ ( e r r − 2 ∗ e r r 1 + e r r 2 ) \Delta{pwm}=K_p*(err-err_1)+K_i*err+K_d*(err-2*err_1+err_2) Δpwm=Kp(errerr1)+Kierr+Kd(err2err1+err2)
e r r err err为本次误差, e r r 1 err_1 err1, e r r 2 err_2 err2前一次,前两次误差。
则控制电机的实际PWM为:
P W M c u r r e n t = P W M p r e v i o u s + Δ p w m PWM_{current}=PWM_{previous}+\Delta{pwm} PWMcurrent=PWMprevious+Δpwm
PID控制算法如下:

//定义PID控制结构体
typedef struct Pid
{
  float kp;
	float ki;
	float kd;
	float A;
	float B;
	float C;
	float error_prev_1;
	float error_prev_2;
	float error_cur;
	float limit;
}PID;
//PID初始化
void pid_init(float kp,float ki,float kd,PID *pid)
{
   pid->kp=kp;
	 pid->ki=ki;
	 pid->kd=kd;
	
	 pid->A= pid->kp + pid->ki + pid->kd;
	 pid->B= -(2.0f*pid->kd + pid->kp);
	 pid->C= pid->kd;
	
	 pid->error_cur=0.0f;
	 pid->error_prev_1=0.0f;
	 pid->error_prev_2=0.0f;
	 pid->limit=0.4;
}
//执行PID计算
float pid(float error, PID * pid)
{
	 float delta_u;
	
	 pid->error_prev_2 = pid->error_prev_1;
	 pid->error_prev_1 = pid->error_cur;
	 pid->error_cur = error;
	
	 delta_u=pid->A * pid->error_cur + pid->B * pid->error_prev_1 + pid->C * pid->error_prev_2;
	
	 if(delta_u > pid->limit)
		 delta_u=pid->limit;
	else if(delta_u < -pid->limit)
		delta_u=-pid->limit;
	
	 return delta_u;
}


应用时,利用定时器周期读取编码器的计数值,然后迅速计算出速度偏差值,送入PID中进行计算,即可实现对电机速度的控制。但是PID控制器需要对参数Kp,Ki,Kd进行整定,这就需要进行大量的测试调试,不断更改这些参数的值,使其逼近最优的参数,才能达到理想的控制效果。
下一篇博客将介绍如何使用stm32驱动3路超声波传感器,测量距离值。

  • 29
    点赞
  • 194
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值