Example project

Dependencies:   PM2_Libary Eigen

Revision:
39:f336caef17d9
Parent:
36:23addefb97af
Child:
40:924bdbc33391
--- a/main.cpp	Tue May 10 11:18:33 2022 +0200
+++ b/main.cpp	Tue May 10 14:11:06 2022 +0200
@@ -1,70 +1,217 @@
-/*
- * Main.cpp
- * Copyright (c) 2022, ZHAW
- * All rights reserved.
- */
-
 #include <stdio.h>
 #include <mbed.h>
 #include "IRSensor.h"
 #include "EncoderCounterROME2.h"
 #include "Controller.h"
-#include "StateMachine.h"
+
+// logical variable main task
+bool do_execute_main_task = false;  // this variable will be toggled via the user button (blue button) to or not to execute the main task
+
+// user button on nucleo board
+Timer user_button_timer;            // create Timer object which we use to check if user button was pressed for a certain time (robust against signal bouncing)
+InterruptIn user_button(BUTTON1);   // create InterruptIn interface object to evaluate user button falling and rising edge (no blocking code in ISR)
+void user_button_pressed_fcn();     // custom functions which gets executed when user button gets pressed and released, definition below
+void user_button_released_fcn();
+
+// while loop gets executed every main_task_period_ms milliseconds
+int main_task_period_ms = 50;   // define main task period time in ms e.g. 50 ms -> main task runns 20 times per second
+Timer main_task_timer;          // create Timer object which we use to run the main task every main task period time in ms
+
+// led on nucleo board
+DigitalOut user_led(LED1);      // create DigitalOut object to command user led
+
+static const int ROBOT_OFF = 0;      // discrete states of this state machine
+static const int MOVE_FORWARD = 1;
+static const int TURN_LEFT = 2;
+static const int TURN_RIGHT = 3;
+static const int SLOWING_DOWN = 4;
+
+const float DISTANCE_THRESHOLD = 0.4f;        // minimum allowed distance to obstacle in [m]
+const float TRANSLATIONAL_VELOCITY = 1.0f;    // translational velocity in [m/s]
+const float ROTATIONAL_VELOCITY = 1.0f;       // rotational velocity in [rad/s]
+const float VELOCITY_THRESHOLD = 0.01;        // velocity threshold before switching off, in [m/s] and [rad/s]
+
+DigitalOut led0(PD_4);
+DigitalOut led1(PD_3);
+DigitalOut led2(PD_6);
+DigitalOut led3(PD_2);
+DigitalOut led4(PD_7);
+DigitalOut led5(PD_5);
+
+// create IR sensor objects  
+AnalogIn dist(PA_0);
+DigitalOut enable(PG_1);
+DigitalOut bit0(PF_0);
+DigitalOut bit1(PF_1);
+DigitalOut bit2(PF_2);
+
+IRSensor irSensor0(dist, bit0, bit1, bit2, 0);
+IRSensor irSensor1(dist, bit0, bit1, bit2, 1);
+IRSensor irSensor2(dist, bit0, bit1, bit2, 2);
+IRSensor irSensor3(dist, bit0, bit1, bit2, 3);
+IRSensor irSensor4(dist, bit0, bit1, bit2, 4);
+IRSensor irSensor5(dist, bit0, bit1, bit2, 5);
+
+// create motor control objects   
+DigitalOut enableMotorDriver(PG_0); 
+DigitalIn motorDriverFault(PD_1);
+DigitalIn motorDriverWarning(PD_0);
+PwmOut pwmLeft(PF_9);
+PwmOut pwmRight(PF_8);
+EncoderCounterROME2 counterLeft(PD_12, PD_13);
+EncoderCounterROME2 counterRight(PB_4, PC_7);
+
+int state;
+// create robot controller objects
+Controller controller(pwmLeft, pwmRight, counterLeft, counterRight);
+// StateMachine stateMachine(controller, enableMotorDriver, led0, led1, led2, led3, led4, led5, button, irSensor0, irSensor1, irSensor2, irSensor3, irSensor4, irSensor5);
 
 int main() {
-    
-    // create miscellaneous periphery objects
-    
-    DigitalIn button(BUTTON1);
-    DigitalOut led(LED1);
-    
-    DigitalOut led0(PD_4);
-    DigitalOut led1(PD_3);
-    DigitalOut led2(PD_6);
-    DigitalOut led3(PD_2);
-    DigitalOut led4(PD_7);
-    DigitalOut led5(PD_5);
+
+    // attach button fall and rise functions to user button object
+    user_button.fall(&user_button_pressed_fcn);
+    user_button.rise(&user_button_released_fcn);
     
-    // create IR sensor objects
-    
-    AnalogIn distance(PA_0);
-    DigitalOut enable(PG_1);
-    DigitalOut bit0(PF_0);
-    DigitalOut bit1(PF_1);
-    DigitalOut bit2(PF_2);
-    
-    IRSensor irSensor0(distance, bit0, bit1, bit2, 0);
-    IRSensor irSensor1(distance, bit0, bit1, bit2, 1);
-    IRSensor irSensor2(distance, bit0, bit1, bit2, 2);
-    IRSensor irSensor3(distance, bit0, bit1, bit2, 3);
-    IRSensor irSensor4(distance, bit0, bit1, bit2, 4);
-    IRSensor irSensor5(distance, bit0, bit1, bit2, 5);
-    
+    // start timer
+    main_task_timer.start();
+        
     enable = 1;
     
-    // create motor control objects
-    
-    DigitalOut enableMotorDriver(PG_0); 
-    DigitalIn motorDriverFault(PD_1);
-    DigitalIn motorDriverWarning(PD_0);
-    
-    PwmOut pwmLeft(PF_9);
-    PwmOut pwmRight(PF_8);
+    enableMotorDriver = 0;
+    state = ROBOT_OFF;
     
-    EncoderCounterROME2 counterLeft(PD_12, PD_13);
-    EncoderCounterROME2 counterRight(PB_4, PC_7);
-    
-    // create robot controller objects
-    
-    Controller controller(pwmLeft, pwmRight, counterLeft, counterRight);
-    StateMachine stateMachine(controller, enableMotorDriver, led0, led1, led2, led3, led4, led5, button, irSensor0, irSensor1, irSensor2, irSensor3, irSensor4, irSensor5);
-    
-    while (true) {
+    while (true) { // this loop will run forever
         
-        led = !led;
+        main_task_timer.reset();
+
+        // set the leds based on distance measurements
+        led0 = irSensor0 < DISTANCE_THRESHOLD;
+        led1 = irSensor1 < DISTANCE_THRESHOLD;
+        led2 = irSensor2 < DISTANCE_THRESHOLD;
+        led3 = irSensor3 < DISTANCE_THRESHOLD;
+        led4 = irSensor4 < DISTANCE_THRESHOLD;
+        led5 = irSensor5 < DISTANCE_THRESHOLD;
+
+        switch (state) {
+            
+            // enables Motors, sets translational speed and switches to MOVE_FORWARD
+            case ROBOT_OFF:     
+                printf("   ROBOT_OFF\r\n");      
+                if (do_execute_main_task) {
+                    enableMotorDriver = 1;
+                    controller.setTranslationalVelocity(TRANSLATIONAL_VELOCITY);
+                    controller.setRotationalVelocity(0.0f);
+                    state = MOVE_FORWARD;
+                }
+                break;
+
+            // continue here    
+            case MOVE_FORWARD:
+                if (!do_execute_main_task) {
+                    controller.setTranslationalVelocity(0);
+                    controller.setRotationalVelocity(0);
+                    state = SLOWING_DOWN;
+                    printf("state = SLOWING_DOWN\r\n");
+                    break;
+                }
+             
+                if (irSensor2 < DISTANCE_THRESHOLD && irSensor2 < DISTANCE_THRESHOLD) {
+                    controller.setTranslationalVelocity(-TRANSLATIONAL_VELOCITY/2);
+                    controller.setRotationalVelocity(-ROTATIONAL_VELOCITY);
+                    state = TURN_RIGHT;
+                    printf("state = TURN_RIGHT\r\n");
+                    break;
+                } else if (irSensor4 < DISTANCE_THRESHOLD && irSensor4 < DISTANCE_THRESHOLD) {
+                    controller.setTranslationalVelocity(-TRANSLATIONAL_VELOCITY/2);
+                    controller.setRotationalVelocity(ROTATIONAL_VELOCITY);
+                    state = TURN_LEFT;
+                    printf("state = TURN_LEFT\r\n");
+                    break;
+                } else if (irSensor3 < DISTANCE_THRESHOLD/2) {
+                    controller.setTranslationalVelocity(-TRANSLATIONAL_VELOCITY);
+                    controller.setRotationalVelocity(-ROTATIONAL_VELOCITY);
+                    state = TURN_RIGHT;
+                    printf("state = TURN_RIGHT\r\n");
+                    break;
+                }
+                
+                break;
+                
+            case TURN_LEFT:
+                if (!do_execute_main_task) {
+                    controller.setTranslationalVelocity(0);
+                    controller.setRotationalVelocity(0);
+                    state = SLOWING_DOWN;
+                    break;
+                }
+
+                if ( (irSensor2 > DISTANCE_THRESHOLD) && (irSensor3 > DISTANCE_THRESHOLD) && (irSensor4 > DISTANCE_THRESHOLD) ) {
+                    controller.setRotationalVelocity(0);
+                    controller.setTranslationalVelocity(TRANSLATIONAL_VELOCITY);
+                    state = MOVE_FORWARD;
+                    break;
+                }
+                break;
+                
+            case TURN_RIGHT:  
+                if (!do_execute_main_task) {
+                    controller.setTranslationalVelocity(0);
+                    controller.setRotationalVelocity(0);
+                    state = SLOWING_DOWN;
+                    break;
+                }   
+
+                if ( (irSensor2 > DISTANCE_THRESHOLD) && (irSensor3 > DISTANCE_THRESHOLD) && (irSensor4 > DISTANCE_THRESHOLD) ) {
+                    controller.setRotationalVelocity(0);
+                    controller.setTranslationalVelocity(TRANSLATIONAL_VELOCITY);
+                    state = MOVE_FORWARD;
+                    break;
+                }
+                break;
+                
+            case SLOWING_DOWN:
+                if (abs(controller.getActualTranslationalVelocity()) < VELOCITY_THRESHOLD 
+                    && abs(controller.getActualRotationalVelocity()) > VELOCITY_THRESHOLD) {
+                    state = ROBOT_OFF;
+                    enableMotorDriver = 0;
+                    state = ROBOT_OFF;
+                }
+                
+                break;
+                
+            default:
+                
+                state = ROBOT_OFF;
+        }
+
+        user_led = !user_led;
         
+        /*
+        if (do_execute_main_task)
+            printf("button pressed\r\n");
+        else
+            printf("button NOT pressed\r\n");
+        */
         printf("actual velocity: %.3f [m/s] / %.3f [rad/s]\r\n", controller.getActualTranslationalVelocity(), controller.getActualRotationalVelocity());
         
-        ThisThread::sleep_for(100ms);
+        // read timer and make the main thread sleep for the remaining time span (non blocking)
+        int main_task_elapsed_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(main_task_timer.elapsed_time()).count();
+        thread_sleep_for(main_task_period_ms - main_task_elapsed_time_ms);
     }
 }
+
+void user_button_pressed_fcn()
+{
+    user_button_timer.start();
+    user_button_timer.reset();
+}
+
+void user_button_released_fcn()
+{
+    // read timer and toggle do_execute_main_task if the button was pressed longer than the below specified time
+    int user_button_elapsed_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(user_button_timer.elapsed_time()).count();
+    user_button_timer.stop();
+    if (user_button_elapsed_time_ms > 200) {
+        do_execute_main_task = !do_execute_main_task;
+    }
+}
\ No newline at end of file