The project I'm working on uses an Arduino UNO R3, and has 4 buttons (non-toggle) to grip a ball using suction cups, then fire the ball out of the suction cups using a ram (powered by an actuator), the ball then bounces against a surface then the suction cups catch the ball on its return.
This project currently runs on a PLC but we're attempting to make it work on an arduino.
The buttons do 4 different things:
Start (Starts the vacuum cups, at which point the ball is placed into the cups)
Fire (Fires the actuator and disengages the vacuum cups)
Toggle (Switches between a continuous mode and a single fire mode)
Stop (Stops the process)
The start and fire buttons both have a loop each, as Start is expected to happen before all else, Then Fire.
Toggle and Stop both utilise the interrupt processes, so can be called at any time. I have posted the code below.
// Initialise Pins and Variables:::::::::::::::::::::::::::::::::::::::::::::::::
const int actuatorPin = 4;
const int vacuumPin = 5;
const int firePin = 6;
const int resetPin = 7;
const int startPin = 8;
const int ledPin = 9;
int bounceMode = LOW; // 1 = singlefire, 0 = multifire
int startRead = LOW;
int fireRead = LOW;
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Begin Program Setup:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
void setup()
{
Serial.begin(9600); // check the baud rate for the Pi
digitalWrite(actuatorPin, LOW);
digitalWrite(vacuumPin, LOW);
digitalWrite(startPin, LOW);
digitalWrite(ledPin, HIGH);
attachInterrupt (0, toggle, RISING); // Modechange Interrupt Handler (pin 2)
attachInterrupt (1, STOP, RISING); // STOP Interrupt Handler (pin 3)
}
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Fire Mode Interrupt Process:::::::::::::::::::::::::::::::::::::::::::::::::::
void toggle()
{
if (bounceMode==LOW){
bounceMode=HIGH;
Serial.println("Bounce Mode = Single Shot");
}
else{
bounceMode=LOW;
Serial.println("Bounce Mode = Continuous");
}
delay(1000);
}
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Start initial loop (detecting start button press):::::::::::::::::::::::::::::
void loop() {
startRead = digitalRead(startPin);
if (startRead==HIGH){
Serial.println("Vacuum = On");
digitalWrite(vacuumPin, HIGH); // Turns Vacuum on
wait4fire(); // This line to next function
}
else {
startRead = LOW;
}
}
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Function to wait for fire button Press::::::::::::::::::::::::::::::::::::::::
void wait4fire(){
fireRead = digitalRead(firePin);
if (fireRead==HIGH){
Serial.println("Ball Fire Detected");
if (bounceMode==LOW){
continuous(); // This line to next function
Serial.println("Continuous Mode Enabled");
}
else{
singleshot(); // This line to next function
Serial.println("Single Shot Mode Enabled");
}
}
else{
fireRead==LOW;
}
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Function to perform continous bouncing:::::::::::::::::::::::::::::::::::::::
void continuous() {
digitalWrite(vacuumPin, LOW);
digitalWrite(actuatorPin, HIGH);
delay(100); // Wait until actuator is at full extension
digitalWrite(actuatorPin, LOW);
delay(200);
digitalWrite(vacuumPin, HIGH);
delay(1000); // Look into this line if you want speed change
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Function to perform single shot bounce:::::::::::::::::::::::::::::::::::::::
void singleshot() {
digitalWrite(vacuumPin, LOW);
digitalWrite(actuatorPin, HIGH);
delay(100); // Wait until actuator is at full extension
digitalWrite(actuatorPin, LOW);
delay(200);
digitalWrite(vacuumPin, HIGH);
wait4fire();
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Interrupt Stop Function::::::::::::::::::::::::::::::::::::::::::::::::::::::
void STOP(){
digitalWrite(vacuumPin, LOW);
digitalWrite(vacuumPin, LOW);
loop();
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
I have not yet hooked up the actuator and vacuum components to the arduino yet as we are waiting on some 24V relays, so I was hoping I could monitor the program through the serial input, However, after connecting up the wires via a breadboard, the serial monitor doesn't report anything back when the buttons are pressed.
I was hoping for a second set of eyes on my code to see if there were any glaring mistakes or anything missing?
The buttons are on a large pendant controller which I think is debounced. There is a primary earth signal from the controller, and each of the switches require a live input, which is then earthed upon a button press.
Interrupts are one way, but if the processor isn't wasting all its time in "delay()" (have a look at the blink without delay example for clues), then it has plenty of time to monitor slow events, like buttons being pressed or switches being thrown.
AWOL:
If you write it without using "delay()", you can probably get rid of the interrupts too.
How would you go about doing this? I thought interrupts would be the only way to recognise the button presses from anywhere in the program.
The basic techniques are covered in the blink without delay tutorial (http://arduino.cc/en/Tutorial/BlinkWithoutDelay). However, I tend to think that tutorial doesn't go far enough to help people asking these types of questions. What you want is a state machine, that says what state each of the things you are controlling are, and when to go to the next state. Every time through loop, you check whether it is time to go to the next state. If not, do nothing. If it is do the action, advance the state, and set the time to go to the next action N milliseconds from now.
Thanks for all the help guys, I've taken out most of the delay functions, just have to test them now.
One thing I was wondering though... once the stop button is pressed, it still calls an interrupt, but I want that interrupt to reset the program completely, is that possible?
Heimdallofasgard:
Thanks for all the help guys, I've taken out most of the delay functions, just have to test them now.
One thing I was wondering though... once the stop button is pressed, it still calls an interrupt, but I want that interrupt to reset the program completely, is that possible?
The simplest thing is just to have stop reset all of the state variables (or reset the state variables after shutting things down gracefully).
You could always wire the stop to the reset button, but you probably want to stop things more gracefully and not have to wait for the bootloader code to timeout waiting for new programs.
I can make the stop interrupt reset all the state variables, but after that, I just want it to go back to the main loop() function and wait there. But I can't call loop() directly (as someone said above)
If you implement a state machine then the first state would be waiting for the Start button to be pressed. If, when you press the Stop button, you set the state variable to the first state then it will effectively make the program go back to the start.
The first thing to do is to decide how many states you need, the actions to be taken whilst in each state, what the conditions are to move to another state and what that next state will be.
I can't see why not. Your program basically has 2 states
state 0 - waiting for the start or toggle buttons with the vacuum off
state 1 - start button has been pressed. Ball is in the cups waiting for fire, toggle or stop
When in state 0
Pressing start moves to state 1 and turns on the vacuum.
Pressing toggle changes the mode flag but stays in state 0 leaving the vacuum off
When in state 1
Pressing fire disengages the vacuum and fires the ball. If the mode is continuous the vacuum is turned on after firing the ball and the program stays in state 1. If the mode is single the vacuum is turned off after firing the ball and the program moves to state 0. Pressing toggle changes the mode flag and stays in state 1 with the vacuum on.
Pressing stop turns off the vacuum and moves to state 0
To do this you need to eliminate the use of all blocking code such as delay() so that key presses can be responded to in either state.