电子设计竞赛控制组——完整旋转倒立摆程序

以前也想过要写博客,但是却一直没有付诸于实践,作为第一篇原创,我还是选择将以前电赛时的作品拿出来,毕竟当初可是花费了好多心血的,汗~

旋转倒立摆是控制组校内赛练手的题目,需要对PID非常熟悉才能调好参数,以下代码是自己搭建好结构后调试出来的程序,其中的参数会根据不同的结构作出调整。

结构组成:

K60开发板(带液晶屏和按键),角度编码器,直流减速电机(带编码器),12V的电机驱动,金属摆臂,12V的电池组。

开发环境:

IAR 7.2

另:以下就是main函数部分了,详细的工程就不展示,核心部分基本都在这儿了,这些能看懂的话,作品也基本没什么问题了,就这样了,哈!

/********************************************************
――――――――――――――――――――――――――――――
**************************旋转倒立摆*********************
――――――――――――――――――――――――――――――
********************************************************/
# include "include.h"
# include "common.h"

#define angle ADC0_SE11// 定义角度传感器引脚为A8

//角度传感器
int16 angle_var = 0;//定义角度变量
int16 banlace_angle=2390;//定义摆杆平衡位置//2390

//编码器变量
int16 Voltage=0;//电机转速
int16 PWM = 0;//最终占空比
int16 val=0;//定义电机转速积分,经过低通滤波

//电机变量
int16 moto1,moto2,dir;

//函数声明
void PIT0_IRQHandler(void);
void Angle_PD_Realize(int16 angle_var,int16 real_angle);
void Speed_PID_Realize(int16 speed);
int16 PID_PWM();
void ADC(void);
void Init_All(void);

/*********************************************************
                   PID结构体定义
*********************************************************/
struct Speed_PID
{
    int16 Last_Speed;//定义上一次速度
    int16 Error_Now;//定义现在速度偏差
    int16 Error_Next;//定义上一次偏差
    int16 Error_Last;//定义上上次偏差
    float Speed_KP,Speed_KI,Speed_KD;//定义PID参数
    int16 integral_Voltage;//定义电机转速积分
    int16 SPEED_PWM;//定义速度偏差补偿占空比
}sp;

struct Angle_PD
{
    int16 Set_Angle;//期望角度
    int16 Real_Angle;//实际角度
    int16 Error_Now;//现在偏差
    int16 Error_Next;//上一次偏差
    float Angle_KP,Angle_KI,Angle_KD;//PD参数
    int16 ANGLE_PWM;//定义角度偏差补偿占空比
}ag;

/******************************************************
                  角度PID算法实现
******************************************************/
void Angle_PD_Realize(int16 banlace_angle,int16 angle_var)
{
  
    ag.Set_Angle = banlace_angle;
    ag.Real_Angle = angle_var;
    ag.Error_Now = ag.Set_Angle - ag.Real_Angle;//现在角度偏差
    ag.ANGLE_PWM = (int16)(ag.Angle_KP*ag.Error_Now +ag.Angle_KD*(ag.Error_Now-ag.Error_Next));// 输出与偏差成正比,与偏差率成正比
    ag.Error_Next = ag.Error_Now;//保存这次的误差 
  
}

/******************************************************
                  速度PID算法实现
******************************************************/
void Speed_PID_Realize(int16 speed)
{
    sp.Error_Now = Voltage-sp.Last_Speed;//现在速度偏差
    sp.SPEED_PWM = (int16)(sp.Speed_KP*val+sp.Speed_KI*sp.integral_Voltage + sp.Speed_KD*(sp.Error_Now-2*sp.Error_Next+sp.Error_Last));
    sp.Last_Speed=Voltage;//保存本次速度
    sp.Error_Last = sp.Error_Next;//保存上一次误差
    sp.Error_Next = sp.Error_Now;//保存本次误差
}

/******************************************************
                   最终占空比调节
******************************************************/
int16 PID_PWM()
{
    PWM = ag.ANGLE_PWM - sp.SPEED_PWM;
    if(PWM>=100){PWM = 100;}
    if(PWM<=-100){PWM = -100;}
    return PWM;
}

/******************************************************
                  电机PWM控制
******************************************************/
void moto(void)
{       
    dir = PID_PWM();
    if(dir<=0){moto1=-dir;moto2=0;}
    else{moto1=0;moto2=dir;}
    ftm_pwm_duty(FTM0, FTM_CH3,moto1);
    ftm_pwm_duty(FTM0, FTM_CH4,moto2);
}

/******************************************************
                    AD转换角度采集
******************************************************/
void ADC(void)
{
   int32 sum = 0;
   for(int i=0;i<20;i++)
   {
      angle_var = (adc_once(ADC0_SE11,ADC_8bit)*3300/(1<<8)-1);
      sum += angle_var;
   }
   angle_var = sum/20;
   sum = 0;
}

/******************************************************
                    定时中断函数
******************************************************/
void PIT0_IRQHandler(void)
{
    //ADC采集角度传感器
    ADC();
  
    //取编码器脉冲值
    //FTM1_A -> PTA12*****A相
    //FTM1_B -> PTA13*****B相
    Voltage = ftm_quad_get(FTM1);
    sp.integral_Voltage+=Voltage;
    val=(int16)(val*0.95+Voltage*6.5);//一阶低通滤波器
    val=val-2;

    //清 FTM 正交解码的脉冲数
    ftm_quad_clean(FTM1);
  
    //获取角度和速度
    Angle_PD_Realize(banlace_angle,angle_var);
    Speed_PID_Realize(0);
  
    //获取PWM最终占空比值
    PID_PWM();
  
    //清中断标志位
    PIT_Flag_Clear(PIT0);
    
}

//初始化所有模块
void Init_All(void)
{     
/***************speed******************/
    sp.Error_Now = 0;
    sp.Error_Next = 0;
    sp.Error_Last = 0;
    sp.Speed_KP = 0.8;//0.8
    sp.Speed_KI = 0.8;//0.4
    sp.Speed_KD = 5;//5
    sp.SPEED_PWM = 0;
    sp.integral_Voltage=0;
  
/***************angle******************/
    ag.Set_Angle = 0;
    ag.Real_Angle = 0;
    ag.Error_Now = 0;
    ag.Error_Next = 0;
    ag.Angle_KP = 0.65;
    ag.Angle_KD = 4;
    ag.ANGLE_PWM = 0;

    //初始化FTM正交解码
    ftm_quad_init(FTM1);   
    
    //初始化AD采集
    adc_init(ADC0_SE11);
    
    //初始化电机正转*****精度为100
    ftm_pwm_init(FTM0,FTM_CH3,10*1000,0);//PTA6
    ftm_pwm_init(FTM0,FTM_CH4,10*1000,0);//PTA7   
    // port_cfg.h 里配置 FTM0_CH3 对应为 PTA6
    // 使能端输入为 0
    
    //定时中断5msVoltage
    pit_init_ms(PIT0,5);
    set_vector_handler(PIT0_VECTORn,PIT0_IRQHandler);
    enable_irq(PIT0_IRQn);
}

/*――――――――――――――――――――――――
――――――――――主函数――――――――――――
――――――――――――――――――――――――*/
void main()
{
    int16 i;
    int16 j;
    Init_All();
    key_init(KEY_A);

/**********************************************
                    起摆
**********************************************/
    while(1)
    {
        if(key_check(KEY_A) == KEY_DOWN)
        {
            DELAY_MS(500);
            break;
        }
        else
        {
        ftm_pwm_duty(FTM0,FTM_CH3,0);
        ftm_pwm_duty(FTM0,FTM_CH4,0);
        }
    }
    //左右来回摆动
    for(j=0;j<2;j++)
    {
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,i);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,i);
          DELAY_MS(20);
        }
    }
    
    //延时等待最佳时机反向
    for(i= 0;i<=3;i++)
    {
    ftm_pwm_duty(FTM0,FTM_CH3,0);
    ftm_pwm_duty(FTM0,FTM_CH4,0);
    DELAY_MS(20);
    }
    
    //瞬间反向起摆
    for(i= 35;i<85;i+=5)
    {
      ftm_pwm_duty(FTM0,FTM_CH3,i);
      ftm_pwm_duty(FTM0,FTM_CH4,0);
      DELAY_MS(20);
    }
    
    //反向缓冲
    for(i= 40;i<90;i+=10)
    {
      ftm_pwm_duty(FTM0,FTM_CH3,0);
      ftm_pwm_duty(FTM0,FTM_CH4,i);
      DELAY_MS(20);
    }
/**********************************************
               动态停机,稳定倒立
**********************************************/
    while(1)
    {
      if(angle_var<=banlace_angle+350&&angle_var>=banlace_angle-350)
      {
        moto();
      }
      else
      {
        ftm_pwm_duty(FTM0,FTM_CH3,0);
        ftm_pwm_duty(FTM0,FTM_CH4,0);
      }
      if(key_check(KEY_A) == KEY_DOWN)
      {
        DELAY_MS(500);
        key_init(KEY_A);
        break;
      }
    }
/**********************************************
                   圆周起摆
**********************************************/
    while(1)
    {
        ftm_pwm_duty(FTM0,FTM_CH3,0);
        ftm_pwm_duty(FTM0,FTM_CH4,0);
        if(key_check(KEY_A) == KEY_DOWN)
        {
            DELAY_MS(500);
            break;
        }
    }
    //左右来回摆动
    for(j=0;j<2;j++)
    {
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,i);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,i);
          DELAY_MS(20);
        }
    }
    
    //延时等待最佳时机反向
    for(i= 0;i<=3;i++)
    {
    ftm_pwm_duty(FTM0,FTM_CH3,0);
    ftm_pwm_duty(FTM0,FTM_CH4,0);
    DELAY_MS(20);
    }
    
    //瞬间反向起摆
    for(i= 30;i<100;i+=5)
    {
      ftm_pwm_duty(FTM0,FTM_CH3,i);
      ftm_pwm_duty(FTM0,FTM_CH4,0);
      DELAY_MS(20);
    }
/**********************************************
                    左右摇摆
**********************************************/
    while(1)
    {
      ftm_pwm_duty(FTM0,FTM_CH3,0);
      ftm_pwm_duty(FTM0,FTM_CH4,0);
      if(key_check(KEY_A) == KEY_DOWN)
      {
        DELAY_MS(500);
        break;
      }
    }
    //左右来回摆动
    for(j=0;j<1;j++)
    {
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,i);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
        for(i= 10;i<=40;i+=2)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,i);
          DELAY_MS(20);
        }
    }
    while(1)
    {
      for(j=0;j<2;j++)
      {
        for(i= 10;i<=20;i+=1)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,i);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
        for(i= 0;i<=5;i++)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
        for(i= 10;i<=20;i+=1)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,i);
          DELAY_MS(20);
        }
        for(i= 0;i<=5;i++)
        {
          ftm_pwm_duty(FTM0,FTM_CH3,0);
          ftm_pwm_duty(FTM0,FTM_CH4,0);
          DELAY_MS(20);
        }
      }
      if(key_check(KEY_A) == KEY_DOWN)
      {
        DELAY_MS(1000);
        Init_All();
        break;
      }
    }
/**********************************************
               倒立快速旋转
**********************************************/    
    while(1)
    {
      if(angle_var<=banlace_angle+350&&angle_var>=banlace_angle-350)
      {
        moto();
        sp.integral_Voltage = 200;
      }
      else
      {
        ftm_pwm_duty(FTM0,FTM_CH3,0);
        ftm_pwm_duty(FTM0,FTM_CH4,0);
      }
      if(key_check(KEY_A) == KEY_DOWN)
      {
        DELAY_MS(500);
        Init_All();
        break;
      }
    }
/**********************************************
               动态停机,稳定倒立
**********************************************/
    while(1)
    {
      if(key_check(KEY_A) == KEY_DOWN)
      {
        DELAY_MS(500);
        Init_All();
      }
      if(angle_var<=banlace_angle+350&&angle_var>=banlace_angle-350)
      {
        moto();
      }
      else
      {
        ftm_pwm_duty(FTM0,FTM_CH3,0);
        ftm_pwm_duty(FTM0,FTM_CH4,0);
      }
    }
}

  • 24
    点赞
  • 146
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值