Pages: [1] 2 3   Go Down
Author Topic: [Video] Electronic Dog Door - few weird things happening ??  (Read 3856 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is my first program using the arduino, and I am sure I have made a 'silly' beginners mistake somewhere in the code and was wondering if someone could cast their eye over my code please.

Project:
Electronic dog door that raises and lowers dependant upon the light level (ie raises in the morning, lowers at night).

Inputs:
1) Light sensor (LDR).
2) Top limit microswitch
3) bottom limit mircroswitch

Outputs:
1) Motor power
2) Motor direction (to lift or lower door)


What is supposed to happen:
At dawn - door lifts up, hits top limit micro, then stops.
At dusk - door lowers, hits bottom micro, then stops.


What is actually happening:
At dawn, door lifts up, hits top micro, then stops - perfect.
At dusk, door keeps opening and closing for 3-4 full times, then stops.  Weird.


The way I tested was to use a torch at night time.  I shined the torch onto the LDR to re-create dawn, then I simply turned the torch off for dusk.

Here is a copy of my actual code.  I would be very grateful if someone can review my code and point out my silly mistake.

Greatly appreciated.
John

~~~~~~~~~~~~~~~~~~~~~~~

/*
created June 2011
Electronic pet door project.
 
 The circuit:
 * light_sensor is an input connected to Analog input 0
 * top_limit_switch is an input on Digital input 5
 * bottom_limit_switch is an input on Digital input 4
 * motor_power is an output on Digital output 6
 * motor_direction is an output on Digital output 7
 * the drive motor is connected to the door through a second cog, which reverses the direction.
 */

// constants won't change. They're used here to show what pins certain things are connected to on the Arduino.
const int light_sensor = 0;                                        // the analog port that the LDR is connected to.
const int top_limit_switch = 5;                                    // the digital pin that the top limit switch is connected to.
const int bottom_limit_switch = 4;                                 // the digital pin that the bottom limit switch is connected to.
const int motor_direction = 6;                                     // the digital pin that changes the direction of the motor (0 = down, 1 = up)
const int motor_power = 7;                                         // the digital pin that turns the power on to the motor.


// these are variables and they change throughout the program.
int light_level = 0;                                               // declare light_level as an integer variable.
int top_switch = 0;                                                // declare top_switch as an integer variable.
int bot_switch = 0;                                                // declare bot_switch as an integer variable.


void setup()
{
  pinMode(light_sensor, INPUT);                                    // tell the Arduino that this is an input.
  pinMode(top_limit_switch, INPUT);                                // tell the Arduino that this is an input.
  pinMode(bottom_limit_switch, INPUT);                             // tell the Arduino that this is an input.
  pinMode(motor_power, OUTPUT);                                    // tell the Arduino that this is an output.
  pinMode(motor_direction, OUTPUT);                                // tell the Arduino that this is an output.
}

void loop()
{
  light_level = analogRead(light_sensor);                          // read the light sensor and the top and bottom switches before we go into the loops
  top_switch = digitalRead(top_limit_switch);
  bot_switch = digitalRead(bottom_limit_switch);
  
  while ((light_level < 50) && (bot_switch == 0))                 // if it is dusk and the bottom switch has not been hit.
  {
    digitalWrite(motor_direction, LOW);                            // change motor direction to 'down'
    digitalWrite(motor_power, HIGH);                               // turn motor on
    bot_switch = digitalRead(bottom_limit_switch);                 // read the bottom switch, the door might have touched it.
  }                                                                              // go back up to the curly bracket above

  while ((light_level > 100  ) && (top_switch == 0))               // if it is dawn and the top switch has not been hit.
  {
    digitalWrite(motor_direction, HIGH);                           // change motor direction to 'up'
    digitalWrite(motor_power, HIGH);                               // turn motor on (and down the door goes)
    top_switch = digitalRead(top_limit_switch);                    // read the top switch, the door might have touched it.
   }                                                                             // go back up to the curly bracket above

  digitalWrite(motor_power, LOW);                                  // turn motor off when either limit switch is hit.
}                                                                                // go back up to the top of the program

« Last Edit: June 16, 2011, 11:30:54 pm by jawbam » Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 634
Posts: 50226
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
 while ((light_level < 50) && (bot_switch == 0))
  {
    digitalWrite(motor_direction, LOW);
    digitalWrite(motor_power, HIGH);
    bot_switch = digitalRead(bottom_limit_switch);
  }
You should separate the action of starting the motor moving, in the right direction, which needs to be done once, from the checking of the limit switch, which needs to happen many times.

Code:
if(light_level < 50)
{
    digitalWrite(motor_direction, LOW);
    digitalWrite(motor_power, HIGH);
    while(bot_switch == 0)
    {
       bot_switch = digitalRead(bottom_limit_switch);
    }
}

To really be able to help you with the problem, we'd need to know how your switches are wired. You are not using the internal pull-up resistors, so you should be using external pull-up or pull-down resistors. Are you?

A delay at the end of loop() to make the checking of the LDR happen only once a minute or so might be useful.
« Last Edit: June 13, 2011, 05:52:02 am by PaulS » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26488
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your while loops don't re-read the light levels.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks PaulS,

In regard to the micro switches, I am using pull down resistors on them both (to ground).

Good idea re the delay at the end of loop.  I will incorporate.

Thanks for your fast reply.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks AWOL,

I did originally check the light level in the While loops, but removed it because it used to 'hunt'.

As a rank beginner, I am happy to take your recommendations on what you would consider the best way to code it.

Greatly appreciated.
Logged

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What can I say, I'm waiting for my board to come in.  smiley-roll-sweat  smiley

Hope you don't mind but I created a version for you. I've not compiled it so you may encounter some typos. Please note this code attempts to address error states which your original code did not. All I ask is you report back how well it worked and what, if any changes were required. Obviously you're free to completely ignore the code I'm providing. Of course, it would be cool to see a video of it in action, including transient error recovery.

Code:
/*
created June 2011
Electronic pet door project.
 
 The circuit:
 * light_sensor is an input connected to Analog input 0
 * top_limit_switch is an input on Digital input 5
 * bottom_limit_switch is an input on Digital input 4
 * motor_power is an output on Digital output 6
 * motor_direction is an output on Digital output 7
 * the drive motor is connected to the door through a second cog, which reverses the direction.
 */

// constants won't change. They're used here to show what pins certain things are connected to on the Arduino.
const int light_sensor = 0;                                        // the analog port that the LDR is connected to.
const int top_limit_switch = 5;                                    // the digital pin that the top limit switch is connected to.
const int bottom_limit_switch = 4;                                 // the digital pin that the bottom limit switch is connected to.
const int motor_direction = 6;                                     // the digital pin that changes the direction of the motor (0 = down, 1 = up)
const int motor_power = 7;                                         // the digital pin that turns the power on to the motor.


// these are variables and they change throughout the program.
int light_level = 0;                                               // declare light_level as an integer variable.
int top_switch = 0;                                                // declare top_switch as an integer variable.
int bot_switch = 0;                                                // declare bot_switch as an integer variable.

// Do these account for cloudy days? What about storms?
const int sunset_threshold = 50 ;
const int sunrise_threshold = 100 ;
const int anti_jitter_delay = 15 * 60 * 1000 ;


void setup()
{
  pinMode(light_sensor, INPUT);                                    // tell the Arduino that this is an input.
  pinMode(top_limit_switch, INPUT);                                // tell the Arduino that this is an input.
  pinMode(bottom_limit_switch, INPUT);                             // tell the Arduino that this is an input.
  pinMode(motor_power, OUTPUT);                                    // tell the Arduino that this is an output.
  pinMode(motor_direction, OUTPUT);                                // tell the Arduino that this is an output.
}

void loop()
{
  light_level = analogRead(light_sensor);                          // read the light sensor and the top and bottom switches before we go into the loops
  top_switch = digitalRead(top_limit_switch);
  bot_switch = digitalRead(bottom_limit_switch);

  if( (0 == top_switch) && (0 == bot_switch) ) {
      // Either we have an error or the door is in
      // a state of transition. Its probably an error
      // as we should never leave our loop until out of transient
      // state. Did we loose power during transition??? If so,
      // should probably attempt to recover here.
      lift_door() ;
  } else {
      // Switches appear good and door is not in transient state
      if( (light_level < sunset_threshold) && (0 == bot_switch) ) {
 // door is up (or at least not down), sun is setting - lower door
 lower_door() ;
      } else if( (light_level > sunrise_threshold ) && (0 == top_switch) ) {
 // door is down (or at least not up), sun is rising - lift door
 lift_door() ;
      } else {
 // This represents status quo during daylight or night.
 // To be power friendly, we should probably sleep for a
 // short duration - say 15 minutes? This also prevents
 // rapid jittering from storms and various weather.
 // I think we can't really do anything without an RTC
 // so we'll fake it just to prevent jittering.
 delay( anti_jitter_delay ) ;
      }
  }
}


void lower_door()
{
    // Start lowering the door
    digitalWrite( motor_direction, LOW ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == bot_switch ) {
bot_switch = digitalRead( bottom_limit_switch ) ;
    }

    // Shut it down and reverse direction as safety
    digitalWrite( motor_power, LOW ) ;
    digitalWrite( motor_direction, HIGH ) ;
}


void lift_door()
{
    // Start lowering the door
    digitalWrite( motor_direction, HIGH ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == top_switch ) {
top_switch = digitalRead( top_limit_switch ) ;
    }

    // Shut it down and reverse direction as safety
    digitalWrite( motor_power, LOW ) ;
    digitalWrite( motor_direction, LOW ) ;
}

Did I mention I can't wait for my board to arrive...

EDIT: Fixed logic state. Another state can be added to detected if both switches report > 0, which probably means a short or switch has gone bad, etc.
EDIT2: Clarified a statement.
EDIT3: All done now - left some old code in place on accident.
« Last Edit: June 13, 2011, 03:10:55 pm by gerg » Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Gerg,

Thank you very much.  Greatly appreciated.

It nearly worked - let me expand...

I compiled and uploaded your code, then this is what happened.

The door was indeed halfway down when I loaded your code and your error handling routine worked a treat, up went the door straight away until it stopped when it hit the upper limit switch.

When I then placed my hand over the LDR (dusk), the door went down, hit the bottom limit switch, then went up, hit the top limit switch and went down again.  It kept repeating the up and down at finitum.....

But!......when I took my hand off the LDR, whne the door got to the top, it stopped.  Nice.

As I had this problem with my code, I am wondering is there is perhaps a problem other than the code (mechanics, micros, etc).

So.......I metered the bottom microswitch to see if it was working.  I metered it at the screw terminals on the wingshield (http://wingshieldindustries.com/products/screwshield/) as my son manually pushed the bottom micro switch.  I could see that it was working fine.

It appears to hit the bottom micro, then instantly change direction.  For some reason, it is not stopping the motor when it hits the bottom micro switch.

This is a major mystery as when I built it a few nights ago, it worked fine when I tested it over approx 20 cycles (torch on, door went up, take torch away, door went down).  Don't understand how it could have worked then but not now.

Your error routine is a great addition, to what hopefully I will be able to get going.

I am happy to provide a video of the door.  What is the best way, post to youtube and put a link into my next reply?

Again, best reagrds

Hmmmmm, mystery.

Logged

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, a little surprising and not if you know what I mean. Let's get some debugging information in there. I should have known better.  smiley-roll

Straight off I wanted to verify the logic states in my head made sense just so we can rule out the obvious. This is what I came up with:
light, top, bot, comment
-, -, 1, 1, error, should never happen, currently ignored by code
<50, 1, 0, lower door
>100, 0, 1, lift door
-, 0, 0, lift door as its in transient state
50-100, 1, 0, attempt to sleep, or at least delay
50-100, 0, 1, attempt to sleep, or at least delay

I'm pretty sure we have full coverage, less the 1, 1, condition, of that state table. That's now been corrected and has been added to the code below.

Code:
/*
created June 2011
Electronic pet door project.
 
 The circuit:
 * light_sensor is an input connected to Analog input 0
 * top_limit_switch is an input on Digital input 5
 * bottom_limit_switch is an input on Digital input 4
 * motor_power is an output on Digital output 6
 * motor_direction is an output on Digital output 7
 * the drive motor is connected to the door through a second cog, which reverses the direction.
 */

// constants won't change. They're used here to show what pins certain things are connected to on the Arduino.
const int light_sensor = 0;                                        // the analog port that the LDR is connected to.
const int top_limit_switch = 5;                                    // the digital pin that the top limit switch is connected to.
const int bottom_limit_switch = 4;                                 // the digital pin that the bottom limit switch is connected to.
const int motor_direction = 6;                                     // the digital pin that changes the direction of the motor (0 = down, 1 = up)
const int motor_power = 7;                                         // the digital pin that turns the power on to the motor.


// these are variables and they change throughout the program.
int light_level = 127 ;                                            // declare light_level as an integer variable.
int light_level_smoothed = 127 ;                         // This prevents us from immediately reacting
int top_switch = 0;                                                // declare top_switch as an integer variable.
int bot_switch = 0;                                                // declare bot_switch as an integer variable.

// Do these account for cloudy days? What about storms?
const int sunset_threshold = 50 ;
const int sunrise_threshold = 100 ;
const int anti_jitter_delay = 15 * 60 * 1000 ;


void setup()
{
  pinMode(light_sensor, INPUT);                                    // tell the Arduino that this is an input.
  pinMode(top_limit_switch, INPUT);                                // tell the Arduino that this is an input.
  pinMode(bottom_limit_switch, INPUT);                             // tell the Arduino that this is an input.
  pinMode(motor_power, OUTPUT);                                    // tell the Arduino that this is an output.
  pinMode(motor_direction, OUTPUT);                                // tell the Arduino that this is an output.

  Serial.begin( 9600 ) ;                                           // Make sure our serial port is configed
  Serial.println( "Setup complete." ) ;
}


void loop()
{
  light_level = analogRead(light_sensor);
  light_level_smoothed += light_level ;
  light_level_smoothed /= 2 ;
  top_switch = digitalRead(top_limit_switch);
  bot_switch = digitalRead(bottom_limit_switch);

  Serial.print( "light_level: " ) ;
  Serial.print( light_level ) ;
  Serial.print( "light_level_smoothed: " ) ;
  Serial.print( light_level_smoothed ) ;
  Serial.print( "top_switch: " ) ;
  Serial.print( top_switch ) ;
  Serial.print( "bot_switch: " ) ;
  Serial.print( bot_switch ) ;

  if( (0 == top_switch) && (0 == bot_switch) ) {
      // Either we have an error or the door is in
      // a state of transition. Its probably an error
      // as we should never leave our loop until out of transient
      // state. Did we loose power during transition??? If so,
      // should probably attempt to recover here.
      Serial.print( "0, 0, error or transient door position; lifting..." ) ;
      lift_door() ;
  } else if( (1 == top_switch) && (1 == bot_switch) ) {
      // This is always an error and probably something series.
      // Ideally we'll never see it.
      // What ya wanna do? Blink an error LED?
      Serial.print( "1, 1, error condition. Ignoring..." ) ;
  } else {
      // Switches appear good and door is not in transient state
      if( (light_level_smoothed < sunset_threshold) && (0 == bot_switch) ) {
 // door is up (or at least not down), sun is setting - lower door
 Serial.print( "light level < sunset_threshold and bottom switch is not active - lowering door..." ) ;
 lower_door() ;
      } else if( (light_level_smoothed > sunrise_threshold ) && (0 == top_switch) ) {
 // door is down (or at least not up), sun is rising - lift door
 Serial.print( "light level > sunrise_threshold and top switch is not active - raising door..." ) ;
 lift_door() ;
      } else {
 // This represents status quo during daylight or night.
 // To be power friendly, we should probably sleep for a
 // short duration - say 15 minutes? This also prevents
 // rapid jittering from storms and various weather.
 // I think we can't really do anything without an RTC
 // so we'll fake it just to prevent jittering.
 Serial.print( "Sleeping or delaying for 15-minutes..." ) ;
 delay( anti_jitter_delay ) ;
      }
  }
  Serial.println( "-------------" ) ;
  delay( 1000 ) ;

}


void lower_door()
{
    Serial.print( "Lowering door." ) ;
    // Start lowering the door
    digitalWrite( motor_direction, LOW ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == bot_switch ) {
bot_switch = digitalRead( bottom_limit_switch ) ;
    }

    // Shut it down and reverse direction as safety
    digitalWrite( motor_power, LOW ) ;
    //digitalWrite( motor_direction, HIGH ) ;
    Serial.print( "Door is now lowered." ) ;
}


void lift_door()
{
    Serial.print( "Lifting door." ) ;
    // Start lifting the door
    digitalWrite( motor_direction, HIGH ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == top_switch ) {
top_switch = digitalRead( top_limit_switch ) ;
    }

    // Shut it down and reverse direction as safety
    digitalWrite( motor_power, LOW ) ;
    //digitalWrite( motor_direction, LOW ) ;
    Serial.print( "Door is now lifted." ) ;
}


I don't know if the Serial.print's are appropriate for your board or not but I assume they are. If they are not, you'll need to change to whatever is appropriate for your setup. Noticing the addition of the serial port configuration line in the setup function.

You previously commented you were seeing jitter from your light sensor and I'm wondering if that's a player in what we're seeing. I'm wondering if we need yet another state and/or some smoothing of your light sensor. As technically, all it requires is one errant reading above or below our threshold values and then the door will be bouncing. I added some very simple smoothing to see if we can remove that from the equation. Its value is also being spit out in the debugging. The smoothing will hopefully prevent a high jitter and/or errant read from causing bounce of the door. Is the light sensor filtered in any way?

With the smoothing, you should see the smoothed light level come up or down to meet the actual light level over a number of loops. Please pay attention to this value and your thresholds. Let's verify our thresholds make sense. By the way, what is our valid range of values from our light sensor? I'm assuming its 0-255, but if that's not valid, we need to look harder at what we're doing with our thresholds as well as the values for our thresholds. And speaking of thresholds, how did you determine 50 and 100 were reasonable threshold values?

EDIT: Added 1-second delay at end of loop as that's a really good idea. I have no idea how long it takes for the light sensor to change and/or stabilize. Ideally we'd be sleeping.

« Last Edit: June 14, 2011, 07:44:50 am by gerg » Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Gerg,

Wow, thanks !

I will give this all a go and let you know the outcomes.

Yes, my Arduino board supports Serial.print, so I will capture the serial output and send that back to you.

But here are the answers to a few of your questions.

1. Board supports Serial.print:
Yes it does.  I was using Serial.print to attempt de-bugging myself, but didn't get too far.

2. Light sensor filtered in any way?
Not sure exactly what you mean here.  The light sensor is an LDR wired as a voltage divider.  I drilled a hole in the wooden door and simply poked the LDR through it.  It is just one of those small LDR's (approx 5mm in diameter).  It has nothing over the top of the LDR, it lies horizontal, facing straight out through a hole in the wooden door.

3. how did you determine 50 and 100 were reasonable threshold values?
When I previously had the serial.print commands in my program (to help debug), I noted that when it was dark the light_level value would be zero, then it would rise as I moved the torch closer to the LDR.  I chose 50 as the level as last week when I tested it for the first time I had the dawn level set at 100, which made the door open up about half an hour after dawn, so I changed the value back to 50 - no real science to it.  I think the maximum light_level gets to is approx 800 (given the resistor I am using in my voltage divider).  The value of light_level that closes the door is not really important as I put the animals to bed at night anyway (approx 10-11pm), so it is always pitch black.  I chose 100 just to make it was different to 50, to avoid the door 'hunting'.  I wasn't too worried about the 50 or 100 numbers as I knew I could fine tune them later on (and if neccessary adjust the value of the resistor in the voltage divder), although I am sure I can just adjust the values in the code.  In reality, I  will pick a number to open the door at first light, and close it when it is getting dark (doesn't matter, as long as the door is closed by the time I put the pets to bed at 10 or 11pm at night.

Other info.
A couple of days ago I put a lot of serial.print debug lines in my code to try and work out what was going on.  I could tell what loop it was in, the value of the top and bottom micro and the light level.  Although I captured all the data, I could not for the life of me work out what was causing the door to continually go up and down when it got dark.

When my wife arrived home tonight (dusk), she told me that she had to disconnect the battery because the door was just going up and down (continuously).

Next steps:
1. I will compile and upload your new code.  If all works, I will shout from the hilltops (and i'd be surpised if you don't hear me ).  If not, I will cut and paste the serial monitor info and post back to you so you can see what is going on.

2. I am also going to try another Arduino board tmrw (as I know the board I am using has 3 x inputs that don't work).  Perhaps it has another problem which may be causing this issue.

3. I will check the full range of light_level to tell you the range that it is currently generating.  I will do this by covering up the LDR (simulating complete darkness), then taking my hand off the LDR (simulating daylight).  I will report back to you on the output.

4. I will double check (again) that all my sensors come back to the correct pins on the Arduino and confirm back.

5. I will draw up a schematic and provide to you so that you have a better view of how it is all wired.

Hope this will help you with as much info as may be required to assist me further.

Greatly appreciate your tremendous support.










Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Gerg,

Quick update......

Just about midnight here but couldn't help myslef.

Just compiled and uploaded your new code.  It seems to work!!!

When I shine the torch on the LDR, the door rises.
When I turn the torch off, the door closes.
No hunting, just works perfect.

I have to hit the snore shelf now, but thought you would appreciate the instant feedback.

I am SO EXCITED.

I will do some more work in the morning and let you know how things go.

THIS IS FANTASTIC - YOU ARE A LEGEND MY FRIEND.

I don't understand how your code works as yet (as I am just a beginner), but I have learnt so much already from the comments in your code.

I truly appreciate your willingness to help a total stranger.

I am hoping that my post tomorrow will be to confirm that everything is working brilliantly.

I will also post a video of the whole project so you can see what you have helped produce.

Best Regards
Logged

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sounds great.

Somethings has been bothering me about our conditions. We've been trying to seek out our resting positions which kind of encourages hunting. I thought we'd change the logic to seek out our activation conditions rather than resting conditions. The old way made sense when we were not recovering from transient states but that too should now be resolved. Feel free to try both versions but this one sits a little better with me as we're testing against current state rather than the state we desire; which is really the preferred condition IMOHO.

I also upped the delay to one minute. I can't imagine we really need to be checking sensors that rapiidly. Besides, we should be spending most of our time in the "sleep mode." Also, I am interested if we're even hitting the "sleep mode". If not, we really need to figure out why.


Code:
/*
created June 2011
Electronic pet door project.
 
 The circuit:
 * light_sensor is an input connected to Analog input 0
 * top_limit_switch is an input on Digital input 5
 * bottom_limit_switch is an input on Digital input 4
 * motor_power is an output on Digital output 6
 * motor_direction is an output on Digital output 7
 * the drive motor is connected to the door through a second cog, which reverses the direction.
 */

// constants won't change. They're used here to show what pins certain things are connected to on the Arduino.
const int light_sensor = 0;                                        // the analog port that the LDR is connected to.
const int top_limit_switch = 5;                                    // the digital pin that the top limit switch is connected to.
const int bottom_limit_switch = 4;                                 // the digital pin that the bottom limit switch is connected to.
const int motor_direction = 6;                                     // the digital pin that changes the direction of the motor (0 = down, 1 = up)
const int motor_power = 7;                                         // the digital pin that turns the power on to the motor.


// these are variables and they change throughout the program.
int light_level = 127 ;                                            // declare light_level as an integer variable.
int light_level_smoothed = 127 ;                                   // This prevents us from immediately reacting
int top_switch = 0;                                                // declare top_switch as an integer variable.
int bot_switch = 0;                                                // declare bot_switch as an integer variable.

// Do these account for cloudy days? What about storms?
const int sunset_threshold = 50 ;
const int sunrise_threshold = 100 ;
const int anti_hunt_delay = 1 * 60 * 1000 ;


void setup()
{
  pinMode(light_sensor, INPUT);                                    // tell the Arduino that this is an input.
  pinMode(top_limit_switch, INPUT);                                // tell the Arduino that this is an input.
  pinMode(bottom_limit_switch, INPUT);                             // tell the Arduino that this is an input.
  pinMode(motor_power, OUTPUT);                                    // tell the Arduino that this is an output.
  pinMode(motor_direction, OUTPUT);                                // tell the Arduino that this is an output.

  Serial.begin( 9600 ) ;                                           // Make sure our serial port is configed
  Serial.println( "Setup complete." ) ;
}


void loop()
{
  light_level = analogRead(light_sensor);
  light_level_smoothed += light_level ;
  light_level_smoothed /= 2 ;
  top_switch = digitalRead(top_limit_switch);
  bot_switch = digitalRead(bottom_limit_switch);

  Serial.print( "light_level: " ) ;
  Serial.print( light_level ) ;
  Serial.print( "light_level_smoothed: " ) ;
  Serial.print( light_level_smoothed ) ;
  Serial.print( "top_switch: " ) ;
  Serial.print( top_switch ) ;
  Serial.print( "bot_switch: " ) ;
  Serial.print( bot_switch ) ;

  if( (0 == top_switch) && (0 == bot_switch) ) {
      // Either we have an error or the door is in
      // a state of transition. Its probably an error
      // as we should never leave our loop until out of transient
      // state. Did we loose power during transition??? If so,
      // should probably attempt to recover here.
      Serial.print( "0, 0, error or transient door position; lifting..." ) ;
      lift_door() ;
  } else if( (1 == top_switch) && (1 == bot_switch) ) {
      // This is always an error and probably something serious.
      // Ideally we'll never see it.
      // What ya wanna do? Blink an error LED?
      Serial.print( "1, 1, error condition. Ignoring..." ) ;
  } else {
      // Switches appear good and door is not in transient state
      if( (light_level_smoothed < sunset_threshold) && (1 == top_switch) ) {
 // door is up, sun is setting - lower door
 Serial.print( "light level < sunset_threshold and bottom switch is not active - lowering door..." ) ;
 lower_door() ;
      } else if( (light_level_smoothed > sunrise_threshold ) && (1 == bot_switch) ) {
 // door is down, sun is rising - lift door
 Serial.print( "light level > sunrise_threshold and top switch is not active - raising door..." ) ;
 lift_door() ;
      } else {
 // This represents status quo during daylight or night.
 // To be power friendly, we should probably sleep for a
 // short duration - say 1 minute? This also prevents
 // rapid jittering from storms and various weather.
 // I think we can't really do anything without an RTC
 // so we'll fake it just to prevent hunting.
 Serial.print( "Sleeping or delaying for 1-minute..." ) ;
 delay( anti_hunt_delay ) ;
      }
  }
  Serial.println( "-------------" ) ;
  delay( anti_hunt_delay ) ;

}


void lower_door()
{
    Serial.print( "Lowering door." ) ;
    // Start lowering the door
    digitalWrite( motor_direction, LOW ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == bot_switch ) {
bot_switch = digitalRead( bottom_limit_switch ) ;
    }

    // Shut it down
    digitalWrite( motor_power, LOW ) ;
    Serial.print( "Door is now lowered." ) ;
}


void lift_door()
{
    Serial.print( "Lifting door." ) ;
    // Start lifting the door
    digitalWrite( motor_direction, HIGH ) ;
    digitalWrite( motor_power, HIGH ) ;

    // Loop until our limit switch is activated
    while( 0 == top_switch ) {
top_switch = digitalRead( top_limit_switch ) ;
    }

    // Shut it down
    digitalWrite( motor_power, LOW ) ;
    Serial.print( "Door is now lifted." ) ;
}


EDIT: Updated code again. Fixed comments, typos, and terminology.
EDIT2: Fixed for 16-bit ints. Thanks. Good catch.
« Last Edit: June 14, 2011, 09:27:42 am by gerg » Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Gerg,

I will try your new code tmrw, however as per my previous post, the door seems to be working fine.

Question, how do you post video content into these posts?  Do I need to upload to youtube, then paste a link into my post?  Never done it before, please excuse my ignorance.

I really want to show you the working product !
Logged

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Gerg,

Quick update......

Just about midnight here but couldn't help myslef.

Just compiled and uploaded your new code.  It seems to work!!!

When I shine the torch on the LDR, the door rises.
When I turn the torch off, the door closes.
No hunting, just works perfect.

I have to hit the snore shelf now, but thought you would appreciate the instant feedback.

I am SO EXCITED.

I will do some more work in the morning and let you know how things go.

THIS IS FANTASTIC - YOU ARE A LEGEND MY FRIEND.

I don't understand how your code works as yet (as I am just a beginner), but I have learnt so much already from the comments in your code.

I truly appreciate your willingness to help a total stranger.

I am hoping that my post tomorrow will be to confirm that everything is working brilliantly.

I will also post a video of the whole project so you can see what you have helped produce.

Best Regards

Wow, that sounds awesome! Very happy to hear that. Let's not get too excited until you've seen it operate for  a day or two.   smiley-grin I suspecting we were not giving time for the sensor to settle or something like that. At any rate, review the debugging code to make sure sanity is found.

I look forward to see that video.

P.S. Ya, just post on youtube and provide the link here.
Logged


Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26488
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
const int anti_jitter_delay = 15 * 60 * 1000 ;
900k into an int does not go.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
const int anti_jitter_delay = 15 * 60 * 1000 ;
900k into an int does not go.

16-bit ints? Can't wait for my hardware to come in so I have something to test against.

Good catch. Code above has been corrected. The delay is now 1-minute.

« Last Edit: June 14, 2011, 09:26:29 am by gerg » Logged


Pages: [1] 2 3   Go Up
Jump to: