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

Also added:
Code:
digitalWrite( motor_direction, LOW);

after digitalWrite (motor_power, LOW); in the lift door function, there is no need for the relay to remain on when the door is raised, this just uses up more power than necessary.
Logged

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

Quote
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?

Gerg, That is just it, it isn't lifting, it is lowering.  However, when the door gets jammed, the spool keeps turning.....

The string comes off the spool, the spool keeps turning, the string then winds up on the spool in the other direction.  Then the door gets lifted up and hits the top micro switch.  Because the code thinks it is lowering the door, it is looking for the bottom micro to be hit, not the top micro.

Does this make sense?

Thanks for sorting out the variable type for anti_hunt_delay.  I will use 'unsigned long' and will change the code back to 15 * 60 * 1000 (thanks to AWOL as well).

Thanks also for the tips to stop the door jamming, I shall use wax.  I will have to give it some more thought and see if I can modify it to be better.  I think the problem is that I am using wood as the rails, and wood is not the smoothest thing in the world.  The door itself is made out of an old nylon bread board that we were throwing out.  If my memory serves me correctly, nylon is a self lubricating material - so I may re-make the rails out of nylon and see how that goes.  Has anyone had any experience with using nylon in this way?  

n00bz0rz,

Thanks also for your comments about turning off motor_power.  You are absolutely right.  I fact I have a 7Amp/hr SLA battery (connected to a float charger).  I get about 1 day out of this and the battery goes flat.  I checked with an ammeter and the circuit was pulling 200ma, which works out to be 4.8AMP/hrs over 24 hours - approx 70% flat.  I can't work out why the battery keeps dying even though it has a dedicated 1 amp SLA charger connected to it.  Any ideas?  Anyway I got fed up with it today and replaced the battery and charger with a 12v, 34amp power supply.  Why 34 amps?  Because I bought 6 of them for $50 at a Ham radio show.  

Thanks for the 'check_door' modification.  Could you please explain what this does different to gergs code? Sorry, it is not obvious to me (beginner  smiley-confuse).

All,

I will post the full schematics for the project for those that are interested, but I already have thought about some future improvements.  These include:
1) Improving the vertical rails so there is no possibility of jamming (if that is possible);
2) Replacing the power and changeover relay (and associated transistor driver board) with a single motor controller chip (that provides direction and power);
3) Powering the complete project with an SLA battery that is charged by a solar panel (my SLA battery and float charger hasn't worked for some reason);
4) Adding an LCD screen to show light level, smoothed light level and top and bottom switch status (saves me connecting the laptop to run the serial monitor).

Regards

Logged

Dallas, Texas
Offline Offline
Sr. Member
****
Karma: 3
Posts: 267
View Profile
WWW
 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 /\/\
  }       
What do you guys think?

My concern with such a change is that by definition, the door is in an indeterminate position and we have no idea if anything is in the portal's threshold. By blinding lowering the door it may pose a risk for any critter in the way. Granted, the door isn't direct drive but its still contrary to my preference for leaning toward a builtin safety. So its not that its wrong, I personally don't feel its as safe. Ultimately, that's not my call to make.
Logged


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

Quote
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?

Gerg, That is just it, it isn't lifting, it is lowering.  However, when the door gets jammed, the spool keeps turning.....

The string comes off the spool, the spool keeps turning, the string then winds up on the spool in the other direction.  Then the door gets lifted up and hits the top micro switch.  Because the code thinks it is lowering the door, it is looking for the bottom micro to be hit, not the top micro.

Does this make sense?

Thanks for sorting out the variable type for anti_hunt_delay.  I will use 'unsigned long' and will change the code back to 15 * 60 * 1000 (thanks to AWOL as well).

Ahhh....yes. That makes sense! Doh!

If my memory serves me correctly, nylon is a self lubricating material - so I may re-make the rails out of nylon and see how that goes.  

Nylon is self lubricating. It also has the advantage in that it doesn't swell from humidity and rain like wood. But do keep in mind, you need to have physical tolerances which work well with your material; including contraction and expansion.

Wax may or may not work well for you. I don't know what kind of climate you have where you're at. But its generally available and at least help alleviate the problem until you can get a better design with tighter tolerances and materials in place.

The usual caveats of uncompiled, untested code apply. This attempts to add several things.
1, it attempts to limit the maximum duration in which a door transition is allowed. Please tweak.
2, attempts to detect an inverted transition within the maximum bounds of condition 1. Please tweak.
3, now has an error function which should never exit without manual intervention. You need to populate with whatever you want it to do.

Code:
// Do these account for cloudy days? What about storms?
const int transition_threshold = 2 * 1000 ;                        // Never run longer than 2-seconds - tweak me
const int inverted_transition_threshold = 100 ;                    // 100 ms to clear limit switch - tweak me
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.
const unsigned int anti_hunt_delay = 1000 ;                        // 60 second delay to stop

And:
Code:
 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.
    error() ;
  }                                                                            // 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..." ) ;
      if( !lower_door() ) {
 error() ;
      }
    }
    
    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..." ) ;
      if( !lift_door() ) {
 error() ;
      }
    }
    
    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 ) ;
}


int lower_door()
{
  int result = 1 ;
  unsigned long start ;
  Serial.println( "Lowering door." ) ;                                            // Start lowering the door
  digitalWrite( motor_direction, LOW ) ;
  digitalWrite( motor_power, HIGH ) ;

  start = millis() ;
  while( 0 == bot_switch && result ) {                                            // Loop until our limit switch is activated
    bot_switch = digitalRead( bottom_limit_switch ) ;

    // Check if we've been here too long
    if( millis() - start > transition_threshold ) {
result = 0 ;
    } else {
// Check to see if other switch is active after a short time of running
// to minimize potential harm/damage.
if( millis() - start > inverted_transition_threshold ) {
   top_switch = digitalRead( top_limit_switch ) ;
   if( 1 == top_switch ) {
result = 0 ;  // We've somehow reversed to shut it down ASAP
   }
}
    }
  }

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

  return result ;
}


int lift_door()
{
  int result = 1 ;
  unsigned long start ;
  Serial.println( "Lifting door." ) ;                                             // Start lifting the door
  digitalWrite( motor_direction, HIGH ) ;
  digitalWrite( motor_power, HIGH ) ;

  start = millis() ;
  while( 0 == top_switch && result ) {                                            // Loop until our limit switch is activated
    top_switch = digitalRead( top_limit_switch ) ;

    // Check if we've been here too long
    if( millis() - start > transition_threshold ) {
result = 0 ;
    } else {
// Check to see if other switch is active after a short time of running
// to minimize potential harm/damage.
if( millis() - start > inverted_transition_threshold ) {
   bot_switch = digitalRead( top_limit_switch ) ;
   if( 1 == bot_switch ) {
result = 0 ;  // We've somehow reversed to shut it down ASAP
   }
}
    }
  }

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

  return result ;
}


void error() {
    Serial.println( "Unrecoverable error." ) ;
    // Do flashy red LED or whatever for visual error announcement
    // Should require reset or button push to recover
}

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 /\/\
  }       
What do you guys think?

My concern with such a change is that by definition, the door is in an indeterminate position and we have no idea if anything is in the portal's threshold. By blinding lowering the door it may pose a risk for any critter in the way. Granted, the door isn't direct drive but its still contrary to my preference for leaning toward a builtin safety. So its not that its wrong, I personally don't feel its as safe. Ultimately, that's not my call to make.


Good point, however, your code will open the door, then lower it should the light level be below the threshold, all I have done is eliminate the need for the door to open before checking where it should be, hopefully saving a little battery life in the process.

As for animal safety, the door is simply being lowered by the spool winding down, the only force pulling the door down is gravity, there is no force pushing the door downwards, I doubt anything but a small rodent would be injured by the force of a fairly light door being lowered relatively slowly.

Plus, for what I want to use this circuit for (chicken coop door opener) that safety measure becomes pretty much redundant, chickens tend to stay away from the door when it's time for bed.

Nice work on the safety measures there, seems like this would be useful in the testing phase of installation. How would I go about implementing a test mode option (delay becomes next to nothing before opening/closing based on LDR value), then a manual close and a manual open button?

Just a simple interrupt at the top for each pin?, something like this:
if (manualclose == high){
lower_door()
}
and the inverse for manual open?

Excuse the syntax, I code not good.                                                                                                                                               
Logged

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

My concern with such a change is that by definition, the door is in an indeterminate position and we have no idea if anything is in the portal's threshold. By blinding lowering the door it may pose a risk for any critter in the way. Granted, the door isn't direct drive but its still contrary to my preference for leaning toward a builtin safety. So its not that its wrong, I personally don't feel its as safe. Ultimately, that's not my call to make.

Good point, however, your code will open the door, then lower it should the light level be below the threshold, all I have done is eliminate the need for the door to open before checking where it should be, hopefully saving a little battery life in the process.

Yes, the opening and closing is by intent and design. It only kicks in when the door is in a transient position which should never occur unless an error or power loss had previously occurred. Basically during testing and tweaking phase, its likely to be seen a lot. Beyond that, unless the power goes out or the door chronically jams, I wouldn't expect it to ever be triggered.

As for animal safety, the door is simply being lowered by the spool winding down, the only force pulling the door down is gravity, there is no force pushing the door downwards, I doubt anything but a small rodent would be injured by the force of a fairly light door being lowered relatively slowly.

I have no idea how large or small the size of his animal. Part of engineering is to plan for reasonable worst case. He may have a tea cup Chihuahua for all I know; whereas a large rodent would be more hardy. I didn't attempt to do the math to see how quickly the door comes down. Therefore, I have no idea what the potential energy looks like. Even if the door closure itself can't physically do harm, a wedged head and extraction isn't likely to endear the animal to the door. Seriously, what does erring on the side of caution really cost us? An extra complete lift following power failure every dozen years; whereby the door was already partially open? Do we really care, especially since its already coded?

Plus, for what I want to use this circuit for (chicken coop door opener) that safety measure becomes pretty much redundant, chickens tend to stay away from the door when it's time for bed.

Different animals have different behaviors. Dogs don't have a problem lying across a threshold. That doesn't mean his specific animal will. The flip side of that is, if you want to keep predators out, you'll likely want a fairly heavy door. Maybe even a locking mechanism via a solenoid. Unless your goal isn't to keep predators out so much as to simply keep them in. In this neck of the woods, snakes, coyotes, and even feral hogs, can all lift such a door. Depending on his animal, he may find a heavier door is also required. But that's more on the physical construction details rather than the programming side of things. Accordingly, this feature should be fairly robust regardless of the actual construction details (heavy door, large spindle diameter, high rpm motor, etc).

Nice work on the safety measures there, seems like this would be useful in the testing phase of installation. How would I go about implementing a test mode option (delay becomes next to nothing before opening/closing based on LDR value), then a manual close and a manual open button?

Just a simple interrupt at the top for each pin?, something like this:
if (manualclose == high){
lower_door()
}
and the inverse for manual open?

Excuse the syntax, I code not good.                                                                                                                                               

IMOHO, you'll likely want the push button to generate an interrupt. You'll need to declare an Interrupt Service Routine (ISR). The ISR should access a volatile global variable (or other shared mechanism), changing its state to reflect the activation of the button, Then, you need to create your own delay function, which also accepts a unsigned long as its argument. Then, loop testing against both the expiration of the requested delay or the change in global variable set by your ISR.

Pseudo code would look something like the following. It can be written better but this should give you an idea.
Code:
// We return the number of milliseconds spent inside
unsigned long delayButtonCheck( unsigned long delay ) {
    unsigned long start = millis() ;
    while( (millis() - start < delay) && (0 == ISRButtonPressed) ) {
    }

    return millis() - start ;
}

And then in your calling code you can do something like:
Code:
#define WAIT_DELAY 1000

if( delayButtonCheck( WAIT_DELAY ) < WAIT_DELAY ) {
    // Means we exited prematurely - potentially rare race condition but worst case
    // it should be caught on our next iteration through.
    handleButtonPress() ;
}
Logged


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