簡體   English   中英

電機PI調節器結構代碼

[英]Motor PI regulator structure code

我實際上正在基於freeRTOS的機器人項目上工作。 PI控制器控制機器人的車輪速度時遇到一些問題。

#define To 100 // 100 ms     
   #define Te 5  // 5 ms
   #define Kp 0.01
   #define Ti 10  //0.1*To
   #define Ki 0.05/10   //Te/ti

   void corrNum(int consigneVitesse) // takes speed as parameter 
   {
        int eL,eR = 0; errors left and right
         float cdeL = 0 ;
         float UpL = 0 ;
         int dutyL = 0 ;
         float cdeR = 0 ;
    float UpR = 0 ;
    int dutyR = 0 ;
    float UiL= 0 ;
    float UiR = 0 ;
    if(consigneVitesse)
    {
            tickL = quadEncoder_GetSpeedL();
            tickR = quadEncoder_GetSpeedR();
            eL = (int)(consigneVitesse - tickL);
            eR = (int)(consigneVitesse - tickR);
            UpL = Kp*eL ;
            UpR = Kp*eR ;
            UiL= UiL + Kp*Ki*eL ;
            UiR= UiR + Kp*Ki*eR ;
            UiL_prev = UiL ;
            UiR_prev = UiR ;
            cdeL = UpL + UiL ;
            cdeR = UpR + UiR ;
            dutyL = cdeL < 100 && cdeL > -100 ? (int)cdeL +100 : 200 ;
            dutyR = cdeR < 100 && cdeR > -100 ? (int)cdeR +100 : 200 ;
            motorLeft_SetDuty(dutyL);
            motorRight_SetDuty(dutyR);
            HAL_Delay(5); // sampling period 5 ms
            term_printf("MOTOR LEFT ::::::> CMD : %d SPEED : %d Err : %d    DUTY : %d\n\r",consigneVitesse,tickL,eL,dutyL`enter code here`);
            term_printf("MOTOR RIGHT ::::::> CMD : %d SPEED : %d Err : %d  DUTY : %d \n\r",consigneVitesse,tickR,eR,dutyR);;
            tickL = 0 ;
            tickR = 0;
    }
    else
    {
        motorLeft_SetDuty(100);
        motorRight_SetDuty(100);
    }


}`

問題是,當誤差達到0.0而不是穩定時,它就會開始振盪。

目前尚不清楚您如何在此解決方案中使用FreeRTOS-片段中沒有FreeRTOS調用,非RTOS HAL_delay()和時間關鍵控制循環中的終端輸出將無濟於事-您只能輸出57個字符5毫秒內-您沒有時間輸出文本。

錯誤信號的計算錯誤是編碼器提供的相對位置而不是速度; 您必須根據位置隨時間的變化來計算速度。

您應該將任務分配給控制回路,並使用RTOS時序來確保高效而准確的調度。 該任務應相對於其他任務以足夠高的優先級運行,以確保無抖動定時。

以下應視為偽代碼; 我不熟悉FreeRTOS API,因此OS調用不是真實的,並且我沒有處理實例化任務本身,也沒有處理擴展和其他您沒有提供足夠信息的細節-建議這樣做您應該從中獲取的控制器結構-而不是逐字記錄實際的代碼:

typedef enum
{
  LEFT = 0,
  RIGHT = 1
} tMotorId

volatile static struct
{
  float integral ;
  int speed ;
  int previous_position ;
} motor_ctrl_data[2] = {{0,0},{0,0}} ;

void setSpeed( tMotorId id, int speed )
{
  motor_ctrl_data[id] = speed ;
}

void motor_ctrl_task()
{
  // Configure RTOS time for 5ms update period
  OS_TIMER timer = creatTimer( 5 ) ;
  startTimer( timer ) ;

  // Get initial encoder counts
  motor_ctrl_data[LEFT].previous_position = getEncoder(LEFT) ;
  motor_ctrl_data[RIGHT].previous_position = getEncoder(RIGHT) ;

  // PI control loop
  for(;;)
  {
    // Loop update timer wait
    waitTimer( timer ) ;

    // For each motor
    for( int m = 0; m < 2; m++ )
    {
      // Calculate speed
      int speed = getEncoder[m] - motor_ctrl_data[m].previous_position ;

      // Calculate speed error
      int error = motor_ctrl_data[m].speed - speed[m] ;

      // Calculate error integral
      motor_ctrl_data[m].integral += error[m] ;

      motorDuty( LEFT, Kp * error +  Ki * motor_ctrl_data[m].integral ) ;
    }
  }
}

當然,這本身並不能解決振盪,但是至少是一種控制器結構能夠控制給定的適當系數。 要調整環路,請設置Ki = 0並增加Kp,直到電機盡可能快地運動而沒有振盪。 這不會使您達到目標速度,因為在目標上誤差為零,因此僅Kp無法工作。 然后開始增加Ki直到達到目標速度。 即使是很小的Ki,最終也能達到目標速度,但動態響應會很慢。 太多,您將獲得超調或振盪。

根據電動機的動態響應,您可能需要進行其他調整,例如積分限制或死區補償。 您甚至可以從微分項中受益,但是對於簡單的速度控制器而言,這通常是不必要的,並且通常很難調整。

如果需要輸出調試數據,請讓循環將調試數據寫入共享變量(例如,如果使用上述建議的結構,則在motor_ctrl_data中),並以較低的優先級任務以終端輸出可以維持的速率異步打印它們。

蒂姆·韋斯科特(Tim Wescott)的文章“ 沒有博士學位的PID ”可能是有用的讀物​​。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM