Go Down

Topic: Need help employing a PID library for fan control (Read 660 times) previous topic - next topic

KyleKing

I'm working on a school project to build a hovercraft and I'm really new to coding and need help troubleshooting this code. So far the code is receiving input from the distance sensor and generates a decreased duty cycle (to reduce fan/LED output) in response to a smaller error. However when the input is greater than the setpoint, there is no output (output=0).

I'm very confused by this and have tried everything I can think of (from using abs then incorporating a separate function (as shown)).

Note: I am using an Arduino UNO and an LED (in place of a fan)

Code: [Select]
/******************************************************************************
        Pin 1 VCC (URM V3.2) -> VCC (Arduino)
        Pin 2 GND (URM V3.2) -> GND (Arduino)
        Pin 4 PWM (URM V3.2) -> Pin 3 (Arduino)
        Pin 6 COMP/TRIG (URM V3.2) -> Pin 5 (Arduino)
       
        Pin 9 (Arduino) -> Mosfet Gate Pin (Left)
        Source Voltage -> LED, Resistor and Mosfet Drain Pin (Middle)
        Ground -> Mosfet Source Pin (Right)
******************************************************************************/

int mosfetLED = 9;                    // Pin to modulate Mosfet Gate
int uPWM = 3;                         // PWM Output for URM37 (u) Comp Pin
int uTRIG = 5;                        // PWM Input for URM 37 (u) to Trigger the PWM Pin
double Input = 0;                     // Sets Distance Variable back to zero

uint8_t EnPwmCmd[4]={0x44,0x02,0xbb,0x01};   
                                       /* Enables EPROM Writing (0x44), Establishes Mode of Operation (0xx02),
                                          to be  PWM Passive Mode (0xbb), Sum=Low 8 bit of the sum of
                                          command+data0+data1 (0x01) (Reutilized from Jiang from DFRobot)
                                          Note: uint8_t is shorthand for unsigned int of 8 bit length */
                                         
#include <PID_v1.h>                    // Calls in the PID Library
double Setpoint, Output;               // Define the variables for input data
double aggKp = 8, aggKi = 0.4, aggKd = 2;    // Define the PID aggressive tuning parameters
double consKp = 1, consKi = 0.05, consKd = 0.25;
                                       //Set conservative tuning parameters
PID myPID (&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
                                       // What does this do?
                                       // ????? Will double and unsigned integers be a problem??
double gap;                             // Distance away from setpoint
// Stand-in Variables:
// double DistanceMeasured = 2000;

void setup() {
  Serial.begin (9600);                  // Sets the baud rate to 9600
  pinMode (uTRIG, OUTPUT);              // Connects to COMP/TRIG Pin on URM37 to initiate the pulse
  digitalWrite (uTRIG, HIGH);           // Won't trigger URM37 (u) (PWM Pin) until LOW again
  pinMode (uPWM, INPUT);                // Input receives time data between pulses
  pinMode (mosfetLED, OUTPUT);          // Allows pin 9 to modulate a MOSFET Transistor connected to an LED
  for (int i=0;i<4;i++){                // Runs URM37 in passive mode four times ???? 4 bits of data??
      Serial.write (EnPwmCmd[i]);       // Writes to the serial monitor the data received from the URM37 ???????
  }
  Setpoint = (20);                         // Desired distance (20 cm)
  myPID.SetMode (AUTOMATIC);               // Activate the PID Control
}

void loop () {
digitalWrite (uTRIG, LOW);             // Triggers the relase of an Ultrasonic signal
    digitalWrite (uTRIG, HIGH);         // Returns to normal, off position
    double DistanceMeasured = pulseIn (uPWM,LOW);
                                        // Counts the ms between LOW readings
    if (DistanceMeasured == 50000){     // the reading is invalid
      Serial.print ("Invalid");   
   }
     else{
      Input = DistanceMeasured/50;      // When valid, every 50ms low level stands for 1cm
   }
  void PIDfunction ();
  double DutyCycle = ((Output/256)*100); // Finds duty cycle percent outpout
  Serial.print ("Input = ");             // Displays Variable Name
  Serial.print (Input);                  // Displays the distance measurement
  Serial.println (" cm");                // Display units and advances a line
  Serial.print ("Output = ");            // Displays Variable Name
  Serial.println (Output);               // Displays Variable Value
  Serial.print ("Duty Cycle = ");        // Displays Variable Name
  Serial.print (DutyCycle);              // Displays Variable Value
  Serial.println ("%");                  // Display units and advances a line
  Serial.print ("Gap = ");               // Displays Variable Name
  Serial.print (abs (gap));              // Displays Variable Value
  Serial.println (" cm");                // Display units and advances a line
  Serial.println (" ");                  // Advances a line
}


void PIDfunction () {
  gap = (Setpoint - Input);       // Distance away from setpoint
  if (gap < 8) {
    myPID.SetTunings (consKp, consKi, consKd);
                                         // Close to Setpoint and don't want to overshoot, use conservative parameters
  }
  else {
     myPID.SetTunings (aggKp, aggKi, aggKd);
                                          // Farther away and need more aggresive repsonse to return
  }
  myPID.Compute ();                      // Compute PID to solve for Output
  if (Output > 0) {
    digitalWrite (mosfetLED, Output);     // Output variable modulates LED brightness
    delay (500);
  }
  else {
      gap = (Input - Setpoint);          // Distance away from setpoint
      if (gap < 8) {
        myPID.SetTunings (consKp, consKi, consKd); // Close to Setpoint and don't want to overshoot, use conservative parameters
      }
      else {
        myPID.SetTunings (aggKp, aggKi, aggKd); // Farther away and need more aggresive repsonse to return
      }
     
      myPID.Compute ();                  // Compute PID to solve for Output
      digitalWrite (mosfetLED, Output);  // Output variable modulates LED brightness
      delay (500);
  }   
}
 


I wondered if anyone could help me with this issue. I would really appreciate any feedback (whether it be on coding, annotating, or other)!

KyleKing

Also, this is the PID library I am using: http://playground.arduino.cc/Code/PIDLibrary

LarryD

I am not sure this will help, but do you want:

digitalWrite (mosfetLED, Output);     // Output variable modulates LED brightness

OR

digitalWrite(mosfetLED, HIGH);   // sets the LED on >>>>>>>>>>>>  http://arduino.cc/en/Reference/DigitalWrite

OR

analogWrite(mosfetLED, val);     //where val is 0 to 255  >>>>>>> http://arduino.cc/en/Reference/AnalogWrite 
The way you have it in your schematic isn't the same as how you have it wired up!

silverxxx

I think the problem is the way you use the distance there. The PID would try to go UP to the limit (from zero) , and the moment it is over it, it would output a negative value to get back to it. However the library outputs 0 - 255 only, so you see zero. I am not sure if changing "DIRECT" to "reverse" will help. For testing you could make Kd=0 since that will be very sensitive to noise. You could make Kp zero, too. Hope you can fix it.

KyleKing

Thanks guys! You are definitely right about analogWrite. Once I get home, I'll start playing around with the PID initiation code. Thanks again!

Go Up