新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 增量式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);//啟動定時器的被動觸發
      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發生捕獲事件
      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 什么什么對程序不太好,各位幫忙寫個優化辦法看看呢? 用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的占空比,不斷調節,直到轉速在穩態的一個小范圍上下浮動。
        上面講到的“得到調整量”就是增量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里面采樣周期(區分于反饋信號的采樣,反饋信號采樣是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));//常規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,在微調。其他的辦法特別是有個尼古拉斯法我發現不適合我這個控制對象。
        先Kp,就是消除積分和微分部分的影響,這里我糾結過到底是讓Ti 等于一個很大的值讓Ki=Kp*(T/Ti)里面的KI接近零,還是直接定義KI=0,TI=0.
        然后發現前者沒法找到KP使系統震蕩的臨界值,第二個辦法可以得到預期的效果:即KP大了會產生震蕩,小了會讓系統穩定下來,當然這個時候是有穩態誤差的。
        隨后把積分部分加進去,KI=Kp*(T/Ti)這個公式用起來,并且不斷調節TI 。TI太大系統穩定時間比較長。
        然后加上Kd=Kp*(Td/T),對于系統響應比較滯后的情況效果好像好一些,我這里的電機反映挺快的,所以Td值很小。
        最后就是幾個參數調節一下,讓波形好看一點。這里的波形實際反映的是采集回來的轉速值,用STM32的DAC功能輸出和轉速對應的電壓,用示波器采集的。
        上一頁 1 2 下一頁

        關鍵詞: 增量式PIDstm32整定過

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 朝阳县| 伊宁县| 临潭县| 会东县| 灵川县| 宝鸡市| 泗水县| 富源县| 贵定县| 苏州市| 永善县| 南京市| 南靖县| 云南省| 建瓯市| 宁化县| 大渡口区| 青铜峡市| 冕宁县| 蒙城县| 万荣县| 安吉县| 金坛市| 丰台区| 神池县| 衡南县| 景谷| 溆浦县| 观塘区| 兰溪市| 富民县| 塘沽区| 阳信县| 通榆县| 高州市| 洞口县| 四川省| 正安县| 花莲县| 银川市| 格尔木市|