PID _ Learning

So I'm in the process to learn PID and how to work with it, I run thru tutorials understood some parts
we get a Input and thru the PID formula get a stable output for our task/robot..etc

So I start searching PID for arduino and I found this:
http://playground.arduino.cc/Code/PIDLibrary

and run thru the basic example:

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

#define PIN_INPUT 0
#define PIN_OUTPUT 3

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(PIN_INPUT);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();
  analogWrite(PIN_OUTPUT, Output);
}

and we got input data the Kp,Ki and Kd but there is no any explaining how to run it use it..etc
thru this lib, what is the setpoint, direct, automatic, why we need setpoint how in general to use
this lib.

I'm a PID beginner so pls if you get any other examples easier to learn that would be nice or please
explain me how this lib works.

I will try to setup a simple example to run thru the PID process, a IR sensor, a motor and H-Bridge
to keep the motor spinning constantly the same speed no mater what so ever if there is friction
or me trying to stop it.

If you are not patient giving few min or hours from your time in the next days pls
don't comment. I try to learn some useful stuff and rage will not be helpful.

D.60

OK. Let me know when you have the motor hooked up so you can use analogWrite() to adjust the speed and you have the IR sensor reading RPM. The RPM value will be your Input. The Setpoint will be the desired RPM. The Output will be the value that you pass to analogWrite().

To tune the PID you will probably want some way to visualize the RPM over time. You may want an analog input for Setpoint and three more for Kp, Ki, and Kd.

So here is my setup, took some time to make it, glue to dry ..etc :smiley:

Used a L293D as H-Bridge drive and TCRT 5000 which it's just some IR leds transmitter/receiver.
took a small motors printer/glued ..etc and done the setup.

I still got some problems using Revolutions per minute (RPM) cause I get IR analog data
0-1023 and I need somehow to use it as RPM, tried few things but didn't worked well
looks like I will need to change the motor step disk to less steps cause they are too many
and hard to read accurate data

Here is the code:

/* L293D H-Bridge Pinout
Left side of the chip:

Pin 8 = +7V (for the motor)
***********************************
Right Side of the chip: 

+5v
inputA = pin 10
output motor
gnd
gnd
output motor
intputB = pin 11
enablePin = pin 6
*/

int inputA = 10;
int inputB = 11;
int EnablePin = 6;

int IRled = 9;

void setup() {
  Serial.begin(9600);
  
  pinMode(inputA, OUTPUT);
  pinMode(inputB, OUTPUT);
  pinMode(EnablePin, OUTPUT);
  
  pinMode(IRled, OUTPUT);
  digitalWrite(IRled, HIGH); //Always HIGH
  
  digitalWrite(inputA, HIGH);
  digitalWrite(inputB, LOW);
  analogWrite(EnablePin, 150); // speed of motor from 0 to 255
}
long now = 0;

/*void AB(){
 if(millis() - now >= 1000){
   digitalWrite(inputA, HIGH);
  digitalWrite(inputB, LOW);
  analogWrite(EnablePin, 100); // start speed of the motor
  

  int sensorValue = analogRead(A0);
  Serial.print("sensorValue: ");
  Serial.println(sensorValue);
  delay(200);
   
  now = millis();
  }
}*/
long nowre = 0;
int rev;
int RPM;
void loop() {
  //AB();
  int sensorValue = analogRead(A0);
  //Serial.println(sensorValue);
       
  if(sensorValue <= 600 ){
   rev++;
        delay(5); 
   if(millis() - nowre >= 1000){   
     RPM = rev;//((rev / 12)*60);
     Serial.println(RPM);
     rev = 0;
     nowre = millis();   
   }
  }
          
  
}



//Domino60

Avoid the comment sections of the code it's just stuff i tried and tested

So hopefully I will try to change the step disk or work thru code or find other type of sensor/hardware
to read the RPM's

D.60

Typically you would not use an analog input for the RPM input. The IR sensor should be arranged to give you a known number of pulses for each revolution of the motor. Counting the pulses and dividing by time gives RPM.

I will try to connect the IR received into a digital pin and receive pulses, if I understood right
and count them. Hopefully that will work.

So cause it takes time to do something I want to give a try to understand the PID 1st in theory
then in practice rebuilding one of my old self balancing robots as practice.

Let's take the photo as an example:
(as use a MPU6050 as an example getting the degrees)

and this simple code:

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
double kp, ki, kd;
void Compute()
{
   /*How long since we last calculated*/
   unsigned long now = millis();
   double timeChange = (double)(now - lastTime);
  
   /*Compute all the working error variables*/
   double error = Setpoint - Input;
   errSum += (error * timeChange);
   double dErr = (error - lastErr) / timeChange;
  
   /*Compute PID Output*/
   Output = kp * error + ki * errSum + kd * dErr;
  
   /*Remember some variables for next time*/
   lastErr = error;
   lastTime = now;
}
  
void SetTunings(double Kp, double Ki, double Kd)
{
   kp = Kp;
   ki = Ki;
   kd = Kd;
}

from this link.

Now we have this formula:

Which we divide in 3, as Ki, Kp, Kd (PID)
and we got the E(error) which is = to ((Input data) - (Setpoint))

Now I understand that the Input data is the data we get from the Gyro in angle degrees
and the Setpoint is the point we set for example 0 degrees to balance for example a
balancing robot.

We got as well the output which as i understand is the final output processed thru the PID

and other stuff that I want to talk as well but I didn't get deep enough cause I want to fully understand how it's working 1st.

EXAMPLE: (let's imagine we got a balancing robot)
Let's take the Basic PID Lib example that the arduino website got:
Link:
http://playground.arduino.cc/Code/PIDLibaryBasicExample

Code:

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(0);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
}

PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

*Input is the data we get from the MPU6050/Gyro
*Setpoint we set it for example to balance at 10 degrees
*Output is the final data coming from the processed functions of PID

*2,5,1 P.I.D settings
*DIRECT, what is that?

myPID.SetMode(AUTOMATIC);

From the arduino website they describe the mode having 2 modes Manual and automatic
"Parameters
mode: AUTOMATIC or MANUAL"

What exactly they are doing and what is the difference?

void loop()
{
Input = analogRead(0);
myPID.Compute();
analogWrite(3,Output);
}

So in the look we get the Gyro input in degrees
Compute as I understand it runs thru the PID algorithm
and final we get the Output in degrees running it thru a mapping
speed and rotation of the wheels for the balancing robot.

And finally we adjust the P.I.D. for our needs

Hope you will not get bored reading it, would be nice to tell me what I skipped and what I didn't
understood.

ps (It will take me sometime to re-build the balancing robot for real tests but for how let's stick
in the theory)

D.60

ni sure about direct, but seem to be where the direction the output gonna be.

Imagine and heater and a cooler.

If you use an heater with a PID, If the temp is lower than setpoint, it give a bigger error.

For a cooler, if the temp higher than setpoint, it give a bigger error.

that is direct or reverse operation. ( I think so)

Regards
Nitrof

Well thanks for help Nitrof I took some long hours of youtube videos about how a PID works
my problem now is the code to understand it fully to be able to work with it and have no problems
about parts that It may not be clear for me.

D.60

If you feel like more reading you may be interested in my attempts to get the better of PID.

Setting values in the PID library?
Attempting to understand PID in a practical way.

I feel like I have now got the hang of it - at the end of the second link :slight_smile:

...R

PID is a tricky one :slight_smile: it is different for every situation. In some cases you get instant results like with a balancing robot. While a room temperature sensor may take 5 minutes to detect any noticable output change. Some situations (balancing bot) we know exactly how much output we need at setpoint (0) while at other times output needed varies drastically (cruise control on a car).

With your motor control the integral (I) of PID will be the most valuable resource.
Here's why: when proportional is at setpoint the proportional output is always ZERO. So only an error from setpoint would provide any power. Unless your motor needs to be off when at setpoint proportional control alone will not work for you.
Derivative only reacts when change occurs. A nosey sensor reading and derivative can become more of a problem than a benefit. So unless your readings are filtered and consistent while controlling a setpoint avoid using derivative at the beginning. This leaves integral. Integral basically says if there's an error let's make a chance to the output by adding/subtracting from the output. This requires a time interval to be used. So setting the reading time interval is an important part. PID_v1 library Arduino.cc uses has preset this time interval. You will need to consider how a fixed sample rate affects variable sample rate of the tachometer. Don't get discouraged if you find it difficult to use this library for motor speed control. I did.
Conclusion:
So basically proportional alone will never reach setpoint. But it will help achieve setpoint rapidly. Integral is the most important for your situation and derivative is the least important. I hope this gets you a start with getting your project going.

Z

Domino60:
*DIRECT, what is that?

The PID needs to know if it should raise OUTPUT to raise INPUT (like a heater) or raise OUTPUT to lower INPUT (like a cooler).

Domino60:
and final we get the Output in degrees running it thru a mapping speed and rotation of the wheels for the balancing robot.

No, Input and Setpoint have to be in the same units of measure but Output does not. If you are trying to control an angle then that is the Input value you are measuring. Setpoint is in the same units and is the desired value of Input. Output is an arbitrary value, defaulting to the range 0 to 255. You can, and should, set the range of Output so that you don't need to 'map' it to a different range. In the case of a bi-directional motor you might want to set it to -255 to 255 so it can express both PWM speed and direction.

Robin2: Good information I followed few replies from the 1st link, the 2nd link is kinda long, it's nice to read but would be better to give question here it will make my learning faster and understanding how it works, ofc I have as well some questions from the 1st link you posted

zhomeslice : Thanks for explaining I already followed lots of tutorials on youtube about how PID
works but my point/goal is to understand how it's working thru code / PID Lib.

Input and Setpoint have to be in the same units of measure but Output does not.

If we got the Input from our sensor like a MPU6050 in degrees for example (50 degrees)
and the Setpoint as I understand the point we want to balance a robot ( 0 degrees)
The Error (e = setpoint - Input) e = 50

After that we run the 50 Thru P, I and D. Am I correct?

Now from the Robins 1st link a guy (in the reply #7) said that :

Output = Kp*Error

So if we get the error = 50 and as example Kp = 2;
Output = 2 * 50
Output = 100

*What is that output ?
*We inject/insert(gryo degrees) in our formula with degrees and running it thru the PID formula, what exactly we get as output?

For example:

I want to balance my robot at 0 degrees and we got the same above example
the robot turns as 50 degrees, run that thru the formula and get a output = 100.
What is 100?
I want to turn the wheels ..etc
How do I use the output?

D.60

Domino60:
So if we get the error = 50 and as example Kp = 2;
Output = 2 * 50
Output = 100

*What is that output ?
*We inject/insert(gryo degrees) in our formula with degrees and running it thru the PID formula, what exactly we get as output?

What is 100?
I want to turn the wheels ..etc
How do I use the output?

That Output is a control signal. In the case of a motor driven by an H-Bridge driver it would probably be Direction and a PWM value to control power. The sign of the Output can be used for Direction and the magnitude (absolute value) of the Output can be used for the PWM signal. BE WARNED: If you use the PID library the default output limits are 0 and 255 so you would have to set new limits for a bidirectional motor driver.
If you want to calculate units, in your case it would be something like Volts, Amps, Watts or Power
If you were controlling temperature in an oven it would be the PWM value for the heater and the range 0-255 would be fine. You can use the PWM value directly if the heater is switched with a MOSFET but if you use a relay to switch the heater on and off you have to slow down the PWM quite a bit. That is why one of the examples uses an upper limit of 5000 and uses the Output as the portion of each 5-second (5000 mS) interval that the heater is on.

BE WARNED: If you use the PID library the default output limits are 0 and 255

So let me give an example to see if I understood correctly.

Using the PID Lib. You get from the range of 0 to 255 as output only.

Example:

Input: 20
Setpoint: 0
E = 20 - 0 = 20
Kp: 2

Output = 2* 20
Output = 40

So the output is PWM not degrees.
If the range of the output is 0 to 255 that means I can never get -255 as output?

so you would have to set new limits for a bidirectional motor driver.

but If i never get -255 or any kind of -14,-60..etc ow do I know which side the gyro is tilted ?

If I could have a negative value as output I could map the speed to my needs and get the job done.

How do i set this limits ? and btw Is it better to use the existing library or should I use the code I posted and found in the #5 reply?

Code:

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
double kp, ki, kd;
void Compute()
{
   /*How long since we last calculated*/
   unsigned long now = millis();
   double timeChange = (double)(now - lastTime);
  
   /*Compute all the working error variables*/
   double error = Setpoint - Input;
   errSum += (error * timeChange);
   double dErr = (error - lastErr) / timeChange;
  
   /*Compute PID Output*/
   Output = kp * error + ki * errSum + kd * dErr;
  
   /*Remember some variables for next time*/
   lastErr = error;
   lastTime = now;
}
  
void SetTunings(double Kp, double Ki, double Kd)
{
   kp = Kp;
   ki = Ki;
   kd = Kd;
}

What do you say about this code? Looks to me more simple and doesn't need to run
in the lib to see how everything is working. Any advice about this code?

I clearly understand that if you get other components like coolers, modules, motors, h-bridge..etc
the value i calculate is always different.

D.60

Domino60:
If the range of the output is 0 to 255 that means I can never get -255 as output?

That is correct. That is why you should set the Output limits appropriate for your needs.

Domino60:
How do i set this limits ?

http://playground.arduino.cc/Code/PIDLibrarySetOutputLimits

Domino60:
Is it better to use the existing library or should I use the code I posted and found in the #5 reply?

That is entirely up to you.

Example:

I don't set the output limits and If i get negative output the value will always be 0 right?

So if I set the output limits from -255 to 255

SetOutputLimits(min, max)

and inside the formula I get negative value in the limit of -255 till 0 I will get negative values right?
Did I understood correctly?

That is entirely up to you.

I will stick a bit with Lib to understand and learn how to use it then I will get deeper reading the
code and probably making my own code. But I want 1st to understand correctly how the code works
in the lib.

So theoretically I can calculate the tilt of a MPU6050 one axe and measure the degrees setting
the limits and driving the motors.

Small example:
1# No limits (0 ~ 255) Basic limits from PID lib

(Input degrees)
Input: 40
Setpoint: 5
E = 5 - 40 = 35 (35 or -35) I know how math works but how math in arduino works?
Kp: 5

Output = 5* 35
Output = 175 (-175)

As example a motor:
(175 PWM speed for a motor "Max speed 255")

1# No limits (-255 ~ 255) Basic limits from PID lib

(Input degrees)
Input: -38
Setpoint: 5
E = -38 - 5 = 35 (-34 - 5 = -)
Kp: 5

Output = *
Output =

I wanted to give an example but came to the point if
Error = Setpoint - Input, even if the input is positive, is the Input became negative or stays positive?

Kinda confusing, I will run a test myself with the basic PID Lib and see what results do I get.

D.60

I still don't understand.

If the Kp formula works as in the link robin gave me then why I don't get output results?
What I'm doing wrong?

You ARE getting results. The result is Output==0. In your test, Input is way higher than Setpoint. Your PID is set for DIRECT control so the way to lower Input is to lower Output. You didn't change the Output limits so 0 is as low as Output can go. The PID library is behaving exactly as I would expect.

If you turn the analog input down to 4 you will likely get Output=255 because (5-4)*20000 == 20000 which will be constrained to 255 because that is the current upper limit on Output.

I'm confused now..

*Isn't the input the data we get in degrees from a Gyro?

  • and Setpoint the point we want to balance a self balancing robot for example at 0 degrees?

Well this is the setup / test. I still don't understand what role the setpoint plays here.
I will make a diagram