0

I want to make a project about automatic gate and garage door via Android app and connected by HC-05 bluetooth module. Each of the gate and garage door have two limit switches(located at each end of travel) to trigger the DC motor to stop.

I have made some code and do researches, but the DC motor will only stop when I pressed it, if I release it again it will start automatically. I want to make it stop until the bluetooth module send the code again. I have input the pull-down resistor into the limit switch.

Can anybody please help me?

Here's my current code, thank you

// Motor for Gate (MotorA)
int IN1 = 2;
int IN2 = 3;
int EnableMotorA = 9;

// Motor for Garage Door (MotorB)
int IN3 = 4;
int IN4 = 5;
int EnableMotorB = 10;

const int LimitSwitch1 = A1;
const int LimitSwitch2 = A2;
const int LimitSwitch3 = A3;
const int LimitSwitch4 = A4;

int state;


void setup(){
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(EnableMotorA,OUTPUT);

  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);
  pinMode(EnableMotorB,OUTPUT);

  pinMode(LimitSwitch1, INPUT);
  pinMode(LimitSwitch2, INPUT);
  pinMode(LimitSwitch3, INPUT);
  pinMode(LimitSwitch4, INPUT);

  digitalWrite(LimitSwitch1, LOW);
  digitalWrite(LimitSwitch2, LOW);
  digitalWrite(LimitSwitch3, LOW);
  digitalWrite(LimitSwitch4, LOW);

  Serial.begin(9600);
}

void loop(){
  if(Serial.available() > 0){
    state = Serial.read();
    }
    if(state == 'A') {
      OpenGate();
      if(digitalRead(LimitSwitch2) == HIGH){
      StopMotorA();
      }
    }
    else if(state == 'B') {
      CloseGate();
      if(digitalRead(LimitSwitch1) == HIGH){
      StopMotorA();
      }
    }
    else if(state == 'C') {
      OpenGarageDoor();
      if(digitalRead(LimitSwitch4) == HIGH){
      StopMotorB();
      }
    }
    else if(state == 'D') {
      CloseGarageDoor();
      if(digitalRead(LimitSwitch3) == HIGH){
      StopMotorB();
      }
    }
}

//******************   Motor A control   *******************
void OpenGate(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(EnableMotorA, 250);
  }
void CloseGate(){
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(EnableMotorA, 250);
}
void StopMotorA(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  analogWrite(EnableMotorA, 0);
 }
//******************   Motor B control   *******************
void OpenGarageDoor(){
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(EnableMotorB, 250);
}
void CloseGarageDoor(){
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(EnableMotorB, 250);
}
void StopMotorB(){
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(EnableMotorB, 0);
}
//**********************************************************
  • 1
    do not start the motor after the switch is closed. start it with BT only. .... draw up a flowchart on paper, then create the code that emulates the flowchart. – jsotola Dec 14 '17 at 7:28
  • I am sorry but what is BT? I have made the flowchart, it goes like motor DC turn in clockwise -> is limit switch pressed? -> if yes, stop the DC motor. and I thought i have made it that way – Husna Amiliansyah Dec 14 '17 at 7:49
  • BT ... bluetooth ..... you are getting your states from a serial connection. that is ok, but you need internal states also. example: state E --- status: everything stopped .... enter from state B when limit switch is activated (and from others) – jsotola Dec 14 '17 at 7:57
  • you need at least 4 separate stop states ... door open, door closed, door stop at opening, door stop at closing. .... do a web search about state machine or arduino state machine – jsotola Dec 14 '17 at 8:06
  • the state is referring the character that is received from the BT. do the if statement for limit switch also included into the stop state? okay i will have a research about that, thank you – Husna Amiliansyah Dec 14 '17 at 8:17
2

DISCLAIMER: I haven't tested the code in this answer, but I hope there are no problems.

Your code has a major problem: what happens when one gate is moving and you trigger another movement? (reply: something bad). This design issue can be solved by using a standard way of designing these kind of state machine.

In your case a small state machine is what best fits your problem. Better give your states a meaningful name, no?

Ok, so just to start, let's define the states and how to transition through them.

You have basically an idle state, open gate, close gate, open garage door, close garage door. What should you do in these states, both when entering the state and during the time you are in the state? Here is a table to summarize

State       | Enter         | During time
----------------------------------------------
Idle        | Stop motors   | -
OpenGate    | Start A dir 1 | -
CloseGate   | Start A dir 2 | -
OpenGarage  | Start B dir 1 | -
CloseGarage | Start B dir 2 | -

The transitions are pretty straightforward. Exit from idle when you receive a (valid) command, exit from the others when you reach the endstop.

The implementation is pretty standard:

// Motor for Gate (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;

// Motor for Garage Door (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;

const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;

const byte State_Idle = 0;
const byte State_OpenGate = 1;
const byte State_CloseGate = 2;
const byte State_OpenGarage = 3;
const byte State_CloseGarage = 4;
byte currentState;

void setup(){
    pinMode(IN1,OUTPUT);
    pinMode(IN2,OUTPUT);
    pinMode(EnableMotorA,OUTPUT);

    pinMode(IN3,OUTPUT);
    pinMode(IN4,OUTPUT);
    pinMode(EnableMotorB,OUTPUT);

    pinMode(LimitSwitch1, INPUT);
    pinMode(LimitSwitch2, INPUT);
    pinMode(LimitSwitch3, INPUT);
    pinMode(LimitSwitch4, INPUT);

    Serial.begin(9600);
    currentState = 0xFF; // Force a change to enter the idle state
}

void loop(){
    // Check if we need to change state
    byte nextState = currentState;
    switch (currentState)
    {
    case State_Idle:
        { // If we received a valid command, start the operation
            if(Serial.available() > 0)
            {
                switch (Serial.read())
                {
                case 'A':
                    nextState = State_OpenGate;
                    break;
                case 'B':
                    nextState = State_CloseGate;
                    break;
                case 'C':
                    nextState = State_OpenGarage;
                    break;
                case 'D':
                    nextState = State_CloseGarage;
                    break;
                default:
                    // Here you can notify that there was a bad command
                    break;
                }
            }
        }
        break;
    case State_OpenGate:
        if(digitalRead(LimitSwitch2)) // == HIGH is not necessary
            nextState = State_Idle;
        break;
    case State_CloseGate:
        if(digitalRead(LimitSwitch1)) // == HIGH is not necessary
            nextState = State_Idle;
        break;
    case State_OpenGarage:
        if(digitalRead(LimitSwitch4)) // == HIGH is not necessary
            nextState = State_Idle;
        break;
    case State_CloseGarage:
        if(digitalRead(LimitSwitch3)) // == HIGH is not necessary
            nextState = State_Idle;
        break;
    default:
        nextState = State_Idle;
        break;
    }

    // If there was a change, switch state and trigger enter condition
    if (nextState != currentState)
    {
        currentState = nextState; // Move in the new state
        switch (currentState)
        { // Entering the new state
        case State_Idle:
            // Stop motor A
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 0);
            // Stop motor B 
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 0);
            break;
        case State_OpenGate:
            // Start motor A
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, HIGH);
            analogWrite(EnableMotorA, 250);
            break;
        case State_CloseGate:
            // Start motor A
            digitalWrite(IN1, HIGH);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 250);
            break;
        case State_OpenGarage:
            // Start motor B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, HIGH);
            analogWrite(EnableMotorB, 250);
            break;
        case State_CloseGarage:
            // Start motor B
            digitalWrite(IN3, HIGH);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 250);
            break;
        }
    }
}

(Note: I changed some types because your poor 8-bit uC asked me to avoid complicating its calculations unnecessarily)

One modification to your algorithm is to detach the two loops, since they seem, well, detached.

// Motor for Gate (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;

// Motor for Garage Door (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;

const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;

const byte StateA_Idle = 0;
const byte StateA_Open = 1;
const byte StateA_Close = 2;
byte currentStateA;

const byte StateB_Idle = 0;
const byte StateB_Open = 1;
const byte StateB_Close = 2;
byte currentStateB;


void setup(){
    pinMode(IN1,OUTPUT);
    pinMode(IN2,OUTPUT);
    pinMode(EnableMotorA,OUTPUT);

    pinMode(IN3,OUTPUT);
    pinMode(IN4,OUTPUT);
    pinMode(EnableMotorB,OUTPUT);

    pinMode(LimitSwitch1, INPUT);
    pinMode(LimitSwitch2, INPUT);
    pinMode(LimitSwitch3, INPUT);
    pinMode(LimitSwitch4, INPUT);

    Serial.begin(9600);
    currentStateA = 0xFF; // Force a change to enter the idle state
    currentStateB = 0xFF; // Force a change to enter the idle state
}

void loop()
{
    byte readChar = 0;
    if(Serial.available() > 0)
        readChar = Serial.read();

    stateMachineA(readChar);
    stateMachineB(readChar);
}

void stateMachineA(byte readChar)
{
    // Check if we need to change state
    byte nextState = currentStateA;
    switch (currentStateA)
    {
    case StateA_Idle:
        { // If we received a valid command, start the operation
            if(readChar > 0)
            {
                switch (readChar)
                {
                case 'A':
                    nextState = StateA_Open;
                    break;
                case 'B':
                    nextState = StateA_Close;
                    break;
                default:
                    // Here you can notify that there was a bad command
                    break;
                }
            }
        }
        break;
    case StateA_Open:
        if(digitalRead(LimitSwitch2)) // == HIGH is not necessary
            nextState = StateA_Idle;
        break;
    case StateA_Close:
        if(digitalRead(LimitSwitch1)) // == HIGH is not necessary
            nextState = StateA_Idle;
        break;
    default:
        nextState = StateA_Idle;
        break;
    }

    // If there was a change, switch state and trigger enter condition
    if (nextState != currentStateA)
    {
        currentStateA = nextState; // Move in the new state
        switch (currentStateA)
        { // Entering the new state
        case StateA_Idle:
            // Stop motor A
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 0);
            break;
        case StateA_Open:
            // Start motor A
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, HIGH);
            analogWrite(EnableMotorA, 250);
            break;
        case StateA_Close:
            // Start motor A
            digitalWrite(IN1, HIGH);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 250);
            break;
        }
    }
}

void stateMachineB(byte readChar)
{
    // Check if we need to change state
    byte nextState = currentStateB;
    switch (currentStateB)
    {
    case StateB_Idle:
        { // If we received a valid command, start the operation
            if(readChar > 0)
            {
                switch (readChar)
                {
                case 'C':
                    nextState = StateB_Open;
                    break;
                case 'D':
                    nextState = StateB_Close;
                    break;
                default:
                    // Here you can notify that there was a bad command
                    break;
                }
            }
        }
        break;
    case StateB_Open:
        if(digitalRead(LimitSwitch4)) // == HIGH is not necessary
            nextState = StateB_Idle;
        break;
    case StateB_Close:
        if(digitalRead(LimitSwitch3)) // == HIGH is not necessary
            nextState = StateB_Idle;
        break;
    default:
        nextState = StateB_Idle;
        break;
    }

    // If there was a change, switch state and trigger enter condition
    if (nextState != currentStateB)
    {
        currentStateB = nextState; // Move in the new state
        switch (currentStateB)
        { // Entering the new state
        case StateB_Idle:
            // Stop motor B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 0);
            break;
        case StateB_Open:
            // Start motor B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, HIGH);
            analogWrite(EnableMotorB, 250);
            break;
        case StateB_Close:
            // Start motor B
            digitalWrite(IN3, HIGH);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 250);
            break;
        }
    }
}

This second implementation has two parallel state machines (sharing only the serial input). This will allow you to control both gates at the same time (for instance when the gate is closin you can open the garage)

  • Oh my god! it works perfectly for my circuit. i planned to make it like your second implementation. Thank you so much! :D – Husna Amiliansyah Dec 14 '17 at 15:24
  • @HusnaAmiliansyah did you already test it? Does it work? Really? :-P – frarugi87 Dec 14 '17 at 15:52
  • of course it works xD, i had tested it on breadboard – Husna Amiliansyah Dec 17 '17 at 9:37
  • btw, const byte StateA_Idle = 0; const byte StateA_Open = 1; const byte StateA_Close = 2; what is this part mean? – Husna Amiliansyah Dec 17 '17 at 9:38
  • 2
    Alright, got it!! thank you so much for your help!! :) btw, i am sorry i can not vote this answer because i dont have enough poin:( – Husna Amiliansyah Dec 28 '17 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.