Example software of using the mbed-rtos to control a simple vehicle's on board computer

Dependencies:   MCP23017 WattBob_TextLCD mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
sk398
Date:
Wed Mar 30 13:10:09 2016 +0000
Parent:
8:6fad4bd89240
Child:
10:95793013ef87
Commit message:
All Tasks operational. All Code Commented.; ; Final Submission Revision;

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Wed Mar 30 09:47:45 2016 +0000
+++ b/main.cpp	Wed Mar 30 13:10:09 2016 +0000
@@ -9,13 +9,23 @@
  
  Date:              March 2016
  
- Function:          This is the main runner containing the Cyclic executive
-                    There are 7 defined tasks and several Auxillary components
-                    which are logically ran periodically at their required time
-                    by a Cyclic Executive sequencer.
-                    Ticks, or slots, to this Cyclic Executive are provided by
-                    a ticker ever 25ms, and then using logical expressions, the
-                    correct task is initiated and allocated the required time.
+ Function:          This code operates to simulate the operation of a Car's
+                    control system. It does so by taking external input for 
+                    elements of a Car; Light Indicators, Engine State and Pedal values
+                    and using a simple Car Simulation model, derives a speed
+                    from which several tasks are included to act upon.
+                    An average speed is generated at a given frequency 
+                    and a total distance is estimated using this average speed.
+                    Output comes in the form of LED's when specific indicators 
+                    are true, and on a LCD screen and Servo Wiper to indicate speed.
+                    Furthermore, a PC Connection is established and a data dump of
+                    current Accelerometer, Brake and Average speed is presented
+                    to the user every 20 seconds.
+                    
+                    This system is constructed using the MBED-RTOS and 
+                    as such, each Task has an associated frequency, found in main, below.
+                    Note that no priority is given to the tasks and no 
+                    extra scheduler controls the synchronisation of tasks,
  
  ##################################################################### */
  
@@ -85,6 +95,9 @@
 
 // Raw Data Structure
 // ----------------------------------------------------------------------------
+
+// CarRawData  is a global memory area and contaims an instance of the Raw data 
+// populated by Task1 and can be accessed through locking Mutex - rawDataMutex
 typedef struct
 {
     bool EngineState;
@@ -92,85 +105,111 @@
     float RawBraking;
 } CarRawData;
 
+// Create Mutex to control access to CarRawData instance
 Mutex rawDataMutex;
+
+// Create Instance of CarRawData
 CarRawData rawData;
 
 // Speed Data Structure
 // ----------------------------------------------------------------------------
+
+// CarSpeedData is a global memory area and contains an instance of the calculated
+// raw speed values and the index to the next available element in the array to be 
+// written to. rawSpeed is calculated by the CarSim and can be accessed through
+// locking Mutex - SpeedMutex
 typedef struct
 {
     float rawSpeed[3];
     int counter;
 } CarSpeedData;
 
-float lastSpeed;
+// Create Mutex to control access to CarSpeedData instance
+Mutex SpeedMutex;
 
-Mutex SpeedMutex;
+// Create instance of CarSpeedData
 CarSpeedData speedData;
 
 // Filtered Data Structure
 // ----------------------------------------------------------------------------
-typedef struct
-{
-    float AverageSpeed;
-} CarFilteredParams;
 
-Mutex filteredParamsMutex;
-CarFilteredParams filteredParams;
+float AverageSpeed;
+float totalDistance;
 
-float totalDistance;
+// Create Mutex to control access to FilteredData
+Mutex filteredDataMutex;
 
 // Mail Queue Structure
 // ----------------------------------------------------------------------------
+
+// PCDumpData is a global memory area which is populated by Taak7 and used as
+// the structure within a MailQueue. Data contained is a copy from the current
+// state of the Control System at a given instance of time.
 typedef struct
 {
     float currentAverageSpeed;
     float currentAccelerometer;
     float currentBraking;
-} PCDump_t;
+} PCDumpData;
+
+// Construct a 100 Element Mail Queue structure
+Mail<PCDumpData,100> Memory_Dump;
 
-Mail<PCDump_t,100> Memory_Dump;
+// Define a Counter to trakc number of entries to Mail Queue
+int MailQueueCounter;
 
+// Create Mutex to control access to the MailQueueCounter variable
 Mutex MailMutex;
-int MailQueueCounter;
 
 
 // ============================================================================
 // Car Simulation
 // ============================================================================
 
+// The CarSimulator Task updates the rawSpeed parameter at a frequenct of 20Hz
 void CarSimulator(void const *arg)
 {
     float newSpeed;
     
+    // Load Shared resources into local variables within the Task
+    // Shared Resources are; Accelerometer value, Braking value and Engine State
     rawDataMutex.lock();
     float currentAccelerometer = rawData.RawAccelerometer;
     float currentBrake = rawData.RawBraking;
     bool currentEngineState = rawData.EngineState;
     rawDataMutex.unlock();   
 
+    // Run simple model which estimates the speed, as a fraction of the MAX SPEED
+    // based on the percentage of either accelerator or brake pressed by the user
+    // Further, newSpeed is set to 0 if the currentEngineState is equal to 0 (Engine off)
     newSpeed = currentAccelerometer*MAX_SPEED*(1-currentBrake)*currentEngineState;
     
+    // Check Speed Counter's range, if out of bounds of array length, reset Counter
+    // to 0
+    // Data contained within Shared Resource therefore the SpeedMutex is used to control access
     SpeedMutex.lock();
     if(speedData.counter > 2)
     {
         speedData.counter = 0;
     }
     
+    // Output a rawSpeed value to the next available index of rawSpeed[] and increment Counter
     speedData.rawSpeed[speedData.counter] = newSpeed;
+    speedData.counter = speedData.counter++;
     SpeedMutex.unlock();
-        
-    speedData.counter = speedData.counter++;
 }
 
 // ============================================================================
 // Control System Tasks
 // ============================================================================
 
-
+// Task1_ReadRawData gathers external inputs and updates the rawData structure
+// It operates at a frequency of 10Hz
 void Task1_ReadRawData(void const *arg)
 {
-//      PCConn.printf("Task1\r\n");
+      // Lock Shared Resource - rawData
+      // Update rawData elements directly from AnalogIn channel values
+      // Unlock Shares Resource
       rawDataMutex.lock();
       rawData.RawBraking = Brake.read();
       rawData.RawAccelerometer = Accelerometer.read();
@@ -178,15 +217,22 @@
 }
 
 
-
+// Task2_ReadEngineState updates the rawData structure and operates ar a frequency of 2Hz
 void Task2_ReadEngineState(void const *arg)
 {
-//    PCConn.printf("Task2\r\n");
+    // Get external input from DigitalIn Channel and store in local variable
     bool currentEngineState = EngineState.read();
+    
+    // Lock Shared Resource - rawData
+    // Take a copy of the local variable currentEngineState and store into Global memory
+    // Unlock Shared Resource
     rawDataMutex.lock();
     rawData.EngineState = currentEngineState;
     rawDataMutex.unlock();
     
+    // Conduct logical check on local varialbe currentEngineState
+    // if currentEngineState is HIGH, set EngineStateInd to HIGH
+    // else set EngineStateInd LOW
     if(currentEngineState)
     {
         EngineStateInd = HIGH;
@@ -198,45 +244,66 @@
 }
        
        
-        
+// Task3_CalcAvSpeed updates the AverageSpeed global varialbe and operates at a frequency of 5Hz    
 void Task3_CalcAvSpeed(void const *arg)
 {
-//    PCConn.printf("Task3\r\n");
+    // Initialise local variable as 0.0
     float speedTotal = 0.0;
     
+    // Lock Shared Resource - speedData
+    // Calculate total from array of rawSpeed values and store locally
+    // Unlock Shared Resource
+    SpeedMutex.lock();
     for(int num = 0; num < 3; num++)
     {
         speedTotal = speedTotal + speedData.rawSpeed[num];
-//        PCConn.printf("Total: %f\r\n",speedTotal);
     }
+    SpeedMutex.unlock();
 
-    filteredParamsMutex.lock();
-    filteredParams.AverageSpeed = (speedTotal/3);
-//    PCConn.printf("Av: %f\r\n",filteredParams.AverageSpeed);
-    filteredParamsMutex.unlock();
+    // Lock Shared Resource - AverageSpeed
+    // Calculate average from local variable speedTotal and store result Globally into AverageSpeed
+    // Unlock Shared Resource
+    filteredDataMutex.lock();
+    AverageSpeed = (speedTotal/3);
+    filteredDataMutex.unlock();
 }
 
 
-
+// Task4_UpdateRCWiper takes the AverageSpeed global variable at a given time and outputs 
+// a representation of this through a Servo. It operates at a frequenct of 1Hz
 void Task4_UpdateRCWiper(void const *arg)
 {
-//    PCConn.printf("Task4\r\n");
-    filteredParamsMutex.lock();
-    float currentAverageSpeed = filteredParams.AverageSpeed;
-    filteredParamsMutex.unlock();
+    // Lock Shared Resource - AverageSpeed
+    // Take local copy of AverageSpeed
+    // Unlock Shared Resource
+    filteredDataMutex.lock();
+    float currentAverageSpeed = AverageSpeed;
+    filteredDataMutex.unlock();
     
+    // Update Servo Position based upon the local copy of AverageSpeed
+    
+    // Servo must be controlled in the range of 1000us to 2000us
+    // Thus a base value of 1000 is included, and as currentAverageSpeed cannot exceed 100,
+    // This is simply scaled by 10, to give a maximum of 2000, which allows Servo to operate
+    // Over full operational range
     AvSpeedWiper.pulsewidth_us(1000+(10*currentAverageSpeed));
 }
 
 
-
+// Task5_OverspeedLED takes the 0th Element of the rawSpeed global variable and computes
+// a logical assessment to detect when the speed is greater than a preset of 70mph and 
+// indicate results through an LED. It operates at a frequency of 0.5Hz
 void Task5_OverspeedLED(void const *arg)
 {
-//    PCConn.printf("Task5\r\n");
+    // Lock Shared Resource - speedData
+    // Take local copy of rawSpeed[0]
+    // // Unlock Shares Resource
     SpeedMutex.lock();
     float currentInstSpeed = speedData.rawSpeed[speedData.counter];
     SpeedMutex.unlock();
     
+    // Using local copy of rawSpeed[0], if this is above preset threshold of 70,
+    // OverSpeedInd is set HIGH, else it is set LOW
     if(currentInstSpeed > 70.0)
     {
         OverSpeedInd = HIGH;
@@ -245,18 +312,34 @@
     {
         OverSpeedInd = LOW;
     }
-    
 }
 
 
+// Task6_UpdateOdometer takes the AverageSpeed global variable and calculates the
+// distance travelled by the Car over a known time increment (the delta of time between this task being ran)
+// Once calculated, the distance is stored globally and also, in conjunction with AverageSpeed, displayed onto
+// a LCD screen. It operates at a frequency of 2Hz
 void Task6_UpdateOdometer(void const *arg)
 {   
-    filteredParamsMutex.lock();
-    float currentAverageSpeed = filteredParams.AverageSpeed;
-    filteredParamsMutex.unlock();
+    // Lock Shared Varialbe - AverageSpeed
+    // Take local copy of AverageSpeed
+    // Unlock Shared Variable
+    filteredDataMutex.lock();
+    float currentAverageSpeed = AverageSpeed;
+    filteredDataMutex.unlock();
     
+    // Compute newTotalDistance from current TotalDistance and average speed
+    
+    // distance = oldDistance +(currentAverageSpeed*timeIncrement)
+    // Note that timeIncrement (0.5 second) is converted from seconds to hours, 
+    // To remain consistant with mph units
+    
+    // NOTE
+    // totalDistance does not need to be protected by a Mutex as this is the only task which updates 
+    // or uses the variable. It is global in order to keep track of a rolling total
     totalDistance = totalDistance + (currentAverageSpeed*(0.5/3600));
     
+    // Output totalDistance and currentAverageSpeed to LCD
     lcd -> cls();
     lcd -> locate(0,0);
     lcd -> printf("Dist: %8.2f",totalDistance);
@@ -265,45 +348,70 @@
 }
 
 
+// Task7_SendToMailQueue takes global variables; AverageSpeed, RawAccelerometer and RawBraking and
+// creates a structure from them, then puts an instanc of this structure onto a Mail Queue, incrementing
+// a globally defined Counter as it does such. It operates with a frequency of 0.2Hz
 void Task7_SendToMailQueue(void const *arg)
 {
-    filteredParamsMutex.lock();
-    float currentAverageSpeed = filteredParams.AverageSpeed;
-    filteredParamsMutex.unlock();
+    // Lock Shared Resource - AverageSpeed
+    // Take local copy of AverageSpeed
+    // Unlock Shared Resource
+    filteredDataMutex.lock();
+    float currentAverageSpeed = AverageSpeed;
+    filteredDataMutex.unlock();
     
+    // Lock Shared Resource - rawData
+    // Take local copy of RawAccelerometer and RawBraking
+    // Unlock Shared Resource
     rawDataMutex.lock();
     float currentAccelerometer = rawData.RawAccelerometer;
     float currentBrake = rawData.RawBraking;
     rawDataMutex.unlock();  
     
-    PCDump_t *currentPCDump = Memory_Dump.alloc();
+    // Allocate Memory for instance of PCDumpData structure
+    PCDumpData *currentPCDump = Memory_Dump.alloc();
+    
+    // Populate instance of PCDumpData with local copies of desired variables
     currentPCDump -> currentAverageSpeed = currentAverageSpeed;
     currentPCDump -> currentAccelerometer = currentAccelerometer;
     currentPCDump -> currentBraking = currentBrake;
     
+    // Push instance of PCDumpData onto Mail Queue
     Memory_Dump.put(currentPCDump);  
     
+    // Lock Shared Resource - MailQueueCounter
+    // Increment MailQueueCounter
+    // Unlock Shared Resource
     MailMutex.lock();
     MailQueueCounter++;
     MailMutex.unlock();  
 }
 
 
-
+// Task8_DumpSerial takes all of the instances of PCDumpData which have been pushed onto the Mail Queue
+// removes them from the Mail Queue and dumps their values over a PC serial connection. Once complete, the
+// counter which stores the number of elements in the Mail Queue is reset to 0. It operates at a frequency of 0.05Hz
 void Task8_DumpSerial(void const *arg)
 {
+    // Lock Shared Resource - MailQueueCounter
+    // Take local copy of MailQueueCounter
+    // Unlock Shared Resource
     MailMutex.lock();
     int currentQueueCounter = MailQueueCounter;
     MailMutex.unlock();
     
+    // Prompt State of Memory Dump
     PCConn.printf("Memory Dump\r\n");
     
+    // For each instance of PCDumpData found in the Mail Queue, import the structure and store locally
+    // Then print the contained values and free the element of the Mail Queue
+    // Repeat for all indexes of the Mail Queue
     for(int num = 0; num < currentQueueCounter; num++)
     {
         osEvent evt = Memory_Dump.get();
         if(evt.status == osEventMail)
         {
-            PCDump_t *currentPCDump = (PCDump_t*)evt.value.p;
+            PCDumpData *currentPCDump = (PCDumpData*)evt.value.p;
             
             PCConn.printf("Av Speed: %f\r\nAcceler: %f\r\nBrake: %f\r\n\r\n",  currentPCDump -> currentAverageSpeed,
                                                                     currentPCDump -> currentAccelerometer,
@@ -312,16 +420,20 @@
         }
     }
     
+    // Lock Shared Resource - MailQueueCounter
+    // Reset MailQueueCounter
+    // Unlock Shared Resource
     MailMutex.lock();
     MailQueueCounter = 0;
     MailMutex.unlock();
 }
 
 
-
+// Task9_ReadSideLight takes external input from SideLightIndicator and conducts a logical test.
+// It operates at a frequency of 1Hz
 void Task9_ReadSideLight(void const *arg)
 {
-//    PCConn.printf("Task9\r\n");
+    // If SideLightIndicator is HIGH, set SideLightInd to HIGH, else set to LOW
     if(SideLightIndicator)
     {
         SideLightInd = HIGH;
@@ -333,11 +445,12 @@
 }
 
 
-
+// Task10_ReadIndicatorLights takes external input from LeftIndicator and RightIndicator and conducts a
+// logical test. It operates at a frequency of 0.5Hz
 void Task10_ReadIndicatorLights(void const *arg)
 {
-//    PCConn.printf("Task10\r\n");
-    // Left Indicator Only
+
+    // If LeftIndicator Only is HIGH, flash LeftLightInd at a frequency of 1Hz, 50% Duty
     if(LeftIndicator && !RightIndicator)
     {
         LeftLightInd.period(1.0);
@@ -347,7 +460,7 @@
         RightLightInd.pulsewidth(0.0);
     }
     
-    // Right Indicator Only
+    // If RightIndicator Only is HIGH, flash RightLightInd at a frequency of 1Hz, 50% Duty
     else if(!LeftIndicator && RightIndicator)
     {
         LeftLightInd.period(1.0);
@@ -357,7 +470,8 @@
         RightLightInd.pulsewidth(0.5);
     }
     
-    // Left and Right Indicators
+    // If LeftIndicator and RightIndicator  are HIGH, flash LeftLightInd and RightLightInd
+    //  at a frequency of 2Hz, 50% Duty
     else if(LeftIndicator && RightIndicator)
     {
         LeftLightInd.period(0.5);
@@ -366,7 +480,7 @@
         LeftLightInd.pulsewidth(0.25);
         RightLightInd.pulsewidth(0.25);
     }
-    
+    // Else, turn off both LeftLightInd and RightLightInd
     else
     {
         LeftLightInd.period(1.0);
@@ -380,43 +494,46 @@
       
 void InitSystem()
 {
+    // Set AvSpeedWiper to 50Hz frequency, for Servo
     AvSpeedWiper.period_ms(20);
     
-    par_port->write_bit(1,BL_BIT); // turn LCD backlight ON
+    // Initiate LCD by lighting Backlight
+    par_port->write_bit(1,BL_BIT);
 
+    // Initiate all Global variables to 0
     rawData.EngineState = 0;
     rawData.RawAccelerometer = 0.0;
     rawData.RawBraking = 0.0;
-
     speedData.counter = 0;
     speedData.rawSpeed[0] = 0.0;
     speedData.rawSpeed[1] = 0.0;
     speedData.rawSpeed[2] = 0.0;
-    
-    filteredParams.AverageSpeed = 0.0;
-    
+    AverageSpeed = 0.0;
     totalDistance = 0.0;
-
     MailQueueCounter = 0;
 }
     
-     
-      
+
 // ============================================================================
 // Entry Point Thread
 // ============================================================================
 
+// Entry Point Thread, this shall be the initialiser for the Car System and 
+// Contains all of the Tasks and their associated properties, such as frequency.
 int main()
 {
+ // Construct Objects for LCD
  par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
  lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display
 
+ // Set PC Connection Baud Rate
  PCConn.baud(115200);
  
+ // Initialise System, including Global Variables
  InitSystem();
   
+// Construct Tasks as RtosTimer objects
  RtosTimer CarSim(CarSimulator,osTimerPeriodic);
- 
  RtosTimer Task1(Task1_ReadRawData,osTimerPeriodic);
  RtosTimer Task2(Task2_ReadEngineState,osTimerPeriodic);
  RtosTimer Task3(Task3_CalcAvSpeed,osTimerPeriodic);
@@ -428,6 +545,7 @@
  RtosTimer Task9(Task9_ReadSideLight,osTimerPeriodic);
  RtosTimer Task10(Task10_ReadIndicatorLights,osTimerPeriodic);
  
+ // Staert RtosTimer objects, with the required frequency
  CarSim.start(50);      // 20Hz
  Task1.start(100);      // 10Hz
  Task2.start(500);      // 2Hz
@@ -440,6 +558,7 @@
  Task9.start(1000);     // 1Hz
  Task10.start(2000);    // 0.5Hz 
  
+ // Ensure that RtosTimer runs within Infinite loop
  Thread::wait(osWaitForever);