色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

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

          增量式PID的stm32實現,整定過程

          作者: 時間:2016-11-28 來源:網絡 收藏
        1. void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
        2. {
        3. TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;//TIM的初始化結構體
        4. NVIC_InitTypeDef NVIC_InitStructure;//中斷配置
        5. TIM_ICInitTypeDefTIM5_ICInitStructure;//TIM4PWM配置結構體
        6. GPIO_InitTypeDef GPIO_InitStructure;//IO口配置結構體
        7. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//Open TIM4 clock
        8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//open gpioB clock
        9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO 1
        10. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;//浮空輸入 上拉輸入
        11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        12. GPIO_Init(GPIOA, &GPIO_InitStructure);
        13. TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
        14. TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鐘頻率除數的預分頻值
        15. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim
        16. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上計數模式
        17. TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
        18. NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
        19. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        20. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        21. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        22. NVIC_Init(&NVIC_InitStructure);
        23. TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
        24. TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
        25. TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
        26. TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        27. TIM5_ICInitStructure.TIM_ICFilter = 0x3;//Filter:過濾
        28. TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);//PWM輸入配置
        29. TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);//選擇有效輸入端
        30. TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);//配置為主從復位模式
        31. TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//啟動定時器的被動觸發(fā)
        32. TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);//中斷配置
        33. TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中斷標志位
        34. TIM_Cmd(TIM5, ENABLE);
        35. }
        36. void TIM5_IRQHandler(void)
        37. {
        38. {
        39. if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕獲1發(fā)生捕獲事件
        40. {
        41. duty_TIM5=TIM_GetCapture1(TIM5); //采集占空比
        42. if(TIM_GetCapture2(TIM5)>600)period_TIM5=TIM_GetCapture2(TIM5);
        43. CollectFlag_TIM5 = 0;
        44. }
        45. }
        46. TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中斷標志位
        47. }
        48. 復制代碼


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

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

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

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


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

          正題:控制流程是這樣的,首先我設定我需要的車速(對應四個輪子的轉速),然后PID就是開始響應了,它先采樣電機轉速,得到偏差值E,帶入PID計算公式,得到調整量也就是最終更改了PWM的占空比,不斷調節(jié),直到轉速在穩(wěn)態(tài)的一個小范圍上下浮動。
          上面講到的“得到調整量”就是增量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為系數的寫法,實際結果是一樣的。
          處理過程放在了TIM6,溢出周期時間就是是PID里面采樣周期(區(qū)分于反饋信號的采樣,反饋信號采樣是1M的頻率)
          相關代碼:
          1. void TIM6_IRQHandler(void)//采樣時間到,中斷處理函數
          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);//重新設定PWM值
          27. TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中斷標志位
          28. }
          復制代碼


          上面幾個代碼是PID實現的關鍵部分

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

          關鍵詞: 增量式PIDstm32整定過

          評論


          相關推薦

          技術專區(qū)

          關閉