PIR-enabled smart cat litter (Help needed for code)

Hey guys,

So I'm working on a project, I think i've got the hardware aspect of the build covered, but when it comes to the code, I'm having a really hard time. I can sort of understand codes that have already been written, but coming up with it myself is darn difficult.

Perhaps you guys could give me a hand.

Here's the basic ideal I want to integrate a PIR sensor in my cat's litter to control 4 relays to work in a sequence.

In this order basically:

  • Cat walks in his litter, PIR goes HIGH for at least one second
  • PIN 2 goes HIGH, turns on LED strips inside the litter for ambient light.
  • Cat walks out, PIR goes LOW, 10000ms delay, PIN 2 goes LOW
  • PIN 3 goes HIGH for 5000ms (turns on computer fan to ventilate litter), then goes back to LOW
  • PIN 4 goes HIGH for 1000ms (activating AirWick freshener), then goes back to LOW

I'm sure this is extremely simple, I've just been having a really tough time trying to code the whole thing myself :(

Bonus pic: |500x500

What Arduino do you have? What code do you have so far? How are things connected? (schematic or equivalent, please) Connecting relays directly to an Arduino is often a bad idea. What do you really have? What relays are you using?

What happens if the cat walks in within the 10000 ms delay? the 5000 ms delay? the 1000 ms delay?

What happens if the PIR does NOT go high for at least one second? When you say the "PIR goes LOW", what do you really mean? How long?

It seems to me that there is no code and incomplete specifications. I can't help you.

It seems like a Finite State Machine (FSM) would handle this easily, but the specification is incomplete.

Thanks for the reply, here are some answers

What Arduino do you have?
I have a Uno

What code do you have so far?
I was using some PIR code but there seems to be quite a few different ones online, I’ve seen one that relied on the PIR unit for delays and what not and others that relied on arduino codes. Long story short, let’s say I have nothing

How are things connected? (schematic or equivalent, please)
Arduino supplies the breadboard with 5v power and ground, PIR is powered via the breadboard and connected to the Arduino at PIN 8, PIN 2,3,4,5 will control a 4-channel relay board

Connecting relays directly to an Arduino is often a bad idea. What do you really have?
I’ll have one 12v-powered LED strip and a computer fan going in the relay, as for the air-wick I have yet to figure that out

What relays are you using?
My relay module is very similar to this one: http://www.selloutsoon.com/albums/ebay/nichegeek/20-018-101/IMG_0058.JPG

What happens if the cat walks in within the 10000 ms delay? the 5000 ms delay? the 1000 ms delay?
the 10000ms delay is meant so that the ambient light and the post-poop sequence won’t initiate until the cat is fully out of the box, once the PIR loses any sighting and goes low, then a 10s delay until the led strips turns off. If the PIR detects any movement while either PIN 3 or 4 are high, then nothing happens and the system waits for the sequence to be over and be ready once again.

What happens if the PIR does NOT go high for at least one second?
Then this should indicate no cat is present in the litterbox and no need to activate the sequence
When you say the “PIR goes LOW”, what do you really mean? How long?
When the PIR senses no motion, then arduino sets a 10s delay until turning off the LEDs and initiating the sequence.

I hope this helps

Thank you for your rapid and point-by-point response.

An Arduino Uno should handle this easily. I asked because some Arduinos have little memory, and some Arduinos might not handle the pins that you specified. You are OK.

I asked about code because usually people come to this forum with some code that has issues. With no code, perhaps you want the "Gigs and Collaborations" section of the forum. I don't want to write code for you (or for anyone), and it would take away the learning experience that an Arduino is supposed to give to you.

The relay module picture provided little information, but it appears to be optically isolated, with transistors driving the relays and with diodes handling inductive kickback from the relay coils. Good!

Unfortunately, there is no information about current draw for the relays and their driver board, and no information about current draw for the PIR. I am concerned about drawing too much current from the Arduino's power supply. I don't know what the Arduino's limit is, but it is low.

If you study and learn about Finite State Machines, then this project should be easy. The FSM will also be a good way to avoid the delay(...) function which is evil and is to be avoided. Actually, for what you specified, delay(...) could work quite well BUT eventually you will want to do some additional things; delay(...) will interfere with these things and cause you to write your code in an undesirable way. Instead, learn to use the millis() function and unsigned long variables.

Good Luck!

A question I don't see asked/answered is will the cat trigger a PIR sensor. Cats tend to be better insulated than people.

Your description identifies several states that the software will be in. The cat is in the box, the light is on, the cat is out, the light is off, the fan is on or the air freshener is on. Each state after the cat leaves happens for a set amount of time.

I've written some basic code to get you started on your sketch. The idea is to do whatever you need to do when in a given state and advance to the next state when necessary. As written, once the post-poop sequence begins it finishes no matter what the PIR is telling you.

I advise you to get your code set before hooking up the relays and complicating matters. First see if you can reliably read the PIR, then see if your code correctly goes through the states using the serial monitor and/or lighting LEDs to let you know what is going on.

/*
- Cat walks in his litter, PIR goes HIGH for at least one second
 - PIN 2 goes HIGH, turns on LED strips inside the litter for ambient light.
 - Cat walks out, PIR goes LOW, 10000ms delay, PIN 2 goes LOW
 - PIN 3 goes HIGH for 5000ms (turns on computer fan to ventilate litter), then goes back to LOW
 - PIN 4 goes HIGH for 1000ms (activating AirWick freshener), then goes back to LOW
 */

// state definitions
const int IDLE_STATE = 0;
const int CAT_IN =     1;
const int CAT_OUT =    2;
const int VENTILATE =  3;
const int AIR_FRESH =  4;

int currentState = IDLE_STATE;  // store current state

unsigned long state_start;    // time currnet state began

byte pirPin = 4;

void setup()
{

}

void loop()
{

  switch(currentState)
  {

  case IDLE_STATE:

    if( digitalRead(pirPin) == HIGH )
    {

      // cat is in box, change state
      currentState = CAT_IN;
      state_start = millis();

    } // if

    break;

  case CAT_IN:

    // if we reached time threshold
    if( (millis() - state_start) > 1000 )
    {

      // turn on light
      digitalWrite(2, HIGH);

      // if motion no longer detected
      if( digitalRead(pirPin) == LOW ) {         

        currentState = CAT_OUT;
        state_start = millis();

      } // else

    } 
    else {

      // false alarm if cat gone before threshold 
      if( digitalRead(pirPin) == LOW ) currentState = IDLE_STATE;


    } // else

    break;

  case CAT_OUT:

    // if cat is gone
    if( (millis() - state_start) > 10000 ) 
    {
      // turn off light and advance to next state
      digitalWrite(2, LOW); 
      currentState = VENTILATE;
      state_start = millis();

    } // if

    break;

  case VENTILATE:

    // fan is on
    digitalWrite(3, HIGH);

    // if time to turn off fan
    if( (millis() - state_start) > 5000 ) 
    {

      // turn off fan, advance state
      digitalWrite(3, LOW);
      currentState = AIR_FRESH;
      state_start = millis();      

    } // if

    break;

  case AIR_FRESH:

    // air freshener on
    digitalWrite(4, HIGH);

    // if done, back to idle
    if( (millis() - state_start) > 1000 ) 
    {
      digitalWrite(4, LOW);
      currentState = IDLE_STATE;

    } // if

    break;

  default:
    break;

  } // switch


}

Hey Blue Eyes,

Wow, thanks, you're code nearly cracks it !

Here are a few things that would need to be modified for this to be 100% operational.

  • Right now, if I wave my hand in front of the PIR, even for a milisecond, the sequence starts after a second delay, i'd like to have the arduino only initiate the sequence once the PIR has been high for at least a second, (in order to prevent accidental sequences when I walk in front of the litter, for example)

  • When I wave my finger in front of the PIR for less than a second, the LED turns on, but if I put my finger back in front of it whilst the LED is on, the arduino doesn't recognize it and the sequence will go on regardless

  • The ventilation and air-freshener occur even if the cat is still inside the litter doing his thing, basically, I'd like to have the LED on as long as the cat is inside the litter, once he leaves the PIR goes low, then the arduino waits 10 seconds until proceeding to the ventilation and air freshener stages, if the PIR goes HIGH at any point, then the 10 seconds delay will start over again.

  • I have noticed that there are two definitions, one for CAT_IN and one for CAT_OUT using two different pins, can you explain the purpose behind these two?

[quote author=Blue Eyes link=msg=2540250 date=1451367315] Your description identifies several states that the software will be in. The cat is in the box, the light is on, the cat is out, the light is off, the fan is on or the air freshener is on. Each state after the cat leaves happens for a set amount of time.

I've written some basic code to get you started on your sketch. The idea is to do whatever you need to do when in a given state and advance to the next state when necessary. As written, once the post-poop sequence begins it finishes no matter what the PIR is telling you.

I advise you to get your code set before hooking up the relays and complicating matters. First see if you can reliably read the PIR, then see if your code correctly goes through the states using the serial monitor and/or lighting LEDs to let you know what is going on.

/*
- Cat walks in his litter, PIR goes HIGH for at least one second
 - PIN 2 goes HIGH, turns on LED strips inside the litter for ambient light.
 - Cat walks out, PIR goes LOW, 10000ms delay, PIN 2 goes LOW
 - PIN 3 goes HIGH for 5000ms (turns on computer fan to ventilate litter), then goes back to LOW
 - PIN 4 goes HIGH for 1000ms (activating AirWick freshener), then goes back to LOW
 */

// state definitions
const int IDLE_STATE = 0;
const int CAT_IN =     1;
const int CAT_OUT =    2;
const int VENTILATE =  3;
const int AIR_FRESH =  4;

int currentState = IDLE_STATE;  // store current state

unsigned long state_start;    // time currnet state began

byte pirPin = 4;

void setup()
{

}

void loop()
{

  switch(currentState)
  {

  case IDLE_STATE:

    if( digitalRead(pirPin) == HIGH )
    {

      // cat is in box, change state
      currentState = CAT_IN;
      state_start = millis();

    } // if

    break;

  case CAT_IN:

    // if we reached time threshold
    if( (millis() - state_start) > 1000 )
    {

      // turn on light
      digitalWrite(2, HIGH);

      // if motion no longer detected
      if( digitalRead(pirPin) == LOW ) {         

        currentState = CAT_OUT;
        state_start = millis();

      } // else

    } 
    else {

      // false alarm if cat gone before threshold 
      if( digitalRead(pirPin) == LOW ) currentState = IDLE_STATE;


    } // else

    break;

  case CAT_OUT:

    // if cat is gone
    if( (millis() - state_start) > 10000 ) 
    {
      // turn off light and advance to next state
      digitalWrite(2, LOW); 
      currentState = VENTILATE;
      state_start = millis();

    } // if

    break;

  case VENTILATE:

    // fan is on
    digitalWrite(3, HIGH);

    // if time to turn off fan
    if( (millis() - state_start) > 5000 ) 
    {

      // turn off fan, advance state
      digitalWrite(3, LOW);
      currentState = AIR_FRESH;
      state_start = millis();      

    } // if

    break;

  case AIR_FRESH:

    // air freshener on
    digitalWrite(4, HIGH);

    // if done, back to idle
    if( (millis() - state_start) > 1000 ) 
    {
      digitalWrite(4, LOW);
      currentState = IDLE_STATE;

    } // if

    break;

  default:
    break;

  } // switch


}

[/quote]

The CAT_IN and CAT_OUT definitions are states, not pins. The former is set when the PIR goes high during IDLE_STATE, the latter is set when PIR goes low during CAT_IN state.

Looking at the code I think that your first issue is covered in the CAT_IN section of the switch statement, since the state is set back to IDLE_STATE if PIR goes LOW before the second is up. I could be overlooking something.

Have you printed out the value of the PIR pin to show that it goes LOW after waving your hand? PIRs can be set up as retriggering or non-retriggering and there are adjustable timeout values as well.

Determine whether the PIR is behaving as you suspect to begin debugging.