I found a treasure in the scrap yard and want to use it! Mighty Mule gate operator with roached control board. Motor and mechanism runs fine.
I have not had time to teach myself C++ so could use some help with the code. For someone who is proficient in coding for Arduino this should be a pretty easy chore...for me, impossible at this time.
DETAILS:
12 VDC gear motor, change direction by polarity reverse. External relays to be controlled by small relay module on Arduino
Three limit switches:
- Close Limit
- Open Limit
- Collision detection on gate. ( bumper bar )
Input via RF key fob.
( I will also have manual open/close/stop buttons available in parallel with RF inputs which I can install inside house later. )
- A= OPEN
- B= CLOSE
- Press any while in motion = STOP
- Collision switch close = STOP
- After a STOP can send gate either direction again.
That's pretty much it!
Optional:
Think about securing the gate by using one of the four channels timed such that the open option will only function within say 20-30 seconds after first pressing one of the four buttons. I used to do this with electric gates in the days before rolling code transmitters for decent security. No one expected to have to send one signal first then a second to open gate and it avoided false operation completely. Few operator controls of the day had more than one or two buttons. I used four button security controls. Not necessary to delay the close function, only the open function.
I ordered a 4 channel unit and will use spare to switch flood lights, toggle on/off with 4th channel.
I have in addition to the actual operator:
- Two UNO's and breadboards and ton of jumpers. ( will have to blow the dust off! )
- 10A 12V coil power relays for motor control. Draws less than 3 amps.
- 4-Relay Output Module for UNO.
- 4-CH RF Receiver Input for UNO. with key fob.
- ( Also one each, 4-ch and 2-ch receivers stand-alone with own relays as options. )*
- 3 Roller Limit Switches
- 12V Gel Battery / Solar charger.
-
Time...I am semi retired and on Social Security...be gentle! :o
Tons of other electrical items, wire and so on to complete the project.
What outputs does the arduino have to play with? Are there two relays? And you hold down the "open" relay until you hit the "open" limit?
If the bumper bar gets hit, will it only be mometarily on? I'll assume that if you hit the bumper than it stays on. So you will have to hold down the button to move the gate if the bumper is being hit.
Here's mine. Completely untested, but it does compile .
const int OPEN_BUTTON_PIN = 1;
const int CLOSE_BUTTON_PIN = 2;
const int OPEN_RELAY_PIN = 3;
const int CLOSE_RELAY_PIN = 4;
const int OPEN_LIMIT_PIN = 5;
const int CLOSE_LIMIT_PIN = 6;
const int BUMPER_PIN = 7;
enum RelayState {
OFF = 0,
OPENING = 1,
CLOSING = 2
} relayState ;
// if you press any switch while moving, motion stops.
// but if you press and hold the switch, I have to ignore that
// until that switch is released or else you'd need to press the
// switches *really* fast.
boolean ignoringSwitchDown;
// this holds the switch state at *this* iteration through the loop
boolean senseOpen;
boolean senseClose;
boolean senseOpenLimit;
boolean senseCloseLimit;
boolean senseBumper;
void setup() {
// put your setup code here, to run once:
pinMode(OPEN_BUTTON_PIN, INPUT_PULLUP);
pinMode(CLOSE_BUTTON_PIN, INPUT_PULLUP);
pinMode(OPEN_RELAY_PIN, OUTPUT);
pinMode(CLOSE_RELAY_PIN, OUTPUT);
pinMode(OPEN_LIMIT_PIN, INPUT_PULLUP);
pinMode(CLOSE_LIMIT_PIN, INPUT_PULLUP);
pinMode(BUMPER_PIN, INPUT_PULLUP);
// not necessary, but included for completeness
relayState = OFF;
ignoringSwitchDown = false;
}
void loop() {
// Debounce logic belongs here. Why not use my awesome library
// https://github.com/PaulMurrayCbr/DebounceInput/wiki ?
senseOpen = !digitalRead(OPEN_BUTTON_PIN);
senseClose = !digitalRead(CLOSE_BUTTON_PIN);
senseOpenLimit = !digitalRead(OPEN_LIMIT_PIN);
senseCloseLimit = !digitalRead(CLOSE_LIMIT_PIN);
senseBumper = !digitalRead(BUMPER_PIN);
if (relayState == OFF)
handleCurrentlyNotMoving();
else
handleCurrentlyMoving();
}
void handleCurrentlyNotMoving() {
// ok. Do we need to start moving?
if(senseOpen == senseClose) {
// if both the buttons are down, or neither is, them meh.
return;
}
// ok! One of the buttons (and not the other) is down!
// Let's start that gate swinging! Maybe!
if(senseOpen && !senseOpenLimit) {
relayState = OPENING;
digitalWrite(OPEN_RELAY_PIN, true);
}
if(senseClose && !senseCloseLimit) {
relayState = CLOSING;
digitalWrite(CLOSE_RELAY_PIN, true);
}
ignoringSwitchDown = true;
}
void handleCurrentlyMoving() {
// ok. Do we need to stop moving?
// we need to stop moving if:
// - the approprate end stop is reached.
// - the bumper is hit and we are not holding down the correct button
// - either of the switches is down, unless we are in a press-and-hold
// situation *for that pin*
// oh, I could make this one big massive condition, but why would you?
boolean weNeedToStop = false;
if(relayState == OPENING && senseOpenLimit) weNeedToStop = true;
if(relayState == CLOSING && senseCloseLimit) weNeedToStop = true;
if(senseOpen && !(relayState == OPENING && ignoringSwitchDown))
weNeedToStop = true;
if(senseClose && !(relayState == CLOSING && ignoringSwitchDown))
weNeedToStop = true;
if(senseBumper) {
// we sensed the bumper. But is the operator holding down the button?
if(senseClose && relayState == CLOSING)
; // ignore
else
if(senseOpen && relayState == OPENING)
; // ignore
else
weNeedToStop = true;
}
// having worked out whether we need to stop or not, let's update the
// 'ignoring stuff' state
// opening, and the operator has taken the finger off the open button
if(ignoringSwitchDown && relayState == OPENING && !senseOpen) ignoringSwitchDown = false;
// closing, and the operator has taken the finger off the close button
if(ignoringSwitchDown && relayState == CLOSING && !senseClose) ignoringSwitchDown = false;
if(weNeedToStop) {
// Holey Moley! We need to stop!
// belt and braces - I'll turn 'em both off
digitalWrite(OPEN_RELAY_PIN, false);
digitalWrite(CLOSE_RELAY_PIN, false);
// not necessary, but meh
ignoringSwitchDown = false;
relayState = OFF;
}
}
Ah! This won't work! If the gate is closing, and you press a switch, the gate will stop and then immediately restart again (because a switch is pressed). I need to add "ignore press and hold" logic for the "gate is not moving" state.
Dammit, there's always something.
Hang on ...
Ok. Here is the code corrected so that if you hit a switch while moving, the gate will stop and wait untill you have released both switches before allowing a switch press to restart the move.
const int OPEN_BUTTON_PIN = 1;
const int CLOSE_BUTTON_PIN = 2;
const int OPEN_RELAY_PIN = 3;
const int CLOSE_RELAY_PIN = 4;
const int OPEN_LIMIT_PIN = 5;
const int CLOSE_LIMIT_PIN = 6;
const int BUMPER_PIN = 7;
// if the bumper is sensed, we will permit 1/2 second nudges
const unsigned long IGNORE_BUMPER_TIME_MS = 500;
enum RelayState {
OFF = 0,
OPENING = 1,
CLOSING = 2
} relayState ;
// if you press any switch while moving, motion stops.
// but if you press and hold the switch, I have to ignore that
// until that switch is released or else you'd need to press the
// switches *really* fast.
boolean ignoringSwitchDown;
// this holds the switch state at *this* iteration through the loop
boolean senseOpen;
boolean senseClose;
boolean senseOpenLimit;
boolean senseCloseLimit;
boolean senseBumper;
void setup() {
// put your setup code here, to run once:
pinMode(OPEN_BUTTON_PIN, INPUT_PULLUP);
pinMode(CLOSE_BUTTON_PIN, INPUT_PULLUP);
pinMode(OPEN_RELAY_PIN, OUTPUT);
pinMode(CLOSE_RELAY_PIN, OUTPUT);
pinMode(OPEN_LIMIT_PIN, INPUT_PULLUP);
pinMode(CLOSE_LIMIT_PIN, INPUT_PULLUP);
pinMode(BUMPER_PIN, INPUT_PULLUP);
// not necessary, but added for completeness
relayState = OFF;
ignoringSwitchDown = false;
}
void loop() {
// Debounce logic belongs here. Why not use my awesome library
// https://github.com/PaulMurrayCbr/DebounceInput/wiki ?
senseOpen = !digitalRead(OPEN_BUTTON_PIN);
senseClose = !digitalRead(CLOSE_BUTTON_PIN);
senseOpenLimit = !digitalRead(OPEN_LIMIT_PIN);
senseCloseLimit = !digitalRead(CLOSE_LIMIT_PIN);
senseBumper = !digitalRead(BUMPER_PIN);
if (relayState == OFF)
handleCurrentlyNotMoving();
else
handleCurrentlyMoving();
}
void handleCurrentlyNotMoving() {
// ok. Do we need to start moving?
// if we stopped moving because of a switch press, then we wait until
// all switches are released before continuing.
if(ignoringSwitchDown) {
if(senseOpen || senseClose))
return;
ignoringSwitchDown = false; // armed and ready!
// having said that, we will immediately exit because neither switch is down, but whatevs
}
if(senseOpen == senseClose) {
// if both the buttons are down, or neither is, them meh.
return;
}
// ok! One of the buttons (and not the other) is down!
// Let's start that gate swinging!
if(senseOpen && !senseOpenLimit) {
relayState = OPENING;
digitalWrite(OPEN_RELAY_PIN, true);
}
if(senseClose && !senseCloseLimit) {
relayState = CLOSING;
digitalWrite(CLOSE_RELAY_PIN, true);
}
ignoringSwitchDown = true;
}
void handleCurrentlyMoving() {
// ok. Do we need to stop moving?
// we need to stop moving if:
// - the approprate end stop is reached.
// - the bumper is hit and we are not holding down the correct button
// - either of the switches is down, unless we are in a press-and-hold
// situation *for that pin*
// oh, I could make this one big massive condition, but why would you?
boolean weNeedToStop = false;
if(relayState == OPENING && senseOpenLimit) weNeedToStop = true;
if(relayState == CLOSING && senseCloseLimit) weNeedToStop = true;
if(senseOpen && !(relayState == OPENING && ignoringSwitchDown))
weNeedToStop = true;
if(senseClose && !(relayState == CLOSING && ignoringSwitchDown))
weNeedToStop = true;
if(senseBumper) {
// we sensed the bumper. But is the operator holding down the button?
if(senseClose && relayState == CLOSING)
; // ignore
else
if(senseOpen && relayState == OPENING)
; // ignore
else
weNeedToStop = true;
}
// having worked out whether we need to stop or not, let's update the
// 'ignoring stuff' state
// opening, and the operator has taken the finger off the open button
if(ignoringSwitchDown && relayState == OPENING && !senseOpen) ignoringSwitchDown = false;
// closing, and the operator has taken the finger off the close button
if(ignoringSwitchDown && relayState == CLOSING && !senseClose) ignoringSwitchDown = false;
if(weNeedToStop) {
// Holey Moley! We need to stop!
// belt and braces - I'll turn 'em both off
digitalWrite(OPEN_RELAY_PIN, false);
digitalWrite(CLOSE_RELAY_PIN, false);
// tell the 'currently not moving' case to wait until all switches are released.
ignoringSwitchDown = true;
relayState = OFF;
}
}
Thanks! Right now some items are on the way in the mail and rest is in a box. I hope to have it all to begin work this weekend. Will do the electronics on bench and test before actually mounting the motor to the gate.
This means my options are pretty open at this point.
All contacts should be treated as momentary although once gate stops in one direction or the other, the respective limit switch will change position. These are all SPDT switches so always one of two positions closed.
The relays for Arduino ( 4-relay module ) are SPDT or DPDT, not sure until they arrive.
The RF receiver is output high, no relay but I also have a stand alone receiver with four SPDT relays I could use as well.
The obvious exception, the relays that drive the motor must remain active while the gate moves, so relay module on Arduino needs to latch for selected direction of travel until a limit is reached or bumb is hit.
The collision bar should be considered a momentary event because a gate could rebound if it hit a vehicle and the switch return to it's default position. Can be either NO or NC as default...really does not matter as it is the change of state that triggers STOP.
I will draw preliminary diagram and upload in a bit.
Thanks again!
This will give me a good head start on learning to program because I can make some sense of this as it relates to my specific needs. I really really need to get cracking so I can find things to do with my other board...I bought two but have had little "umph" to learn.
Funny thing. I was setting up for yard sale and among the books is a C++ manual! Think I will set that aside.
I actually have four but the other two are dedicated for 2 machines.
3D printer and CNC mill. I build a ShapeOko about a year ago. Of course they came with the code so I had no learning curve on that aspect...just the design of things to print/cut. But being a web developer I work with graphics all the time.
Edited to add pictorial diagram.
To avoid having to dig a ditch, the close limit and collision will both be mounted on the end of the gate.
PaulKruger:
This will give me a good head start on learning to program because I can make some sense of this as it relates to my specific needs.
Very much so.
While you are waiting for your bits to turn up, I'd suggest you stick some pushbuttons into a breadboard for the buttons (maybe slider switches for the end stops), some LEDs for the relays, and just watch that the sketch behaves as you would want it to when you simulate what might happen to your gate.
The main thing that is important with a respect to understanding an arduino program is that the loop() function gets called over and over - thousands of times a second. The other main thing is understanding variable lifetime. Variables declared inside a curly-brace code block
int foo() {
int im_a_local_variable;
}
"vanish" when that block finishes. Variables outside the block hang around for as long as the board is plugged in. So my sketch puts values in relayState in order to communicate with the next time the loop is run.
I think of it as like instructing a goldfish. Each time it circles the bowl, it forgets everything unless you have specifically written it down. Every process, every sequence of things-to-do, needs to be rephrased in terms of "what do I do right now"?
As for electronics - it's not my thing . All I know is that normally when a button is pressed, it is grounded. This is why I have a not operator (the !) when I read the button state.
To make sure a button is sensed as "not pressed" correctly, it needs to be attached with a resistor to +5v. If you set up the button as INPUT_PULLUP, then this egts done on-board.
The other thing I know is that it might be a bit rude to hook up an arduino output pin directly to a relay coil that pulls enough current to switch mains power. Talk to the electronics guys about electronics. I bought a darlington array chip to drive a stepper motor, the advantage being that it has all the correct bits to drive an inductive load (flashback diodes? something like that). Maybe that would work for your relays.
Paul
I was reading the code and have a question. Where it responds and says relay pull up am I assuming this sends a +5 to the relay module? The relay module uses -5 to activate the relays.
I received the RF module in the mail today. Have not played with it so don't yet know if it's output is + or - 5V.
Will let you know when I test it. I decided to forego the relay output module I have to simplify and save space.
This is a 4 channel module but will initially use only two channels, one for open and one for close. Got to thinking a relay for flood light was stupid idea because the flood light has motion detector anyway and will always turn on after dark if I pull into driveway.
Those other two outputs will be dormant until I come up with some brilliant idea for them! If I have any false triggers opening the gate I may use one in series with the OPEN relay and reprogram to hold that relay for about 20 seconds so that the OPEN relay will only be effective for that short period.
Thanks again for your help.
PaulKruger:
Paul
I was reading the code and have a question. Where it responds and says relay pull up am I assuming this sends a +5 to the relay module? The relay module uses -5 to activate the relays.
A warning from another Paul! I recently replaced a 2-relay module in a device that quit working. The original board used -5 to activate, just like yours. The replacement board uses +5 to activate the relays. Had to change the program.
Also, the relay that quit working on the first board stopped because of arcing between contacts. Running at 12 volts, 4 amps max. Autopsy showed a pit on the moving contact and a built up point on the NC contact. The arcing made an insulator out of the contacts.
Good luck. I have a dual Mighty Mule system on my driveway gates.
Paul
PaulKruger:
I was reading the code and have a question. Where it responds and says relay pull up am I assuming this sends a +5 to the relay module? The relay module uses -5 to activate the relays.
Ah, well for that you'll need to speak to an electronics person - I'm just a programmer
Ok...Guess that is me. I am electronics person but since Im not that familiar yet with Arduino Code did not know if the polarity issue was assigned in code or was hardwired attribute of the Arduino.
Having read more I see it is a programming decisions that is already dealt with in your code.
Had to move this to back burner for a few weeks. Mom (she is 100) had to go to hospital and I spent time driving back and forth each day for a week and lots of other stuff fell behind. She is much better now>\