STM32F4速度环加角度环串级PID

小白学习笔记,欢迎指正~~~

整体思路

1.定时器配置编码器模式,实现对电机输出A,B相

void TIM2_ENCODER_Init(void)                      
{ 
  GPIO_InitTypeDef         GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef        TIM_ICInitStructure;
 

   /*GPIO初始化*/

    (RCC_AHB1Periph_GPIOA,ENABLE); 	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;//AB相接线
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM2);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM2);

	TIM_TimeBaseStructure.TIM_Period=65535-1;
	TIM_TimeBaseStructure.TIM_Prescaler=1;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Down;
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

	TIM_ICInitStructure.TIM_Channel=TIM_Channel_2|TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler=15;
	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//IC1映射到TI上   
    TIM_ICSelection
	TIM_ICInitStructure.TIM_ICFilter=0;//输入通道的滤波参数
	TIM_ICStructInit(&TIM_ICInitStructure); 
	
	TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
	
  TIM_Cmd(TIM2,ENABLE);

	   
      
} 

2.定时器设置一段时间读取CNT的值

void TIM3_Int_Init()
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

  TIM_TimeBaseInitStructure.TIM_Period = 5000-1; 	//自动重装载值 //5ms记一次数
	TIM_TimeBaseInitStructure.TIM_Prescaler=84-1;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00; //抢占优先级1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00; //
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	TIM_Cmd(TIM3,ENABLE); //使能定时器3
}

3.定时器输出PWM模式,输出经过PID算法后的电压值

//PWM输出
void TIM_PWM_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
  TIM_OCInitTypeDef	TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	
	TIM_TimeBaseInitStructure.TIM_Period=3000-1;
	TIM_TimeBaseInitStructure.TIM_Prescaler=2-1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);

    
  TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;        // PWM模式2:CNT>CCR时输出有效
  TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效为高电平
  TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
  TIM_OC1Init(TIM4,&TIM_OCInitStructure);        
  TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);        //使能预装载寄存器
    	

	TIM_Cmd(TIM4,ENABLE);




}

4.pid部分

void PID_Init(float A,float Kp,float Ki,float Kd,float target)
{	
error=target-A;   //目标速度小于电机速度,误差负值
integral+=error;    //误差累积
if(integral>2750)  {integral=2750;}   //积分限幅
if(integral<-2750) {integral=-2750;}	
p_out=Kp*error;
i_out=Ki*integral;
d_out=Kd*(error-error_last);
if(error>2000) {i_out=0;}      //积分分离
pwmout=p_out+i_out+d_out;
error_last =error;
if(pwmout>2750) {pwmout=2750;}
if(pwmout<-2750) {pwmout=-2750;}
change(pwmout);
return pwmout;
} 





void change(float a)
{
 if(a<0)
 {
	a=-a;
	TIM_SetCompare1(TIM4,a); 
	D0=0;
	D1=1;
 }
 else if(a>0)
 {
  TIM_SetCompare1(TIM4,a);
	D0=1;
	D1=0;	 
 }
 else
{
  TIM_SetCompare1(TIM4,0);
	D0=0;
	D1=0;
}
}

change()函数实现对pwmout正负数限制,电机反转时,pwmout为负值;电机正转,pwmout正值;

5.对速度解算

float encoder_now =0 ;
float encoder_last=0;
float e ;
float count;
float Read_counter(void)
{

	encoder_last = encoder_now;             
  encoder_now = TIM2->CNT;
	e = encoder_now - encoder_last;
		if(e > 32767) //
		{
			e =e-65535;//
		}
		else if(e<-32767)
		{
			e = e + 65535;//
		}		
		else 
		{
			e=e;//普通情况
		}	 
		
	 return e;
	}

float calculate_speed()
{
	  A = Read_counter(); 
	  n =A/(11*4*9.6);//电机一圈脉冲数*倍频*减速比
	  speed=n/0.005;       
	  return speed;
}

6.最后对PID实现

void TIM3_IRQHandler(void)  
{  
 if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
 {
	 float speed_temp;
	 static float angle_temp;
	 speed_temp=Read_counter(); 读取CNT
	 angle_temp+=speed_temp;     角度是对速度积分
	 real_angle=angle_temp*0.85227;   将CNT转为角度,用读取的CNT/一圈脉冲数*360
	 speed_temp= calculate_speed();
	 motorspeed=speed_temp*100;//扩大速度倍数
	 motorspeed=filter(motorspeed);//滤波后得到可用的速度
  
//角度环输出值为速度环输入值
	 pid_angle=pid_init(goal_angle,x,y,z,real_angle);
	 pid_speed=pid_init(pid_angle,13.5,1.25,36,motorspeed);
	

	 TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
 }
 }

  • 4
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
角度串联角速度环是一种常见的控制算法,其实现原理是通过控制机器人关节的角度和角速度来达到精准的控制效果。下面是一个简单的角度串联角速度环的伪代码实现: ``` // 定义角度PID控制器参数 float angle_Kp = 0.5; float angle_Ki = 0.1; float angle_Kd = 0.2; // 定义角速度环PID控制器参数 float speed_Kp = 0.3; float speed_Ki = 0.2; float speed_Kd = 0.1; // 初始化PID控制器 float angle_err, angle_last_err, angle_int_err, angle_derivative_err; float speed_err, speed_last_err, speed_int_err, speed_derivative_err; float angle_output, speed_output; float desired_angle, desired_speed, current_angle, current_speed; while(1) { // 读取期望角度和期望角速度以及当前角度和当前角速度 desired_angle = read_desired_angle(); desired_speed = read_desired_speed(); current_angle = read_current_angle(); current_speed = read_current_speed(); // 计算角度的误差和控制输出 angle_err = desired_angle - current_angle; angle_int_err += angle_err; angle_derivative_err = angle_err - angle_last_err; angle_output = angle_Kp * angle_err + angle_Ki * angle_int_err + angle_Kd * angle_derivative_err; angle_last_err = angle_err; // 计算角速度环的误差和控制输出 speed_err = desired_speed - current_speed; speed_int_err += speed_err; speed_derivative_err = speed_err - speed_last_err; speed_output = speed_Kp * speed_err + speed_Ki * speed_int_err + speed_Kd * speed_derivative_err; speed_last_err = speed_err; // 将角度的输出作为角速度环的输入 set_speed_reference(angle_output); // 将角速度环的输出作为电机控制信号输出 set_motor_output(speed_output); } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值