新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 增量式PID的stm32實現(xiàn),整定過程

增量式PID的stm32實現(xiàn),整定過程

作者: 時間:2016-11-28 來源:網(wǎng)絡(luò) 收藏
  • void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
  • {
  • TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;//TIM的初始化結(jié)構(gòu)體
  • NVIC_InitTypeDef NVIC_InitStructure;//中斷配置
  • TIM_ICInitTypeDefTIM5_ICInitStructure;//TIM4PWM配置結(jié)構(gòu)體
  • GPIO_InitTypeDef GPIO_InitStructure;//IO口配置結(jié)構(gòu)體
  • RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//Open TIM4 clock
  • RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//open gpioB clock
  • GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO 1
  • GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;//浮空輸入 上拉輸入
  • GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  • GPIO_Init(GPIOA, &GPIO_InitStructure);
  • TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
  • TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來作為TIMx時鐘頻率除數(shù)的預分頻值
  • TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時鐘分割:TDTS = Tck_tim
  • TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上計數(shù)模式
  • TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時間基數(shù)單位
  • NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
  • NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  • NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  • NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  • NVIC_Init(&NVIC_InitStructure);
  • TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
  • TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  • TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  • TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  • TIM5_ICInitStructure.TIM_ICFilter = 0x3;//Filter:過濾
  • TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);//PWM輸入配置
  • TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);//選擇有效輸入端
  • TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);//配置為主從復位模式
  • TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//啟動定時器的被動觸發(fā)
  • TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);//中斷配置
  • TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中斷標志位
  • TIM_Cmd(TIM5, ENABLE);
  • }
  • void TIM5_IRQHandler(void)
  • {
  • {
  • if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕獲1發(fā)生捕獲事件
  • {
  • duty_TIM5=TIM_GetCapture1(TIM5); //采集占空比
  • if(TIM_GetCapture2(TIM5)>600)period_TIM5=TIM_GetCapture2(TIM5);
  • CollectFlag_TIM5 = 0;
  • }
  • }
  • TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中斷標志位
  • }
  • 復制代碼


    PID部分:
    準備部分:先定義PID結(jié)構(gòu)體:
    1. typedef struct
    2. {
    3. int setpoint;//設(shè)定目標
    4. int sum_error;//誤差累計
    5. float proportion ;//比例常數(shù)
    6. float integral ;//積分常數(shù)
    7. float derivative;//微分常數(shù)
    8. int last_error;//e[-1]
    9. int prev_error;//e[-2]
    10. }PIDtypedef;
    復制代碼

    這里注意一下成員的數(shù)據(jù)類型,依據(jù)實際需要來定的。
    在文件中定義幾個關(guān)鍵變量:
    1. floatKp =0.32; //比例常數(shù)
    2. floatTi =0.09 ; //積分時間常數(shù)
    3. float Td =0.0028 ;//微分時間常數(shù)
    4. #define T0.02 //采樣周期
    5. #define KiKp*(T/Ti)// Kp Ki Kd 三個主要參數(shù)
    6. #define KdKp*(Td/T)
    復制代碼

    C語言好像用#define 什么什么對程序不太好,各位幫忙寫個優(yōu)化辦法看看呢? 用const?

    PID.H里面主要的幾個函數(shù):
    1. void PIDperiodinit(u16 arr,u16 psc);//PID 采樣定時器設(shè)定
    2. void incPIDinit(void);//初始化,參數(shù)清零清零
    3. int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);//PID計算
    4. void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);//設(shè)定 PID預期值
    5. void PID_set(float pp,float ii,float dd);//設(shè)定PIDkp ki kd三個參數(shù)
    6. void set_speed(float W1,float W2,float W3,float W4);//設(shè)定四個電機的目標轉(zhuǎn)速
    復制代碼


    PID處理過程:
    岔開一下:這里我控制的是電機的轉(zhuǎn)速w,實際上電機的反饋波形的頻率f、電機轉(zhuǎn)速w、控制信號PWM的占空比a三者是大致線性的正比的關(guān)系,這里強調(diào)這個的目的是
    因為樓主在前期一直搞不懂我控制的轉(zhuǎn)速怎么和TIM4輸出的PWM的占空比聯(lián)系起來,后來想清楚里面的聯(lián)系之后通過公式把各個系數(shù)算出來了。

    正題:控制流程是這樣的,首先我設(shè)定我需要的車速(對應(yīng)四個輪子的轉(zhuǎn)速),然后PID就是開始響應(yīng)了,它先采樣電機轉(zhuǎn)速,得到偏差值E,帶入PID計算公式,得到調(diào)整量也就是最終更改了PWM的占空比,不斷調(diào)節(jié),直到轉(zhuǎn)速在穩(wěn)態(tài)的一個小范圍上下浮動。
    上面講到的“得到調(diào)整量”就是增量PID的公式:
    1. int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
    2. {
    3. int iError,iincpid;
    4. iError=PIDx->setpoint-nextpoint;//當前誤差
    5. iincpid=//增量計算
    6. PIDx->proportion*(iError-PIDx->last_error)
    7. +PIDx->integral*iError
    8. +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
    9. PIDx->prev_error=PIDx->last_error; //存儲誤差,便于下次計算
    10. PIDx->last_error=iError;
    11. return(iincpid) ;
    12. }
    復制代碼

    注釋掉的是第一種寫法,沒注釋的是第二種以Kp KI kd為系數(shù)的寫法,實際結(jié)果是一樣的。
    處理過程放在了TIM6,溢出周期時間就是是PID里面采樣周期(區(qū)分于反饋信號的采樣,反饋信號采樣是1M的頻率)
    相關(guān)代碼:
    1. void TIM6_IRQHandler(void)//采樣時間到,中斷處理函數(shù)
    2. {
    3. if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中斷
    4. {
    5. frequency1=1000000/period_TIM4; //通過捕獲的波形的周期算出頻率
    6. frequency2=1000000/period_TIM1;
    7. frequency3=1000000/period_TIM2;
    8. frequency4=1000000/period_TIM5;
    9. PID1.sum_error+=(incPIDcalc(&PID1,frequency1));//計算增量并累加
    10. pwm1=PID1.sum_error*4.6875 ; //pwm1 代表將要輸出PWM的占空比
    11. frequency1=0; //清零
    12. period_TIM4=0;
    13. PID2.sum_error+=(incPIDcalc(&PID2,frequency2));//計算增量并累加 Y=Y+Y
    14. pwm2=PID2.sum_error*4.6875 ; //將要輸出PWM的占空比
    15. frequency2=0;
    16. period_TIM1=0;
    17. PID3.sum_error+=(incPIDcalc(&PID3,frequency3));//常規(guī)PID控制
    18. pwm3=PID3.sum_error*4.6875 ; //將要輸出PWM的占空比
    19. frequency3=0;
    20. period_TIM2=0;
    21. PID4.sum_error+=(incPIDcalc(&PID4,frequency4));//計算增量并累加
    22. pwm4=PID4.sum_error*4.6875 ; //將要輸出PWM的占空比
    23. frequency4=0;
    24. period_TIM5=0;
    25. }
    26. TIM_SetCompare(pwm1,pwm2,pwm3,pwm4);//重新設(shè)定PWM值
    27. TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中斷標志位
    28. }
    復制代碼


    上面幾個代碼是PID實現(xiàn)的關(guān)鍵部分

    整定過程:
    辦法有不少,這里用的是先KP,再TI,再TD,在微調(diào)。其他的辦法特別是有個尼古拉斯法我發(fā)現(xiàn)不適合我這個控制對象。
    先Kp,就是消除積分和微分部分的影響,這里我糾結(jié)過到底是讓Ti 等于一個很大的值讓Ki=Kp*(T/Ti)里面的KI接近零,還是直接定義KI=0,TI=0.
    然后發(fā)現(xiàn)前者沒法找到KP使系統(tǒng)震蕩的臨界值,第二個辦法可以得到預期的效果:即KP大了會產(chǎn)生震蕩,小了會讓系統(tǒng)穩(wěn)定下來,當然這個時候是有穩(wěn)態(tài)誤差的。
    隨后把積分部分加進去,KI=Kp*(T/Ti)這個公式用起來,并且不斷調(diào)節(jié)TI 。TI太大系統(tǒng)穩(wěn)定時間比較長。
    然后加上Kd=Kp*(Td/T),對于系統(tǒng)響應(yīng)比較滯后的情況效果好像好一些,我這里的電機反映挺快的,所以Td值很小。
    最后就是幾個參數(shù)調(diào)節(jié)一下,讓波形好看一點。這里的波形實際反映的是采集回來的轉(zhuǎn)速值,用STM32的DAC功能輸出和轉(zhuǎn)速對應(yīng)的電壓,用示波器采集的。
    上一頁 1 2 下一頁

    關(guān)鍵詞: 增量式PIDstm32整定過

    評論


    相關(guān)推薦

    技術(shù)專區(qū)

    關(guān)閉