Using PID library to regulate position

Hello,
Here's what I want to do : Use the PID library for arduino Arduino Playground - PIDLibrary , to tell my robot to stop at a certain (x,y) position.

Now, to test the library, I 'm trying to tell one wheel to stop when its encoder ticks reach a certain value.
The code :

#include <PID_v1.h>

#define encoderPinA 25 // Encoder A pin
#define encoderPinB 24 // Encoder B pin

int encoderStateA ; // Digital State of Encoder A
int encoderStateB ; // Digital State of Encoder B
int lastState=0; // Iast digital state of Encoder
int encoderTicks;

// PID Variables 
#define SAMPLE_TIME 25 // Time interval in ms for PID sampling 
#define POS_SETPOINT 79 // Analog value corresponding to 1000 ticks
double positionSetPoint, positionInput, positionOutput;     // Define Variables we'll be connecting to
double aggKp=4, aggKi=0.2, aggKd=1; // aggressive PID parameters if there's a large gap between setpoint and input 
double consKp=1, consKi=0.01, consKd=0.25; // Conservative PID parameters if input is close to setpoint 
PID positionPID(&positionInput, &positionOutput, &positionSetPoint, aggKp, aggKi, aggKd, DIRECT); // Specify the links and initial tuning parameters

 // Motor Driving variables
 #define TOPSPEED 255
 #define FORWARD_SPEED 150
 #define TURN_SPEED 60
 // motor A
 int dir1PinA = 13;
 int dir2PinA = 12;
 int speedPinA = 10;
 // motor B
 int dir1PinB = 11;
 int dir2PinB = 8;
 int speedPinB = 9;
 int speed[2]={0}; //speed[0] = left wheel ; speed[1] = right wheel

void setup(){
  init_motors(); // Motor Pin intialization
  init_positionPID(); // Pid initialization
  init_encoders(); //Encoders Pin initialization
  Serial.begin(38400);
}

void loop(){
//Reads encoders and increments or decrements ticks
readEncoder();
// The input has to be an analog Value (0 to 1023) so this function is to transfer the range of the ticks from 0->25875 to 0->1023
positionInput = map(encoderTicks, 0, 25875, 0, 1023); 
//Decides whether to launch PID algorithm
  positionPID.Compute();
// Sets the PID parameters
  if(abs(positionInput-positionSetPoint)<5){
  positionPID.SetTunings(consKp, consKi, consKd);}
  else{
  positionPID.SetTunings(aggKp, aggKi, aggKd);}
  // Robot goes forward till it reaches the setpoint, backwards if it goes above Setpoint
  if(positionInput<=positionSetPoint){
  go_forward(0,positionOutput);
  }else{
  go_backwards(0,positionOutput);
  }
}

void  init_encoders(){
pinMode(encoderPinA, INPUT); // Encoder pin A INPUT
pinMode(encoderPinB, INPUT); // Encoder pin B INPUT
}

void readEncoder(){
encoderStateA = digitalRead(encoderPinA); // lit l'état de la broche en entrée
encoderStateB = digitalRead(encoderPinB);
if(encoderStateA!=lastState){
  lastState=encoderStateA;
  if(encoderStateA==1 && encoderStateB ==1) { 
   encoderTicks++;
   Serial.println(encoderTicks);
 }
  else if(encoderStateA==1 && encoderStateB==0) { 
   encoderTicks--;
   Serial.println(encoderTicks);
  }
}
}
void go_forward(int left, int right){
  speed[0]=left;
  speed[1]=right;
  analogWrite(speedPinA, speed[0]);
  analogWrite(speedPinB, speed[1]);
  digitalWrite(dir1PinA, HIGH);
  digitalWrite(dir2PinA, LOW);
  digitalWrite(dir1PinB, HIGH);
  digitalWrite(dir2PinB, LOW);
}
void go_backwards(int left, int right){
  analogWrite(speedPinA, speed[0]);
  analogWrite(speedPinB, speed[1]);
  digitalWrite(dir1PinA, LOW);
  digitalWrite(dir2PinA, HIGH);
  digitalWrite(dir1PinB, LOW);
  digitalWrite(dir2PinB, HIGH);
}
void init_positionPID(){
  // initialize the variables we're linked to
  positionInput = 0;
  positionSetPoint = POS_SETPOINT; 
  // turn the PID on
  positionPID.SetMode(AUTOMATIC);
  positionPID.SetSampleTime(SAMPLE_TIME); 
  }  
void init_motors(){
  pinMode(dir1PinA, OUTPUT);
  pinMode(dir2PinA, OUTPUT);
  pinMode(speedPinA, OUTPUT);
  pinMode(dir1PinB, OUTPUT);
  pinMode(dir2PinB, OUTPUT);
  pinMode(speedPinB, OUTPUT);
}

In this code, as I said I'm only experimenting on the right wheel.
Now the problem is when I use the function readEncoders() alone it works perfectly : Increments when I manually turn the wheel forward, and decrements when I turn backwards. It also works when I tell the motor to turn at a constant speed(still without using PID).
But when I use the PID algorithm, on the Serial monitor I see the ticks going crazy (sometimes decrementing a few times then incrementing again) while the wheel is only going forward, and sometimes they go from like 300 to 540 :smiley: Missing 240 ticks is a little weird...don't you think? o_O
So if you have any ideas please share^^
Thanks

Up

Up :grin:

There is nothing obviously wrong with the code you posted. Try removing sections of loop until the problem disappears. Start with this...

void loop(){
//Reads encoders and increments or decrements ticks
readEncoder();
// The input has to be an analog Value (0 to 1023) so this function is to transfer the range of the ticks from 0->25875 to 0->1023
positionInput = map(encoderTicks, 0, 25875, 0, 1023);
//Decides whether to launch PID algorithm
positionPID.Compute();
/
// Sets the PID parameters
if(abs(positionInput-positionSetPoint)<5){
positionPID.SetTunings(consKp, consKi, consKd);}
else{
positionPID.SetTunings(aggKp, aggKi, aggKd);}
// Robot goes forward till it reaches the setpoint, backwards if it goes above Setpoint
if(positionInput<=positionSetPoint){
go_forward(0,positionOutput);
}else{
go_backwards(0,positionOutput);
}
/
}

Thanks for the rep! I've been waiting :smiley:

Okay! I'll try!

Just a quick question? Am I right to use the map function? Is there a way to avoid using it because I think it takes a lot of time!

Thanks

amine:
Just a quick question? Am I right to use the map function? Is there a way to avoid using it because I think it takes a lot of time!

Compared to the math performed by the PID library, map is insignificant.