Balance robot PID understanding

Hello all,
I have been struggling with part of the PID code below. I am having a hard time understandung how the "out" part of this PID drives the motors to the setpoint. In the code below the" out " is mentioned once in the code. I (being new to Arduino) would have expected to see "out = drive(0,0);" to drive the motors to the setpoint. But as I said "out" is mentioned only once(except for the return). Maybe I am missing something that has been starring me in the face the whole time.
My goal is to use THIS PID to do other fun things and learn. I understand that there are other PID examples, and tutorials out there to learn from, but I am dead set to understand this one
So if I wanted to make a code that measured how hot one of my sensers(reading) is, and cool it down. And the temp I wanted it to be (target).
And if I used a fan (out) to cool it down. What part of the PID below would be used to drive the motor of the fan to the target temp?
For most of you this is an easy explaination, and I appreciate all help so I can move forword.

#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif


MPU6050 mpu;

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector



volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}


/* Variables for the PID controller */
float Kp = 58.30f;
float Kd = 0.00039f;
float Ki = 0.0024f;  //0.0020 seems to work good

float reading = 0.0f;
float target = -1.79f;// Add negative to give more PWM to rear // rear is the uno side

float errorCurrent = 0.0f;
float errorLast = 0.0f;
float errorSum = 0.0f;
float errorDelta = 0.0f;

unsigned long timeLast = 0;

int correction = 0;

/* Variables for Motor control*/
const int MotorLeftPin1 = 8;
const int MotorLeftPin2 = 9;
const int MotorLeftPinEn = 10; //PWM enabled side the Mega is on

const int MotorRightPin1 = 12;
const int MotorRightPin2 = 13;
const int MotorRightPinEn = 11; //PWM enabled oposit side of Mega

const int minSpeed = 90; // defines the useful PWM range of the motors [minSpeed, 255]


// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

   
    mpu.initialize();

  
    devStatus = mpu.dmpInitialize();

    if (devStatus == 0) {
        
        mpu.setDMPEnabled(true);

       
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        
        dmpReady = true;

        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
       
    }
    pinMode(MotorLeftPin1, OUTPUT);
    pinMode(MotorLeftPin2, OUTPUT);
    pinMode(MotorLeftPinEn, OUTPUT);
      
    pinMode(MotorRightPin1, OUTPUT);
    pinMode(MotorRightPin2, OUTPUT);
    pinMode(MotorRightPinEn, OUTPUT); 
   
 
  #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
   
  to:
  #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(1 * 510))
   
 

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;

    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
      
        
//        drive(255, 255);
//        delay(5000);
//        drive(0,0);
//        delay(5000);
 
    }

    
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

  
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        //Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
       
        fifoCount -= packetSize;

        #ifdef OUTPUT_READABLE_QUATERNION
            // display quaternion values in easy matrix form: w x y z
            mpu.dmpGetQuaternion(&q, fifoBuffer);
//           
        #endif

        #ifdef OUTPUT_READABLE_EULER
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);

        #endif

        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            
            if (millis()>=15000) {
              reading = ypr[2] * 180/M_PI;
                
                // stop motors and the PID controller if the bot is tilted more than 30 degrees
                if ((int)reading >=-30 && reading <= 30) {
                correction = pid();
                drive(correction, correction);
                }
                 
                else {
                  drive(0,0);
                }
            }
   
     
        #endif
       
}

void drive(int leftMotorSpeed, int rightMotorSpeed) {
  int left = constrain(leftMotorSpeed, -255, 255);
  int right = constrain(rightMotorSpeed, -255, 255);
  
  if (left < 0) {
    if (left >= -40) {left = 0;}
    else if (left >= -100) {left = -100;}
    
    digitalWrite(MotorLeftPin1, LOW);
    digitalWrite(MotorLeftPin2, HIGH);
    analogWrite(MotorLeftPinEn, -left);
  }
  
  else if (left == 0) {
    digitalWrite(MotorLeftPin1, LOW);
    digitalWrite(MotorLeftPin2, LOW);
    digitalWrite(MotorLeftPinEn, LOW);
  }
  
  else {
    if (left <= 40) {left = 0;}
    else if (left <= 100) {left = 100;}
        
    digitalWrite(MotorLeftPin1, HIGH);
    digitalWrite(MotorLeftPin2, LOW);
    analogWrite(MotorLeftPinEn, left);
  }
  
    if (right < 0) {
      
    if (right >= -40) {right = 0;}
    else if (right >=-100) {right = -100;}
    
    digitalWrite(MotorRightPin1, LOW);
    digitalWrite(MotorRightPin2, HIGH);
    analogWrite(MotorRightPinEn, -right);
  }
  
    else if (right == 0) {
    digitalWrite(MotorRightPin1, LOW);
    digitalWrite(MotorRightPin2, LOW);
    digitalWrite(MotorRightPinEn, LOW);
  }

  else {
    if (right <= 45) {right = 0;}
    else if (right <= 90) {right = 90;};
    
    digitalWrite(MotorRightPin1, HIGH);
    digitalWrite(MotorRightPin2, LOW);
    analogWrite(MotorRightPinEn, right);
  }
}

int pid() {
  // Calculate elapsed time since last run
  unsigned long now = millis();
  float timeDelta = (float)(now - timeLast); 
  // initialize timeDelta as float to help with the next calculations
  
  // Compute error data
  errorCurrent = target - reading;
  errorSum = errorSum + (errorCurrent * timeDelta);
  errorDelta = (errorCurrent - errorLast) / timeDelta;
  
  // constrain the output to the acceptable range for motor PWM signal
  float pTerm = Kp * errorCurrent;
  float iTerm = Ki * errorSum;
  float dTerm = Kd * errorSum;
  
  // constrain the integral term to [-255; 255]
  float limit = 255.0f;
  
  if (iTerm > limit) {iTerm = limit;}
  else if (iTerm < -limit) {iTerm = -limit;}
  
  // Calculate PID output
  float pid = pTerm + iTerm + dTerm;
  
  // constrain the PID output to [-255; 255]
  if (pid > limit) {pid = limit;}
  else if (pid < -limit) {pid = -limit;}
  
  // Store some data for the next run
  errorLast = errorCurrent;
  timeLast = now;
  
  int out = (int)pid * (-1); // not worried about correct rounding here
  return out;
}

I have been struggling with part of the PID code below.

FYI,
There is no code "below".

THIS PID

What PID ?

Where did you get the code ?
What is the project ?
What are you trying to do ?

The code is for a balancing robot using MPU6050. Amd as I explained above . Im trying to figure out how the PID is driving the motors.

The code is for a balancing robot using MPU6050. Amd as I explained above . Im trying to figure out how the PID is driving the motors.

Really ? I can see that. That's not what I asked you.

Where did you get the code ?

correction = pid();
                drive(correction, correction);

This is the part of the main loop( ) which calls the pid( ) and drive( ) functions.

Raschemmel what is you problem. All I asked is fora little help.

Michinyon,
That just stops the motors if the target is greater than , or less than 30 off. Thanks for the reply and help.

Raschemmel what is you problem. All I asked is fora little help.

How am I supposed to help if you won't tell me where you got the code ?

This is where I got the code. Thanks for replying. I really could use some help withthis.

Where's the link for this library ?
#include "MPU6050_6Axis_MotionApps20.h"  

I found the header file here:

but it's not a library . There's no zip file and no "*.cpp " file and no KEYWORDS file so I'm getting a compile error .
Are you able to compile it without the .cpp file and KEYWORDS file ?

I found the MPU6050.cpp file here and I put it in a folder named "MPU6050" in my libraries folder but your sketch is still not compiling.

ATTACHED IS THE COMPILER VERBOSE OUTPUT NOTEPAD FILE

PID_Self_Balancing_Robot_compiler_error_verbose_output.txt (16.7 KB)

Thats not it. I just posted the link to you.

I downloaded all the libraries at that link and then later discovered all those files are in the I2dev library folder but I still get errors trying to compile your sketch. Does yours compile ?

Yes it does. Just follow the link to download the entire library. Again thanks for the help

ATTACHED IS SCREENSHOT OF DOWNLOAD PAGE.
WHERE Is the link that says "Download" ?
Is the library a zip file ?
How do you download the whole library. (most library links have a link that says "Download ZIP file".

Im new and I am wondering if you are planning to do some reverse engineering to help me. Is that why you need to compile the code? Im not trying to be rude. But cant you just look at the Pid () , and see how the MOTORS are controlled by the PID.

 // orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
   // Compute error data
  errorCurrent = target - reading;
  errorSum = errorSum + (errorCurrent * timeDelta);
  errorDelta = (errorCurrent - errorLast) / timeDelta;
  
  // constrain the output to the acceptable range for motor PWM signal
  float pTerm = Kp * errorCurrent;     <================   pTerm <=== IS THIS NOT A PID VARIABLE for Gain ?
  float iTerm = Ki * errorSum;             <================   iTerm <=== IS THIS NOT A PID VARIABLE for Integral ?
  float dTerm = Kd * errorSum;

<================ dTerm <=== IS THIS NOT A PID VARIABLE for Derivitive ?

  /* Variables for the PID controller */  <================== PID PARAMETERS !!!!  (FROM LAPLACE TRANSFORM)
float Kp = 58.30f;                                                  < ===============( READ UP ON TRANSFORM ANALYSIS )
float Kd = 0.00039f;
float Ki = 0.0024f;  //0.0020 seems to work good

float reading = 0.0f;
float target = -1.79f;// Add negative to give more PWM to rear // rear is the uno side

float errorCurrent = 0.0f;
float errorLast = 0.0f;
float errorSum = 0.0f;
float errorDelta = 0.0f;
// Calculate PID output
  float pid = pTerm + iTerm + dTerm;    <================== PID !!!
  
  // constrain the PID output to [-255; 255]
  if (pid > limit) {pid = limit;}
  else if (pid < -limit) {pid = -limit;}
  
  // Store some data for the next run
  errorLast = errorCurrent;
  timeLast = now;
  
  int out = (int)pid * (-1); // not worried about correct rounding here
  return out;
  #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            
            if (millis()>=15000) {
              reading = ypr[2] * 180/M_PI;
                
                // stop motors and the PID controller if the bot is tilted more than 30 degrees
                if ((int)reading >=-30 && reading <= 30) {




                correction = pid();<==WHAT IS THIS ? WHAT DOES IT MEAN (getting correction from PID)
                drive(correction, correction);     <==WHAT IS THIS ? WHAT DOES IT MEAN (sending correction values to  motor)
                }
                 
                else {
                  drive(0,0);  < ===== IF THERE IS NO CORRECTION TO BE MADE, WHAT SHOULD THE MOTORS DO ?
                                             // (Wouldn't that mean it is perfectly balanced and there is no reason to move the motors ?)
                }
            }
   
     
        #endif

Intro to PID:
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

PID LIBRARY:
http://playground.arduino.cc/Code/PIDLibrary

Does that answer your question ?