Self Balancing Robot with PID Control

Hi Guys,

Currently I am working on a PID control based system that will allow my robot to self balance. However, I am having some issues and I am relatively new to Arduino, let alone coding. The current list of parts I am using include:

  • Tamaya Double Gear Box with 2 DC Motors from Polulu
  • Tamaya Wheel set from Polulu
  • AXDL203EB - Dual-Axis Accelometer
  • Arduino Uno
  • Adafruit Motorshield V2

The main issue I am having is getting my robot to balance and whether or not my coding is correct in this case. I have read a lot in regards to Brett's PID library, Kas' robots, Instructables, and the fourm, but I am still confused on why it doesn't balance. I have encased all my components within a grey box mounted on the side of my robot, which makes its sorta heavy on one side..., but I think my coding may be the real issue? I have attached the code below for anyone who is interested in helping me with this project.

I also tried using the PID library to attempt this, but I ran into a few problems in regards to setting the read speed and the output limits. I tried using the functions but it wouldn't let me do so in my code and gave me an error code.

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

#include <PID_v1.h>
#include <Wire.h> //define wire library
#include <Adafruit_MotorShield.h> //define adafruit motorshield library

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

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

//Specifiy Motor Control Parameters
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); //Define the motorshield as an object
Adafruit_DCMotor *myMotor = AFMS.getMotor (1); //Define motor 1
Adafruit_DCMotor *myMotor2 = AFMS.getMotor (2); //Define motor 2

///Bias Parameters
float Vb = 0;
int sampleNum = 500;

void setup()
{
Serial.begin(115200);

//////////////////// Motor Controller ///////////////////

//turn motorcontroller on
AFMS.begin(); //Turn on the motorshield
myMotor->setSpeed(0);
myMotor2->setSpeed(0);

/////////////////////////  PID ///////////////////////

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

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  
  SetOutputLimits (-255,255);
  SetSampleTime (10);

/////////////////////// Vb (Counts) ///////////////////////////

//500 samples of readings Vb 
 for(int n=0;n<sampleNum;n++)
 { 
    float Accel_X = analogRead(A0); 
     Vb += Accel_X; 
  }
  
Vb = Vb/sampleNum;

delay(1000);

}

void loop()
{
  Input = analogRead(0);
  Input = Input - Vb;
  Input = Input * 0.00488758553;
  Input = Input / 0.0159;
  myPID.Compute();
  float wer = analogRead(0);
  
    if ( Output > 0)
      {
        myMotor->setSpeed(abs(Output));
        myMotor2->setSpeed(abs(Output));
        myMotor->run(BACKWARD);
        myMotor2->run(BACKWARD);
      }
        else if (Output < 0)
          {
              myMotor->setSpeed(abs(Output));
              myMotor2->setSpeed(abs(Output));
              myMotor->run(FORWARD);
              myMotor2->run(FORWARD);
          }
}

Balancing_Attempt_5.ino (9.19 KB)

Try putting "myPID." before the name "SetOutputLimits" so it knows which PID you are talking about. Same for "SetSampleTime".

You can leave this part out:

  Input = Input * 0.00488758553;
  Input = Input / 0.0159;

The PID will work just as well on the un-scaled values.

One problem that I see is that your motors probably won't start to move until the PWM value (Output) goes high enough. I mean, there is some minimum value of PWM to get the motor to move at all so you might need to a bit of "bias".

Adding the myPID. in front of the code worked, however I am not quite sure what you mean by the motor bias. How exactly would i implement in this bias especially if the motors are already given the command to run up to its maximum 255 PWM?

As an update my PID doesn't run anymore... after i changed the settings and I am not quite sure why it dose this

What exactly do you mean by "doesn't run anymore"?

SegwayRobo:
As an update my PID doesn't run anymore... after i changed the settings and I am not quite sure why it dose this

If you want help with that: Show your sketch and describe what it does different from what you thought you told it to do.

So the code is using a PID controller in order to make the robot self balance. I am currently using an ADXL-203EB accelometer as my sensor and DC motors from a Tamiya Double Gearbox kit. My understand of code is that it will take the sensor readings and convert it into an angle and take 0 as the setpoint. The PID would then attempt to control the motors to get the sensor readings back to 0 and output a PWM between -255, 255 to control the motors. The negative -255 would represent a backwards movement and 255 forward, note that in the code this is reversed on motor commands because the polarity of the motors were switched. However, when I run this code it does nothing...

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

#include <PID_v1.h>
#include <Wire.h> //define wire library
#include <Adafruit_MotorShield.h> //define adafruit motorshield library

//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,7, DIRECT);

//Specifiy Motor Control Parameters
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); //Define the motorshield as an object
Adafruit_DCMotor *myMotor = AFMS.getMotor (1); //Define motor 1
Adafruit_DCMotor *myMotor2 = AFMS.getMotor (2); //Define motor 2

///Bias Parameters
float Vb = 0;
int sampleNum = 500;

void setup()
{
Serial.begin(115200);

//////////////////// Motor Controller ///////////////////

//turn motorcontroller on
AFMS.begin(); //Turn on the motorshield
myMotor->setSpeed(0);
myMotor2->setSpeed(0);

/////////////////////////  PID ///////////////////////

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


  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  
 myPID. SetOutputLimits (-255,255);
 myPID. SetSampleTime (10);


/////////////////////// Vb (Counts) ///////////////////////////

//500 samples of readings Vb 
 for(int n=0;n<sampleNum;n++)
 { 
    float Accel_X = analogRead(A0); 
     Vb += Accel_X; 
  }
  
Vb = Vb/sampleNum;

delay(1000);

}

void loop()
{
  Input = analogRead(0);
  Input = Input - Vb;
  
  myPID.Compute();

Serial.print(Output);

    if ( Output > 0)
      {
        myMotor->setSpeed(abs(Output));
        myMotor2->setSpeed(abs(Output));
        myMotor->run(BACKWARD);
        myMotor2->run(BACKWARD);
      }
        else if (Output < 0)
          {
              myMotor->setSpeed(abs(Output));
              myMotor2->setSpeed(abs(Output));
              myMotor->run(FORWARD);
              myMotor2->run(FORWARD);
          }
}