Pages: 1 [2] 3   Go Down
Author Topic: [Video] Electronic Dog Door - few weird things happening ??  (Read 3483 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 287
Posts: 25682
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

"delay" takes an "unsigned int" - you would have been just as well leaving the constant value as it was, and simply changing the data type.
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

I wanted to minimize the back-n-forth so I took the lazy way out. Given that its not actually sleeping, I figured one minute verses fifteen isn't really going to make much difference. Nonetheless, I appreciate the feedback and the catch. Besides, 900k is greater than 2**16 and I was too lazy to check if longs were actually longs so again, lazy way...  smiley-mr-green Which means I would of needed either a long or unsigned long. But since you mentioned it, I checked. We've got 16-bit ints and 32-bit longs. Yaahooo!


Logged


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

Gerg,

Got some interesting feedback on progress to date.......

I made some changes to your code as below:
1. I changed 'const int anti_jitter_delay = 15 * 60 * 1000 ;' to 'const unsigned int anti_hunt_delay = 15 * 60 * 1000 (as per AWOL's comment).

2. I changed the light and dark thresholds to the following:
sunset_threshold = 200 ;
sunrise_threshold = 25 ;

I have noticed some very interesting behaviour with your code and will try to describe what is happening.  I have attached (below) the serial output so you can see your debug dump.

What is happening:
Firstly I changed 'anti_jitter_delay' down to 1000 so I could capture some debug data without waiting hours.
Starting from total darkness, I shone a dim torch on the LDR and watched the 'light_level' value change through your serial output (on the laptop).  I noticed it slowly rise up, and 'light_level_smoothed' came up slowly as well.  When 'light_level_smoothed' hit 25, the door went up.  Hooray.

When I then slowly took the torch away, I noticed the value of the 'light_level' (instantaneous) and 'light_level_smoothed' (more gradually) reduce in value.  When the value of 'light_level' got down to 25, the door closed, however it keep going up and down until the level of 'light_level_smoothed' got down to 25 as well.

In summary:
Door keeps going up and down until the value of 'light_level_smoothed' reaches the threshold levels.

Copy of debug dump:

Setup complete.
light_level: 23
light_level_smoothed: 75
top_switch: 0
bot_switch: 0
0, 0, error or transient door position; lifting...
Lifting door.
Door is now lifted.
-------------
light_level: 22
light_level_smoothed: 48
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 22
light_level_smoothed: 35
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 21
light_level_smoothed: 28
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 22
light_level_smoothed: 25
top_switch: 0
bot_switch: 1
Sleeping or delaying for 1-minute...
-------------



light_level: 63
light_level_smoothed: 39
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 68
light_level_smoothed: 53
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 68
light_level_smoothed: 60
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 70
light_level_smoothed: 65
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 69
light_level_smoothed: 67
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 70
light_level_smoothed: 68
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 70
light_level_smoothed: 69
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 70
light_level_smoothed: 69
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 70
light_level_smoothed: 69
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 69
light_level_smoothed: 69
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 69
light_level_smoothed: 69
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 68
light_level_smoothed: 68
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 68
light_level_smoothed: 68
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 34
light_level_smoothed: 51
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 28
light_level_smoothed: 39
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 29
light_level_smoothed: 34
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 29
light_level_smoothed: 31
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 29
light_level_smoothed: 30
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 28
light_level_smoothed: 29
top_switch: 0
bot_switch: 1
light level > sunrise_threshold and top switch is not active - raising door...
Lifting door.
Door is now lifted.
-------------
light_level: 6
light_level_smoothed: 17
top_switch: 1
bot_switch: 0
light level < sunset_threshold and bottom switch is not active - lowering door...
Lowering door.
Door is now lowered.
-------------
light_level: 8
light_level_smoothed: 12
top_switch: 0
bot_switch: 1
Sleeping or delaying for 1-minute...
-------------

Copy of code in next post.
Logged

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

Copy of code referred to in my last post.

Regards

Code:
/*
created June 2011
 Electronic pet door project.
 Program by Gerg (from Arduino forum), v2
 
 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 = 200 ;
const int sunrise_threshold = 25 ;
const unsigned int anti_hunt_delay = 1000 ;                             // 60 second delay to stop


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.println( light_level ) ;
  Serial.print( "light_level_smoothed: " ) ;
  Serial.println( light_level_smoothed ) ;
  Serial.print( "top_switch: " ) ;
  Serial.println( top_switch ) ;
  Serial.print( "bot_switch: " ) ;
  Serial.println( bot_switch ) ;

  if( (0 == top_switch) && (0 == bot_switch) ) {                               // Either we have an error or the door is in
   Serial.println( "0, 0, error or transient door position; lifting..." ) ;      // a state of transition. Its probably an error
   lift_door() ;                                                               // 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.
 
  else if( (1 == top_switch) && (1 == bot_switch) ) {                          // This is always an error and probably something serious.
    Serial.println( "1, 1, error condition. Ignoring..." ) ;                     // Ideally we'll never see it.
  }                                                                            // What ya wanna do? Blink an error LED?
 
  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.println( "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.println( "light level > sunrise_threshold and top switch is not active - raising door..." ) ;
      lift_door() ;
    }
   
    else {                                                                    // This represents status quo during daylight or night.
      Serial.println( "Sleeping or delaying for 1-minute..." ) ;                // To be power friendly, we should probably sleep for a
      delay( anti_hunt_delay ) ;                                              // 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.println( "-------------" ) ;
  delay( anti_hunt_delay ) ;
}


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

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

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


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

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

  digitalWrite( motor_power, LOW ) ;                                              // Shut it down
  Serial.println( "Door is now lifted." ) ;
}
Gerg, can you also please explain how the smoothing part of your program works.  I am sure this would be a very valuable thing for me to understand for future programs.

Again, thanks Gerg.



« Last Edit: June 16, 2011, 08:09:22 am by jawbam » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Copy of code referred to in my last post.
How many times do we need to ask you to post code properly. Go back and modify your posts. Select all the code, and press the # button on the second row. Save the changes.

Then, we'll help you with your problems.
Logged

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

PaulS,

Sorry, I didn't see anyone provide me with those instructions previously.

My apologies.
Logged

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

For it to work properly, the logic assumes the sunrise threshold is always equal or larger than the sunset threshold. You violated my undocumented requirement and assumption with your change. That's the bad thing with undocumented requirements.  smiley-razz I stared for several minutes at the logic trying to figure out how the debugging values could possibly cause the behavior. It clicked that it was only possible if the thresholds were violating my assumption and I recalled you saying something about changing threshold values.

Originally it was:
Code:
// Do these account for cloudy days? What about storms?
const int sunset_threshold = 50 ;
const int sunrise_threshold = 100 ;

You changed it to the following, which is bad:
Code:
// Do these account for cloudy days? What about storms?
const int sunset_threshold = 200 ;
const int sunrise_threshold = 25 ;


I now recommend something like this:
Code:
// Do these account for cloudy days? What about storms?
const int sunset_threshold = 200 ;
const int sunrise_threshold = sunset_threshold * 1.2 ;             // This must remain a larger value than sunset - must be larger than 1.0.

With this, you can tweak two values. Tweak sunset up or down and the sunrise threshold is always larger. If you need to tweak the distance between, make sure that number is always larger than 1.0.

In case it wasn't clear, by inverting the relationship of the threshold values, you created a window of 175 units in which the door will hunt as it would always satisfy one of the two conditions.

I'm pretty sure when you change your threshold limits, things will be sane again. Let us know. I'm looking forward to seeing that video. smiley
« Last Edit: June 16, 2011, 09:55:45 am by gerg » Logged


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

Gerg,

Thanks very much for your feedback.  I had no idea that by reversing the sunset and sunrise numbers it would cause the hunting.

I put together the following video to show you the result of your coding work.



Could you please, when you get a minute, explain to me how your smoothing code works.

Thanks again to you (and all the others) who contributed to this project.

Gerg, I will will let you know how it goes in 2-3 days time of continuous running.

Cheers
Logged

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

Awesome. Thanks for sharing!

This smoothing basically works by creating a running average. Its the simplest smoothing technique I know. Its also one of the easiest to allow an outlier peak or trough get through. Its simplicity, by far, is its greatest strength. Signal distortion is by far its greatest disadvantage; see attached chart. There are many other ways to do the same thing and they would also be more effective at preventing distortion. Of course, they would also be more complex; generally requiring a running window of samples, more complex math, and more CPU overhead. But given the purpose here, where we care more for the trend rather than signal integrity, combined with simplicity of implementation, it seems like a good fit.

The notion is that we don't want a single spike, say one created from lightening, to cause the sensor to trigger our state change condition. But, this is why we have our anti-hunt delay; which limits our sampling frequency. Even with a really long string of chain lightening, we are limiting our sample rate (via anti-hunt delay) and therefore our maximum sensor velocity over time. The combination means all lightening samples should be less than our nyquest frequency. Effectively meaning, the event will not be sampled unless its >= 2*anti_hunt_delay, in length, on average; which sunrise/sunset should always satisfy unless the sun goes out. And if lightening is sampled, we shouldn't see enough samples to actually trigger our thresholds because the transient spikes are smoothed, effectively reducing our sensor's velocity, over a large span of time.

In a nut shell, by adding the current value to the current smoothed value and dividing in half, you are reducing the weight of the current light value by 50%. Likewise, the weight of the previous light value has been reduced by 75% (50% of 50% + 50%). So on and so on.

BTW, kudos on the builtin safety feature of it being gravity powered down and spindle powered up. I had envisioned it being direct drive. That, specifically, is why, for transient recovery, I made it do a lift rather than lower. Still probably not a bad idea but not nearly the risk, lowering for recovery, as it would be for a direct drive system.

Now then, I noticed in a previous comment you said you went with the "unsigned" code change. Since you're new to coding, I wanted to explain why that's actually not good enough if you want to use the original value. I got the impression you didn't follow one of my comments. Here's why. The original value I provided was 15*60*1000, which equals 900,000 (or 900k). I originally used a 16-bit signed integer to hold that value. The largest value a signed 16-bit integer can hold is (16 bits available, one bit used for the sign, providing 15 bits to hold our value) 15**2, which equals 32,768. That's why AWOL rightly pointed out I coded up a bug. The value I assigned overflowed the variable. It simply can't hold a value that large. He recommended changing the variable's type to "unsigned int", but that's still a bug with the original value, which is why I very obtusely pointed that out in my reply. Why? Well, an unsigned 16-bit integer (2**16) can only hold a value as large as 65536. Again, 900k overflows that value. To hold 900k, we really need a long (2**31=2,147,483,648) or an unsigned long (2**32=4,294,967,296). The problem with that is the delay function requires an unsigned int, which he also pointed out (I've not confirmed), so our only option is to use a smaller delay value which can fit into a 16-bit, unsigned integer. And that's why the proper fix is to both reduce the value (~60k) AND change the int to unsigned.

Edit: I'll also point it, if the magnitude of the lightening reading (should it actually be sampled) is significant enough (it is very bright after all, which is what I meant by allowing a peak through), I expect the door will bounce but even still, the combination of the above should significantly minimize if and when it does occur.


* SmoothedLightSensorChart.png (39.56 KB, 1133x660 - viewed 23 times.)
« Last Edit: June 17, 2011, 09:33:40 am by gerg » Logged


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

Good grief!
I can't believe I wrote "unsigned int".
I blame the Armagnac.

Apologies for the confusion caused.
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

Gerg,

Thanks very much for explaining (in detail) how the smoothing algorithm works.

And also thanks for the explanation in relation to the intricacies of defining 'anti_hunt_delay".  On a previous occasion (when it was defined as 'const int anti_hunt_delay =  15 * 60 * 1000') the program would hang.  When I did some research into the different variables I found out that as an 'int' it could not be more than 32,767, and when I reduced the number below that, the program worked.

Shouldn't the compiler pick this error up?  Obviously it does not.  A trap for young players (like myself).

Anyway, what I have done is changed it to an 'unsigned int' and reduced the anti_hunt_delay to 60 * 1000 (as recommend by you).  I am sure this anti_hunt_delay will be sufficient, do you?

Just an idea, is it possible to have a nested delay loop to provide the full 15 minutes?  (ie loop 1 (outside loop) runs 15 times and loop 2 (inside loop) runs 60,000 times).  Would this then produce the total of 15 * 60 * 1000 as suggested by you originally?  Perhaps it is all too much trouble and the 60 seconds (60 *1000) is enough, I am just curious to know if my approach would work.

On a side note, thought you would be very interested to hear of another issue that I had.  Last night when I was running the door with the laptop attached so I could watch the serial monitor in order to see how your smoothing algorithm worked.  As the door was lowering, the door itself jammed in the rails, the motor kept going until all the string wound off the spool, then immediately started winding up again in the opposite direction and started to lift the door.  The door hit the top limit switch but didn't stop (off course not as this is not a condition that I, or assumingly you, could ever have imagined would happen) and the motor kept going.  There was lots of gear clunking and groaning going on as the motor continued to turn.  I had to quickly pull the power out to kill it.  It was a wake up call to me to see the potential power in the motor - potentially scary stuff!  I have also decided to screw in a piece of wood across the top of the door to stop the door at its top position.  This will also stop the potential of the door ripping the top limit switch off. 

I sprayed some silicone spray all throughout the vertical rails and the door slides up and down much better now.  I am also going to shave the edge of the doors a bit thinner to make the door slide up and down easier.

Could this potential issue be resolved by checking if either limit switch has been hit (regrdless of whether the door is lifting or lowering)?

Best Regards

Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Anyway, what I have done is changed it to an 'unsigned int' and reduced the anti_hunt_delay to 60 * 1000 (as recommend by you).  I am sure this anti_hunt_delay will be sufficient, do you?
Make it an unsigned long, instead. Then, it CAN hold the 15 * 60 * 1000 value,
Logged

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

Perfect!

Thanks PaulS.
Logged

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

And also thanks for the explanation in relation to the intricacies of defining 'anti_hunt_delay".  On a previous occasion (when it was defined as 'const int anti_hunt_delay =  15 * 60 * 1000') the program would hang.  When I did some research into the different variables I found out that as an 'int' it could not be more than 32,767, and when I reduced the number below that, the program worked.

Shouldn't the compiler pick this error up?  Obviously it does not.  A trap for young players (like myself).

Yes. It should. Its disappointing the compiler doesn't provide a warning of type overflow. This is a gimme on just about any modern c/c++ compiler. Perhaps they don't enable warnings when they call the compiler? I dunno. If so, that's not so smart. Compilers typically emit warnings for good reason.

Quote from: gerg
The problem with that is the delay function requires an unsigned int, which he also pointed out (I've not confirmed)
Anyway, what I have done is changed it to an 'unsigned int' and reduced the anti_hunt_delay to 60 * 1000 (as recommend by you).  I am sure this anti_hunt_delay will be sufficient, do you?

Just an idea, is it possible to have a nested delay loop to provide the full 15 minutes?  (ie loop 1 (outside loop) runs 15 times and loop 2 (inside loop) runs 60,000 times).  Would this then produce the total of 15 * 60 * 1000 as suggested by you originally?  Perhaps it is all too much trouble and the 60 seconds (60 *1000) is enough, I am just curious to know if my approach would work.


Okay, I decided to put this to rest. No more laziness on my part. I'm checking. According to this page, delay accepts an unsigned long rather than an unsigned int. That's very typical for time functions to accept unsigned longs, so its not really surprising.

And I quote:
Quote from: library reference
delay(ms)

Parameters

ms: the number of milliseconds to pause (unsigned long)

So yes, as stated by PaulS, change the type to unsigned long as that is the proper data type expected by the delay function.

I also want to stress, 15-minutes is a completely arbitrary value. Also please note, we delay the anti-hunt duration at the end of every loop AND every time a condition did not trigger a transition. So that means we'll delay up to 2x the anti-hunt delay every loop. This is important to remember because it sets an upper threshold of up to 2x the anti-hunt delay before our door will transition. This means, when we experience a false positive, we'll have to wait up to 2x delay before the door resumes its proper state. So just food for thought.

If you want, you can take the delay out of the else, simply leave the delay at the end of every loop, and add a blinky led or whatever in the else condition. Doing so will keep you from having split-delay behavior. Regardless, the else is really there to allow you to do something else when at state of rest (most of the day or night; aka, steady-state) is observed by the system.

On a side note, thought you would be very interested to hear of another issue that I had.  Last night when I was running the door with the laptop attached so I could watch the serial monitor in order to see how your smoothing algorithm worked.  As the door was lowering, the door itself jammed in the rails, the motor kept going until all the string wound off the spool, then immediately started winding up again in the opposite direction and started to lift the door.  The door hit the top limit switch but didn't stop (off course not as this is not a condition that I, or assumingly you, could ever have imagined would happen) and the motor kept going.  There was lots of gear clunking and groaning going on as the motor continued to turn.  I had to quickly pull the power out to kill it.  It was a wake up call to me to see the potential power in the motor - potentially scary stuff!  I have also decided to screw in a piece of wood across the top of the door to stop the door at its top position.  This will also stop the potential of the door ripping the top limit switch off.  

I sprayed some silicone spray all throughout the vertical rails and the door slides up and down much better now.  I am also going to shave the edge of the doors a bit thinner to make the door slide up and down easier.

Could this potential issue be resolved by checking if either limit switch has been hit (regrdless of whether the door is lifting or lowering)?

Best Regards

I'm don't really understand how the door lifting, hitting the top limit switch, didn't stop the door. That is, the entire purpose of the lift function. Any idea? Or do I misunderstand?

I thought about something like that. I didn't really expect the door to jam on the rails but it did occur to me a pet or other obstruction may get caught. I didn't mention it because of the spindle design rather than direct drive. You're going to need to allow for expansion and contraction of the material. Because of expansion, it might bind up. Because of contraction, the door might wobble in the slot and jam. Your design needs to account for the materials, season, and weather. You might consider using a roller track, such as what you would use for a drawer, rather than a slot. Or, have some wheels/bearings move in the slot rather than the door itself.

Murphy is a bitch. There are many options to look at in an attempt to avoid catastrophic failure. What I had originally envisioned was a simple timer in the lift and lower functions. If it takes a second to lift or lower, a timer of something like one and half to two seconds may be an viable threshold. If it hasn't completely opened or closed within the allotted window of time, then you know you have an error condition. I'm not entirely sure a completely automatic recovery is always possible.

I'll also point out, this is one of those cases where having an RTC can greatly simplify things. I really wish an RTC were far more common on board designs. Its far, far easier for me to think of cases where an RTC isn't needed than to think of all the cases where an RTC makes things easier. And contrary to popular mantra, RTC's empower far, far more than just time stamped logging. In this case, with an RTC, you'd define an ISR and volatile variable. On entry into lift or lower you'd set an alarm of the desired duration. In the loop, you'd also check for a change in the alarm's state. If either variable changed, you exit the loop. But I digress... At any rate, it can be simulated by assigning the current millis time to a variable before you enter your loop and doing some math in the loop against current millis time to see if you should exit. If you need help, let us know.

P.S. Wax is an old school lubricant which does not attract dirt and dust; especially if the lubricated surface is used daily. Its also naturally water proof. I'm frequently surprised how many people don't know wax can be a lubricant. There are commercial wax lubricants (frequently used on motorcycle chains) available as well as simple block paraffin, or even a simple candle. Just remember, whatever you use needs to be appropriate for weather and season. I've used wax, right off of a candle, on sliding doors and stuck windows.
« Last Edit: June 18, 2011, 09:50:38 am by gerg » Logged


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

Hi guys, great work you're doing here, just thought i'd throw in my $0.02.

I have got the code working fine, however, I have changed the part when both inputs are read as 0 to do a double check.

The code I have changed is here:
Code:
if( (0 == top_switch) && (0 == bot_switch) ) {                               // Either we have an error or the door is in
   Serial.println( "0, 0, error or transient door position; Checking what position the door should be in." ) ;      // a state of transition. Its probably an error
// \/\/CHANGED CODE \/\/
   check_door() ;                                                               // as we should never leave our loop until out of transient
// /\/\CHANGED CODE /\/\
  }       

And I have added this above void lower_door:
Code:
void check_door()
{
  if( (light_level_smoothed < sunset_threshold) && (0 == top_switch) ) {     // door is up, sun is setting - lower door
      Serial.println( "light level < sunset_threshold and bottom switch is not active - lowering door..." ) ;
      lower_door() ;
    }
   else if( (light_level_smoothed > sunrise_threshold ) && (0 == bot_switch) ) {  // door is down, sun is rising - lift door
      Serial.println( "light level > sunrise_threshold and top switch is not active - raising door..." ) ;
      lift_door() ;
    }
}

This stops the door from opening itself again if it doesn't need to. At least, that is what I intend for it to do.

What do you guys think?
Logged

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