Society of Robots - Robot Forum

Software => Software => Topic started by: Benn on May 01, 2010, 04:01:59 AM

Title: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 01, 2010, 04:01:59 AM
Hi all. I'm facing another problem. I made a robot that travel from one point to another, avoiding obstacles, using Wavefront Algorithm. The algorithm is working very good, but the robot didn't use to go straight, so i tried to implement a PID controller. Now the robot is going more good than without PID, but still bad:( Sometimes he oscillates, overshoot the setpoint,, or moving brutally...
The gears  have encoders with 57pulses/rotation, and the PID rate is 10 times/sec.
I tried different values for Kp, Kd, Ki, but still bad.
Does anyone have an idea of the problem?
Here is the PID function:

void PID(void)
{
   int errorl = 0;       //error from left encoder
   int errorr = 0;       //error from right encoder
   int derrorl = 0;       //derivative error left
   int derrorr = 0;       //derivative error right
   
   int KP = 2;       //PID proportional gain constant
   float KD = 1;       //PID derivative gain constant
   float KI = 0.5;    //PID intergral gain constant

   

   errorl = setpoint - a; //calculate error values
   errorr = setpoint - b; // a is the encoder counter for left motor and b for right motor

   a = 0; //reset encoder counts ready for next sample
   b = 0;

   derrorl = (errorl - preverrorl);
   derrorr = (errorr - preverrorr);

   cl = ((KP*errorl) + (KD*derrorl) + (KI*Ierrorl)); //PID equations
   cr = ((KP*errorr) + (KD*derrorr) + (KI*Ierrorr));


   if (cl > cr)
   {
      OC2R = dtcMtrMedium + cl; //use output from PID equations to alter motor speeds
      OC2RS = dtcMtrMedium + cl;

      OC3R = dtcMtrMedium - cr;
      OC3RS = dtcMtrMedium - cr;
   }

   else
   if (cl < cr)
   {   
      OC2R = dtcMtrMedium - cl;  
      OC2RS = dtcMtrMedium - cl;
   
      OC3R = dtcMtrMedium + cr;
      OC3RS = dtcMtrMedium + cr;
   }   
   else
   {
      OC2R = dtcMtrMedium + cl;  
      OC2RS = dtcMtrMedium + cl;
   
      OC3R = dtcMtrMedium + cr;
      OC3RS = dtcMtrMedium + cr;   
   }

   preverrorl = errorl; //set previous error to current error
   preverrorr = errorr;

   Ierrorl = Ierrorl + errorl; //add current error to integral error
   Ierrorr = Ierrorr + errorr;
}
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: madsci1016 on May 02, 2010, 04:36:29 PM
You have no code to limit I wind-up, that could be your problem.

How are you tuning the system? First set I and D to 0.

Find a good P term that gives a quick response, but will have oscillations. Then find a D to reduce oscillations.

I would stay away from the I term for your system. Keep I = 0, for now, and tell me how your systems looks.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 03, 2010, 01:16:45 PM
I did as you say...left I = 0, and tuned the others...and it looks good for a short movement, but in time, it deviates from the path very much:((
I also increased the PID rate at 100 times/second, and the robot reaches it's setpoint very quick and very good, but, as i said, in time, it goes very bad:(
WHYY??:(:(:(:(:(
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: madsci1016 on May 03, 2010, 07:41:23 PM
When you say it deviates after a while, do you mean that if you are telling it to run a straight line, after a while it starts to curve one way or the other? Or that it starts oscillating?

If you are just saying it curves one way or the other, the answer is, ... tough. Adding a small amount of an I term (starting with 0.1 and up) may help some, but you also need to limit how large Ierror can get, or the system will oscillate from I term wind-up. 

But really, you have encoders with low resolution per turn, 57 pulses per rotation. To compare, on my SAGAR robot the wheels have 3000 pulses per rotation. The lower resolution means less ability to precisely keep the wheel spinning a certain speed. A faster control rate will just make it worse, as it will be even less precise. i wouldn't have a rate faster then 5Hz.

Also, you could be suffering from slip. wheels with encoders are never perfect, they always have some give that throw off encoder calculations, that can't be fixed.

Your best bet for you project, since you are using the encoder to localize your position, would be to track the number of pulses, and compute your location, rather then trying to force your robot to go straight, as it will never go perfectly straight.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 03, 2010, 08:24:01 PM
How are you using the wheel encoders?
Counting how many encode ticks happen in a fixed period of time? Or how many hardware timer counts happen for one encoder tick?

I have used the second method on a couple of bots with 8 and 12 encoder ticks per wheel revolution and the bot would track straight for a long distance. This only uses Proportional feedback, there is some over-shoot and oscillation in the speed but barely noticeable by watching the bot move.
The PWM duty is up-dated at every encoder tick, new count available, and not on a fixed time period.

I also have a diagnostic output to the serial port (cabled with MAX232 to comm port or XBees to com port). When working on the wheel speed feed-back code I output the encoder count, PWM duty count, encoder target count (this sets the desired wheel speed). I capture the data to a file using either Hyperterm or Teraterm then import the data file into Excel for plotting and analysis. It really helps to get real data to evaluate the feed-back control loop.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 06, 2010, 02:31:41 PM
So, waltr, i count up to 5 encoder pulses per one period of PID.
Do you think i have a chance to make it going straight with only 57 pulses/revolution?
Could you explain your metod please much more?
The Saturday, 15th of May, is the deadline for the project. Everything is perfect, but i'm so disapointed with those error, because the bot it's deviating from his path, and not going straight:(
I tried hundreds of times to get the error as small as posible, but in vain...
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 06, 2010, 03:25:16 PM
Ahh...you count the number of encoder pulse in a fixed period and 5 pulses is at the maximum speed. So at half that speed there is 2 encoder pulses. This is not much resolution of the bots real speed.

My method is to run a hardware timer/counter in the processor. On each encoder pulse I save the counter value and reset the counter to zero. I get about 50 counts at nominal speed. So if the bots wheels at 10% slow I get a count of 55. If your bot's wheels are 10% low you get a count of 5 or maybe 4 depending on where the encoder position is when the PID cycle starts.

So basically you can not resolve a small error and thus can not make a correction until the error is large enough. Another example: if the error is about 8% then no correctable error is detected and the bot merrily turns. Once the error is over ~15-20% then it is detectable and can be corrected to less than about 20%.

Since my encoders have a low number of counts per wheel revolution I went the other way and measured the time from one encoder pulse to the next with a fairly fast hardware counter. That allowed me to get finer resolution of the wheel speed. I also correct the PWM duty on every encoder pulse so that any little speed error actually averages out.

Does that help?
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 06, 2010, 03:31:28 PM
Man, that's genial...it did not cross my mind such an idea...hmmm...that's very good for a bot with so few pulses/revolution.
Thank you very much. I'll try to implement this and see the result. It sounds like the solution for my problem...i'll tell you if i'll get it work:)
Thanks again;)
One more question: did you use PID or not? from your explanation i understand that you didn't...?
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 06, 2010, 08:04:01 PM
Correct, I only used 'P'. I have the code in for 'D' but found that I didn't need it.

Good luck and keep us updated.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 07, 2010, 09:33:46 AM
Benn,

 I'll post the answer to your PM here so that anyone interested can follow.


I would never expect the encoder pulses from each wheel to happen at the same time. Each wheel is handled separately. I don't have the code here (I'm at work and the code is at home) and I am using a PIC so the code isn't 100% comparable.  However, since the latest code is written in C (the original code was in assembler) I'm sure you could benefit from looking it over. All the wheel speed measurements, corrections and PWM duty cycle setting in done in an ISR (Interrupt Service Routine). Here is a short overview:

ISR:
if timer interrupt // about every 200us
  increment left_wheel_encoder_count
  increment right_wheel_encoder_count
  clear timer interrupt flag

// wheel encoder pulse input is on a pin that causes an interrupt
if right wheel encode pulse is a rising edge
  new_right_wheel_speed = right_wheel_encoder_count
  clear right_wheel_encoder_count   // start a new count
  set new_right_wheel_speed_flag

if left wheel encode pulse is a rising edge
  new_left_wheel_encoder_count = left_wheel_encoder_count
  clear left_wheel_encoder_count
  set new_left_wheel_speed_flag

// PWM interrupt every fourth PWM period, about 1.2msec
if new_right_wheel_speed_flag is set
  right_wheel_error = new_right_wheel_encoder_count - right_wheel_target_speed // be sure to obtain the correct sign
  right_PWM_count = (Pconstant * right_wheel_error) + PWM_count // here the correction is applied
  clear new_right_wheel_speed_flag
  PWM_DC_REG = right_PWM_count  // will be loaded on the next PWM cycle

if new_left_wheel_speed_flag is set
  left_wheel_error = new_left_wheel_encoder_count - left_wheel_target_speed
  left_PWM_count = (Pconstant * left_wheel_error) + PWM_count
  PWM_DC_REG = right_PWM_count
  clear new_left_wheel_speed_flag
exit from ISR

So there are three interrupt routines (6 if you count each wheel separately).
The Timer ISR only counts the encode pulse time.
The wheel encoder pulse (rising only) saves the count from the Timer and sets a flag (bit) to let the PWM ISR know there is a new speed measurement.
The PWM ISR calculates to wheel speed error and applies the correction to the PWM duty cycle register (hardware module). It then clears the new speed count flag since it is finished with this new value.

You will need to use different values for the Timer interrupts period and the PWM update period.

When the MAIN code wishes to change the wheel speed it changes the value of right_wheel_target_speed & left_wheel_target_speed. This allows the feedback control loop to do the actual speed change.

Does this help? If you want to see may PIC C code let me know and I'll post it tonight.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 07, 2010, 01:53:31 PM
Thank you very much. It's very helpfull. Also, if you have time, please post the C code, because i work also with PIC32MX, and MPLab.
Thanks again. I'll let you know the result.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 07, 2010, 06:55:34 PM
Ok Benn, here is my code as it currently stands.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: Benn on May 25, 2010, 07:14:58 AM
ok...i promised to come back with some informations...
The Contest is over, i won a prize for the best presentation.
Regarding PID, it worked ok...also not perfect. Special thanks to waltr for his help, and also others!
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: waltr on May 25, 2010, 08:33:30 AM
Congrats on the prize.
Title: Re: PID Tuning problem or wrong PID Implementation?
Post by: eschulma on April 13, 2012, 09:24:39 AM
Just wanted to thank waltr for his suggestion about using timing between pulses for low value encoders (mine have 128 per revolution). In my case I simply wanted to drive in a straight line. So I just looked to see if pulse timing for the left encoder matched the right encoder, to the extent it didn't, that error was fed into my PID controller. (I found I did have to add an integral term to get it running in a stable way.)

You can do this without putting the code directly in the interrupt routine, if you are already running a very fast loop (as I was) at the expense of a small amount of accuracy.