Need help coding a fire suppresion system.

Hello, i'm doing a fire suppression system with gas for my bachelor degree and im a little bit lost in code.
I got 3 solenoid valves, 3 flame sensors and 3 led-s grouped in 3 rooms.

This is what i would like to achieve:

Fire sensor gets activated(digital low ) and keeps its state for 1 second do this:

-open solenoid valve(with relay) for 5 seconds and blink the led(also with relay) for the same ammount of time.

Does'nt sound hard but i need to use millies because if 1 room cycle is active i still want the otehr two to be able to get activated as well in case of detection.

I kinda unerstand how to work with millies, but using it to check if the sensor is on for 1 sec then using it for the loop and also for the led blink leaves me scratching my head.

Would really apreciate if you could give me some hints!

This is the code i wrote but doesnt have the time cycles, just reads and commands instantly.
r - are the relay and s are the sensors

int s1 = 51 ;
int s2 = 52 ;
int s3 = 53 ;
int r1 = 31 ;
int r2 = 32 ;
int r3 = 33 ;
int flame_detected1 ;
int flame_detected2 ;
int flame_detected3 ;

void setup()
{
  Serial.begin(9600) ;
  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);
  pinMode(r3, OUTPUT);
  
  pinMode(s1, INPUT) ;
  pinMode(s2, INPUT) ;
  pinMode(s3, INPUT) ;
}
void loop()
{
  flame_detected1 = digitalRead(s1);
  flame_detected2 = digitalRead(s2);
  flame_detected3 = digitalRead(s3);
  if (flame_detected1 == 0)
  {
    Serial.println("111Flame detected...! take action immediately.");
    digitalWrite(r1, LOW);
  }
  else if (flame_detected2 == 0)
  {
    Serial.println("222Flame detected...! take action immediately.");
    digitalWrite(r2, LOW);
  }
   else if (flame_detected3 == 0)
  {
    Serial.println("333Flame detected...! take action immediately.");
    digitalWrite(r3, LOW);
  }
  else
  { 
   
    Serial.println("No flame detected. stay cool");
 
    digitalWrite(r1, HIGH);
    digitalWrite(r2, HIGH);
    digitalWrite(r3, HIGH);
  }
  delay(100);

Your code is missing the closing }. Is there anything else missing?

Start by removing the 100ms delay at the end. Without that, the "no flame detected" message will transmit as fast as it can. We need to slow that down first. Copy the blink-without-delay code and put this serial message in there instead of the blink. Change the names of the timing variables to something that makes sense to you, like "lastOKPrintedTime". You are going to create a few of these variables for different purposes and giving them names like "previousMillis7" is not going to be helpful

Allright so something like this for the blinking led? ofc i need to add it in all 3 . Now to integrate it in the 5second alarm duration i guess? and then do the 1 second sensor reading for the whole cycle to activate?

const int ledr = 34;
int s1 = 51 ;
int s2 = 52 ;
int s3 = 53 ;
int r1 = 31 ;
int r2 = 32 ;
int r3 = 33 ;
int flame_detected1 ;
int flame_detected2 ;
int flame_detected3 ;
int ledState = LOW;
const long blink_interval = 500;
unsigned long previous_blink = 0;
void setup()
{
  Serial.begin(9600) ;
  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);
  pinMode(r3, OUTPUT);
  
  pinMode(s1, INPUT) ;
  pinMode(s2, INPUT) ;
  pinMode(s3, INPUT) ;
}
void loop()
{
  unsigned long currentMillis = millis();

  flame_detected1 = digitalRead(s1);
  flame_detected2 = digitalRead(s2);
  flame_detected3 = digitalRead(s3);
  if (flame_detected1  == 0)
  {
     if (currentMillis - previous_blink >= blink_interval) {
    previous_blink = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledr, ledState);
    Serial.println("111Flame detected...! take action immediately.");
    digitalWrite(r1, LOW);
  }
  else if (flame_detected2 == 0)
  {
    Serial.println("222Flame detected...! take action immediately.");
    digitalWrite(r2, LOW);
  }
   else if (flame_detected3 == 0)
  {
    Serial.println("333Flame detected...! take action immediately.");
    digitalWrite(r3, LOW);
  }
  else
  { 
   
    Serial.println("No flame detected. stay cool");
 
    digitalWrite(r1, HIGH);
    digitalWrite(r2, HIGH);
    digitalWrite(r3, HIGH);
    }
}

crysty1810:
I kinda unerstand how to work with millies, but using it to check if the sensor is on for 1 sec then using it for the loop and also for the led blink leaves me scratching my head.

If you want to check that something is on continuously for a period of time then you need to test for when it is not on. Like this

sensorVal = digitalRead(sensorPin);

if (sensorVal == HIGH) { // assumes LOW when ON
   lastTimeSensorWasHigh = millis();
}

if (millis() - lastTimeSensorWasHigh >= interval) {
   // sensor has been continuously on throughout the interval
   // do stuff
}

The demo Several Things at a Time illustrates the use of millis() to manage timing for several things. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

Any time you have something like this:

int s1 = 51 ;
int s2 = 52 ;
int s3 = 53 ;

It's a sign that you should learn about/use arrays. Failing that, more descriptive names would improve matters.

I mean, i got only 3 sensors/ and 3 relays for the solenoids and 3 for the led-s. And using arrays would confuse me even more.

What should happen if a sensor is still low (ie still seeing a fire) after the 5 second spray (ie the fire didn't go out). Should the 5 seconds get extended until the sensor goes high (ie no fire) or does the sensor need to be seen as active for a second again, as if it was a new fire, to trigger a new 5 second spray?

I think just reseting the cycle and sensor being active for 1 secod again should be fine, i will extend the 5 seconds if the fire doesnt go out in time, but it will, i use a argon gas tank and it works pretty well from my tests.

crysty1810:
I think just reseting the cycle and sensor being active for 1 secod again should be fine, i will extend the 5 seconds if the fire doesnt go out in time, but it will, i use a argon gas tank and it works pretty well from my tests.

Fortunately for the fire fighters that will be called you will never have your system in a real situation.

Paul

Of course the real thing wont even come close to this, the point of it is just a demonstration in a small scale, i got the real thing elaborated in my writen document but you realise i cant demonstrate a real system in such a small scale respecting every small detail and not spend a ton of time and money.

It was really hard even getting my hands on an argon gas tank with a preassure regulator and the distribution system . At this point im trying to keep it simple, but if you got a suggestion i would like to hear it

Off the top of my head, I'd try this (for each room):

  • Have a flag thereIsAFireInRoomX initialised false
  • If it's false, read the sensor (let's not complicate things by reading the sensor all the time and extending the spray if the fire didn't go out)
  • If the sensor is active for the 1 second (using Robin2's suggestion above) set thereIsAFireInRoomX true and set a time value say fireInRoomXDetectedAt to millis() and open the spray
  • If thereIsAFireInRoomX is true, check if 5 seconds is up since fireInRoomXDetectedAt
  • If 5 seconds is not up, blink the led (delay()-lessly of course :wink: )
  • If the 5 seconds is up, turn off the spray and the led, and set thereIsAFireInRoomX back to false

... or something like that anyway.

Thank you! I will try to get the code done and get back to you.

crysty1810:
Of course the real thing wont even come close to this, the point of it is just a demonstration in a small scale, i got the real thing elaborated in my writen document but you realise i cant demonstrate a real system in such a small scale respecting every small detail and not spend a ton of time and money.

It was really hard even getting my hands on an argon gas tank with a preassure regulator and the distribution system . At this point im trying to keep it simple, but if you got a suggestion i would like to hear it

Does your system include the ability to vent the argon gas from the room after the fire is out?

Paul

Maybe a bit more advanced than you want but reasonably elegant (not tested but does compile...):

//fire detectors
const byte pinSensor1 = 51;
const byte pinSensor2 = 52;
const byte pinSensor3 = 53;
//
const byte pinExtinguisher1 = 31;
const byte pinExtinguisher2 = 32;
const byte pinExtinguisher3 = 33;
//
const byte pinIndicatorLED1 = 34;           //just guessed at these; if LED "blinking" is just tied to relay on-time, things can be simplified
const byte pinIndicatorLED2 = 35;
const byte pinIndicatorLED3 = 36;

//defines
#define LED_PER_DIV_2           125         //LED blinking period is 250mS (this constant defines LED toggle period)
#define MIN_DETECT_ACTIVE_TIME  1000ul      //mS minimum time for detector to "see" fire before moving to extinguish
#define EXTINGUISH_ACTIVE_TIME  5000ul      //mS extinguisher discharge time

//state names
#define ST_IDLE             0
#define ST_TIME_DETECT      1
#define ST_TIME_EXTINGUISH  2


typedef struct
{
    byte        stateFM;                    //state variable
    byte        pinDetector;                //pin assigned to the detector
    byte        pinExtinguisher;            //pin assigned to the extinguisher (relay)
    byte        pinIndicatorLED;            //pins assigned to the LED indicator for this instance
    bool        bLEDEnable;                 //if true, LED blinking for this room is enabled
    unsigned long   timeEvent;              //used for timing detect and extinguish events

    
}structFireManagement;

structFireManagement FireManagement[3]=
{
    {   //room 1
        .stateFM = ST_IDLE,
        .pinDetector = pinSensor1,
        .pinExtinguisher = pinExtinguisher1,
        .pinIndicatorLED = pinIndicatorLED1,
        .bLEDEnable = false,
        .timeEvent = 0
                    
    },
    {   //room 2
        .stateFM = ST_IDLE,
        .pinDetector = pinSensor2,
        .pinExtinguisher = pinExtinguisher2,
        .pinIndicatorLED = pinIndicatorLED2,
        .bLEDEnable = false,
        .timeEvent = 0
        
    },
    {   //room 3
        .stateFM = ST_IDLE,
        .pinDetector = pinSensor3,
        .pinExtinguisher = pinExtinguisher3,
        .pinIndicatorLED = pinIndicatorLED3,
        .bLEDEnable = false,
        .timeEvent = 0
        
    }
};

void setup() 
{
    //detectors
    pinMode( pinSensor1, INPUT );
    pinMode( pinSensor2, INPUT );
    pinMode( pinSensor3, INPUT );
    
    //extinguisher relays
    pinMode( pinExtinguisher1, OUTPUT );
    pinMode( pinExtinguisher2, OUTPUT );
    pinMode( pinExtinguisher3, OUTPUT );

    //LED indicators
    pinMode( pinIndicatorLED1, OUTPUT );
    digitalWrite( pinIndicatorLED1, LOW );
    pinMode( pinIndicatorLED2, OUTPUT );
    digitalWrite( pinIndicatorLED2, LOW );
    pinMode( pinIndicatorLED3, OUTPUT );
    digitalWrite( pinIndicatorLED3, LOW );

    //can add debug messages where desired...
    Serial.begin(9600);
    
}//setup

void loop() 
{
    //state machine handles all room fire detection and extinguishing tasks and timing
    StateMachine();

    //LED handler blinks LEDs for rooms on fire
    LEDHandler();

}//loop

void StateMachine( void )
{
    static byte
        roomIndex = 0;

    //each pass through the SM services one room (pointed to by roomIndex)
    //each room object tracks its own state via stateFM
    switch( FireManagement[roomIndex].stateFM )
    {
        case    ST_IDLE:
            //check if fire detection signal has gone low
            if( digitalRead( FireManagement[roomIndex].pinDetector ) == LOW )
            {
                //has gone low; get the time now to time the low pulse and move to detect timing state
                FireManagement[roomIndex].timeEvent = millis();     //note how each object has its own time variable...
                FireManagement[roomIndex].stateFM = ST_TIME_DETECT;
                    
            }//if
            
        break;

        case    ST_TIME_DETECT:
            //during timing, if detect pin goes high, just return to idle state
            if( digitalRead( FireManagement[roomIndex].pinDetector ) == HIGH )
                FireManagement[roomIndex].stateFM = ST_IDLE;
            else
            {
                //still low; check if period has elapsed
                if( millis() - FireManagement[roomIndex].timeEvent >= MIN_DETECT_ACTIVE_TIME )
                {
                    //yes; turn on extinguisher, enable LED blink and get time for timing duration
                    digitalWrite( FireManagement[roomIndex].pinExtinguisher, LOW );
                    FireManagement[roomIndex].timeEvent = millis();
                    FireManagement[roomIndex].bLEDEnable = true;
                    FireManagement[roomIndex].stateFM = ST_TIME_EXTINGUISH;
                    
                }//if
                
            }//else
            
        break;
        
        case    ST_TIME_EXTINGUISH:            
            //timing extinguisher duration here; has time elapsed?
            if( millis() - FireManagement[roomIndex].timeEvent >= EXTINGUISH_ACTIVE_TIME )
            {
                //yes; turn off the extinguisher, disable the LED blink and return to idle
                digitalWrite( FireManagement[roomIndex].pinExtinguisher, HIGH );                    
                FireManagement[roomIndex].bLEDEnable = false;
                FireManagement[roomIndex].stateFM = ST_IDLE;
                
            }//if
            
        break;
                
    }//switch

    //bump roomIndex to point to next room
    //0, 1, 2 then back to 0...
    roomIndex++;
    if( roomIndex > 2 )
        roomIndex = 0;
        
}//StateMachine

void LEDHandler( void )
{
    static bool
        bState = false;
    static unsigned long
        timeLED = 0;
    unsigned long
        timeNow;

    //toggle boolean variable; its state will be driven to enabled LEDs
    timeNow = millis();
    if( timeNow - timeLED > LED_PER_DIV_2 )
    {
        timeLED = timeNow;
        bState ^= true;
    }//if

    //this is quick so we can do all three rooms in one loop
    for( byte i=0; i<3; i++ )
    {
        //if LED blinking is enabled...
        if( FireManagement[i].bLEDEnable == true )
            //drive indicator LED for this room based on bState (toggling variable)
            digitalWrite( FireManagement[i].pinIndicatorLED, (bState==true)?HIGH:LOW );
        else
            //not enabled; just turn indicator LED off
            digitalWrite( FireManagement[i].pinIndicatorLED, LOW );
    }//for

}//LEDHandler

Paul_KD7HB:
Does your system include the ability to vent the argon gas from the room after the fire is out?

Paul

No, i dont see any point in doing so.

Cristian :slight_smile:

Blackfin:
Maybe a bit more advanced than you want but reasonably elegant:

//fire detectors

const byte pinSensor1 = 51;
const byte pinSensor2 = 52;
const byte pinSensor3 = 53;
//
const byte pinExtinguisher1 = 31;
const byte pinExtinguisher2 = 32;
const byte pinExtinguisher3 = 33;
//
const byte pinIndicatorLED1 = 34;           //just guessed at these; if LED "blinking" is just tied to relay on-time, things can be simplified
const byte pinIndicatorLED2 = 35;
const byte pinIndicatorLED3 = 36;

//defines
#define LED_PER_DIV_2           125         //LED blinking period is 250mS (this constant defines LED toggle period)
#define MIN_DETECT_ACTIVE_TIME  1000ul      //mS minimum time for detector to "see" fire before moving to extinguish
#define EXTINGUISH_ACTIVE_TIME  5000ul      //mS extinguisher discharge time

//state names
#define ST_IDLE             0
#define ST_TIME_DETECT      1
#define ST_TIME_EXTINGUISH  2

typedef struct
{
   byte        stateFM;                    //state variable
   byte        pinDetector;                //pin assigned to the detector
   byte        pinExtinguisher;            //pin assigned to the extinguisher (relay)
   byte        pinIndicatorLED;            //pins assigned to the LED indicator for this instance
   bool        bLEDEnable;                 //if true, LED blinking for this room is enabled
   unsigned long   timeEvent;              //used for timing detect and extinguish events

}structFireManagement;

structFireManagement FireManagement[3]=
{
   {   //room 1
       .stateFM = ST_IDLE,
       .pinDetector = pinSensor1,
       .pinExtinguisher = pinExtinguisher1,
       .pinIndicatorLED = pinIndicatorLED1,
       .bLEDEnable = false,
       .timeEvent = 0
                   
   },
   {   //room 2
       .stateFM = ST_IDLE,
       .pinDetector = pinSensor2,
       .pinExtinguisher = pinExtinguisher2,
       .pinIndicatorLED = pinIndicatorLED2,
       .bLEDEnable = false,
       .timeEvent = 0
       
   },
   {   //room 3
       .stateFM = ST_IDLE,
       .pinDetector = pinSensor3,
       .pinExtinguisher = pinExtinguisher3,
       .pinIndicatorLED = pinIndicatorLED3,
       .bLEDEnable = false,
       .timeEvent = 0
       
   }
};

void setup()
{
   //detectors
   pinMode( pinSensor1, INPUT );
   pinMode( pinSensor2, INPUT );
   pinMode( pinSensor3, INPUT );
   
   //extinguisher relays
   pinMode( pinExtinguisher1, OUTPUT );
   pinMode( pinExtinguisher2, OUTPUT );
   pinMode( pinExtinguisher3, OUTPUT );

//LED indicators
   pinMode( pinIndicatorLED1, OUTPUT );
   digitalWrite( pinIndicatorLED1, LOW );
   pinMode( pinIndicatorLED2, OUTPUT );
   digitalWrite( pinIndicatorLED2, LOW );
   pinMode( pinIndicatorLED3, OUTPUT );
   digitalWrite( pinIndicatorLED3, LOW );

//can add debug messages where desired...
   Serial.begin(9600);
   
}//setup

void loop()
{
   //state machine handles all room fire detection and extinguishing tasks and timing
   StateMachine();

//LED handler blinks LEDs for rooms on fire
   LEDHandler();

}//loop

void StateMachine( void )
{
   static byte
       roomIndex = 0;

//each pass through the SM services one room (pointed to by roomIndex)
   //each room object tracks its own state via stateFM
   switch( FireManagement[roomIndex].stateFM )
   {
       case    ST_IDLE:
           //check if fire detection signal has gone low
           if( digitalRead( FireManagement[roomIndex].pinDetector ) == LOW )
           {
               //has gone low; get the time now to time the low pulse and move to detect timing state
               FireManagement[roomIndex].timeEvent = millis();     //note how each object has its own time variable...
               FireManagement[roomIndex].stateFM = ST_TIME_DETECT;
                   
           }//if
           
       break;

case    ST_TIME_DETECT:
           //during timing, if detect pin goes high, just return to idle state
           if( digitalRead( FireManagement[roomIndex].pinDetector ) == HIGH )
               FireManagement[roomIndex].stateFM = ST_IDLE;
           else
           {
               //still low; check if period has elapsed
               if( millis() - FireManagement[roomIndex].timeEvent >= MIN_DETECT_ACTIVE_TIME )
               {
                   //yes; turn on extinguisher, enable LED blink and get time for timing duration
                   digitalWrite( FireManagement[roomIndex].pinExtinguisher, LOW );
                   FireManagement[roomIndex].timeEvent = millis();
                   FireManagement[roomIndex].bLEDEnable = true;
                   FireManagement[roomIndex].stateFM = ST_TIME_EXTINGUISH;
                   
               }//if
               
           }//else
           
       break;
       
       case    ST_TIME_EXTINGUISH:            
           //timing extinguisher duration here; has time elapsed?
           if( millis() - FireManagement[roomIndex].timeEvent >= EXTINGUISH_ACTIVE_TIME )
           {
               //yes; turn off the extinguisher, disable the LED blink and return to idle
               digitalWrite( FireManagement[roomIndex].pinExtinguisher, HIGH );                    
               FireManagement[roomIndex].bLEDEnable = false;
               FireManagement[roomIndex].stateFM = ST_IDLE;
               
           }//if
           
       break;
               
   }//switch

//bump roomIndex to point to next room
   //0, 1, 2 then back to 0...
   roomIndex++;
   if( roomIndex > 2 )
       roomIndex = 0;
       
}//StateMachine

void LEDHandler( void )
{
   static bool
       bState = false;
   static unsigned long
       timeLED = 0;
   unsigned long
       timeNow;

//toggle boolean variable; its state will be driven to enabled LEDs
   timeNow = millis();
   if( timeNow - timeLED > LED_PER_DIV_2 )
   {
       timeLED = timeNow;
       bState ^= true;
   }//if

//this is quick so we can do all three rooms in one loop
   for( byte i=0; i<3; i++ )
   {
       //if LED blinking is enabled...
       if( FireManagement[i].bLEDEnable == true )
           //drive indicator LED for this room based on bState (toggling variable)
           digitalWrite( FireManagement[i].pinIndicatorLED, (bState==true)?HIGH:LOW );
       else
           //not enabled; just turn indicator LED off
           digitalWrite( FireManagement[i].pinIndicatorLED, LOW );
   }//for

}//LEDHandler

Wow your code is really cool, in looking it over and understanding it right now, going to test it later, thank you!

crysty1810:
for my bachelor degree

I really hope that this isn't your final year grad project for which someone has provided pretty much working out-the-box code. I was reluctant to even supply the very rough algo that I did, never mind a working sketch, but at least that would have meant you did the actual coding.

I understand your concern, most of the work involved in my project is related to analising types of fire suppression systems and talking about the tehnical and theoretical aspects, theyr benefits , riscs and stuff like that. The practical part is there just because i thought it would be cool to show them somehting. This code is not the important part of my project but even so, i wont use the code until i don't understand every last bit of it, and also i won't take credit for it.

I know you expressed reluctance to use arrays but it seems to me it would be simplest to start with an array for one room containing the room sensor pin, room suppressor pin, room led pin, time fire was detected, and the time the suppression was turned on.

In the main loop
Test the sensor then check if the fire detection value is not zero.
If both are zero, then the room is idle.
If either are not zero, then do the fire function.

In the fire function
If the fire detected time is zero, set the fire detected time to now.
If the time since sensor detection is more than the suppressor trigger time and the suppressor activation time is zero, set the suppressor activation time to now.
If the suppressor activation time is not zero and the time since suppressor activation is less than suppressor max time, activate suppression.
If the time since suppressor activation is odd, turn LED on, if even turn LED off.
if the time since suppressor activation is more than suppressor max time, set the suppressor activation time and sensor detection time back to zero. Turn LED off
return to loop

Then you can create an array that contains the room array for all the rooms and loop through each room in the main loop.

Be aware that the timer will rollover.

crysty1810:
No, i dont see any point in doing so.

Cristian :slight_smile:

You would if your entered the room without your Scott airpack.

Paul