제어에 쓰이는 PID
개념은 너무나 쉽기 때문에 설명하지 않겠다.
게인을 잡는 것은 너무 어렵기 때문에 그것도 설명하지 않겠다.
그냥 경험상 P게인 잡고, D게인 잡고, I게인 잡고, 다시 반복하면 된다.
스텝 리스펀스를 이용해서 잡으면 된다.
헤더 파일
typedef struct { float Ref; // Input: Reference input float Fdb; // Input: Feedback input float Err; // Variable: Error float ErrSum; // Variable: Error Sum float Kp; // Parameter: Proportional gain float Up; // Variable: Proportional output float Ui; // Variable: Integral output float Ud; // Variable: Derivative output float OutPreSat; // Variable: Pre-saturated output float OutMax; // Parameter: Maximum output float OutMin; // Parameter: Minimum output float Out; // Output: PID output float iMax; // Parameter: Maximum Integration float Ki; // Parameter: Integral gain float Kd; // Parameter: Derivative gain float ErrPrev; // History: Previous error void (*calc)(); // Pointer to calculation function } PIDREG3; typedef PIDREG3 *PIDREG3_handle; #define PWM_MIN 1500 // 20ms PID 제어주기 // 속도 제어 PID 게인 #define L_Kp 33.0 //30.0 //30.0 #define L_Ki 6.0 //5.0 //8.0 #define L_Kd 0 #define L_OutMax 4900.0 #define L_OutMin -4900.0 #define L_iMax 4900.0 void pid_reg3_calc_v(PIDREG3_handle); #define PIDREG3_V_LEFT { 0.0, 0.0, 0.0, 0.0, L_Kp, 0.0, 0.0, 0.0, 0.0, \ L_OutMax, L_OutMin, 0.0, L_iMax, L_Ki, L_Kd, 0.0, \ (void (*)(Uint32))pid_reg3_calc_v }
소스 파일
void pid_reg3_calc_v(PIDREG3 *v) { float outpresave; // Compute the error v->Err = v->Ref - v->Fdb; // Compute the error sum v->ErrSum = v->ErrSum + v->Err; // Compute the proportional output v->Up = v->Kp * v->Err; // Compute the integral output v->Ui = v->Ki*v->ErrSum; if(v->Ui > v->iMax) v->Ui = v->iMax; else if(v->Ui < (-1.0 * v->iMax) ) v->Ui = -1.0 * v->iMax; // Compute the derivative output v->Ud = v->Kd * (v->Err - v->ErrPrev); // Compute the pre-saturated output v->OutPreSat = v->Up + v->Ui + v->Ud; outpresave = v->OutPreSat; // PWM 값이 20KHz에서 0 ~ 4000 까지의 값을 가질 수 있지만 // 최소 어느 정도의 값을 줘야 실제 로봇(O2)의 바퀴가 // 천천히 돌기 시작하기 때문에 다음과 같이 한다. if(v->OutPreSat < PWM_MIN && v->OutPreSat > 0.0 && v->Ref!=0) v->OutPreSat = PWM_MIN; else if(v->OutPreSat > -PWM_MIN && v->OutPreSat < 0.0 && v->Ref!=0) v->OutPreSat = -PWM_MIN; // Saturate the output if(v->OutPreSat > v->OutMax) v->Out = v->OutMax; else if(v->OutPreSat < v->OutMin) v->Out = v->OutMin; else v->Out = v->OutPreSat; v->ErrPrev = v->Err; // myprintf("Vcalc: "); // myprintf("Kp: %d Ki: %d Kd: %d \r\n", (int)v->Kp, (int)v->Ki, (int)v->Kd ); // myprintf("Ref: %d Fdb: %d Err: %d ErrSum: %d Outpre: %d(%d+%d+%d) Out: %d \r\n", (int)(v->Ref), (int)(v->Fdb), (int)(v->Err), (int)(v->ErrSum), (int)(outpresave), (int)(v->Up), (int)(v->Ui), (int)(v->Ud), (int)(v->Out) ); }
실제 사용
PIDREG3 pidVR = PIDREG3_V_RIGHT; PIDREG3 pidVL = PIDREG3_V_LEFT; { ........ pidVR.Fdb = (float)(g_EncoderR - Encoder_R_prev); pidVL.Fdb = (float)(g_EncoderL - Encoder_L_prev); pidVR.calc(&pidVR); pidVL.calc(&pidVL); rightS = (int32)pidVR.Out; leftS = (int32)pidVL.Out; SetDriveDirection(leftS, rightS); mR_PWM(rightS); mL_PWM(leftS); } Encoder_R_prev = g_EncoderR; Encoder_L_prev = g_EncoderL;
'Enginius > Firmware' 카테고리의 다른 글
PIC32 - PWM (0) | 2010.02.19 |
---|---|
PIC32 - Input Capture (0) | 2010.02.19 |
PIC32 - I2C (0) | 2010.02.17 |
PIC32 - GPIO (0) | 2010.02.17 |
PIC32 - Interrupt (0) | 2010.02.17 |