Minor Biorobotics 2016 Demo of a possible state machine implementation.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
megrootens
Date:
Fri Oct 28 13:55:21 2016 +0000
Commit message:
Minor Biorobotics example State Machine

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Oct 28 13:55:21 2016 +0000
@@ -0,0 +1,253 @@
+/**
+ * Minor BioRobotics 2016
+ * M.E. Grootens [at] utwente.nl,
+ *
+ * Example code for a 'state machine' with four states:
+ *  - 'Off'                 (LEDs off)
+ *  - 'Calibration'         (Blinking red LED)
+ *  - 'Ready'               (Continues green LED)
+ *  - 'Motion control'      (Blinking blue LED)
+ *
+ * The user can use SW2 to  switch the state:
+ *  - from 'Off' we switch to 'Calibration'
+ *  - from 'Ready' we go to 'Motion control'
+ *  - If the user presses SW2 during another state (i.e. either 'Calibration' or 
+ *      'Motion control'), we switch to 'Off'
+ *  
+ * The 'Calibration' state is finished automatically, after which the machine
+ * goes into 'Ready' state.
+ *
+ * This is just an example of a _possible_ way to create a state machine; there
+ * are endless possibilities
+ */
+
+#include "mbed.h"
+
+// Serial communication
+#define SERIAL_TX           USBTX
+#define SERIAL_RX           USBRX
+#define SERIAL_BAUD         115200
+
+// Interrupt switches
+#define SW_STATE            SW2
+
+// LEDs
+#define LED_READY           LED_GREEN
+#define LED_CALIBRATION     LED_RED
+#define LED_MOTION_CTRL     LED_BLUE
+#define LED_ON              false
+
+/*__ USER IO _________________________________________________________________*/
+ 
+// Serial communication
+Serial serial(SERIAL_TX, SERIAL_RX);
+
+// User interrupt to witch state
+InterruptIn sw_state(SW_STATE);
+
+// LEDs to display state
+DigitalOut led_ready(LED_READY);
+DigitalOut led_calibration(LED_CALIBRATION);
+DigitalOut led_motion_ctrl(LED_MOTION_CTRL);
+
+/*__ TIMING / SETTINGS _______________________________________________________*/
+
+// 'Control'
+const float kPeriodControl = 0.5f;  // 2 Hz 'control' loop
+Ticker tick_control;                // Control ticker
+
+// 'Calibration'
+const int kNumCalibrations = 6;     // Number of times Calibration() is executed
+int i_calibration = 0;              // Counter
+
+
+
+/*__ SYSTEM STATES ___________________________________________________________*/
+
+// Definition of system states
+enum State {OFF, CALIBRATION, READY, MOTION_CONTROL};
+
+// Initial state is OFF
+State state_current = OFF;
+
+/**
+ * Get the name of the State
+ * @param state, State of which we want to know the name
+ * @return char array that contains the name of the State
+ */
+char* StateName(State state)
+{
+    switch(state) {
+        case OFF:               return "Off";
+        case CALIBRATION:       return "Calibration";
+        case READY:             return "Ready";
+        case MOTION_CONTROL:    return "Motion Control";
+        default:                return "_UNKNOWN_";
+    }
+}
+
+
+
+/**
+ * Set the new state and print the change to terminal
+ *
+ * Also do 'resets' if needed
+ *  - If we go into calibration mode, we need to reset the counter
+ *
+ * __Only allow to change the state through this function__
+ *
+ * @param state_new new state to be set
+ * @ensure state_current == state_new
+ */
+void SetNewState(State state_new)
+{
+    serial.printf("\r\n[New State: %s (previous: %s)]\r\n",
+        StateName(state_new), StateName(state_current));
+    state_current = state_new;
+    
+    switch (state_new) {
+        case CALIBRATION: {
+            i_calibration = 0;
+            break;
+        } 
+        default: break;
+    }
+}
+
+/**
+ * Switches the state; called by user interrupt from SW2
+ * The new state depends on the current state; read the switch statements
+ */
+void ToggleState()
+{
+    serial.printf("\r\n<User interrupt>\r\n");
+    switch (state_current) {
+        case OFF: {
+            // If the machine is off, then the user wants to start the machine,
+            // but it first needs to be 'calibrated'.
+            SetNewState(CALIBRATION);
+            break;
+        }
+        case READY: {
+            // If the system is ready (after 'calibration'), the user wants to
+            // start 'motion control'
+            SetNewState(MOTION_CONTROL);
+            break;
+        }
+        default: {
+            // If the user presses the button during 'calibration' _or_ 'motion
+            // control', he wants to turn the machine off.
+            SetNewState(OFF);
+            break;
+        }
+    }
+}
+
+/*__ FAKE CALIBRATION AND CONTROL FUNCTIONS __________________________________*/
+
+/**
+ * Fake calibration function.
+ * - Blinks the LED for a specified number of times
+ * - Then switches to 'ready' mode.
+ */
+void Calibration()
+{
+    // LED display
+    led_calibration = !led_calibration;
+    led_ready = !LED_ON;
+    led_motion_ctrl = !LED_ON;
+    
+    // Printing calibration status
+    if (i_calibration==0) {
+        serial.printf("\r\nCalibrating...");
+    }
+    
+    ++i_calibration; // count number of calibration steps
+    serial.printf("%d...",i_calibration);
+    
+    if (i_calibration>=kNumCalibrations) {
+        // finished, so switch state
+        serial.printf("ready\r\n");
+        SetNewState(READY);
+    }
+    
+}
+
+/**
+ * Fake motion control function; blinks a LED
+ */
+void MotionControl()
+{
+    led_calibration = not LED_ON;
+    led_ready = not LED_ON;
+    led_motion_ctrl = !led_motion_ctrl;
+}
+
+/*__ MACHINE FUNCTION DEPENDS ON CURRENT STATE _______________________________*/
+
+/**
+ * 'Control' function that is called by a Ticker.
+ * Depending on the current state, the machine carries out a different task
+ */
+void Control()
+{
+    switch(state_current) {
+        case CALIBRATION: {
+            Calibration();
+            break;
+        }
+        case MOTION_CONTROL: {
+            MotionControl();
+            break;
+        }
+        case READY: {
+            // Ready state is shown by continuous green LED
+            led_calibration = !LED_ON;
+            led_ready       =  LED_ON;
+            led_motion_ctrl = !LED_ON;
+            break;
+        }
+        default: {
+            // Off state is shown by all LEDs off
+            led_calibration = !LED_ON;
+            led_ready       = !LED_ON;
+            led_motion_ctrl = !LED_ON;
+            break;
+        }
+    }
+}
+
+/*__ MAIN FUNCTION ___________________________________________________________*/
+
+/**
+ * Main / initialization function
+ *  - Switch off LEDs
+ *  - Serial comm
+ *  - Attach interrupts
+ *  - Start control ticker
+ */
+int main()
+{
+    // Turn off LEDs
+    state_current = OFF;
+    Control();
+    
+    // Serial baud
+    serial.baud(SERIAL_BAUD);
+    
+    serial.printf("\r\n**STARTING STATE MACHINE DEMO**\r\n");
+    
+    // Interrupt
+    sw_state.fall(&ToggleState);
+    
+    serial.printf("- Interrupts attached\r\n");
+    
+    // Ticker
+    tick_control.attach(&Control, kPeriodControl);
+    
+    serial.printf("- Tickers attached\r\n");
+    serial.printf("Ready. Awaiting user input through SW2...\r\n\r\n");
+    
+    // Infinite loop
+    while (true);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Oct 28 13:55:21 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/9bcdf88f62b0
\ No newline at end of file