EXAMPLE 1:
Press button1 --> Open Gate (relay1 ON)
While Gate is opening if I press button1 again --> Stop Gate (relay1 OFF)
EXAMPLE 2:
Press button1 --> Open Gate (relay1 ON)
While Gate is opening if I press button2 --> Open a (relay2 ON)
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2
}
void loop() {
if (mySwitch.available()) {
button_time = millis();
Serial.print("Value");
int value = mySwitch.getReceivedValue();
Serial.println(value);
if (value == 0) {
Serial.print("Unknown encoding");
} else {
Serial.println("Value: ");
Serial.println(value);
}
if (value == 21763) {
Serial.println("OPEN");
openGate(); //PROBLEM!! WHEN ENTER HERE, STOPS TO RECEIVE NEW COMMANDS UNTIL END
}
if (value == 21772) {
Serial.println("CLOSE");
closeGate(); //PROBLEM!! WHEN ENTER HERE, STOPS TO RECEIVE NEW COMMANDS UNTIL END
}
....
}
mySwitch.resetAvailable();
}
}
You are screaming. We may be a bunch of grumpy old men, but we aren't deaf.
Its not to hear better... it's to see better
PaulS:
2) You haven't posted the code for openGate().
Ok, the code is here. But the point is: when it enters on another function (ex. openGate) I cant send any commands until it finishes.
void openGate() {
digitalWrite(relayOpen, HIGH);
Serial.println("Portao a abrir");
flag = true;
long now = millis(); Serial.println("NOW: "); Serial.println(now);
long start = millis(); Serial.println("START: "); Serial.println(start);
while (flag == true) {
now = millis();
if (now >= (start + timeOpening)) {
digitalWrite(relayOpen, LOW);
Serial.println("OPENGATE Opened and waiting some time so the car can get in");
paused = true;
}
if ((now >= start + timeOpening + timeOpen) && (paused == true)) {
Serial.println("OPENGATE I will close");
flag = false;
paused = false;
}
Serial.println(now);
}
closeGate();
}
But the point is: when it enters on another function (ex. openGate) I cant send any commands until it finishes.
Not true. What is true is that you pay no attention to new commands until you have completely finished dealing with the previous one. openGate() should do nothing more than start the gate opening. closeGate() should do nothing more than start the gate closing. Testing limit switches, etc. should be done in loop(), where you also read the remote control switches.
Opening or closing a gate by powering a motor for a fixed period of time is not a good idea.
What I'm trying to achieve is something like a gate opener that I've bought.
It works like this:
While infrared sensors not interrupted: EX 1: Press button --> gate start to open x time --> gate is opened --> delay y time --> start to close x time --> gate closed EX 2: Press button --> gate start to open x time --> press button again --> gate stops --> press button again --> start to close --> press button again --> gate stops --> press button again --> start to open . . . . . . gate closed
I think it can be done with the attachInterrupt() but the mySwitch.enableReceive(0) Receive on inerrupt 0 => that is pin #2
PaulS:
Opening or closing a gate by powering a motor for a fixed period of time is not a good idea.
I plan to use other things like switches to stop it, but I have to make small steps.
I'm trying to make this project with a old gate motor that my fried gave to me. It has 3 wires for running the motor plus 3 wires for other options like give the information about the force/pressure that is doing. Its one more thing to explore...
That can be another way to stop it.
The other nice thing about using small functions is that you can try them out separately in a short test sketch.
You can also create a stub, and call the function. The function doesn't really need to do anything.
void openGate()
{
Serial.println(F("I need to actually make the gate start opening...));
}
Then, when the order of operations is correct - you see something like:
I need to actually make the gate start opening...
I need to test that the gate is moving and hasn't hit something like a limit switch
I need to stop the gate moving - it hit something
-or-
I need to stop the gate moving - it is all the way open
you can then pick one function and write that code.
Then, pick another, and actually write that code. Then another. Pretty soon, the code will be complete.
If, at any point, you think of something else that needs to be done, like listening to the remote control, it is much easier to incorporate that into 30 tiny functions than it is to incorporate it into one huge function that you don't understand.
Ok, I will write all the small functions I need and try to separate everything, then, I think I will need your help again
I will take some time because I'm working on this project just at the weekends.
Thanks for your advises
Ok, I've made some changes and tried to have everything separated but the problem is the same:
When I press the button the program starts and, when it's doing something (ex: opening/closing) it will not receive another signal from the remote control.
So, my question is: How do I change this interrupt thing to make it respond every time I press the button.
Thanks again
/*
Simple example for receiving
http://code.google.com/p/rc-switch/
*/
#include <RCSwitch.h>
const unsigned long timeOpening = 5000; // open & close time
const unsigned long timeOpen = 2000; // time to be opened
unsigned long button_time = 0;
unsigned long last_button_time = 0;
boolean flag = false;
boolean paused = false;
const int relayOpen = 11; // pin 11
const int relayClose = 12; // pin 12
int switchOpen = 9; // pin 9
int switchClose = 10; // pin 10
RCSwitch mySwitch = RCSwitch();
/*-------------------------------------------------------------------------------*/
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2
pinMode(relayOpen, OUTPUT);
pinMode(relayClose, OUTPUT);
pinMode(switchOpen, INPUT_PULLUP);
pinMode(switchClose, INPUT_PULLUP);
}
/*-------------------------------------------------------------------------------*/
void loop() {
if (mySwitch.available()) {unsigned long lastRequest = 0; // when you last made a request
button_time = millis(); //function to ignore signal if press button < 2 seconds
if (button_time - last_button_time > 2000)
{
last_button_time = button_time;
Serial.print("Value");
int value = mySwitch.getReceivedValue();
Serial.println(value);
if (value == 0) {
Serial.print("Unknown encoding");
} else {
Serial.println("Value: ");
Serial.println(value);
}
if (value == 21763) { //Value received fron button 1
Serial.println("Lets Start");
openGate();
openGateTimer();
closeGate();
closeGateTimer();
}
}
mySwitch.resetAvailable();
}
}
/*-------------------------------------------------------------------------------*/
void openGate() {
if (digitalRead(switchOpen) == HIGH) {// switchOpen is pressed - its HIGH just for testing without the switch
digitalWrite(relayOpen, HIGH);
Serial.println("The gate is opening");
}
}
/*-------------------------------------------------------------------------------*/
void closeGate() {
if (digitalRead(switchClose) == HIGH) {// switchClose is pressed - its HIGH just for testing without the switch
digitalWrite(relayClose, HIGH);
Serial.println("The gate is closing");
}
}
/*-------------------------------------------------------------------------------*/
void openGateTimer() {
flag = true;
long now = millis(); //Serial.println("NOW: "); Serial.println(now);
long start = millis(); //Serial.println("START: "); Serial.println(start);
while (flag == true) {
now = millis();
if ((now >= (start + timeOpening)) && (digitalRead(switchClose) == HIGH)) {//until switchClose is pressed
digitalWrite(relayOpen, LOW);
Serial.println("Making some time...");
paused = true;
}
if ((now >= start + timeOpening + timeOpen) && (paused == true)) {
Serial.println("I have to close now");
flag = false;
paused = false;
}
//Serial.println(now);
}
}
/*-------------------------------------------------------------------------------*/
void closeGateTimer() {
flag = true;
long now = millis(); //Serial.println("NOW: "); Serial.println(now);
long start = millis(); //Serial.println("START: "); Serial.println(start);
while (flag == true) {
now = millis();
if ((now >= (start + timeOpening)) && (digitalRead(switchOpen) == HIGH)) {//until switchOpen is pressed
digitalWrite(relayClose, LOW);
Serial.println("Gate is closed");
flag = false;
}
Serial.println(now);
}
}
The code in (for example) openGate() would check the saved switch value to see if it should start working. The switches would NOT be read within the function.
The code in stopGate() would check if the gate has gone far enough - probably also based on switch states saved in the first function.
Because the code loops around very quickly it will pick up the next switch press quickly.
Yes, but that doest solve my problem...
The thing I'm trying to do is to be able to read the radio signal of remote control every time.
In you example when the program enter on function openGate(), or nay other, it will stop to receive the RF signal until is exit from function.
Thanks for you help Robin
anjoze:
The thing I'm trying to do is to be able to read the radio signal of remote control every time.
In you example when the program enter on function openGate(), or nay other, it will stop to receive the RF signal until is exit from function.
In the concept in my mind the code will only be in each function for a number of microseconds so it will get back to reading the remote plenty fast enough. My outline should, obviously, have had a function to read the remote as in
Writing your own delay() function does not alter the fact that you spend long periods of time NOT reading the switch.
What you MUST do is understand that NO function should block. On any given pass through loop, you want to read the switch and you might want to start opening the gate, start closing the gate, stop opening the gate, or stop closing the gate.
Contrary to what Robin says, I think you need to make the decisions in loop(), and only call the functions as needed. Keep the logic in one place. Keep the mechanics of how to do what needs to be done in the functions.
After lots of Googling I found this thread. I thought I am the only one in the universe to have this challenge
The problem described here by anjoze is identical to the problem I have, except I'm using a simple stepper motor, but also using the RCSwitch library.
Case:
When I push the Remote Control button (say 'Right), the motor start to run clockwise. (AccelStepper library; non-blocking method 'runSpeed()' is being used in the loop().) Idem for 'Left'.
Problem: During this action, The RC commands do not work until the motor has stopped (using endswitches).
Deepest wish:
I want to pause the motor by pressing the same RC switch a second time and I also want to be able to stop the motor by pressing the RC button of the opposite direction.
My code is well-designed using a Finite State Machine based on a nice state diagram.
I hope someone can enlighten me since I'm getting pretty frustrated...
I deliberately made a set of similar functions (the 'void do_*' series). This is just to make things clear for the moment. I'll optimize it as soon as the code works as expected... Cheers.
#include <RCSwitch.h>
#include <AccelStepper.h>
// Button RC code definitions
#define D3_ON 5246997
#define D3_OFF 5246996
// Interrupts definitions
#define ReceiverInt 0 // Pin 2
// Pin definitions
#define EndSwitchPin 3
#define MotorPin1 8
#define MotorPin2 10 // Correction on motordriver wiring bug
#define MotorPin3 9 // Correction on motordriver wiring bug
#define MotorPin4 11
#define LedPin 13
// Stepper data
#define SPEED 500
#define HALF_STEP 4
#define FULL_STEP 8
// States
#define STOP 0
#define STOP_LEFT -1
#define STOP_RIGHT 1
#define TURN_LEFT -2
#define TURN_RIGHT 2
#define PAUSE_LEFT -3
#define PAUSE_RIGHT 3
// Classses --------------------------------------------------------
AccelStepper stepper(HALF_STEP, MotorPin1, MotorPin2, MotorPin3, MotorPin4);
RCSwitch rfSwitch = RCSwitch(); // 434 receiver
// Functions --------------------------------------------------------
void flash_led() {
digitalWrite(LedPin, true);
digitalWrite(LedPin, false);
}
void do_stop() {
Serial.println("STOP");
stepper.setSpeed(0);
stepper.disableOutputs();
}
void do_turn_right() {
Serial.println("TURN_RIGHT");
stepper.setSpeed(SPEED);
}
void do_turn_left() {
Serial.println("TURN_LEFT");
stepper.setSpeed(-SPEED);
}
void do_pause_left() {
Serial.println("PAUSE_LEFT");
stepper.setSpeed(0);
stepper.disableOutputs();
}
void do_pause_right() {
Serial.println("PAUSE_RIGHT");
stepper.setSpeed(0);
stepper.disableOutputs();
}
void do_stop_left() {
Serial.println("STOP_LEFT");
stepper.setSpeed(0);
stepper.disableOutputs();
}
void do_stop_right() {
Serial.println("STOP_RIGHT");
stepper.setSpeed(0);
stepper.disableOutputs();
}
void setup() {
stepper.setMaxSpeed(SPEED);
stepper.setSpeed(0);
digitalWrite(EndSwitchPin, INPUT_PULLUP);
rfSwitch.enableReceive(ReceiverInt);
Serial.begin(115200);
if (digitalRead(EndSwitchPin) == LOW) {
Serial.println("Endswitch activated. Please initialise manually.");
}
while (digitalRead(EndSwitchPin) == LOW) {
digitalWrite(LedPin, true);
delay(200);
digitalWrite(LedPin, false);
delay(200);
}
Serial.println("System Ok.");
Serial.println("[+] Listening");
flash_led();
}
// Endswitch state handling
int endSwitchState = HIGH;
int lastEndSwitchState = HIGH;
// Remote control command handling
long previousRCMillis = 0;
long RCinterval = 700;
// State machine
int state = STOP;
void loop() {
int command;
unsigned long currentMillis = millis();
if (currentMillis - previousRCMillis > RCinterval) {
if (rfSwitch.available()) {
switch (rfSwitch.getReceivedValue()) {
case D3_ON:
command = TURN_LEFT;
break;
case D3_OFF:
command = TURN_RIGHT;
break;
default:
command = 0;
}
rfSwitch.resetAvailable();
}
previousRCMillis = currentMillis;
}
// Falling edge detection for endswitches
endSwitchState = digitalRead(EndSwitchPin);
if (endSwitchState != lastEndSwitchState) {
if (endSwitchState == LOW) {
if (state == TURN_LEFT) {
command = STOP_LEFT;
}
if (state == TURN_RIGHT) {
command = STOP_RIGHT;
}
}
lastEndSwitchState = endSwitchState;
}
if (command != 0) {
switch (state) {
case STOP:
switch (command) {
case TURN_LEFT:
state = TURN_LEFT;
do_turn_left();
break;
case TURN_RIGHT:
state = TURN_RIGHT;
do_turn_right();
break;
}
break;
case TURN_LEFT:
switch (command) {
case TURN_LEFT:
state = PAUSE_LEFT;
do_pause_left();
break;
case STOP_LEFT:
state = STOP_LEFT;
do_stop_left();
break;
case TURN_RIGHT:
state = STOP;
do_stop();
break;
}
break;
case TURN_RIGHT:
switch (command) {
case TURN_RIGHT:
state = PAUSE_RIGHT;
do_pause_right();
break;
case STOP_RIGHT:
state = STOP_RIGHT;
do_stop_right();
break;
case TURN_LEFT:
state = STOP;
do_stop();
break;
}
break;
case STOP_LEFT:
switch (command) {
case TURN_RIGHT:
state = TURN_RIGHT;
do_turn_right();
break;
}
break;
case STOP_RIGHT:
switch (command) {
case TURN_LEFT:
state = TURN_LEFT;
do_turn_left();
break;
}
break;
case PAUSE_LEFT:
switch (command) {
case TURN_LEFT:
state = TURN_LEFT;
do_turn_left();
break;
case TURN_RIGHT:
state = STOP;
do_stop();
break;
}
break;
case PAUSE_RIGHT:
switch (command) {
case TURN_RIGHT:
state = TURN_RIGHT;
do_turn_right();
break;
case TURN_LEFT:
state = STOP;
do_stop();
break;
}
break;
}
}
stepper.runSpeed();
}
I monitored the SREG, EIMSK and EICRA registers when I send a command, while the motor runs and after the motor has stopped. (One of my thoughts was that the interrupt setting temporarily toggled for some reason)
They do not change, however.
Update:
When I replace 'stepper.runSpeed()' with 'delay(1)', 'delay(10)', 'delay(100)' or even 'delay(1000)', the statemachine reacts to the RC commands. I know stepper.runSpeed() returns very fast. Since a delay of 100ms already superceeds the time setSpeed() needs to return, this is weird.
Fresh start...
Forget arduino for the moment.
Setup the gate so that
While Relay1 is on the gate opens, Relay2 is disabled and then stops when fully open. It is very unreliable to use time as it can easily be mucked up by a power failure.
while opening, Relay1 OFF will stop the gate opening.
Relay2 is ON gate closes, Relay1 is disabled and the stops when fully closed.
While closing, Relay2 OFF will stop the gate closing.
Sensor Options:
A microswitch opens Relays to stop opening or closing
or a sensor of some sort is used to determine when the gate is fully open or closed
or the drive motor has a clutch and is designed to slip when fully closed or open. In this case a timer could be used instead of switches or sensors.
Once we fully understand the gate electrical, then we can dive into code.
Thanks for posting your code, but I can't figure it out. It seems far more complicated than I imagine to be necessary.
My mental picture is that there is a function readRemote() which saves a value picked up from the remote control and a function that reads all the current switch values. Then the function to open, close or stop the gate will act on that data.
I really do have in mind that the only code in loop() will be the code in Reply #11 - or maybe 2 or 3 lines more.
I stripped the code to a working minimum.
There still is a state machine as follows:
STOP -> TURN_LEFT <-> TURN_RIGHT
Also, I separated the RC code in a readRemote() function, to match your mental picture.
That's all there is.
The loop is now:
Listen for a matching RC command
If there is a matching RC command, execute the corresponding state (which is: Serial.println("name of the state"))
Step motor
There ar three states defined to be able to demonstrate the state changes (which currently do not work)
/*
#include <RCSwitch.h>
#include <AccelStepper.h>
#define D3_ON 5246997
#define D3_OFF 5246996
#define STOP 0
#define TURN_LEFT -2
#define TURN_RIGHT 2
int state = STOP; // Start state
AccelStepper stepper(8, 8, 10, 9, 11);
RCSwitch rfSwitch = RCSwitch(); // 434 receiver
void setup(void) {
stepper.setMaxSpeed(1000);
stepper.setSpeed(0);
rfSwitch.enableReceive(0);
Serial.begin(115200);
}
int readRemote() {
int command;
if (rfSwitch.available()) {
switch (rfSwitch.getReceivedValue()) {
case D3_ON:
Serial.println("command = TURN_LEFT");
command = TURN_LEFT;
break;
case D3_OFF:
Serial.println("command = TURN_RIGHT");
command = TURN_RIGHT;
break;
default:
command = 0;
}
rfSwitch.resetAvailable();
}
return command;
}
void loop(void) {
int command = readRemote();
if (command != 0) {
switch (state) {
case STOP:
switch (command) {
case TURN_LEFT:
state = TURN_LEFT;
Serial.println("state = TURN_LEFT");
break;
case TURN_RIGHT:
state = TURN_RIGHT;
Serial.println("state = TURN_RIGHT");
break;
}
break;
case TURN_LEFT:
switch (command) {
case TURN_RIGHT:
Serial.println("state = TURN_RIGHT");
break;
}
break;
case TURN_RIGHT:
switch (command) {
case TURN_LEFT:
state = STOP;
Serial.println("state = TURN_LEFT");
break;
}
break;
}
}
stepper.runSpeed();
}