Go Down

Topic: Need help employing a PID library for fan control (Read 768 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
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy