How to add two limit switches

It will be appreciated if anyone can help me with arduino codes for following project.

  1. Turn on pushbutton // initializing the cycle. (power ON)

  2. If power is ON and limitswitch1 is HIGH then;

(output 1 is HIGH, delay 2 seconds then Output2 is HIGH, delay 2 seconds then Output3 is HIGH)

  1. If limitswitch2 is HIGH and limitswitch1 is LOW then output 3 is LOW & output 4 is HIGH

  2. If limitswitch2 is LOW and limitswitch1 is LOW then;

(output 4 is LOW, delay 2 seconds then Output2 is LOW, delay 2 seconds then Output1 is LOW)

  1. Stop cycle.

What have you written so far ?

What is operating the limit switches, perhaps a motor of some kind ?

warunaap: 1. Turn on pushbutton // initializing the cycle. (power ON)

Is that a switch that just turns the Arduino on at its power source?

Or is it on a pin read by the Arduino that when "on" (which would likely mean "low" since it's customary to wire switches to ground with a pullup) would say move us from an "idle" state to a "running" state?

Does the power being on as in 2, also refer to 3 and 4?

And regarding 5, I'm not seeing this a cycle: with all those if()'s in play, and presumably the limit switches triggering from time to time, it could freely move between 2, 3 and 4. A cycle is a sort of pre-arranged sequence with a beginning and and end, and optionally a repeat.

So what doe 5 mean?

What I'm seeing is that when the Arduino fires up we enter the "idle" state and await the power switch (edit: which isn't power to the Arduino of course, but more of a "start" button"), to start running. At that point we read the limit switches and go to 2 or 3 or 4 accordingly, and do all those things with outputs.

Are you saying with stop cycle, that we DON'T read the limit switches again, and that once those list of outputs have completed in 2,3 or 4 it goes back to "idle" and waits another nudge from the power on (edit: "start") button?

And I wonder if your instructions for the outputs are complete, for example:

2) ... output3 is high 3) ... output3 is low 4) silent on the matter of output3

So is it correct if we go to (4) for output3 just to stay high or low as it was after (2) or (3)?

The coding for this stuff is really pretty simple iff the instructions are unambiguous.

hello, Sorry for the delay, my project is solar panel cleaning system which has a forward and reverse travelling mechanism and some replay operations. The point where i cant understand is how to manage codes when same "if" conditions occurred in several times in the code flow. (ex. limit1 will be HIGH two times in the cycle.) Hear is the codes i compiled. Thanks and hope your kind help.

int reverse=2; int limit2=3; int limit1=4; int brush=5; int water=6; int power=7; int start=8; int forward=9; int buttonState=0; int buttonState1=0; int buttonState2=0;

void setup() { pinMode(power, OUTPUT); pinMode(start, INPUT); pinMode(water, OUTPUT); pinMode(brush, OUTPUT); pinMode(limit1, INPUT); pinMode(limit2, INPUT); pinMode(forward, OUTPUT); pinMode(reverse, OUTPUT); Serial.begin(9600);


void loop() {

buttonState=digitalRead(start); Serial.println(buttonState);

if(buttonState==HIGH){ digitalWrite(power,HIGH); Serial.println("Power ON"); }


digitalWrite(water,HIGH); Serial.println("Water ON");


digitalWrite(brush,HIGH); Serial.println("Brush ON");


buttonState1=digitalRead(limit1); Serial.println(buttonState1);

if(buttonState1==HIGH){ digitalWrite(forward,HIGH); Serial.println("Forward");}


buttonState2=digitalRead(limit2); Serial.println(buttonState2);

if(buttonState2==HIGH){ digitalWrite(forward,LOW); delay(1000); digitalWrite(reverse,HIGH); Serial.println("Reverse");}


if((buttonState2==LOW) && (buttonState1==HIGH)){ //till this point it is working well, after that it // goes to previous if conditions // if(buttonState1==HIGH){ //digitalWrite(forward,HIGH); // Serial.println("Forward");} digitalWrite(reverse,LOW); Serial.println("Cleaning completed");} delay(5000);

digitalWrite(brush,LOW); Serial.println("Brush OFF");

digitalWrite(water,LOW); Serial.println("Water OFF");

digitalWrite(power,LOW); Serial.println("Power OFF");


(ex. limit1 will be HIGH two times in the cycle.)

... but under different circumstances. Rather than a complicated spaghetti of ifs and elses, you should probably step back and look at using a state machine approach. then limit1 high in "state X" will have an obviously different meaning and effect than limit1 high in "state Y". I started drawing a state diagram for this, but wasn't really sure what's supposed to happen.

So why don't you forget about coding for a while, and explain here in words just what exactly the sequence of events is. Then we'll be able (I hope) to draw a diagram, and design the states. Then the coding's reasonably simple.

Earlier you referred to outputs as output1 to output4 but now they have names which makes more sense. (Except now you have 5: power, water, brush, forward, reverse, not 4?)

Step back, and try describe this thing in words....

Thanks for guiding me,,

Here is the sequence of events. (Solar panel cleaner.)

  1. power button - to start the cycle (using a relay) (power ON to the mechanism)

  2. wait 2 seconds

  3. The water valve solenoid to be opened.

  4. wait 5 seconds

  5. cleaning brush rotation to be stared.

  6. if the forward limit (limit1) is touched (at parking position), forward movement to be started.

  7. when reached to the other end and reverse limit (limit2) is touched, stop the forward movement.

  8. wait 3 seconds.

  9. then reverse movement to be started.

  10. when returned to the parking end and limit1 is touched, reverse movement to be stopped.

  11. wait 3 seconds brush to be stopped.

  1. wait 3 seconds.

  2. water valve solenoid to be closed.

  3. Stop the cycle. (or power off)

  4. The cycle only should be started after the power button pressed again.

That's much clearer, thanks.

Just to clarify, in 6, since the brush is stationary (rotating, but not moving across the panel), the touch of limit1 is by a human to start the forward motion? Then at the other end, limit2 is touched by the movement forward, and when it gets back to parking, that touch of limit1 is due to the reverse motion driving into the switch?

Oh wait hang on… when 10 completes, limit1 is touched and that’s what stops the reverse direction. So at power up next time, limit1 is presumably still touched so the forward motion starts automatically in 6?

(It’s normal by the way to start motion automatically towards one end, in case the actuator was in the middle somewhere. So you could consider starting in reverse, then it will surely touch limit1 just in case it had moved, then immediately change direction to forward. but let’s leave that for now :wink: and add that later)

So we power on, start the water, start the brush, run forwards, run back, brush off, water off, power off… should be do-able.

Alas it’s my bed-time soon…

Dear 12Stepper,

You got it very clear, let me add some information;

  • The brush is to clean the panel surface, it is rotating only one direction.

  • The brush is fixed to a moving carriage.

  • The carriage can move forward and reverse.

  • Initially the carriage is in left side while touching the limit1 by itself. (limit1=HIGH)

  • After forward motion is started, both limits are LOW until limit2 touches by carriage.

  • When the carriage is at the left (parking position), the limit1 should be always Pressed. (HIGH)

*And so on...


Yep it’s clear to me how it works now.

I did some coding yesterday which matched (sort of) what I understood, but now it’s clearer I’ll do further. It will be easier now that the outputs have decent names like brush and forward etc. It’s easier to work if you can picture “a brush” in your mind not just “output2”.

One point on the start button and the limit switches. I see you have their pinMode as INPUT, and then a HIGH is “on”. Do you have external pulldown resistors fitted to ensure they stay low and don’t float high accidentally when they shouldn’t be high?

Best practice is to wire switches to ground from their pins, to 5V, and use a pullUP not a pullDOWN, and as you probably know, there are internal pullups built in. They are enabled by INPUT_PULLUP in pinMode. I’m going to do it that way, it’s much easier. But I’ll put an “if” in the code to switch between those two logic approaches.

From a safety point of view how do you handle an emergency off? I think the best is not to try to handle that in code, but just have a master switch on the mains to cut all the power…

yes i have attached external pull-down resisters.

and there is a main power switch which use as an emergency switch.

Hi, I would do the process;

So we power on, PRESS PROCESS START BUTTON.start the water, start the brush, run forwards, run back, brush off, water off, PROCESS OFF.... should be do-able.

This way you power up and have some checking code, water pressure, carriage in the HOME position, check that both LIMITS aren't active. Call your limits HOME and AWAY. (Sorry :o :o :o :o) Then you press a button to begin the process. Inclusion of a STOP BUTTON and an E-STOP.

Tom.... :)

yes i have attached external pull-down resisters.

In the long run, you might want to re-consider that: go for the built in pullups, and reverse the logic so pressed=low, unpressed=high.

How's this diagram as a representation so far (reference numbers ala #7)

(I would certainly agree with TomGeorge that limit1 and limit2 should be given better names, and I would as I mentioned earlier, advocate checking them at start up. Certainly process start/off are better names that power on/off, which is confusing with Arduino power up.)

just for your information;

The point where i stuck in my codes is when it comes to state 10 then state 6 is also activated.

As an exercise I'm doing it all as a state machine with I find that's the only way that "works for me", to keep it clear in my head what the heck's going on.

EDIT: because then in this case, in state_start-up, limit1 being pressed means run forward while in state_reverse, limit1 being pressed means stop, and that's unambiguous.

[u]Update[/u]: OP has my state machine version by PM and says it's cool. Will post it here after a bit more testing.

There are currently 2 items on the ToDo which may or may not get done in the fullness of time:

  • When the carriage is homed, the outer limit switch should be checked for being open, in case something's accidentally pressing it closed. If it was closed, when the carriage started its forward journey it would immediately think it was finished
  • As the carriage moves away from each limit switch, it should a short while (half second or so?) later check that the switch has opened and is not jammed closed.

Meantime here's the as-built state diagram:

And here for the record is the code that goes with the above diagram. I’ll leave it to the OP to complete the ToDo items if he feels the urge. It does need some safety checks if it will end up in any kind of production. Right now it seems to be used in the development of a mechanical system, and OP is the user. No walk-ins…

//  limit switches and states V2 to suit new understanding
//  all output timing is delay()-less
//  there is a bwod on led13 to prove no blocking
unsigned long previousBlink;
int blinkInterval = 500;
bool blinkState;

// to use CLOSED or OPEN in if(digitalRead()==...) for switches, instead of HIGH or LOW
//(un-)comment the next line depending on the button's logic <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#define weHaveActiveLowButtons
#ifdef weHaveActiveLowButtons
#define CLOSED LOW   // active low, internal or external pullup
#define OPEN HIGH
#define CLOSED HIGH   // active high, external pulldown
#define OPEN LOW

//input and output pins
const int run = 8; //previously known as start, and should be a toggle switch not a button
const int limitHOME = 4;
const int limitOUT = 3;
const int reverse = 2;
const int brush = 5;
const int water = 6;
const int power = 7;
const int forward = 9;

enum {ST_idle, ST_start_up, ST_forward, ST_reverse, ST_shut_down} currentState = ST_idle;
bool running = true; //used later to prevent re-run without turning off first
bool newVisitToStart_up; //see later so as not to mess the timing
unsigned long stateTransitionAtMillis;

void setup()
  // initialize serial communication:
  Serial.println("setup() ... ");
  Serial.println("brush and water carriage control");
  Serial.print("Compiler: ");
  Serial.print(", Arduino IDE: ");
  Serial.print("Created: ");
  Serial.print(", ");

  //pulse led

  //inputs REMEMBER to check if #define weHaveActiveLowButtons is commented or not as needed
  pinMode(run, INPUT_PULLUP);
  pinMode(limitHOME, INPUT_PULLUP);
  pinMode(limitOUT, INPUT_PULLUP);
  pinMode(water, OUTPUT);
  pinMode(brush, OUTPUT);
  pinMode(power, OUTPUT);
  pinMode(forward, OUTPUT);
  pinMode(reverse, OUTPUT);

  Serial.println("setup() done");
  Serial.println(" ");

void loop()
  //run switch must be read all the time,
  //  to turn process off from any state for safety
} //loop

void readRunSwitch()
  if (digitalRead(run) == OPEN)
    if (currentState != ST_idle) currentState = ST_idle;

void proofOfLife()
  if (millis() - previousBlink >= blinkInterval)
    previousBlink = millis();
    blinkState = !blinkState;
    digitalWrite(LED_BUILTIN, blinkState);

void manageStates()
// ST_idle, ST_start_up, ST_forward, ST_reverse, ST_shut_down
  switch (currentState)
    case ST_idle:
      Serial.print("state idle");
      if (digitalRead(run) == OPEN) running = false; //prevents re-run until powered off
      if (!running) Serial.println(" ready");
      else Serial.println(" turn off to make ready");
      //everything off for safety
      digitalWrite(water, LOW);
      digitalWrite(brush, LOW);
      digitalWrite(power, LOW);
      digitalWrite(forward, LOW); //assuming forward and reverse both low is stopped
      digitalWrite(reverse, LOW);
      //closing the run switch takes us from here to start_up
      if (digitalRead(run) == CLOSED && !running)
        currentState = ST_start_up;
        running = true;
        newVisitToStart_up = true;

    case ST_start_up:
      if (newVisitToStart_up)
        digitalWrite(power, HIGH);
        //home the carriage (bit of lazy coding blocking here, sorry ;) )
        while (digitalRead(limitHOME) == OPEN)
          Serial.println("homing carriage");
          digitalWrite(reverse, HIGH);
        digitalWrite(reverse, LOW);
        stateTransitionAtMillis = millis(); //start clock after homing is done
        newVisitToStart_up = false; //so as not to restart becaue of loop

      //wait 2, water on, wait 5, brush on
      if (millis() - stateTransitionAtMillis >= 2000) digitalWrite(water, HIGH);
      if (millis() - stateTransitionAtMillis >= 2000 + 5000)
        digitalWrite(brush, HIGH);
        currentState = ST_forward; //we know carriage is homed


    case ST_forward:
      digitalWrite(forward, HIGH);
      // should actually check that limitHOME is released once been going forward a while,
      //     if not it means mech problem, maybe in V3 ;)

      //check limitOUT, if closed stop forward, go to state revesre
      if (digitalRead(limitOUT) == CLOSED)
        digitalWrite(forward, LOW);
        currentState = ST_reverse;
        stateTransitionAtMillis = millis();

    case ST_reverse:
      //wait 3 then start reverse
      if (millis() - stateTransitionAtMillis >= 3000)
        digitalWrite(reverse, HIGH);

      //check limitHOME until we are back
      if (digitalRead(limitHOME) == CLOSED)
        digitalWrite(reverse, LOW);
        currentState = ST_shut_down;
        stateTransitionAtMillis = millis();

    case ST_shut_down:
      //wait 3 brush off, wait 3 water off, power off
      if (millis() - stateTransitionAtMillis >= 3000) digitalWrite(brush, LOW);
      if (millis() - stateTransitionAtMillis >= 3000 + 3000)
        digitalWrite(water, LOW);
        digitalWrite(power, LOW);
        currentState = ST_idle;