Help with simple photoresistor chicken coop project

Hey everyone I am new to programming and this is my first bigger project. It's a motorized door for a chicken coop. Its been working okay besides a few hiccups. I am a machinist not a programmer :smile: . Basically has an upper microswitch and a lower microswitch. It looks at the amount of light to determine if the door should be up or not then after a predetermined amount of time it will react to the light by opening or closing with a small geared motor overhead.

I'm looking for someone to help me with the code that I can have an 3 leds light up at different times depending on the condition. Also something written into the code where the motor will only run for a certain amount of time before it shuts itself off then lights up an LED if the proper microswitch isn't met in that time. I already have them installed in the coop facing the house. I was thinking green when the door is down, red for when the door is up, then yellow for the timed out fault. Thank you guys so much for your help. Been lurking on here for a long time, this is my first real project!

// Initialize the motor values to the pins 8, 9, 10. 
//Pins 8 and 9 send high or low to the motor controller.
//pin 10 enables motor one on the motor controller. 
int enA = 10;
int in1 = 9;
int in2 = 8;


//Initialize "lightSensor" as the value from pin A0 and read in the value. This is the photoresistor.
int lightSensor = analogRead(A0);
//The lightVal will hold the value of lightsensor in this variable
int lightVal = 0;

//These are the pins for the reed switches
// reed1Pin is the lower switch on the door. This is digital pin 2
int reed1Pin = 2;
//reed2Pin is the top switch on the door. This is digital pin 4
int reed2Pin = 4;
//These are the variables that hold the state of the reed switches
int switchState1 = 0;
int switchState2 = 0;

//This only runs once.
void setup()
{
  // set the motor control pins as outputs. This means pins 8, 9, 10 are outputs to the l298n motor controller.
  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
//read the state of switch 1 (the bottom one) and place it in switchState1
switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);
//this is important to make sure that the door starts up when the program gains power.
//if switchState2 is not high then go to the while statement
if (switchState2 != HIGH)
{
// this function will run the motor down as long as switch 1 has not been triggered
  while (switchState2 != HIGH) 
{
  // turn on motor and set speed to 255 
  analogWrite(enA, 255);
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  //read the state of the switch again to make sure that it has not been triggered
  switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);   
}
  // once switchstate2 has been triggered turn off the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
}
}

//this runs over and over
void loop() 
{
  //read the light sensor and place it in lightval
  lightVal = analogRead(lightSensor);
//read the state of switch 1 (the bottom one) and place it in switchState1
switchState1 = digitalRead(reed1Pin);
  //read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);
  //the lightSensor is read and placed into lightVal. if its less than 200 and switchState2 is 
  //equal to high then go to the motor down code. But if the light is greater than 200 and the switchstate1
  //is equal to high then call motor up code
 if (switchState2 = HIGH && lightVal < 50) 
{
 delay(2000);
    motordown();
} 
 else if (switchState1 = HIGH && lightVal > 50)
{
  delay(2000);
   motorup();
}
}

void motordown()
{
  //Read the state of switch 1 (the Bottom one) and place it in switchState1
switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);

  //If switchState2 is high and the light is dark then continue
  if (switchState2 = HIGH && lightVal < 50)
 //wait 2 seconds
 delay(2000);
   //read the state of switch 1 (the bottom one) and place it in switchState1
switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);
  
  while (switchState1 != HIGH) {
  // turn on motor and set speed to 255 
  analogWrite(enA, 255);
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW); 
 //read the state of switch 2 (the top one) and place it in switchState2
  switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);
  }
  //wait 1 second before turning off the motor to let the locks engage at the bottom
  delay(200);
  // now turn off motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
}

void motorup()
{
  //read the state of switch 1 (the bottom one) and place it in switchState2
switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);

  //if switchState1 is high and the light is bright then continue
  if (switchState1 = HIGH && lightVal > 50)
 {

    //read the state of switch 1 (the bottom one) and place it in switchState1
switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin);
  //delay 2 seconds
  delay(5000);
  //while switchState2 is not high turn on the motor up
  while (switchState2 != HIGH) 
 {
  // this function will run the motor as long as switch 2 has not been triggered
  // turn on motor and set speed to 255 
  analogWrite(enA, 255);
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  //read the state of switch 1 (the bottom one) and place it in switchState2
  switchState1 = digitalRead(reed1Pin);
//read the state of switch 2 (the top one) and place it in switchState2
switchState2 = digitalRead(reed2Pin); 
 }
  // now turn off motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
}
}

Hello
I´ve taken a look to the sketch. My recommendations are:

  1. design a function to control the motor, e.g. motor(int direction); direction {up,down,stop}
  2. design a timekeeper function based on the BLINKWITHOUTDELAY example from the IDE.
  3. design a FSM with the follwing states {IsUp,MovesDown,IsDown,MovesUp}

With these recommendations the design of the chicken coop door control shall be easy.
The mentioned led control is related to the current state of the FSM.
Give it a try.

Have a nice day and enjoy coding in C++.
Дайте миру шанс!

This is a mistake. Both the comment and the code line. Take a look at how lightSensor is used in the rest of the code.

A good tip is to give all your variables and functions names that are as descriptive as possible. Calling them "1" and "2" is arbitrary and does not describe what they are for. This leads to confusion and mistakes. In this case you could use "top", "upper" or "higher" and "bottom", "down" or "lower". Better still, "open" and "closed". This means you don't always need comments to give explanations of what variables or functions are for.

Another tip is to use Auto-Format frequently to ensure the indentation of your code is correct. Indentation does not alter how the code works, but it makes it more readable because lines that will be executed together in sequence are all at the same level of indentation. This helps you to spot where { and } are in the wrong place or missing.

1 Like

more complicated than i thought

consider

const byte SensorPin    = A0;
#if 0
const byte LedPins   [] = { 11, 12, 13 };
const byte MotorPins [] = { 4, 5 };
#else
const byte LedPins   [] = { 4, 5 };
const byte MotorPins [] = { 11, 12, 13 };
#endif
const byte LimitPins [] = { A1, A2 };
const byte SpeedPin     = 10;

const int  Speed        = 200;

unsigned long  msecLst;
#define Timeout    3000

enum { Off = HIGH, On = LOW };
enum { OK, Error };

enum { Forward, Reverse, Stop };
const char *dirStrings [] = { "Forward", "Reverse", "Stop" };

enum { Up, Down, Unknown };
int position = Down;

const char *posStrings [] = { "Up",   "Down",    "Unknown" };

#define ThreshUp      300
#define ThreshDown    280

// -----------------------------------------------------------------------------
void
motorDir (
    int    dir )
{
    Serial.print   ("motorDir: ");
    Serial.println (dirStrings [dir]);

    switch (dir)  {
    case Forward:
        digitalWrite (MotorPins [0], Off);
        digitalWrite (MotorPins [1], On);
        break;

    case Reverse:
        digitalWrite (MotorPins [1], Off);
        digitalWrite (MotorPins [0], On);
        break;

    case Stop:
    default:
        digitalWrite (MotorPins [0], Off);
        digitalWrite (MotorPins [1], Off);
        break;
    }
}

// -----------------------------------------------------------------------------
int
moveMotor (
    int   dir,
    byte  limitSwPin )
{
    Serial.print   ("moveMotor: ");
    Serial.print   (limitSwPin);
    Serial.print   (" ");
    Serial.println (dirStrings [dir]);

    motorDir (dir);

    msecLst = millis ();
    while ((millis() - msecLst) < Timeout)  {
        if (LOW == digitalRead (limitSwPin))  {
            Serial.println (" limit-switch");
            motorDir (Stop);
            return dir;
        }
    }

    Serial.println (" Timeout");
    motorDir (Stop);
    return Unknown;
}

// -----------------------------------------------------------------------------
void
setLeds (
    int   upDownUnk )
{
    Serial.print   ("setLeds: ");
    Serial.println (posStrings [upDownUnk]);

    for (unsigned n = 0; n < sizeof(LedPins); n++)
        digitalWrite (LedPins [n], Off);

    digitalWrite (LedPins [upDownUnk], On);
}

// -----------------------------------------------------------------------------
void loop() {
    int      sensor = analogRead (SensorPin);

#if 0
    delay (500);
    Serial.print (sensor);
    Serial.print ("  ");
#endif

    if (Up == position && ThreshDown >= sensor)
        position = moveMotor (Down, LimitPins [Down]);

    if (Down == position && ThreshUp <= sensor)
        position = moveMotor (Up, LimitPins [Up]);

    // recovery
    if (Unknown == position)  {
        if (LOW == digitalRead (LimitPins [Down]))
            position = Down;
        if (LOW == digitalRead (LimitPins [Up]))
            position = Up;
    }

    setLeds (position);
}


// -----------------------------------------------------------------------------
void setup() {
    Serial.begin (9600);

    for (unsigned n = 0; n < sizeof(LimitPins); n++)
        pinMode      (LimitPins [n], INPUT_PULLUP);

    for (unsigned n = 0; n < sizeof(LedPins); n++)  {
        digitalWrite (LedPins [n], Off);
        pinMode      (LedPins [n], OUTPUT);
    }
    
    for (unsigned n = 0; n < sizeof(MotorPins); n++)  {
        digitalWrite (MotorPins [n], Off);
        pinMode      (MotorPins [n], OUTPUT);
    }
    
    analogWrite (SpeedPin, Speed);
}

So the there are some comments in the usual pretty short way which is not my style.

I second that you should use self-descriptive names for everything.

in a state-machine you could program a timeout that works this way:

start motor to close the door. With starting the motor store a timestamp into a variable.
let the motor run and in parallel do a repeated calculation how much time has passed by

Let's assume that closing the door normally takes 10 seconds
If something goes a little hard it may take 15 seconds but not 20

So you are "measuring" how many seconds is the motor running?
This measuring is done by calculating
actual_time - startTime

if the result reaches 20 seconds and the corresponding switch hasn't switched yet
switch on yellow LED to indicate there is something wrong with closing the door.

The same thing can be done for opening the door.

To be able to do such things you have to learn

two

new things

  1. non-blocking timing
  2. how state-machines work

You are requesting a pretty advanced functionality. And this pretty advanced functionality means to learn pretty advanced programming techniques.

Stay relaxed. Even for a machinist as you are this is easy

if

the steps to proceed are small and the eplanations are easy to understand.
I have written two tutorials about that who claim to explain it as simply as possible.

Whether it is really easy to understand needs to be checked by newcomers like you.

When questions arise, please ask those questions. Your questions will help me to make the explanation even easier to understand.

So here are the links to the tutorials

best regards Stefan

I hope @mgers21 comes back to read this topic. Quite a lot of effort has gone into the replies already!

I've been thinking about a simpler approach, hopefully easier to understand for a beginner.

I think there are 5 conditions/actions here:

  1. Light below a low level, door is not closed, motor is not closing door: start motor to close door, switch off green led and record time motor was started.
  2. Motor is closing door and door is closed: stop motor and light red led.
  3. Light above a higher level, door is not open and motor is not opening door: start motor to open door, switch off red led, record time motor was started.
  4. Motor is opening door and door is open: stop motor and light green led.
  5. Motor is running (either to open or close, and has been for too long: stop motor and light yellow led.

If I've got that right, the code would be 5 simple if statements.

Timing would be done using millis().

To test if the motor is opening or closing the door, you could use digitalRead() on the motor output pins, which could be considered a little "hacky", but will work just fine and avoids having yet more potentially confusing variables!

i think code needs to start the motor and wait for either an active limit switch or timeout. these two things are coupled or a FSM is needed to handle a timeout

it's unclear what to do when a timeout occurs

I think my suggested approach will do that.

In effect, my suggested solution is an FSM, where the state is determined by a small number of HIGH/LOW values rather than a single, multi-value state variable.

i understood that after a timeout, the motor is shut off and the 3rd led lit. (see code)

so how do you recover?

Check the mechanicals and hit reset, I guess!

My proposal is to check the wiring and restart the system by pressing both limit switches at the same time.
Paul was faster.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.