I'm trying to run 2 different functions (A and B) sequentially, over and over 3 times and then move onto the next function "C". I've never done anything like this before and can't seem to find any good leads on either Google or the Arduino forums.
(I'm sorry for my bad explanation)
Example:
(Enter main loop)
Function A (Completes successfully the 1st time)>
Function B (Completes successfully the 1st time)>
Function A (Completes successfully the 2nd time)>
Function B (Completes successfully the 2nd time)>
Function A (Completes successfully the 3rd time)>
Function B (Completes successfully the 3rd time)>
Move onto function "C"
That'll go out of scope as soon as the function ends. I suspect @midnightsparks is looking for something that will 'remember' the count even if the function is called and exits several times.
@callthedutch Thank you for your feedback. I understand what you're saying. Okay, Ill try to edit something like that into my code. It looks like it would work.
thinking about it, not sure if you even need the if(acounter < 3) part, just increment the counter on success and run C to check it every time a or b succeeded and have c reset the counter (sorry just got out of bed, brain still starting up )
Can you expand on the difference between "how many times a function has been run" and "Completes successfully".
Completes successfully could mean it returns a flag indicating that the internal operations of the function were successful - opening a file on an SD card for example.
in proper script/syntax, basicly yes.
There are a few ways to implement the "theory", depends on the situation (don't forget to reset the boolean flags for function A and B )
THANK YOU guys for all your help and advice, I appreciate it!
@alto777 - I'm trying to code a "Finite State Machine" for a prototype I'm working on.
I've already tried using Yakindu (software specifically designed for creating "FSM's") to help me with the control structure of my code. Unfortunately, it's not really user friendly; the learning curve is pretty sharp.
This is essentially what I'm trying to accomplish.
@markd833 I was asking how to keep track of how many times a function (successfully) has run because some of them will need to be repeated over and over until a "complete" flag would indicate otherwise.
I like your SD card idea though to keep track of what "state" my machine is in if it's powered down. That would be helpful.
That was my experience as well. I didn't persevere, so it was just a short session with it, but it looked like a tool that would be very useful if you're actually intending to generate code directly from the tool etc. I only used it to model an FSM at a very basic level and ended up doing it in MS Excel instead.
Here's my code currently (it verifies good). I'm more concerned with getting the code's "control structure" correct. From there, I can tweak my functions as necessary.
I'm aware that my "void loop" section looks a bit funny. It's easier for me to read this way.
/*
//HARDWARE LIST
- Arduino Uno R3 (x1)
- Servo Motors (MG996R, x2)
- Parallax Continuious Rotation Servo Motor with Feedback Pin (x1)
- Adafruit INA219 Current Sensor (x2)
- Adafruit IR Sensor (x1)
- 4-Pin LED Module (x4)
*/
//---------------
//LIBRARIES
#include <Wire.h> //Used for the current monitors
#include <Adafruit_INA219.h> //Used for the INA219 current sensors
#include <Servo.h> //Used for Servo's 2 and 3
#include "FeedBackServo.h" //Used for Servo 1
//CURRENT MONITORS
Adafruit_INA219 ina219_1; //Instance for Servo1's current monitor
Adafruit_INA219 ina219_3; //Inmstance for Servo3's current monitor
//PARALLAX SERVO 1
const int FEEDBACK_PIN = 2; //Define feedback signal pin (Yellow wire)
const int SERVO_PIN = 3; //Define control pin (White wire)
FeedBackServo Servo_1 = FeedBackServo(FEEDBACK_PIN); //Servo_1 - Set feedback signal pin number
//SERVO 2 & SERVO 3
Servo Servo_2; //Instance for the servo motor 2
Servo Servo_3; //Instance for the servo motor 3
//IR SENSOR
const int IR_Sensor_Pin = 4; //Defines the IR sensor pin to pin 2
//LEDS
const int RED = 3; //PWM pin 3
const int GREEN = 5; //PWM pin 5
const int BLUE = 6; //PWM pin 6
//VARIABLES
const int Reset_Button_Pin = 8;
int Servo_1_Micro_Position_2_Count = 0;
int Servo_1_Position_1_Count = 0;
int Servo_1_Position_1_Dispensing_Count = 0;
int Servo_1_Position_2_Count = 0;
int Servo_1_Position_3_Count = 0;
int Servo_3_Position = 0;
//STATES
int IR_Sensor_State = HIGH; //HIGH = The natural "state" of the variable when the beam is unbroken
int Reset_Button_State = HIGH; //State of the Reset_Button without being pressed
//FLAGS
bool IR_Beam_Broken = false; //false = The natural "state" of the variable
bool Servo_1_Micro_Adjustments_Complete = false;
bool Servo_1_Micro_Position_2_Complete = false;
bool Servo_1_Position_1_Complete = false;
bool Servo_1_Position_2_Complete = false;
bool Servo_1_Position_3_Complete = false;
bool Servo_2_Forward_Complete = false;
bool Servo_2_Backward_Complete = false;
bool Servo_3_Slowly_Forward_Complete = false;
bool Servo_3_Backward_Complete = false;
bool Dispense_Bowls_Complete = false;
bool Maint_Light_Active_Complete = false;
bool Maint_Light_Inactive_Complete = false;
//---------------
void setup()
{
//Initialize Serial Monitor
Serial.begin(9600); //Initialize the serial monitor
//Initialize LED's
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
analogWrite(RED, 0);
analogWrite(GREEN, 0);
analogWrite(BLUE, 0);
//Initialize IR Sensor
pinMode(IR_Sensor_Pin, INPUT); //Initialize the IR sensor pin as an input
digitalWrite(IR_Sensor_Pin, HIGH); //Turn on the internal Arduino pullup resistor to set the sensor HIGH
//Initialize Current Sensors
ina219_1.begin(); //Start Servo 1's current module
ina219_3.begin(); //Start Servo 3's current module
uint32_t currentFrequency; //Part of the INA219 library. Not sure what this is for, but if I delete it, the current sensors wont work right
//Initialize Servo 1
Servo_1.setServoControl(SERVO_PIN); //Set Servo1 control pin number
Servo_1.setKp(1.0);
//Initialize Servo's 2 and 3
Servo_2.attach(10); //Attach servo 2 to PWM pin 10
Servo_3.attach(11); //Attach servo 3 to PWM pin 11
//Servo 3 Backward Setup
Servo_3_Backward_Setup();
//Servo 2 Backward Setup
Servo_2_Backward_Setup();
//Servo 2 Forward Setup
Servo_2_Forward_Setup();
//Servo 1 Position 1 Setup
Servo_1_Position_1_Setup();
}
//---------------
void loop()
{
IR_Beam();
if (IR_Beam_Broken = true);
{
Servo_3_Slowly_Forward();
if (Servo_3_Slowly_Forward_Complete = true);
{
Servo_2_Backward();
if (Servo_2_Backward_Complete = true);
{
Servo_1_Micro_Adjustments();
if (Servo_1_Micro_Position_2_Complete = true);
{
Servo_1_Micro_Position_2_Count++;
}
if (Servo_1_Position_1_Complete = true)
{
Servo_1_Position_1_Count++;
}
if ((Servo_1_Micro_Position_2_Count == 3) && (Servo_1_Position_1_Count == 3));
{
Servo_1_Micro_Adjustments_Complete = true;
}
if (Servo_1_Micro_Adjustments_Complete = true)
{
Servo_2_Forward();
if (Servo_2_Forward_Complete = true)
{
Servo_3_Backward();
if (Servo_3_Backward_Complete = true)
{
Dispense_12_Bowls();
if (Servo_1_Position_2_Complete = true);
{
Servo_1_Position_2_Count++;
}
if (Servo_1_Position_1_Complete = true);
{
Servo_1_Position_1_Dispensing_Count++;
}
if ((Servo_1_Position_2_Count == 12) && (Servo_1_Position_1_Count == 12));
{
Dispense_Bowls_Complete = true;
}
if (Dispense_Bowls_Complete = true)
{
Reset_All_Flags(); //End of loop
}
}
}
}
}
}
}
}
//---------------
//SETUP FUNCTION LIST
void Servo_3_Backward_Setup()
{
Servo_3.write(0); //Move Servo 3 backward to 0 degrees
delay(1500);
//Create an if statement here to determine if Servo 3 moved backward sucessfully
Serial.println("Servo 3 Backward Setup completed successfully");
Serial.println();
}
void Servo_2_Backward_Setup()
{
Servo_2.write(0); //Move Servo 2 backward to 0 degrees
delay(1500);
Serial.println("Servo 2 Backward Setup completed successfully");
Serial.println();
}
void Servo_2_Forward_Setup()
{
Servo_2.write(180); //Move Servo 2 forward to 180 degrees
delay(1500);
Serial.println("Servo 2 Forward Setup completed successfully");
Serial.println();
}
void Servo_1_Position_1_Setup()
{
Servo_1.rotate(0, 4); //Rotate to 0 degrees + - 4 degrees
Serial.println("Servo_1_Position_1_Setup completed successfully");
Serial.println();
}
//---------------
//LOOP FUNCTION LIST
void IR_Beam() //Check the IR beam's "state"
{
if (IR_Sensor_State == LOW) //LOW = The IR beam is broken
{
Serial.println("The IR beam is broken");
Serial.println();
IR_Beam_Broken = true;
}
else (IR_Sensor_State == HIGH); //HIGH = The IR beam is unbroken
{
return; //Would this exit the function keep looping until the "IR_Sensor_State" changes from HIGH to LOW?
}
}
void Servo_1_Position_1()
{
Servo_1.rotate(0, 4); //Rotate to 0 degrees + - 4 degrees
//Create an if statement here to determine if servo 1 moved sucessfully to position 1
Serial.println("Servo 1 Position 1 completed successfully");
Serial.println();
Servo_1_Position_1_Complete = true;
}
void Servo_1_Micro_Position_2()
{
Servo_1.rotate(35, 4); //Rotate to 35 degrees + - 4 degrees
//Create an if statement to determine if servo 1 moved sucessfully to micro-position 1
Serial.println("Servo 1 Micro Position 1 has completed successfully");
Serial.println();
Servo_1_Micro_Position_2_Complete = true;
}
void Servo_1_Position_2()
{
Servo_1.rotate(175, 4); //Rotate to 175 degrees + - 4 degrees
//Create an if statement here to determine if servo 1 moved sucessfully to position 2
Serial.println("Servo 1 Position 2 completed successfully");
Serial.println();
Servo_1_Position_2_Complete = true;
}
void Servo_1_Position_3()
{
Servo_1.rotate(220, 4); //Rotate to 220 degrees + - 4 degrees
//Create an if statement here to determine if Servo 1 moved sucessfully to position 3
Serial.println("Servo 1 Position 2 completed successfully");
Serial.println();
Servo_1_Position_2_Complete = true;
}
void Servo_2_Forward()
{
Servo_2.write(180); //Move Servo 2 forward to 180 degrees
delay(1500);
//Create an if statement here to determine if Servo 1 moved sucessfully to position 3
Serial.println("Servo 2 Forward completed successfully");
Serial.println();
Servo_2_Forward_Complete = true;
}
void Servo_2_Partially_Backward()
{
Servo_2.write(150); //Move Servo 2 backward 30 degrees
delay(1500);
//Create an if statement here to determine if Servo 2 moved successfully
Serial.println("Servo 2 Forward completed successfully");
Serial.println();
Servo_2_Forward_Complete = true;
}
void Servo_2_Backward()
{
Servo_2.write(0); //Move Servo 2 backward to 0 degrees
delay(1500);
Serial.println("Servo_2_Backward completed successfully");
Serial.println();
Servo_2_Backward_Complete = true;
}
void Servo_3_Slowly_Forward() //Servo 3 slowly goes from 0 degrees to 180 degrees in increments of 1 degree at a time
{
for (Servo_3_Position = 0; Servo_3_Position <= 180; Servo_3_Position += 1)
{
Servo_3.write(Servo_3_Position); //Move Servo 3 to 'Servo_3_Position'
float current_mA = 0; //This is for the current monitor
current_mA = ina219_3.getCurrent_mA(); //This is for the current monitor
Serial.print("Servo 3 Forward: ");
Serial.print(current_mA); //Serial print "current_mA"
Serial.println(" mA"); //Serial print "mA"
Serial.print("Degree: ");
Serial.println(Servo_3_Position); //Serial print "Servo_3_Position"
Serial.println();
delay(15); //Controls Servo 3's rotational speed from 1 degree to the next. Example: Going from 1 degree to 2 degrees has a 15ms delay in between each degree
if ((current_mA) >= 120.00 && Servo_3_Position > 15) //If the current monitor detects a value greater than or equal to 120.00 and has a degree greater than 15. This eliminates the chance of a false flag due to the initial current inrush when Servo_3 starts.
{
delay(1);
Serial.println("Servo 3 Slowly Forward - FLAG #1 - Failed to move forward successfully");
Serial.println();
float current_mA = 0; //This is for the current monitor
current_mA = ina219_3.getCurrent_mA(); //This is for the current monitor
Serial.print("Servo 3 Forward: ");
Serial.print(current_mA); //Serial print "current_mA"
Serial.println(" mA"); //Serial print "mA"
Serial.print("Degree: ");
Serial.println(Servo_3_Position); //Serial print "Servo_3_Position"
Serial.println();
if ((current_mA) >= 120.00) //If the current monitor detects a value greater than or equal to 120.00 for the 2nd time
{
delay(1);
Serial.println("Servo 3 Slowly Forward - FLAG #2 - Failed to move forward successfully");
Serial.println();
float current_mA = 0; //This is for the current monitor
current_mA = ina219_3.getCurrent_mA(); //This is for the current monitor
Serial.print("Servo 3 Forward: ");
Serial.print(current_mA); //Serial print "current_mA"
Serial.println(" mA"); //Serial print "mA"
Serial.print("Degree: ");
Serial.println(Servo_3_Position); //Serial print "Servo 3 Position"
Serial.println();
if ((current_mA) >= 120.00) //If the current monitor detects a value greater than or equal to 120.00 for the 3rd time
{
Serial.println("Servo 3 Slowly Forward - FLAG #3 - Failed to move forward successfully");
Serial.println();
float current_mA = 0; //This is for the current monitor
current_mA = ina219_3.getCurrent_mA(); //This is for the current monitor
Serial.print("Servo 3 Forward: ");
Serial.print(current_mA); //Serial print "current_mA"
Serial.println(" mA"); //Serial print "mA"
Serial.print("Degree: ");
Serial.println(Servo_3_Position); //Serial print the variable "Servo_3_Position"
Serial.println();
if ((current_mA) >= 120.00) //If the current monitor detects a value greater than or equal to 120.00 for the 4th time
{
Servo_3.detach(); //Disconnect Servo 3 from PWM pin 9
Blue_LEDs_On(); //Turn on the blue LED's
Serial.println("Servo 3 Slowly Forward - Flag #4 - Software Reset");
Serial.println();
delay(1500);
Reset_All_Flags();
Software_Reset();
}
}
}
}
}
Serial.print("////////////////////////////////////"); //Print a dividing line for easy viewing
Serial.println();
Serial.println();
delay(1000);
Serial.println("Servo 3 Slowly Forward has completed successfully");
Serial.println();
Servo_3_Slowly_Forward_Complete = true;
}
void Servo_3_Backward()
{
Servo_3.write(0); //Move Servo 3 backward to 0 degrees
delay(1500);
//Create an if statement to determine if Servo 3 moved backward sucessfully
Serial.println("Servo 3 Backward Setup completed successfully");
Serial.println();
}
//---------------
//MISC. FUNCTIONS
void Servo_1_Micro_Adjustments()
{
Servo_1_Micro_Position_2();
Servo_1_Position_1();
}
void Dispense_12_Bowls()
{
Servo_1_Position_2();
Servo_1_Position_1();
}
void Green_LEDs_On()
{
analogWrite(RED, 0); //Off
analogWrite(GREEN, 255); //On - Max value
analogWrite(BLUE, 0); //Off
}
void Yellow_LEDs_On()
{
analogWrite(RED, 255); //On - Max value
analogWrite(GREEN, 155); //On
analogWrite(BLUE, 0); //Off
}
void Red_LEDs_On()
{
analogWrite(RED, 255); //ON - Max value
analogWrite(GREEN, 0); //Off
analogWrite(BLUE, 0); //Off
}
void Blue_LEDs_On()
{
analogWrite(RED, 0); //Off
analogWrite(GREEN, 0); //Off
analogWrite(BLUE, 255); //On - Max Value
}
void LEDs_Off()
{
analogWrite(RED, 0); //Off
analogWrite(GREEN, 0); //Off
analogWrite(BLUE, 0); //Off
}
void Maint_Light_Active()
{
Blue_LEDs_On();
Servo_2.detach();
Servo_3.detach();
Serial.println("The Maintenance Light has been activated");
Serial.println();
Maint_Light_Active_Complete = true;
//Add code to check if the maintenance bypass key has been used. If so, call Maint_Light_Inactive
}
void Maint_Light_Inactive()
{
//Code to watch if the maint key has been used, if so:
LEDs_Off();
Serial.println("The Maintenance Light has been deactivated");
Serial.println();
Maint_Light_Inactive_Complete = true;
Software_Reset();
}
void Reset_Button()
{
//Add code here to check to see if the reset button has been pressed
}
void Software_Reset()
{
//Add code here to reset the Arduino via software command
}
void Reset_All_Flags()
{
bool IR_Beam_Broken = false; //false = The natural "state" of the variable
bool Servo_1_Micro_Adjustments_Complete = false;
bool Servo_1_Micro_Position_2_Complete = false;
bool Servo_1_Position_1_Complete = false;
bool Servo_1_Position_2_Complete = false;
bool Servo_1_Position_3_Complete = false;
bool Servo_2_Forward_Complete = false;
bool Servo_2_Backward_Complete = false;
bool Servo_3_Slowly_Forward_Complete = false;
bool Servo_3_Backward_Complete = false;
bool Dispense_Bowls_Complete = false;
bool Maint_Light_Active_Complete = false;
bool Maint_Light_Inactive_Complete = false;
}
Fine, but it didn't create pretty pictures or anything. Basically I just made a worksheet with all the distinct states, then another worksheet with a list of routes that defines 'from state', 'to state' and 'action' which basically determines the behavior of the system. I used it to auto-generate arrays and structs so I didn't have to type them by hand. Worked like a charm for the most part; the only annoying parts were the way Excel adds double quotes if you copy-paste stuff to another app and the character limit for the contents of a single cell. Otherwise it was quite convenient. I basically wrote a generic state machine library (actually, a collection of libraries) that perform all fundamental tasks and I could define machine behavior in terms of which outputs to activate at what point etc. by adding lines in the Excel sheet. So none of the actual states, inputs or outputs are hardcoded apart from a few configuration files that contain the auto-generated code from Excel.
Note that the Excel stuff wasn't a substitute for a 2D flow chart, but an intermediary step between the flow chart and the actual C++ code. You could of course take the 'routes' worksheet and turn it into a flowchart pretty easily - or vice versa. That's what Yakindu essentially does as well, but it's a bit bloated if you want to keep your project somewhat basic.