123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /************************************************************************
- Description:PID控制器的代码实现。
- Author: www.corvin.cn
- History: 20180209: init this file;
- **************************************************************************/
- #include "pid_controller.h"
- #include "encoder_driver.h"
- static SetPointInfo AWheelPID, BWheelPID, CWheelPID;
- /*default PID Parameters */
- static int AWheel_Kp = 11;
- static int AWheel_Kd = 15;
- static int AWheel_Ki = 0;
- static int AWheel_Ko = 50;
- static int BWheel_Kp = 11;
- static int BWheel_Kd = 15;
- static int BWheel_Ki = 0;
- static int BWheel_Ko = 50;
- static int CWheel_Kp = 11;
- static int CWheel_Kd = 15;
- static int CWheel_Ki = 0;
- static int CWheel_Ko = 50;
- static unsigned char moving = 0; // is the base in motion?
- void setWheelPIDTarget(int value_A, int value_B, int value_C)
- {
- AWheelPID.TargetTicksPerFrame = value_A;
- BWheelPID.TargetTicksPerFrame = value_B;
- CWheelPID.TargetTicksPerFrame = value_C;
- }
- unsigned char getMoveStatus(void)
- {
- return moving;
- }
- void setMoveStatus(unsigned char state)
- {
- moving = state;
- }
- void updatePIDParam(int index, int kp, int kd, int ki, int ko)
- {
- switch (index)
- {
- case A_WHEEL:
- AWheel_Kp = kp;
- AWheel_Kd = kd;
- AWheel_Ki = ki;
- AWheel_Ko = ko;
- break;
- case B_WHEEL:
- BWheel_Kp = kp;
- BWheel_Kd = kd;
- BWheel_Ki = ki;
- BWheel_Ko = ko;
- break;
- case C_WHEEL:
- CWheel_Kp = kp;
- CWheel_Kd = kd;
- CWheel_Ki = ki;
- CWheel_Ko = ko;
- break;
- default:
- break;
- }
- }
- /*
- Initialize PID variables to zero to prevent startup spikes
- when turning PID on to start moving
- In particular, assign both Encoder and PrevEnc the current encoder value
- See http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
- Note that the assumption here is that PID is only turned on
- when going from stop to moving, that's why we can init everything on zero.
- */
- void resetPID(void)
- {
- AWheelPID.TargetTicksPerFrame = 0.0;
- AWheelPID.Encoder = readEncoder(A_WHEEL);
- AWheelPID.PrevEnc = AWheelPID.Encoder;
- AWheelPID.output = 0L;
- AWheelPID.PrevInput = 0;
- AWheelPID.ITerm = 0;
- BWheelPID.TargetTicksPerFrame = 0.0;
- BWheelPID.Encoder = readEncoder(B_WHEEL);
- BWheelPID.PrevEnc = BWheelPID.Encoder;
- BWheelPID.output = 0L;
- BWheelPID.PrevInput = 0;
- BWheelPID.ITerm = 0;
- CWheelPID.TargetTicksPerFrame = 0.0;
- CWheelPID.Encoder = readEncoder(C_WHEEL);
- CWheelPID.PrevEnc = CWheelPID.Encoder;
- CWheelPID.output = 0L;
- CWheelPID.PrevInput = 0;
- CWheelPID.ITerm = 0;
- }
- /* PID routine to compute the next A motor commands */
- void doAWheelPID(SetPointInfo *p)
- {
- long Perror = 0L;
- long output = 0L;
- int input = 0;
- p->Encoder = readEncoder(A_WHEEL);
- input = p->Encoder - p->PrevEnc;
- Perror = p->TargetTicksPerFrame - input;
- /*
- Avoid derivative kick and allow tuning changes,
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- output = (AWheel_Kp * Perror - AWheel_Kd * (input - p->PrevInput) + p->ITerm) / AWheel_Ko;
- p->PrevEnc = p->Encoder; //save current encoder value to preEncoder
- // Accumulate Integral error *or* Limit output. Stop accumulating when output saturates
- output += p->output;
- if (output >= MAX_PWM)
- {
- output = MAX_PWM;
- }
- else if (output <= -MAX_PWM)
- {
- output = -MAX_PWM;
- }
- else
- {
- /*
- allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- p->ITerm += AWheel_Ki * Perror;
- }
- p->output = output; //save current pid output for next pid
- p->PrevInput = input;
- }
- /* PID routine to compute the next motor commands */
- void doBWheelPID(SetPointInfo *p)
- {
- long Perror = 0L;
- long output = 0L;
- int input = 0;
- p->Encoder = readEncoder(B_WHEEL);
- input = p->Encoder - p->PrevEnc;
- Perror = p->TargetTicksPerFrame - input;
- /*
- Avoid derivative kick and allow tuning changes,
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- output = (BWheel_Kp * Perror - BWheel_Kd * (input - p->PrevInput) + p->ITerm) / BWheel_Ko;
- p->PrevEnc = p->Encoder;
- // Accumulate Integral error *or* Limit output. Stop accumulating when output saturates
- output += p->output;
- if (output >= MAX_PWM)
- {
- output = MAX_PWM;
- }
- else if (output <= -MAX_PWM)
- {
- output = -MAX_PWM;
- }
- else
- {
- /*
- allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- p->ITerm += BWheel_Ki * Perror;
- }
- p->output = output;
- p->PrevInput = input;
- }
- /* PID routine to compute the next motor commands */
- void doCWheelPID(SetPointInfo *p)
- {
- long Perror = 0L;
- long output = 0L;
- int input = 0;
- p->Encoder = readEncoder(C_WHEEL);
- input = p->Encoder - p->PrevEnc;
- Perror = p->TargetTicksPerFrame - input;
- /*
- Avoid derivative kick and allow tuning changes,
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- output = (CWheel_Kp * Perror - CWheel_Kd * (input - p->PrevInput) + p->ITerm) / CWheel_Ko;
- p->PrevEnc = p->Encoder;
- // Accumulate Integral error *or* Limit output. Stop accumulating when output saturates
- output += p->output;
- if (output >= MAX_PWM)
- {
- output = MAX_PWM;
- }
- else if (output <= -MAX_PWM)
- {
- output = -MAX_PWM;
- }
- else
- {
- /*
- allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
- */
- p->ITerm += CWheel_Ki * Perror;
- }
- p->output = output;
- p->PrevInput = input;
- }
- /* Read the encoder values and call the PID routine */
- void updatePID(void)
- {
- if (!moving) /* If we're not moving, resetPID() there is nothing more to do */
- {
- /*
- Reset PIDs once, to prevent startup spikes,
- see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
- PrevInput is considered a good proxy to detect whether reset has already happened
- */
- if (AWheelPID.PrevInput != 0 || BWheelPID.PrevInput != 0 || CWheelPID.PrevInput != 0)
- {
- resetPID();
- }
- }
- else
- {
- /* Compute PID update for each motor */
- doAWheelPID(&AWheelPID);
- doBWheelPID(&BWheelPID);
- doCWheelPID(&CWheelPID);
- /* Set the motor speeds accordingly */
- setMotorSpeeds(AWheelPID.output, BWheelPID.output, CWheelPID.output);
- }
- }
- long readPidIn(int wheel)
- {
- long pidin = 0L;
- if (wheel == A_WHEEL)
- {
- pidin = AWheelPID.PrevInput;
- }
- else if (wheel == B_WHEEL)
- {
- pidin = BWheelPID.PrevInput;
- }
- else
- {
- pidin = CWheelPID.PrevInput;
- }
- return pidin;
- }
- long readPidOut(int wheel)
- {
- long pidout = 0L;
- if (wheel == A_WHEEL)
- {
- pidout = AWheelPID.output;
- }
- else if (wheel == B_WHEEL)
- {
- pidout = BWheelPID.output;
- }
- else
- {
- pidout = CWheelPID.output;
- }
- return pidout;
- }
|