Automated Chicken Coop Door

Next Version - Arduino plus Ardumotor

The next version is currently in development. It will use an Arduino and a Sparkfun Ardumotor to reduce the electronics build even further.

The picture below shows how the components will likely fit in the same enclosure as the enclosure used in the previous versions below.

However, one difference is that while this is the same enclosure, it is the version with a transparent lid, which should save the cost of drilling a hole for the chick coop door opener's photo-resistor light sensor.

Here's the Arduino code for this Ardumotor version. It's untested as yet. So if you find any bugs, let me know.

chicken_coop_door_opener_with_ardumotor.pde
//****************************************************************
/*
 * Chicken Coop Door Controller
 * Includes auto chicken-feeder motor driver
 * Photoresistor on analog0 
 * Piezo Speaker on pin 13
 * 
 * By Lee Kimber
 * Based on 'Nightingale' by:
 * KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 */
 
//****************************************************************
 
#include <avr/sleep.h>
#include <avr/wdt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
 
// sleep between runs
int pause = 6000;
int beeps = 250;
int lightlevel = 830;
 
int nint;
int pinPiezoSpeaker=13; // make pin 13, was 10
volatile boolean f_wdt=1;
 
// Lee adds
// drive lines for the L298D motor driver
//int pwm_a = 3;  //PWM control for motor outputs 1 and 2 is on digital pin 3
//int pwm_b = 11;  //PWM control for motor outputs 3 and 4 is on digital pin 11
//int dir_a = 12;  //direction control for motor outputs 1 and 2 is on digital pin 12
//int dir_b = 13;  //direction control for motor outputs 3 and 4 is on digital pin 13
 
int door_up=4; // becomes 5, was 11
int door_down=5; // becomes 4, was 12
 
// Set up chicken feeder driver
int feeder1=7;  // becomes 7, was 8
int feeder2=6; // becomes 6, was 9
 
void setup(){
  delay(1000);
 
  {
  pinMode(pwm_a, OUTPUT);  //Set control pins to be outputs
  pinMode(pwm_b, OUTPUT);
  pinMode(dir_a, OUTPUT);
  pinMode(dir_b, OUTPUT);
 
  analogWrite(pwm_a, 100);  //set both motors to run at (100/255 = 39)% duty cycle (slow)
  analogWrite(pwm_b, 100);
 
}
 
  Serial.begin(38400);
//  pinMode(pinLed,OUTPUT);
  pinMode(pinPiezoSpeaker,OUTPUT);
 
  // Lee adds
  pinMode(door_up,OUTPUT);
  pinMode(door_down,OUTPUT);
  pinMode(feeder1,OUTPUT);
  pinMode(feeder2,OUTPUT);
 
  delay(10000);  
  Serial.println("Chicken coop door opener");
 
  // CPU Sleep Modes 
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)
 
  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode
 
  setup_watchdog(7);
}
 
byte del;
int cnt;
byte state=1;
int light=0;
 
// Lee adds
int topswitch=2; // becomes 2, was 4
int bottomswitch=3; // becomes 3, was 5
int ts=0;
int bs=0;
 
//****************************************************************
//****************************************************************
//****************************************************************
 
void loop(){
 
{
  digitalWrite(dir_a, LOW);  //Set motor direction, 1 low, 2 high
  digitalWrite(dir_b, LOW);  //Set motor direction, 3 high, 4 low
 
  delay(1000);
 
  analogWrite(pwm_a, 255);  //set both motors to run at 100% duty cycle (fast)
  analogWrite(pwm_b, 255)
 
  delay(1000);
 
  digitalWrite(dir_a, HIGH);  //Reverse motor direction, 1 high, 2 low
  digitalWrite(dir_b, HIGH);  //Reverse motor direction, 3 low, 4 high
 
  delay(1000);
 
  analogWrite(pwm_a, 100);  //set both motors to run at (100/255 = 39)% duty cycle
  analogWrite(pwm_b, 100);
 
  delay(1000);
 
// Set feed motor-driver line low to save power
digitalWrite(feeder1,LOW);
digitalWrite(feeder2,LOW);
// Set piezoSpeaker output low to mute unwanted noises
digitalWrite(pinPiezoSpeaker, LOW);
//digitalWrite(pinLed,LOW);
 
  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag
    light=analogRead(0);  // reading photoresistor
 
    // Lee adds
    ts=digitalRead(topswitch);  // read the top reed switch
    bs=digitalRead(bottomswitch);  // read the bottom reed switch
 
    Serial.print("light: " );
    Serial.print(light );
    Serial.print(" bs: ");
    Serial.print(bs);
    Serial.print(" ts: ");
    Serial.println(ts);
 
    // Lee add door-state reporting here
    if (ts == 1 && bs == 0) {
      Serial.println("Door is open"); 
    } else if (ts == 0 && bs == 1) {
      Serial.println("Door is closed"); 
    } else if (bs == 1 && ts == 1) {
      Serial.println("ALARM: Door state monitoring is faulty");
      alarm();
    } else {
      Serial.println("Door state is indeterminate (or possibly faulty)"); 
    }
 
    switch (state){
    case 0:     // waiting for dawn
      if (light < lightlevel && ts == 0) {  // light threshold high and door not open (ts open)
        state=1;
        Serial.println("Calling door-open function");
        open();
        // Door open, nothing to do for six hours
        delay(pause);
      }
      break;
    case 1:  // waiting for dusk
      if (light > lightlevel && bs == 0)  { // light threshold low and door not closed (bs open)
        state=0;
        //whistle();
        beep();
        Serial.println("Calling door-closer function");
        close();
        // Door closed, nothing to do for six hours
        delay(pause);
      }
      break;
    }
 
    nint++;
//    digitalWrite(pinLed,1);  // let led blink
 
    Serial.print("Sleep " );
    Serial.println(nint );
    delay(2);               // wait until the last serial character is send
//    digitalWrite(pinLed,0);
//    pinMode(pinLed,INPUT); // set all used ports to intput to save power
    pinMode(pinPiezoSpeaker,INPUT); // set all used port to intput to save power
 
    // Lee add: do as above with Lee's added pins
    pinMode(door_up,INPUT);
    pinMode(door_down,INPUT);
    pinMode(feeder1,INPUT);
    pinMode(feeder2,INPUT);
 
    system_sleep();
//    pinMode(pinLed,OUTPUT); // set all ports into state before sleep
    pinMode(pinPiezoSpeaker,OUTPUT); // set all ports into state before sleep
 
    // Lee add: do as above with Lee's added pins
    pinMode(door_up,OUTPUT);
    pinMode(door_down,OUTPUT);
    pinMode(feeder1,OUTPUT);
    pinMode(feeder2,OUTPUT);
  }
}
 
//****************************************************************  
 
// put some whistle sound on piezo
void whistle() {
 
for (int ii = 0; ii<= 20; ii++) {  
  for (del=0; del <=254; del++) {
  digitalWrite(pinPiezoSpeaker,0);
  delayMicroseconds((ii*5)+(del * 2));
  digitalWrite(pinPiezoSpeaker,1);
  delayMicroseconds((ii*5)+(del * 2));
  }
 
//  PORTB ^= 32;  // toggle pinLed
}
}
 
//****************************************************************  
 
// put some beep sound on buzzer
void beep() {
 
  // Start the automatic chicken feeder motor
  Serial.println("Starting feed motor");
  // Set feed motor-driver line high here
  digitalWrite(feeder1,HIGH);
  digitalWrite(feeder2,LOW);
 
  // Let the chickens know we're closing up
  // 1850 cycle-time / 1000 / 60 = 6.167 minutes warning
  Serial.println("Starting 200 beeps");
  for (long i=0; i < beeps; i++) {
    Serial.println("Beep routine started");
 
    digitalWrite(pinPiezoSpeaker, LOW);
    delay(1500);
    digitalWrite(pinPiezoSpeaker, HIGH);
    delay(300);
  }    
 
    Serial.println("Stopping feed motor");
// Set feed motor-driver line low here
  digitalWrite(feeder1,LOW);
  digitalWrite(feeder2,LOW);
  // Set piezoSpeaker output low to mute unwanted noises
  digitalWrite(pinPiezoSpeaker,LOW);
//  digitalWrite(pinLed,LOW);
}
//****************************************************************  
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep() {
  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // System sleeps here
    sleep_disable();                     // System continues execution here when watchdog timed out 
    sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}
 
//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
 
void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;
  Serial.println(ww);
  MCUSR &= ~(1<<WDRF);
 
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
 
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);
}
 
//****************************************************************  
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}
 
//****************************************************************  
// Door-opener function
// It became day
// open()
 
void open() {
// Photocell detected day-break
// Door closed condition
// Top sensor open (pin grounded)
//Open door
Serial.println("Open function called");
 
while (ts == 0) {
    digitalWrite(door_up,HIGH);
    digitalWrite(door_down,LOW);
    ts=digitalRead(topswitch);  // re-read the top reed switch
}
 
// Door open, reset motor-driver lines
    digitalWrite(door_up,LOW);
    digitalWrite(door_down,LOW);
    // Set piezoSpeaker output low to mute unwanted noises
    digitalWrite(pinPiezoSpeaker,LOW);
//    digitalWrite(pinLed,LOW);
 
// now sleep for six hours
//sleep 60;
 
}
 
//****************************************************************  
// Door-closer function
// It became night
// nightingale sounded
// close()
 
void close() {
// Photocell detected dusk
// Door open condition
// Bottom sensor open (pin grounded)
// Close door
Serial.println("Close function called");
 
while (bs == 0) {
    digitalWrite(door_up,LOW);
    digitalWrite(door_down,HIGH);
    bs=digitalRead(bottomswitch);  // re-read the bottom reed switch
}
 
//Door closed, reset motor-driver lines
    digitalWrite(door_up,LOW);
    digitalWrite(door_down,LOW);
 
// now sleep for six hours
//sleep 60;
}
 
//****************************************************************  
// Door-sensor fault alarm function
 
void alarm() {   
    for (int j=0; j<=600; j++) {
        whistle();
        delay(6000);
    }
}
 
//****************************************************************  
// Door-sensor test on start-up
// Moves the door to whatever open/closed position it is not currently in
// then moves it back
 
void test() {   
  if (bs == 1) {
    open();
    close();
  } else if (ts == 1) {
    close();
    open();
  }
}

Current Version - Arduino plus L293 Motor Driver method

I almost finished the initial all-electronics version of the chicken coop door opener described in the section below. However, while testing and re-working the door-closing beeper circuit, I concluded that the circuit was physically too cumbersome to survive continually moving in an out of the enclosure.

So I built a L293 motor-driver on a piece of stripboard and replaced the light-sensing, door position-sensing, motor-driver, and beeper logic with an Arduino.

It took a weekend to prototype to working. That's a fraction of the time it took to prototype the all-electronics version.

Here's a video of the unit working at dusk:

Coop door closing at dusk

This view of the case shows the Arduino stuffed in to the enclosure it the L293 driver stripboard on the right. With all the sensor wires and logic lines, there's a lot of wires heading to the stripboard.

Here's the Arduino code for that. This is a slightly improved version of the code running the door opener in the video link above and I haven't tested it yet. So, if you find any bugs, let me know.

chicken_coop_door_opener.pde
//****************************************************************
/*
 * Chicken Coop Door Controller
 * Includes auto chicken-feeder motor driver
 * Photoresistor on analog0 
 * Piezo Speaker on pin 13
 * 
 * By Lee Kimber
 * Based on 'Nightingale' by:
 * KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 */
 
//****************************************************************
 
#include <avr/sleep.h>
#include <avr/wdt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
 
// sleep between runs
int pause = 6000;
int beeps = 250;
int lightlevel = 830;
 
int nint;
//int pinLed=13; // stop using, was 13
int pinPiezoSpeaker=13; // make pin 13, was 10
volatile boolean f_wdt=1;
 
// Lee adds
// drive lines for the L293D motor driver
int door_up=4; // becomes 5, was 11
int door_down=5; // becomes 4, was 12
 
// Set up chicken feeder driver
int feeder1=7;  // becomes 7, was 8
int feeder2=6; // becomes 6, was 9
 
void setup(){
 
  Serial.begin(38400);
//  pinMode(pinLed,OUTPUT);
  pinMode(pinPiezoSpeaker,OUTPUT);
 
  // Lee adds
  pinMode(door_up,OUTPUT);
  pinMode(door_down,OUTPUT);
  pinMode(feeder1,OUTPUT);
  pinMode(feeder2,OUTPUT);
 
  delay(10000);  
  Serial.println("Chicken coop door opener");
 
  // CPU Sleep Modes 
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)
 
  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode
 
  setup_watchdog(7);
}
 
byte del;
int cnt;
byte state=1;
int light=0;
 
// Lee adds
int topswitch=2; // becomes 2, was 4
int bottomswitch=3; // becomes 3, was 5
int ts=0;
int bs=0;
 
//****************************************************************
//****************************************************************
//****************************************************************
 
void loop(){
 
// Set feed motor-driver line low to save power
digitalWrite(feeder1,LOW);
digitalWrite(feeder2,LOW);
// Set piezoSpeaker output low to mute unwanted noises
digitalWrite(pinPiezoSpeaker, LOW);
//digitalWrite(pinLed,LOW);
 
  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag
    light=analogRead(0);  // reading photoresistor
 
    // Lee adds
    ts=digitalRead(topswitch);  // read the top reed switch
    bs=digitalRead(bottomswitch);  // read the bottom reed switch
 
    Serial.print("light: " );
    Serial.print(light );
    Serial.print(" bs: ");
    Serial.print(bs);
    Serial.print(" ts: ");
    Serial.println(ts);
 
    // Lee add door-state reporting here
    if (ts == 1 && bs == 0) {
      Serial.println("Door is open"); 
    } else if (ts == 0 && bs == 1) {
      Serial.println("Door is closed"); 
    } else if (bs == 1 && ts == 1) {
      Serial.println("ALARM: Door state monitoring is faulty");
      alarm();
    } else {
      Serial.println("Door state is indeterminate (or possibly faulty)"); 
    }
 
    switch (state){
    case 0:     // waiting for dawn
      if (light < lightlevel && ts == 0) {  // light threshold high and door not open (ts open)
        state=1;
        Serial.println("Calling door-open function");
        open();
        // Door open, nothing to do for 'pause' hours
        delay(pause);
      }
      break;
    case 1:  // waiting for dusk
      if (light > lightlevel && bs == 0)  { // light threshold low and door not closed (bs open)
        state=0;
        beep();
        Serial.println("Calling door-closer function");
        close();
        // Door closed, nothing to do for 'pause' hours
        delay(pause);
      }
      break;
    }
 
    nint++;
//    digitalWrite(pinLed,1);  // let led blink
 
    Serial.print("Sleep " );
    Serial.println(nint );
    delay(2);               // wait until the last serial character is send
//    digitalWrite(pinLed,0);
//    pinMode(pinLed,INPUT); // set all used ports to intput to save power
    pinMode(pinPiezoSpeaker,INPUT); // set all used port to intput to save power
 
    // Lee add: do as above with Lee's added pins
    pinMode(door_up,INPUT);
    pinMode(door_down,INPUT);
    pinMode(feeder1,INPUT);
    pinMode(feeder2,INPUT);
 
    system_sleep();
//    pinMode(pinLed,OUTPUT); // set all ports into OUTPUT state after sleep
    pinMode(pinPiezoSpeaker,OUTPUT); // set all ports into state after sleep
 
    // Lee add: do as above with Lee's added pins
    pinMode(door_up,OUTPUT);
    pinMode(door_down,OUTPUT);
    pinMode(feeder1,OUTPUT);
    pinMode(feeder2,OUTPUT);
  }
}
 
//****************************************************************  
 
// put some whistle sound on piezo
void whistle() {
 
for (int ii = 0; ii<= 20; ii++) {  
  for (del=0; del <=254; del++) {
  digitalWrite(pinPiezoSpeaker,0);
  delayMicroseconds((ii*5)+(del * 2));
  digitalWrite(pinPiezoSpeaker,1);
  delayMicroseconds((ii*5)+(del * 2));
  }
 
//  PORTB ^= 32;  // toggle pinLed
}
}
 
//****************************************************************  
 
// put some beep sound on buzzer
void beep() {
 
  // Let the chickens know we're closing up
  // 1850 cycle-time / 1000 / 60 = 6.167 minutes warning
  Serial.println("Starting 200 beeps");
  for (long i=0; i < beeps; i++) {
    Serial.println("Beep routine started");
 
    digitalWrite(pinPiezoSpeaker, LOW);
    delay(1500);
    digitalWrite(pinPiezoSpeaker, HIGH);
    delay(300);
  }    
 
  // Set piezoSpeaker output low to mute unwanted noises
  digitalWrite(pinPiezoSpeaker,LOW);
//  digitalWrite(pinLed,LOW);
}
//****************************************************************  
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep() {
  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // System sleeps here
    sleep_disable();                     // System continues execution here when watchdog timed out 
    sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}
 
//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
 
void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;
  Serial.println(ww);
  MCUSR &= ~(1<<WDRF);
 
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
 
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);
}
 
//****************************************************************  
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}
 
//****************************************************************  
// Door-opener function
// It became day
// open()
 
void open() {
// Photocell detected day-break
// Door closed condition
// Top sensor open (pin grounded)
Serial.println("Open function called");
 
//Open door but as it opens so early, let's pause for an hour
delay(3600000);
 
while (ts == 0) {
    digitalWrite(door_up,HIGH);
    digitalWrite(door_down,LOW);
    ts=digitalRead(topswitch);  // re-read the top reed switch
}
 
  // Door open, reset motor-driver lines
  digitalWrite(door_up,LOW);
  digitalWrite(door_down,LOW);
  // Set piezoSpeaker output low to mute unwanted noises
  digitalWrite(pinPiezoSpeaker,LOW);
 
  // And provide chickens some feed 
  // Start the automatic chicken feeder motor
  Serial.println("Starting feed motor");
  // Set feed motor-driver line high here
  digitalWrite(feeder1,HIGH);
  digitalWrite(feeder2,LOW);
 
  // Assume feeder runs for ten minutes
  delay(600000);
 
  Serial.println("Stopping feed motor");
// Set feed motor-driver line low here
  digitalWrite(feeder1,LOW);
  digitalWrite(feeder2,LOW);
 
// now sleep for six hours
//sleep 60;
 
}
 
//****************************************************************  
// Door-closer function
// It became night
// nightingale sounded
// close()
 
void close() {
// Photocell detected dusk
// Door open condition
// Bottom sensor open (pin grounded)
// Close door
Serial.println("Close function called");
 
while (bs == 0) {
    digitalWrite(door_up,LOW);
    digitalWrite(door_down,HIGH);
    bs=digitalRead(bottomswitch);  // re-read the bottom reed switch
}
 
//Door closed, reset motor-driver lines
    digitalWrite(door_up,LOW);
    digitalWrite(door_down,LOW);
 
// now sleep for six hours
//sleep 60;
}
 
//****************************************************************  
// Door-sensor fault alarm function
 
void alarm() {   
    for (int j=0; j<=600; j++) {
        whistle();
        delay(6000);
    }
}
 
//****************************************************************  
// Door-sensor test on start-up
// Moves the door to whatever open/closed position it is not currently in
// then moves it back
 
void test() {   
  if (bs == 1) {
    open();
    close();
  } else if (ts == 1) {
    close();
    open();
  }
}

Original Version - All-Electronics

Owners of chickens often wail about having to get up to let their loved ones out to forage - and about having to abandon dinner to round their loved ones up and into the safety of their coop at the end of the day.

After finding a couple of drawer runners abandoned by the verge and partnering them up with a small electric motor in my junk-box, I decided to noodle out an electronic circuit that would open and shut a coop door at dawn and dusk.

Testing the limit-switches that stop the coop door motor when the door is fully open or fully closed

In the above video, the door lifts as light falls on the light-dependent resistor, Simulating dawn. The door lifts until a magnet mounted on it closes a reed switch near the top of the vertical rails. When my hand covers the LDR again - simulating nightfall - the circuit waits five seconds before lowering the door until the magnet closes a reed switch mounted near the bottom of the vertical rails. The 'closing' delay is to sound an alert to warn the hens that the door is about to close, though, outside of this test, it would usually be set for ten minutes or so.

The exercise turned out to be a revelation in electronic design principles.

Here's how.

The dawn-dusk piece is pretty easy - just use an adjustable light-level detector. That part of the circuitry could be a standard combination of light-dependent resistor and op-amp comparator. More challenging was the problem of having the motor change direction depending on whether it is dawn or dusk; whether the door needs opening or closing and sensing where the door is in its travel.

Click here to read more

Click here to see less

Click here to see less

I started thinking through how the circuit would assess where the door is and therefore in which direction to turn the motor. I figured I could use an H-bridge circuit to drive the door and discovered that discrete and integrated H-bridges use two (usually) complementary input states to determine in which direction to drive the motor. That is: a 1 + 0 drives the motor in one direction and a 0 + 1 drives the motor in the other direction.

The logic would need to prevent the motor running after the door reached the end of its travel - otherwise the motor would likely burn out. It seemed to me I'd need logic that would determine where the door is and to deliver the correct logic output pair until the door reached the correct location: fully open or fully closed.

The problems with that scenario are that there are any number of places the door can be between open and closed that are hard to sense cheaply and rather harder to design position-assessment logic around cheaply. Also, if we care about knowing which end-travel sensors are in which position all the time, then we are having to use three-input logic/truth tables, which are slightly newer to me than two-input logic/truth tables.

I batted that around for three days or so. One of the problems I considered was that building in logical fault sensing was much more complicated if we cared about the door's position. I spent some time considering if the H-bridge's 'enable/disable' pin could be hacked to help out with this.

The breakthrough came when I realised that it doesn't matter whether the system knows where the door is; what matters is where the door is *not* when the light level changes up (dawn) or down (dusk).

Click here to read more

Click here to see less

Click here to see less

In other words, if the light level has just changed up at dawn, what matters is that the door heads towards being open until fully open. Similarly, if the light level has just changed down at dusk, what matters is that the door heads towards being closed until fully closed.

That revelation reveals that I only needed to create logic around two conditions:

  1. If the light level is high and the door is not open, drive the door until it is sensed as being open.
  2. If the light level is low and the door is not closed, drive the door until it is sensed as being closed.

Two reed switches - one at the top of the door's travel and one at the bottom - would provide the position sensing if the door was fitted with magnets that would trip the reed switches. The reed switches' *logic* output could be pre-set by biasing each switch with resistors.

Click here to read more

Click here to see less

Click here to see less

Fault detection - if provided at all - could be reduced to detecting any condition where the door was out of either of fully open or fully closed position for more than the time known for the door to complete its travel from one extreme to the other, plus a couple of other 'switch failure' conditions.

With the revelation behind me, I started to look at the logic I'd need, focusing on the chips that are cheap or that I already had in my junk box. The comparator piece was easy: use a 741 or an LM393 along with three 1k resistors from the junkbox. I took an LDR from a discarded night-light.

After some scratching around I realised that the reed switch logic could be simplified if the logic conditions we look for were reduced to:

Light sensor = high + lower reed switch = high (1 + 1)

and

Light sensor = low + upper reed switch = low (0 + 0)

because the first (1 + 1) can be handled by an AND gate and the second (0 + 0) can be handled by an NOR gate. That is: if the reed switches and their voltage bias were judiciously arranged, the 1 + 1 AND condition could handle the 'door opening' condition and the 0 + 0 NOR condition could handle the 'door closing' condition.

Click here to read more

Click here to see less

Click here to see less

To conceptualise this another way, the door controller strives to get away from the pair of AND conditions that exist when the light sensor is high and one of the reed switches is set 'high', or when the light sensor is low and one of the reed switches is set 'low'. The reed switch high/low conditions are set not by whether or not the reed switches are open but by their role in a resistor-divider that sets up one each of the AND and NOR gate inputs.

This logic is shown in the truth tables below:

Door opens

Light Sensor Upper Switch Action Notes
11Door opensLight level went high; AND Gate triggers

Door closes

Light Sensor Lower Switch Action Notes
00Door closesLight level went low; NOR Gate triggers

Click here to see complete truth table

Click here to hid complete truth table

Click here to hid complete truth table

Complete Truth Table
Light Sensor Upper Switch Lower Switch Action Notes
000Door close startsDusk, close starts after 555-determined delay
001Door closingDoor has begun to close. Fault condition if prolonged
011Door closedThis condition should last through night
010Fault condition
111Door open startsDawn, open starts immediately
101Door openingDoor has begun to open. Fault condition if prolonged
100Door openThis condition should last through day
110Fault condition

Click here to read more

Click here to see less

Click here to see less

I began by setting up and Arduino and the Arduino MotorShield to drive the motor. But testing with the Arduino motor drive code example from LadyAda's MotorShield library revealed that the controller combination consumed 100-115mA even in quiescent mode. Too high for this application. I abandoned that approach and turned to CMOS logic.

A little more scratching around revealed that I could use three NOR gates to create an AND gate, which meant that I could use the four NOR gates in the CMOS 4001 in my junkbox to handle all the logic. Two-input logic gates being more common than three-input logic gates, particularly in my junk-box.

So far, the cost of this project was nil.

Click here to read more

Click here to see less

Click here to see less

After reading up on the L293D and L298 H-bridge chips, I breadboarded the light detector and logic circuitry to check it would provide the 0 + 1 and 1 + 0. It worked fine.

The next step was to figure out how to give the chickens some warning that the door was going to close each night. After all, you don't want your agricultural assets clustered around a closed coop door as the foxes close in.

What I needed was to delay the operation of the H-bridge - and possibly the operation of the CMOS logic gates - when the light level was detected as changing from high to low. During the delay, a piezo-buzzer should sound to warn the hens of the coop door's imminent closure.

Click here to read more

Click here to see less

Click here to see less

I needed a monostable multivibrator that could preserve the 'door OK to be open' logic condition based on light-level that holds during the day while also sounding a buzzer. Having messed around with Maplin's monostable kits before and knowing that their output level sits low until triggered, I realised I could switch into the door-closing logic one of these monostables so that feeding the monostable's output to the input to the NOR logic gate could keep the logic gate input at 0 + 1 rather than 0 + 0 until the monostable timed out to a low output level.

The difficulty with this trick is that we want to detect only low-going light level changes, not the high-going changes. That is, we only care to insert this delay at dusk, when the light level is falling, and not at dawn, when the light level is rising.

Fixing this proved easy: it's possible to configure a 555-based monostable like the Maplin kit to trigger only on low-going edges by sandwiching a capacitor between two pull-up resistors at the trigger pin (pin 2) of the 555. A couple of diodes inserted after the output stage of the light-level detector and the monostable isolated their respective outputs from each other so that only the 'high' output of either sub-circuit made its way to the inputs of the 4001's NOR gate.

Automatic Chicken Coop Door Controller circuit (First Draft - H bridge untested)

Breadboard tests proved the viability of the design. However, I have since updated this circuit a little so contact me (bottom right of the page) to nudge me to retrieve the latest circuit diagram.

Stripboard Testing

Click here to read more

Click here to see less

Click here to see less

Unit did not work when completed and tested.

Careful simulation of lighting and switching showed that the logic and electronics through to the ping 3 and 4 outputs of U3 CMOS 4001 worked correctly.

Testing around U4 L293D showed that its logic power supply on pin 16 Vcc1 and Enable pin 1 was at 2.10 volts instead of the 5.1V theoretically delivered by the combination of 5.1V zener D3 and 1k resistor R14.

Given that this logic power supply had been tested delivering 5.1V before U4 L293D was inserted, it seemed likely that the issue was that the 1k resistor R14 was dropping too many volts at the current required by the L293D's logic power supply Vcc2.

So, let's work out what we need:

Logic Supply Voltage VCC1: 2.14V not 5.1V as it should be

Output Supply Voltage VCC2 in use: 12.5V

Voltage drop is:

6.39V

over 1kR

Logic supply current ICC1 is = 0.0064 6.4mA

According to TI's L293D datasheet, ICC1 is min: 13mA and max (in this application): 35mA

Calculate new R14 resistance:

12.5 - 5.1 = 7.4

At max I<subL</sub> current 7.4 / 0.035 = 211R

At min I<subL</sub> current 7.4 / 0.013 = 569R

Use 200R or close

Calculate resistor wattage rating: 7.4 * 0.035 = 0.26W

'Use' Cases

Click to read more

Click to see less

Click to see less

These use cases show how the door's actual position correlates with the logic conditions in the truth tables above.

Case 1:

Night-time, door closed, 0 + 1 presented to the AND gate; 0 + 1 presented to the NOR gate

Light Sensor = 0
Upper Switch = 1

  |
  |
  |
  ||
  ||

Lower Switch = 1

Case 2:

Dawn breaks, light sensor output goes high, 1 + 1 presented to the AND gate; 1 + 1 presented to the NOR gate

Light Sensor = 1
Upper Switch = 1

  |
  |
  |
  ||
  ||

Lower Switch = 1

Case 3:

Day-time, light sensor output has gone high, AND gate high output has begun to pull door open, lower switch opens and goes low, 1 + 1 presented to the AND gate; 1 + 0 presented to the NOR gate

Light Sensor = 1
Upper Switch = 1

  |
  |
  ||
  ||
  |

Lower Switch = 0

Case 4: Day-time, light sensor output high, door fully open, upper switch closes and goes low, 1 + 0 presented to the AND gate; 1 + 0 presented to the NOR gate

Light Sensor = 1
Upper Switch = 0

  ||
  ||
  |
  |
  |

Lower Switch = 0

Case 5:

During daytime, light sensor output high, door fully open, 1 + 0 presented to the AND gate; 1 + 0 presented to the NOR gate

Light Sensor = 1
Upper Switch = 0

  ||
  ||
  |
  |
  |

Lower Switch = 0

Case 6:

Dusk, light sensor output goes low, door fully open, 0 + 0 presented to the AND gate; 0 + 0 presented to the NOR gate; NOR gate output goes high

Light Sensor = 0
Upper Switch = 0

  ||
  ||
  |
  |
  |

Lower Switch = 0

Case 7:

Dusk, light sensor output low, NOR gate beginning to close door, upper switch opens and goes high, 0 + 1 presented to the AND gate; 0 + 0 presented to the NOR gate; NOR gate output goes high and begins to close door

Light Sensor = 0
Upper Switch = 1

  |
  ||
  ||
  |
  |

Lower Switch = 0

Case 8:

Night-time, light sensor output low, NOR gate completes door-closing, lower switch closes at completion of door-closing and goes high, 0 + 1 presented to the AND gate; 0 + 1 presented to the NOR gate; NOR gate output goes low again as door closes. Same as case 1.

Light Sensor = 0
Upper Switch = 1

  |
  |
  |
  ||
  ||

Lower Switch = 1

Useful Links

Discussion

Enter your comment
CVEYH
 
automatic_chicken_coop_door.txt · Last modified: 2011/07/29 09:28 by lee
Translate: AR CN DE ES FR HI PT PT-br RU UR