Go Down

Topic: EE660 Sensor for Very Low Air Velocity in Biosafety Cabinet Class II (Read 348 times) previous topic - next topic

B1ng05

Hello Guys,

I'm using PID library by brett to regulate the EC Fan Centrifugal speed (PWM) , I want the value of Air speed to be between 0.25 m/s and 0.5 m/s , if the Sensor speed is < 0.25m/s or > 0.5m/s , I want an Alarm (buzzer + red led) to go on but after the system is stable , i mean a delay of lets say 3 minutes , I tried this code but the Alarm is always off !

Code: [Select]

#include <PID_v1.h>
#include <LiquidCrystal.h>

//------------------OUTPUT_PINs------------------------------
int ALARM = 3;
int Red_Led = A4;
int FAN_PWM = 9;
int in1_FAN_Relay = A5 ; // the Relay PIN , turned on by setting it to LOW

LiquidCrystal lcd(12, 11, 4, 5, 6, 7);
boolean SwitchFANState = false; // if it was in the main loop it would be reset every time thorough the code

//-------------------INPUT_PINs------------------------------------
const int Switch_FAN = A2; // when the switch on the relay is and the EC Fan is on
int AirFlow_Sensor = A1;

//--------------------PID_variables--------------------------
double Setpoint, Input , Output;

//Define the aggressive and conservative Tuning Parameters
double aggKp = 4, aggKi = 18, aggKd = 0;
double consKp = 2, consKi = 5, consKd = 1;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, P_ON_M, DIRECT);

//---------------------Timing----------------------------------------
unsigned long previousMillis = 0;

void setup()
{

  //-------------------Inputs------------------------
  pinMode(Switch_FAN, INPUT);
  lcd.begin(16, 2);

  //---------------------Outputs----------------

  digitalWrite(in1_FAN_Relay , HIGH);
  pinMode(in1_FAN_Relay, OUTPUT);
  Setpoint = 0.25; // the desired AirFlow speed in m/s
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  //Serial.begin(9600);
}

void loop()
{
  Input = analogRead(AirFlow_Sensor);
  Input = (Input * 5.0 * 100.0) / 256000.0; // to get AirFlow speed in m/s , the sensor have values from 0 to 2 m/s
  unsigned long currentmillis = millis();
  if (currentmillis - previousMillis > 250)
  {
    lcd.clear();
    lcd.print("AirFlow= ");
    lcd.setCursor(0, 1);
    lcd.print(Input);
    lcd.print(" m/s");
    previousMillis = currentmillis;
  }

  double gap = abs(Setpoint - Input); //distance away from setpoint
  if (gap < 0.05)
  { //we're close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
    //we're far from setpoint, use aggressive tuning parameters
    myPID.SetTunings(aggKp, aggKi, aggKd);
  }

  SwitchFANState = digitalRead(Switch_FAN);

  if (SwitchFANState == HIGH)
  {
    digitalWrite(in1_FAN_Relay, LOW); // turn on Relay
    myPID.Compute(); // get Output PWM value
    analogWrite(FAN_PWM, Output);
    //delay(1000UL * 60 * 3);

    //------------------ALARM CODE----------------------------------

    unsigned long now = millis();
    if (now - previousMillis >= (3 * 60 * 1000UL))
    {
      previousMillis = now;
      if (Input < 0.20) {
        digitalWrite(Red_Led, HIGH);
        tone(ALARM, 1000, 500);

      }
      else
      {
        digitalWrite(Red_Led, LOW);
        noTone(ALARM);
      }
      if (Input > 0.55)
      {
        digitalWrite(Red_Led, HIGH);
        tone(ALARM, 1000, 500);
      }
      else
      {
        digitalWrite(Red_Led, LOW);
        noTone(ALARM);
      }
    }
 

  //-------------------------------------------------------------
} else
{
  analogWrite(FAN_PWM, 0);
  digitalWrite(in1_FAN_Relay, HIGH);
  digitalWrite(Red_Led, LOW);
  noTone(8);
}

}


I don't want to use delay , because it's going to block the PID good work.

thank you

mikb55

Is this for a real biosafety cabinet, or is it a student project?

pylon

I ask the same question as mikb55.

You're resetting previousMillis every 250ms for the LCD output. So the check for the 3 minutes will never be reached.

MarkT

I see a lot of this idiom:
Code: [Select]

  unsigned long currentmillis = millis();
  if (currentmillis - previousMillis > 250)
  {
    ........
    previousMillis = currentmillis;
  }


There's a leaner, simpler, more precise way to do regular timed operations:

Code: [Select]

  if (millis() - previousMillis >= 250)
  {
    previousMillis += 250 ;   // step forward new target time precisely.
    ........
  }

No extra variable, no time-slop, will catch up with itself if something causes an
actual delay occasionally.  Of course its not always the right thing to do (catching up), but
when you want timing without random drift due to code execution time, this works.

Actually this is such a common operation I reckon there should be a function to do this:
Code: [Select]

boolean time_has_passed (unsigned long & targetvar, unsigned long period)
{
  if (millis() - targetvar >= period)
  {
    targetvar += period ;
    return true;
  }
  return false;
}

void loop()
{
  if (time_has_passed (previousMillis, 250))
  {
    .....
  }
}
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

B1ng05

Quote
@mikb55
Is this for a real biosafety cabinet, or is it a student project?
Actually, I have a friend that works at university laboratory and which owns an old BSC, so he asked me to help him repair it. I started working on it using Arduino UNO ( which later I will change to Arduino Mega). I learned a lot throughout the process and I am intending to put all project files ( hardware+software) on my Github page.

I wonder if it's a bad idea to use Arduino? Because, it gave me great results so far.


@MarkT

Thank you so much for your response.
I changed the code:

Code: [Select]

#include <PID_v1.h>
#include <LiquidCrystal.h>

//------------------OUTPUT_PINs------------------------------
int ALARM = 3;
int Red_Led = A4;
int FAN_PWM = 9;
int in1_FAN_Relay = A5 ; // the Relay PIN , turned on by setting it to LOW

LiquidCrystal lcd(12, 11, 4, 5, 6, 7);
boolean SwitchFANState = false; // if it was in the main loop it would be reset every time thorough the code

//-------------------INPUT_PINs------------------------------------
const int Switch_FAN = A2; // when the switch on the relay is and the EC Fan is on
int AirFlow_Sensor = A1;

//--------------------PID_variables--------------------------
double Setpoint, Input , Output;

//Define the aggressive and conservative Tuning Parameters
double aggKp = 4, aggKi = 18, aggKd = 0;
double consKp = 2, consKi = 5, consKd = 1;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, P_ON_M, DIRECT);

//---------------------Timing----------------------------------------
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long currentmillis1 = 0;
void setup()
{
  //-------------------Inputs------------------------
  pinMode(Switch_FAN, INPUT);
  lcd.begin(16, 2);

  //---------------------Outputs----------------
  pinMode(Red_Led, OUTPUT);
  digitalWrite(Red_Led, HIGH);

  digitalWrite(in1_FAN_Relay , HIGH);
  pinMode(in1_FAN_Relay, OUTPUT);

  Setpoint = 0.40; // the desired AirFlow speed in m/s
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  //Serial.begin(9600);
}

void loop()
{
  Input = analogRead(AirFlow_Sensor);
  Input = (Input * 5.0 * 100.0) / 256000.0; // to get AirFlow speed in m/s , the sensor have values from 0 to 2 m/s
  unsigned long currentmillis = millis();
  //---------------Display_Sensor_Speed----------------------------
  if (currentmillis - previousMillis >= 250)
  {
    lcd.clear();
    lcd.print("AirFlow= ");
    lcd.setCursor(0, 1);
    lcd.print(Input);
    lcd.print(" m/s");
    previousMillis = currentmillis;
  }
  //---------------------------------------------------------------------

  double gap = abs(Setpoint - Input); //distance away from setpoint
  if (gap < 0.05)
  { //we're close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
    //we're far from setpoint, use aggressive tuning parameters
    myPID.SetTunings(aggKp, aggKi, aggKd);
  }

  SwitchFANState = digitalRead(Switch_FAN);
  if (SwitchFANState == HIGH)
  {
    digitalWrite(in1_FAN_Relay, LOW); // turn on Relay
    myPID.Compute(); // get Output PWM value
    analogWrite(FAN_PWM, Output);

    //------------------ALARM CODE----------------------------------
    unsigned long now = millis();
    if (now - previousMillis1 >= (3 * 60 * 1000UL))
    {
      //Serial.println(now / 1000);
      previousMillis1 = now;
      if (Input < 0.20)
      {
        digitalWrite(Red_Led, HIGH);
        tone(ALARM, 1000, 500);
        //---------------Alarm_Dispaly--------------------------------
        unsigned long currentmillis1 = millis();
        if (currentmillis1 - previousMillis2 >= 250)
        {
          lcd.clear();
          lcd.print("AirFlow");
          lcd.setCursor(0, 1);
          lcd.print("Problem!!!");
          previousMillis2 = currentmillis1;
        }
        //----------------------------------------------------------------
      }
      else
      {
        digitalWrite(Red_Led, LOW);
        noTone(ALARM);
      }
    }
    //-------------------------------------------------------------
  } else
  {
    analogWrite(FAN_PWM, 0);
    digitalWrite(in1_FAN_Relay, HIGH);
    digitalWrite(Red_Led, LOW);
    noTone(ALARM);
  }
}


 It actually worked. Every three minutes the "if" checks the Sensor speed, if it's true the Alarm goes on. But what I want is for the "If" to check continuously after the system is powered on precisely after 3 minutes.
Thanks

mikb55

Think legal liability and consequences.

If you are actively involved in the project, and not just publishing something for others to use, then you will be legally liable for damages should someone get sick or die as a consequence of the repair not working to spec.

In addition the university employee will likely lose their job for taking advice from someone who isn't suitably qualified or insured.

Go Up