Working on a gate opener motor driver

I’m very new at this coding thing, I understand the logic but have a lot of learning ahead of me. I am designing a gate opener that has a single open button, 2 limit switches and a obstruction switch.
The open button switch starts the motor. The run command goes for 10 seconds or until the limit switch goes low. If the open button is pressed any time during that interval the motor is stopped.

My first obstacle is getting the code to read the open button as a single press (to get things started) but not stop everything if it is held too long.
.
I installed ezbutton library but am confused if it will do what I need, and what call out to use, any suggestions?

Have a look at state-change , so the switch only registers once for each specific action. Not a state-machine, although that might be useful once you get the button figured out.

Remember, to keep your project ‘responsive’ - lose any delay() calls.

  • Always start with a proposed schematic.

  • Scan switches, say every 50ms; look for a change in the switches state.

1 Like

Where will this be located and what is the power source. You can indicate that on the schematic.

You can refer to this tutorial Arduino - button long press and short press

This will tell you all you need to know about programming for buttons:
https://www.ladyada.net/learn/arduino/lesson5.html
Just remember to debounce your button.

EzButton has a naming convention issues and misspellings. That's rough when you are just getting started.

Hi @helijoc

welcome to the arduino-forum.

I describe this behaviour with my own words:

  • check if push-button is pressed
    • if push-button press is detected
      ===> start motor and make a note of the time when the motor is switched on

after that the code should do something different:

  • check if 10 seconds since motor switching on have passed by

    • if 10 seconds have passed by since motor on
      ====> stop motor
  • check if limit-switch is LOW

    • if limit switch IS low
      ====> stop motor
  • check if push-button is pressed (again)
    ====> stop motor

This can be seen as two different modes of operation.
In Programming such modes of operation are called "states"

state idling:

  • check if open-switch is triggered
    • if push-button-press is detected
      ===> start motor and make a note of the time when the motor is switched on
      ===> change to state openingGate

state openingGate:

  • check if 10 seconds since motor switching on have passed by

    • if 10 seconds have passed by since motor on
      ====> stop motor
  • check if limit-switch is LOW

    • if limit switch IS low
      ====> stop motor
  • check if push-button is pressed (again)
    ====> stop motor

The code should do either idling or openingGate

A very elegant solution for this is to use a state-machine by using the
switch-case-break;-statement

ATTENTION !

The break; is very very important !

The break; is that detail that makes code-execution mutually exclusive

remember:
you want to either

start the motor if switch triggered

or

stop the motor if switch is triggered

Which are opposite things start/stop
Further down the road you will have some more "states"

what shall happen if the door is completely opened and motor has stopped?
wait a fixed amount of time then closing it automatically ?
wait for switch to be triggered again closing the door?

With a state-machine it will be very easy to expand your code to add this behaviour

I have written a small tutorial about how state-machines are coded
take a look at it

best regards Stefan

Hello helijoc

Welcome to the world's best Arduino forum ever.

Post your current sketch, well formated, with well-tempered comments in so called code tags and schematic to see how we can help.

Have a nice day and enjoy coding in C++.

look this over

const byte      PinBut = A2;
byte            butState;
unsigned long   msecBut;
unsigned long   msecButPeriod;

void loop ()
{
    unsigned long  msec = millis ();

    // check for "too long"
    if (0 < msecButPeriod && msec - msecBut >= msecButPeriod)  {
        msecButPeriod = 0;          // disable
        Serial.println (" too long");
    }

    // check for button press
    byte but = digitalRead (PinBut);
    if (butState != but) {
        butState = but;
        delay (20);                     // debounce

        if (LOW == but) {
            msecBut = msec;
            msecButPeriod = 1000;       // one second
        }
        else if (0 < msecButPeriod)  {
            msecButPeriod = 0;          // disable
            Serial.println ("button press");
        }
    }
}

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

    pinMode (PinBut, INPUT_PULLUP);
    butState = digitalRead (PinBut);
}

Here is a WOKWI-Simulation that demonstrates the code-behaviour as far as you have described it

You will have to add code that goes on after opening the gate and how to detect some kind of switch that detects gate fully opened

best regards Stefan

Just edit the name of this thread!

I’m very new at this coding thing, I understand the logic but have a lot of learning ahead of me. I am designing a gate opener.

There are (4) inputs;

One NO push button, (2) NO limit switches, electric eye that basically operates as a NO switch and becomes NC if something in in the gate’s path.

The push button starts the gate in motion with a press, a second press if the gate is in motion will stop the gate, a third press will start the gate in motion (opposite direction), etc.

Once the gate is in motion there will be a 15 second (safety) timer that will stop the motor if a limit switch isn’t triggered first. If the gate is stopped mid-way the arduino should be able to calculate the time and use that value instead of 15 seconds, (this may be too hard to code).

When the gate is in motion and the push button is pressed the gate will stop, the next button press will cause the gate to be the opposite direction.

If a limit switch is triggered the next motion will be the opposite direction.

If the 15 second time limit is reached the gate will stop, the next motion will be the opposite direction.

In short, every time the motor / gate stops its next move will be the opposite direction.

I also want a ramp for the actuator motor on start and maybe stop, not sure on stop but it would be nice to play with.

The board I am using is an UNO and a Cytron shield MC-10

I am very new at programming, I have enlisted the help of a friend who did programming many years ago but is new at this Arduino thing but types fast and is real good at explaining what he is doing. We have looked at a lot of other code, copied some and played with it. I have the boards prototyped on the table, it works in some areas but integrating ALL the requirements is making for some long days.

Below is the code we have so far, ezbutton library has been added but it isn't used yet.

Here is what we have so far, we are both open for comments and help.

#include <ezButton.h>
#include "CytronMotorDriver.h"

CytronMD motor(PWM_DIR, 3, 4);                     // PWM = Pin 3, DIR = Pin 4.
//#define MotorDirection 3                            //Pin to use for DIR control
//#define MotorSpeed 2                                //Pin to use for PWM control

int buttonPin = A1;
int counter = 0;
int buttonState = 0;
int lastButtonState = 0;
int limitOpen = A2;
int limitClose = A3;
int lastState = 0;
int count = 0;

int currentButtonState = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100;  //Set button press time needed to start

void setup() {
  pinMode(buttonPin,INPUT);                   //Set input pin as momentary switch that can be monitored
  digitalWrite(buttonPin, INPUT_PULLUP);
  pinMode (limitOpen, INPUT);
  digitalWrite(limitOpen, INPUT_PULLUP);
  pinMode (limitClose, INPUT);
  digitalWrite(limitClose, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() 
{
  motor.setSpeed(0);
  currentButtonState = digitalRead(buttonPin);
  if (currentButtonState != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (currentButtonState != buttonState) {
      buttonState = currentButtonState;
      }
      if (buttonState == 0 && lastState == 0) {
          openGate();
          return;
    }
  }
    if ((millis() - lastDebounceTime) > debounceDelay) {
    if (currentButtonState != buttonState) {
      buttonState = currentButtonState;
      }
     if (buttonState == 0 && lastState == 1) {
          closeGate();
    }
  }
  if (lastState == 0)
  {
    lastState = 1;
  }
  else{
    lastState = 0;
  }
  lastButtonState = currentButtonState;
}

void openGate()
{
  int i = 10;
    Serial.println("Opening");
    while (i > 0)
    {
    i--;
    Serial.println(i);
    motor.setSpeed(128);
    delay(300);
    currentButtonState = digitalRead(buttonPin);
    Serial.println(currentButtonState);
  if (currentButtonState == 0)
  {
     motor.setSpeed(0);
     delay(1000);
    return;
  }
 }
}

void closeGate()
{
  int j = 10;
  Serial.println("Closing");
    while (j > 0)
    {
    j--;
    Serial.println(j);
    motor.setSpeed(-128);
    delay(300);
    currentButtonState = digitalRead(buttonPin);
    Serial.println(currentButtonState);
  if (currentButtonState == 0)
  {
    motor.setSpeed(0);
    delay(1000);
    return;
  }
 }
}

I have merged your cross-posts @helijoc.

Cross-posting is against the Arduino forum rules. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting can result in a suspension from the forum.

In the future, please only create one topic for each distinct subject matter. This is basic forum etiquette, as explained in the "How to get the best out of this forum" guide. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

No need to delete it. I already corrected what you did wrong by merging the two topics into one. No further action is needed; just don't create multiple topics for the same subject matter in the future and everything will be fine.

The information in the deleted post is useful to this discussion so I have restored it.

Pert,

I understand cross posting, “multiple posts same subject”.

I honestly don’t believe I did that. The first post was about how to make a push button switch to a single press. I got a lot of information on making that work. Then I thought I would ask for suggestions about the whole project which is a lot more involved than a push button. I created a new post topic discuss the project.

You merged and basically buried that topic at the bottom of the button discussion.

Since the topic about the gate opener motor driver is not seen in the topic line it is less likely I will get the help I am looking for.

The forum actually asks to make the topic descriptive to attract correct help.

Walt

image001.jpg

look this over

// gate controller

const byte PinDir = 12;
const byte PinMot = 13;

const int  Ninp   = 2;
const byte PinInp   [] = { A2, A3 };
      byte butState [Ninp];

const int  ButSw = 0;
const int  LmtSw = 1;

const int On  = LOW;
const int Off = HIGH;

int dir = 1;    // open
int run = 0;

// -----------------------------------------------------------------------------
int
butChk (
    int  n)
{
    byte but = digitalRead (PinInp [n]);
    if (butState [n] != but)  {
        butState [n] = but;
        delay (20);

        if (LOW == but)
            return 1;
    }
    return 0;
}

// -----------------------------------------------------------------------------
void
motorStopReverse ()
{
    Serial.println ("Stop");

    run = Off;
    digitalWrite (PinMot, run);
    dir = ! dir;
    digitalWrite (PinDir, dir);
}

// -----------------------------------------------------------------------------
void
loop ()
{
    if (butChk (LmtSw))  {
        motorStopReverse ();
    }

    if (butChk (ButSw))  {
        if (Off == run)  {
            run = On;
            digitalWrite (PinMot, run);

            if (1 == dir)
                Serial.println ("Open");
            else
                Serial.println ("Close");
        }
        else
            motorStopReverse ();
    }
}

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

    for (int n = 0; n < Ninp; n++)  {
        pinMode (PinInp [n], INPUT_PULLUP);
        butState [n] = digitalRead (PinInp [n]);
    }

    digitalWrite (PinDir, Off);
    digitalWrite (PinMot, Off);
    pinMode      (PinDir, OUTPUT);
    pinMode      (PinMot, OUTPUT);
}
1 Like

This is a misunderstanding how the function-calls pinMode() and digitalWrite() work

The option INPUT_PULLUP is used in the function-call pinMode()

pinMode () INPUT_PULLUP

// configure the IO-pin named buttonPin to work in INPUT_PULLUP-mode
 pinMode(buttonPin,INPUT_PULLUP);

digitalWrite() is used for switching the logic state of the IO-pin
of IO-pins that are used as OUTPUT

in the code you have posted above there are no outputs defined.

using inputs is recommended to be used in INPUT_PULLUP-mode.
INPUT_PULLUP requires a different wiring
and
INPUT_PULLUP inverts the logic states
You can read this here
Nick Gammon Switches / Buttons

best regards Stefan

1 Like

Hello helijoc

Have you ever thought about replacing the motor with a servo?

1 Like

The decision is final. Whining about it won't change anything. I suggest you dedicate your energy towards progressing with your Arduino project.

You are welcome to edit it:

  1. Click the following link to open this topic at the first post:
    https://forum.arduino.cc/t/pushbutton-switch-to-single-press/1209180/1
  2. You will see a 🖉 icon on the right side of the topic title. Click that icon.
    The topic title will now be shown in a text edit field.
  3. Adjust the topic title as you like.
  4. Click the button.