Railway Challenge / Mbed 2 deprecated challenge-ChaiUpdated-AutostopTest-30Throttle

Dependencies:   mbed millis

Files at this revision

API Documentation at this revision

Comitter:
rwcjoliver
Date:
Fri Mar 13 11:48:04 2020 +0000
Child:
1:ba85dae98035
Commit message:
Uncommented RegenBRaking lines to allow capacitors to charge up from the batteries

Changed in this revision

challenge.cpp Show annotated file Show diff for this revision Revisions of this file
challenge.h Show annotated file Show diff for this revision Revisions of this file
dashboard.cpp Show annotated file Show diff for this revision Revisions of this file
dashboard.h Show annotated file Show diff for this revision Revisions of this file
definitions.cpp Show annotated file Show diff for this revision Revisions of this file
definitions.h Show annotated file Show diff for this revision Revisions of this file
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
millis.lib Show annotated file Show diff for this revision Revisions of this file
motor.cpp Show annotated file Show diff for this revision Revisions of this file
motor.h Show annotated file Show diff for this revision Revisions of this file
remoteControl.cpp Show annotated file Show diff for this revision Revisions of this file
remoteControl.h Show annotated file Show diff for this revision Revisions of this file
rtc.cpp Show annotated file Show diff for this revision Revisions of this file
rtc.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/challenge.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,284 @@
+#include <mbed.h>
+#include "definitions.h"
+#include "challenge.h"
+#include "remoteControl.h"
+#include "dashboard.h"
+#include "motor.h"
+
+ChallengeMode::ChallengeMode(InterruptIn& autoStopTrigger, Dashboard& dashboard, Remote& remote, Motor& motor1) : 
+                            _autoStopTrigger(autoStopTrigger), _dashboard(dashboard), _remote(remote), _motor1(motor1) {
+    // CONSTRUCTOR
+                                
+    // ATTACH AUTOSTOP INTERRUPT
+    _autoStopTrigger.rise(this, &ChallengeMode::autoStopTriggered);
+    
+    // FUNCTIONS
+    regenThrottleOff(); // Make sure regen throttle is off
+    autoStopOff();      // Make sure auto-stop is off
+    innovationOff();    // make sure innovation (collision detection mode) is off
+    
+    // VARIABLES
+    
+    contactBatt = 1;
+    
+    // Auto-Stop Challenge
+    autoStopActive = false;             // Flag is auto-stop mode is active
+    autoStopInProgress = false;         // Flag if auto-stop track-side sensor has been detected and auto-stop is in progress
+    autoStopCruiseSpeed = 0;            // Speed of loco at time of auto-stop trackside sensor triggering so loco can maintain this speed without operator input
+    autoStopThrottle = 0;               // Throttle rate applied at the time of triggering autostop
+    targetDistance = 25.00f;            // How far in meters to bring the loco to a stop
+    remainingDistance = targetDistance; // How far the loco has left to go before reaching target distance
+    decelerationGradient = 0;           // Gradient of y=mx+c linear speed-distance curve that is used in this auto-stop version
+    requiredSpeed = 0;                  // How fast the loco should be going according to y=mx+c line
+    
+    // Innovation Challenge
+    innovationDistanceLimit = 1500;     // Stopping distance in mm from IR sensors
+    stopLoco = false;                   // Flag to stop the loco when obstacle has been detected
+    
+    // IR Output voltages at various distances (for calibration purposes)
+    voltageAt5500 = 0;
+    voltageAt5000 = 0;
+    voltageAt4500 = 0;
+    voltageAt4000 = 0;
+    voltageAt3500 = 0;
+    voltageAt3000 = 0;
+    voltageAt2500 = 0;
+    voltageAt2000 = 0;
+    voltageAt1500 = 0;
+    voltageAt1000 = 2.2f;
+    voltageAt500  = 3.0f;
+    
+}    // CONSTRUCTOR
+
+void ChallengeMode::regenThrottleOn() {
+    // OPEN THE BATTERY CONTACTOR SO POWER IS DELIVERED BY SUPERCAPS
+    
+    contactCapCharge = 0;               // Open supercap charging contactor to prevent charging
+    
+    contactBatt = 0;                    // Open battery contactor so all power comes from supercaps
+    regenThrottleActive = true;         // Flag to indicate that regen throttling is on
+    pc.printf("Regen Throttle On\r\n");
+}
+
+void ChallengeMode::regenThrottleOff() {
+    // CLOSE THE BATTERY CONTACTOR
+//    if (regenBrakingActive == false) {  // If regen braking is not active and using the supercaps, allow capacitor to pre-charge from batteries
+//        contactCapCharge = 1;           // Close the supercap charging contactor
+//    }
+    
+    contactBatt = 1;                    // Close the battery contactor so power comes from batteries
+    regenThrottleActive = false;        // Flag to indicate that regen throttling is off
+    pc.printf("Regen Throttle Off\r\n");
+}
+
+bool ChallengeMode::regenBrakingOn() {
+    // TURN ON REGEN BRAKING
+    if (superCapVoltage == 0) {             // If super caps are not full
+        contactCapCharge = 0;               // Open the super cap pre-cahrging contactor
+        contactBatt = 0;                    // Open battery contactor so all power comes from supercaps
+        regenBrakingActive = true;          // Flag to indicate that regen throttling is on
+        pc.printf("Regen Braking On\r\n");
+        return 1;                           // Return 1 if regen braking switched on
+    }
+    else {
+        return 0;                           // Return 0 is regen braking didnt turn on due to full supercaps
+    }
+}
+
+void ChallengeMode::regenBrakingOff() {
+    // TURN OFF REGEN BRAKING
+    if (regenThrottleActive == false) {     // If regen throttle is not active and using the supercaps, allow capacitor to pre-charge from batteries
+        contactCapCharge = 1;               // Close the supercap pre-charge contactor
+    }
+    regenBrakingActive = false;             // Flag that regen braking is off
+    contactBatt = 1;                    // Close battery contactor so all power comes from supercaps
+    pc.printf("Regen Braking Off\r\n");
+}
+
+void ChallengeMode::autoStopOn() {
+    // TURN ON AUTOSTOP MODE
+    autoStopActive = true;                  // Flag that auto-stop mode is on
+    pc.printf("Auto-Stop On\r\n");
+}
+
+void ChallengeMode::autoStopTriggered() {
+    // INTERRUPT FUNCTION CALLED WHEN TRACK-SIDE TRIGGER HAS BEEN DETECTED
+    if (autoStopActive == true && autoStopInProgress == false) {    // If auto-stop mode is on and signal has not yet been detected
+        autoStopInProgress = true;                                  // Flag that auto-stop is in progress and fully autonomous
+        autoStopCruiseSpeed = _dashboard.currentSpeed;              // Set the speed the loco was going at the point of triggering
+        autoStopThrottle = _remote.throttle;
+        
+        _dashboard.currentDistance = 0.00f;                         // Reset the distance-travelled counter to 0
+//        timeToReachTarget = targetDistance / (autoStopCruiseSpeed * 1000 / 3600);   // Time(s) = Distance(m) / Speed(converted to m/s)
+        decelerationGradient = (autoStopCruiseSpeed - 1) / (targetDistance - 1);    // m = y / x → to get to 1kph at 24m, leaving ~ 4 seconds to get to target of 25m
+        pc.printf("Auto-Stop Triggered\r\n");
+    }
+}
+
+void ChallengeMode::autoStopControl() {
+    // FUNCTION TO MANAGE THE LOCO THROTTLE AND BRAKING WHEN AUTO-STOPPING
+    remainingDistance = targetDistance - _dashboard.currentDistance;        // Calculate remaining distance from target distance
+//    timeToReachTarget = int(_dashboard.currentSpeed) > 0 ? remainingDistance / _dashboard.currentSpeed : 999;
+    
+    // FOLLOWING DECELERATION GRADIENT
+    
+    if (remainingDistance > 2.0f) {    // IF OVER 3M FROM TARGET, CONTROL SPEED (1m + 2m sensor to nose of train)
+    
+        _motor1.throttle(0.3f);     // Apply 30% throttle
+        //requiredSpeed = (decelerationGradient * _dashboard.currentDistance) + autoStopCruiseSpeed;  // (y = mx + c)
+//        
+//        if (_dashboard.currentSpeed < requiredSpeed) {  // If train is below the speed it should be, apply 30% throttle and no braking
+////            _motor1.throttle(0.3f);
+////            _motor2.throttle(0.1f);
+////            _motor1.brake(0.0f);
+////            _motor2.brake(0.0f);
+//
+//            brakeValve32 = 1;
+//        }
+//        else {                                                              // If loco is going faster than is should be
+//            int speedDifference = _dashboard.currentSpeed - requiredSpeed;  // Work out how much faster it is going and apply a proportional amount of motor braking
+//            
+//            _motor1.throttle(0.0f);         // Turn off throttle
+////            _motor2.throttle(0.0f);
+//
+//            brakeValve32 = 0;
+//            if (pressureSwitch1.read() == 0) {
+//                brakeValve22 = 0;
+//                pc.printf("Pressure 1 Reached");
+//            }
+//            
+//            switch (speedDifference) {  // MOTOR BRAKING
+//                case 1:
+//                    _motor1.brake(0.1f);
+////                    _motor2.brake(0.1f);
+//                    break;
+//                    
+//                case 2:
+//                    _motor1.brake(0.2f);
+////                    _motor2.brake(0.2f);
+//                    break;
+//                    
+//                case 3:
+//                    _motor1.brake(0.3f);
+////                    _motor2.brake(0.3f);
+//                    break;
+//                    
+//                case 4:
+//                    _motor1.brake(0.4f);
+////                    _motor2.brake(0.4f);
+//                    break;
+//                    
+//                case 5:
+//                    _motor1.brake(0.5f);
+////                    _motor2.brake(0.5f);
+//                    break;
+//                    
+//                case 6:
+//                    _motor1.brake(0.6f);
+////                    _motor2.brake(0.6f);
+//                    break;
+//                    
+//                case 7:
+//                    _motor1.brake(0.7f);
+////                    _motor2.brake(0.7f);
+//                    break;
+//                    
+//                case 8:
+//                    _motor1.brake(0.8f);
+////                    _motor2.brake(0.8f);
+//                    break;
+//                    
+//                case 9:
+//                    _motor1.brake(0.9f);
+////                    _motor2.brake(0.9f);
+//                    break;
+//                    
+//                default:
+//                    _motor1.brake(1.0f);
+////                    _motor2.brake(1.0f);
+//                    break;
+//            }   // switch
+//        }// else
+    }// if 
+    else {  // IF REACHED STOPPING TARGET AREA
+        rtc_Trigger = 0;        // APPLY EMERGENCY BRAKES
+//        if (remainingDistance > 0.2f) {     // If more than 20cm to go, stay at 1kph
+//        
+//        }
+//        else {                              // If less than 20cm from target apply full mechanical brakes and turn off throttle
+//            _motor1.throttle(0.0f);
+////            _motor2.throttle(0.0f);
+//            
+//            // MECHANICAL BRAKES
+//            brakeValve32 = 1;
+//            if (pressureSwitch3 == 0) {
+//                brakeValve22 = 0;
+//            }
+//            else {
+//                brakeValve22 = 1;   
+//            }
+//        }
+    }
+    
+    pc.printf("remainingDistance  %f\r\n", remainingDistance);
+//    pc.printf("timeToReachTarget %f\r\n", timeToReachTarget);
+}
+
+void ChallengeMode::autoStopOff() {
+    // TURN OFF AUTOSTOP MODE
+    autoStopActive = false;         // CLEAR AUTOSTOP MODE FLAG
+    autoStopInProgress = false;     // CLEAR AUTOSTOPPING
+    rtc_Trigger = 1;
+    pc.printf("Auto-Stop Off\r\n");
+}
+
+void ChallengeMode::innovationOn() {
+    // TURN ON INNOVATION MODE
+    innovationActive = true;
+    stopLoco = false;
+    rtc_Trigger = 1;
+    _motor1.setSpeedMode(1);     // SET MOTORS TO INCH FORWARD MODE
+//    _motor2.setSpeedMode(1);
+    pc.printf("Innovation On\r\n");
+}
+
+void ChallengeMode::innovationOff() {
+    // TURN OFF INNOVATION MODE
+    innovationActive = false;
+    stopLoco = false;
+    rtc_Trigger = 1;
+    _motor1.setSpeedMode(3);     // SET MOTOR SPEED LIMIT TO MAX
+    pc.printf("Innovation Off\r\n");
+}
+
+int ChallengeMode::innovationControl(int requestedThrottle) {
+    // CONTROL THE TRAIN THROTTLING AND BRAKING
+    
+    int count = 0;
+    
+    if (irSensor_1 > voltageAt1000 / 3.3f) { count++; }
+    if (irSensor_2 > voltageAt1000 / 3.3f) { count++; }
+    if (irSensor_3 > voltageAt1000 / 3.3f ) { count++; }
+    
+    if (count >= 2) {
+        stopLoco = true;
+    }
+
+    
+    if (stopLoco == true) { // IF SENSORS INDICATE TRAIN SHOULD STOP
+    
+//        // APPLY MECHANICAL BRAKES
+//        brakeValve32 = 0;
+//        brakeValve22 = 1;
+
+        // APPLY E-BRAKE
+        rtc_Trigger = 0;
+        
+        pc.printf("Obstacle Detected\r\n");
+        
+        return 0;       // RETURN THROTTLE = 0 TO INDICATE TRAIN SHOULD STOP
+    }
+    else {
+        return requestedThrottle;   // OTHERWISE THROTTLE = USER REQUEST
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/challenge.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,75 @@
+#ifndef _CHALLENGE_H_
+#define _CHALLENGE_H_
+
+#include <mbed.h>
+#include "dashboard.h"
+#include "remoteControl.h"
+#include "motor.h"
+
+class ChallengeMode {
+    public:
+        // CONSTURCTOR
+        ChallengeMode(InterruptIn& autoStopTrigger, Dashboard& dashboard, Remote& remote, Motor& motor1);
+        
+        // FUNCTIONS
+        // Regen Mode
+        void regenThrottleOn();
+        void regenThrottleOff();
+        bool regenBrakingOn();
+        void regenBrakingOff();
+        
+        // Auto-Stop Mode
+        void autoStopOn();
+        void autoStopOff();
+        void autoStopTriggered();
+        void autoStopControl();
+        
+        // Innovation Mode
+        void innovationOn();
+        void innovationOff();
+        int innovationControl(int requestedThrottle);
+        
+        // VARIABLES
+        bool regenThrottleActive;
+        bool regenBrakingActive;
+        bool autoStopActive;
+        bool innovationActive;
+        
+        int autoStopCruiseSpeed;
+        int autoStopThrottle;
+        bool autoStopInProgress;
+    
+    private:
+        InterruptIn& _autoStopTrigger;
+        Dashboard& _dashboard;
+        Remote& _remote;
+        Motor& _motor1;
+//        Motor& _motor2;
+        
+        // AutoStop
+        float targetDistance;
+        float remainingDistance;
+
+//        float timeToReachTarget;
+        float decelerationGradient;
+        float requiredSpeed;
+        
+        // Innovation
+        int innovationDistanceLimit;    // Distance(mm) from IR sensors to apply brakes
+        bool stopLoco;
+        
+        // IR Output voltages at various distances (for calibration purposes)
+        float voltageAt5500;
+        float voltageAt5000;
+        float voltageAt4500;
+        float voltageAt4000;
+        float voltageAt3500;
+        float voltageAt3000;
+        float voltageAt2500;
+        float voltageAt2000;
+        float voltageAt1500;
+        float voltageAt1000;
+        float voltageAt500;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dashboard.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,152 @@
+#include <mbed.h>
+#include "definitions.h"
+#include "dashboard.h"
+
+Dashboard::Dashboard(InterruptIn& hallSensor) : _hallSensor(hallSensor) {    // CONSTRUCTOR
+    
+    _hallSensor.rise(this, &Dashboard::tachoInterrupt);           // Register everytime hall sensor is detected
+    tachoTimer.start();                         // Timer for counting time between hall sensor triggers
+    
+    numberOfMagnets = 1;    // How many magnets on the wheels
+    
+    currentSpeed = 0.00f;
+    passedTime_ms = 0.00f;
+    passedTime = 0.00f;
+    lastTime = 0.00f;
+    wheelCircumference = 0.73513268f; // in meters. Radius = 0.117m
+    
+    currentDistance = 0.00f;
+    tachoCounter = 0;
+    currentTime = 0;
+}
+
+void Dashboard::tachoInterrupt() {
+    
+    currentTime = tachoTimer.read_ms();
+    passedTime = (currentTime - lastTime) / 1000;
+    pc.printf("Passed Time: %.2f\r\n", passedTime);
+    
+//    if (passedTime > 0.03) {
+    
+//        tachoCounter++;     // Increment tacho counter = number of strips detected
+        //pc.printf("count = %d\r\n", tachoCounter);
+        
+    //    getCurrentSpeed();
+    //    //   PASSED TIME IN ms
+    //    passedTime_ms = tachoTimer.read_ms() - lastTime;// - 21;  // 20ms propogation delay
+    //    
+    //    if (passedTime_ms > 100) { // IGNORE SHORT PULSES
+    //        lastTime = tachoTimer.read_ms();
+            currentDistance += (wheelCircumference / numberOfMagnets);
+            pc.printf("Current Distance = %.2f\r\n", currentDistance);
+            
+    //        passedTime = passedTime_ms / 1000.00f;
+    ////        pc.printf("Passed TimeMS Int: %d\r\n", passedTime_ms);
+    ////        pc.printf("Passed Time Int: %.2f\r\n", passedTime);
+    ////        pc.printf("Tacho Interrupt\r\n");
+    //    }
+        
+//        pc.printf("count = %d\r\n", tachoCounter);
+        
+        wheelFreq = 1 / (passedTime * numberOfMagnets);
+//        pc.printf("wheelFreq = %.2f\r\n", wheelFreq);
+        
+//        tachoCounter = 0;   // RESET
+        lastTime = currentTime;
+        
+        
+        if (passedTime > 0.00f) {    // Stops dividing by 0
+    
+            // 1 Hz FREQ = 1 RPS -> x60 for minutes
+            float rpm = wheelFreq * 60.00f;       /// MAX RPM AT 15KPH = 340RPM
+//            pc.printf("RPM = %.2f\r\n",rpm);
+            
+    //        if (rpm < 15.0f) {
+            
+                float kph = (wheelCircumference * rpm * (60.00f / 1000.00f));
+                printf("Speed = %.2f\r\n", kph);
+        
+//                if (kph > 17.0f) {
+//                    currentSpeed = 0;
+//                }
+//                else {
+                currentSpeed = int(kph);
+//                }
+    //        }
+            
+            
+//        }
+//        else {
+//            currentSpeed = 0;
+//             
+//        }
+    }
+
+}
+
+void Dashboard::getCurrentSpeed() {
+    
+    // USE THESE
+//    tachoCounter
+//    currentTime
+//    lastTime
+
+    currentTime = tachoTimer.read_ms();
+    if ((currentTime - lastTime) > 5000) {
+        currentSpeed = 0;
+    }
+//    passedTime = (currentTime - lastTime) / 1000;
+//    pc.printf("Passed Time: %.2f\r\n", passedTime);
+    
+    //pc.printf("count = %d\r\n", tachoCounter);
+//    
+//    wheelFreq = tachoCounter / (passedTime * numberOfMagnets);
+//    pc.printf("wheelFreq = %.2f\r\n", wheelFreq);
+//    
+//    tachoCounter = 0;   // RESET
+//    lastTime = currentTime;
+//    
+//    
+//    if (passedTime > 0.00f) {    // Stops dividing by 0
+        // PASSED TIME IN SECONDS = 1000 / TIME IN ms
+        // FREQ = 1/T = 1 * 1000 / T
+        
+//        pc.printf("Passed Time Calc: %.2f\r\n", passedTime);
+        
+//        if ((tachoTimer.read_ms() / 1000.00f) - lastTime < 10.00f) {
+//             wheelFreq = 1 / (numberOfMagnets * passedTime);
+////             pc.printf("wheelFreq set\r\n");
+//        }
+//        else {
+//            wheelFreq = 0.00f;  // Set frequency to zero if not sensed for more than 10s
+//            passedTime = 0.00f;
+////            pc.printf("wheelFreq Zeroed\r\n"); 
+//        }
+       
+                
+//        pc.printf("wheelFreq = %.4f\r\n", wheelFreq);
+        
+        // 1 Hz FREQ = 1 RPS -> x60 for minutes
+//        float rpm = wheelFreq * 60.00f;       /// MAX RPM AT 15KPH = 340RPM
+//        pc.printf("RPM = %.2f\r\n",rpm);
+//        
+//        // rpm x 60 = rph
+//        // speed = distance / time
+//        // kph = rph / (1km x circumference [m])
+//        
+//        // kph = 2πr × RPM × (60/1000)
+//        float kph = wheelCircumference * rpm * (60.00f / 1000.00f);
+////        float kph = (rpm * 60.00f) / (1000.00f * wheelCircumference);
+////        pc.printf("KM/H = %.2f\r\n",kph);
+//        if (kph > 15) {
+//            currentSpeed = 0;
+//        }
+//        else {
+//            currentSpeed = int(kph);
+//        }
+//    }
+//    else {
+//        currentSpeed = 0;
+//         
+//    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dashboard.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,29 @@
+#ifndef _DASHBOARD_H_
+#define _DASHBOARD_H_
+
+#include <mbed.h>
+
+class Dashboard {
+    public:
+        Dashboard(InterruptIn& hallSensor);    // CONSTRUCTOR
+        
+        void tachoInterrupt();
+        void getCurrentSpeed();
+        
+        int currentSpeed;
+        float currentDistance;
+        
+    private:
+        InterruptIn& _hallSensor;
+        Timer tachoTimer;
+        int passedTime_ms;
+        float passedTime;
+        float lastTime;
+        float wheelFreq;
+        float wheelCircumference;
+        int numberOfMagnets;
+        int tachoCounter;
+        int currentTime;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/definitions.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,82 @@
+#include <mbed.h>
+#include "definitions.h"
+
+// COMMS DEFINITIONS
+Serial pc(USBTX, USBRX);
+
+// INTERRUPTS
+InterruptIn rtc_output(PF_11, PullUp);
+InterruptIn autoStopTrigger(PD_2, PullDown);        //interrupt on lineside equipment detection
+InterruptIn hallSensor(PG_3);              // For Hall Sensor Tachometer
+
+// PIN DEFINITIONS
+
+// INNOVATION/ COLLISION DETECTION
+AnalogIn irSensor_1(PF_6);
+AnalogIn irSensor_2(PF_7);
+AnalogIn irSensor_3(PC_2);
+
+//RTC individual inputs//
+DigitalIn rtc_1(PG_4, PullUp);
+DigitalIn rtc_2(PG_6, PullUp);
+DigitalIn rtc_3(PG_7, PullUp);
+DigitalIn rtc_4(PG_5, PullUp);
+DigitalIn rtc_5(PD_10, PullUp);
+DigitalIn rtc_6(PG_8, PullUp);
+DigitalIn rtc_7(PE_0, PullUp);
+DigitalIn rtc_override(PG_14, PullUp);
+
+// RTC Outputs
+DigitalOut rtc_Trigger(PD_14);
+
+// Output LEDs
+//DigitalOut led_rtcOutput();    // No need as RTC has led output
+//DigitalOut led_emergencyBrake(PE_11);
+DigitalOut led_parkMode(PF_10);
+
+
+//Motor outputs               // ENSURE YOU USE DAC PINS - BOTH MOTORS SHARE PINS
+AnalogOut motorAccelerator(PA_5);
+AnalogOut motorBrake(PA_4);
+
+////motor 1 settings
+DigitalOut keySwitchM1(PF_1);
+DigitalOut directionFwd(PF_0);
+DigitalOut directionRev(PD_1);
+//DigitalOut directionM1(PA_3); // FORWARD AND REVERSE NEED TO BE SEPARATE
+DigitalOut footswitchM1(PD_4);
+DigitalOut seatM1(PD_5);
+DigitalOut inchFwdM1(PD_6);
+DigitalOut speedLimit2M1(PD_7);
+DigitalOut speedLimit3M1(PE_3);
+
+////motor 2 settings;
+//DigitalOut keySwitchM2(PD_10);
+//DigitalOut directionM2(PG_6);
+//DigitalOut footswitchM2(PG_4);
+//DigitalOut seatM2(PC_8);
+//DigitalOut inchFwdM2(PC_6);
+//DigitalOut speedLimit2M2(PA_12);
+//DigitalOut speedLimit3M2(PA_11);
+
+DigitalIn superCapPreCharge(PB_11);    // Supercaps are pre-charged
+DigitalIn superCapVoltage(PB_2);  // Supercaps are Full
+
+//Contactors as digital outputs
+DigitalOut contactBatt(PE_8);        // C-BAT
+DigitalOut contactCompressor(PG_10);   // C-COM
+DigitalOut contactCapCharge(PG_11);   // C-CHA
+
+//DigitalOut contactMtr1(PE_0); // DRIVEN BY MOTOR CONTROLLER
+//DigitalOut contactMtr2(PG_8);
+
+//mechanical braking and other air components.
+DigitalOut brakeValve32(PF_2);
+DigitalOut brakeValve22(PG_1);
+DigitalOut whistleValve32(PG_15);
+
+DigitalIn pressureSwitch1(PC_13, PullUp);
+DigitalIn pressureSwitch2(PC_1, PullUp);
+DigitalIn pressureSwitch3(PC_15, PullUp);
+//DigitalIn brakePressure(PH_0);      // NOT INSTALLED
+DigitalIn mainlinePressure(PH_1, PullUp);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/definitions.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,85 @@
+#ifndef DEFINITIONS_H
+#define DEFINITIONS_H
+
+#include <mbed.h>
+
+extern Serial pc;
+
+//// INTERRUPTS
+extern InterruptIn rtc_output;
+extern InterruptIn autoStopTrigger;                     //interrupt on lineside equipment detection
+extern InterruptIn hallSensor;              // For Hall Sensor Tachometer
+//
+
+
+// PIN DEFINITIONS
+
+// INNOVATION/ COLLISION DETECTION
+extern AnalogIn irSensor_1;
+extern AnalogIn irSensor_2;
+extern AnalogIn irSensor_3;
+
+//RTC individual inputs//
+extern DigitalIn rtc_1;
+extern DigitalIn rtc_2;
+extern DigitalIn rtc_3;
+extern DigitalIn rtc_4;
+extern DigitalIn rtc_5;
+extern DigitalIn rtc_6;
+extern DigitalIn rtc_7;
+extern DigitalIn rtc_override;
+
+// RTC Outputs
+extern DigitalOut rtc_Trigger;
+
+
+// Output LEDs
+//DigitalOut led_rtcOutput;    // No need as RTC has led output
+//extern DigitalOut led_emergencyBrake;
+extern DigitalOut led_parkMode;
+
+
+//Motor outputs               // ENSURE YOU USE DAC PINS - BOTH MOTORS SHARE PINS
+extern AnalogOut motorAccelerator;
+extern AnalogOut motorBrake;
+
+//motor 1 settings
+extern DigitalOut keySwitchM1;
+extern DigitalOut directionFwd;
+extern DigitalOut directionRev;
+extern DigitalOut footswitchM1;
+extern DigitalOut seatM1;
+extern DigitalOut inchFwdM1;
+extern DigitalOut speedLimit2M1;
+extern DigitalOut speedLimit3M1;
+
+//motor 2 settings;
+//extern DigitalOut keySwitchM2;
+//extern DigitalOut directionM2;
+//extern DigitalOut footswitchM2;
+//extern DigitalOut seatM2;
+//extern DigitalOut inchFwdM2;
+//extern DigitalOut speedLimit2M2;
+//extern DigitalOut speedLimit3M2;
+
+// Power
+extern DigitalIn superCapVoltage;
+//extern DigitalIn batteryVoltage;
+
+//Contactors as digital outputs
+extern DigitalOut contactBatt;
+extern DigitalOut contactCompressor;
+extern DigitalOut contactCapCharge;
+
+//mechanical braking and other air components.
+extern DigitalOut brakeValve32;
+extern DigitalOut brakeValve22;
+extern DigitalOut whistleValve32;
+
+extern DigitalIn pressureSwitch1;
+extern DigitalIn pressureSwitch2;
+extern DigitalIn pressureSwitch3;
+//extern DigitalIn brakePressure;
+extern DigitalIn mainlinePressure;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,575 @@
+#include <mbed.h>
+#include "millis.h"
+
+#include "definitions.h"
+#include "remoteControl.h"
+#include "dashboard.h"
+#include "rtc.h"
+#include "motor.h"
+#include "challenge.h"
+
+//  SET UP REMOTE CONTROL COMMS
+SPI remoteControl(PE_14, PE_13, PE_12);   // (SPI_MOSI, SPI_MISO, SPI_SCK)
+DigitalOut remoteControlCS(PE_11);    // (SPI_SS)
+
+//  CREATE OBJECTS
+Remote remote(remoteControl, remoteControlCS);
+Dashboard dashboard(hallSensor);
+RoundTrainCircuit rtc(rtc_1, rtc_2, rtc_3, rtc_4, rtc_5, rtc_6, rtc_7, rtc_override);
+Motor motor1(motorAccelerator, motorBrake, keySwitchM1, directionFwd, directionRev, footswitchM1, seatM1, inchFwdM1, speedLimit2M1, speedLimit3M1);
+ChallengeMode challenge(autoStopTrigger, dashboard, remote, motor1);
+
+int driveMode = 2;      // Drive mode - fwd(0), rev(1), park(2)
+bool emergencyStopActive = false;
+
+// FUNCTIONS
+
+void startupHealthCheck() {
+       
+   while(1) {
+
+        if (remote.commsGood == 1) {
+            if (rtc_output.read() == 0) {
+//                if (batteryVoltage == true) {
+                    if (superCapVoltage == true) {
+//                        
+//
+                        return;     // Exit the function if all checks are passed
+//
+                    }
+                    else {
+                        pc.printf("System Start-Up Health Check: SuperCap Voltage Check Failed\r\n");
+                    }
+//                }
+//                else {
+//                    pc.printf("System Start-Up Health Check: Battery Voltage Check Failed\r\n");
+//                }
+            }
+            else {
+                pc.printf("System Start-Up Health Check: RTC Check Failed\r\n");
+            }           
+        }
+        else {
+            pc.printf("System Start-Up Health Check: CommsCheck Failed\r\n");
+        }
+        remote.sendError('H');     // Send error to remote
+        wait(100); // Wait a while until trying again
+    }
+}
+
+void emergencyStop() {
+//    pc.printf("Emergency Stop Active\r\n");
+    if (emergencyStopActive == false) {
+        
+        emergencyStopActive = true;
+                
+        motor1.disengage();     // Disengage both motors
+//        motor2.disengage();
+        
+        motor1.setPark();       // Clear Motor Directions
+//        motor2.setPark();
+        
+        if (rtc_output.read() == 1) {
+            rtc.getTriggerCause();        // Get RTC input status
+        }
+    }
+}
+
+// Prototype"!!!!
+void speedControl(int);
+
+void brakeControl(int brakeRate) {
+    if (driveMode == 2) {   // PARK MODE
+        //  BREAK RATE LEVEL 1
+        speedControl(0);
+        brakeValve32 = 0;
+        brakeValve22 = 1;
+        //if (pressureSwitch1 == 0) {
+//            brakeValve22 = 0;
+//        }
+//        else {
+//            brakeValve22 = 1;   
+//        }
+    }
+    else {
+        
+        if (challenge.regenBrakingActive == true) { // REGEN BRAKING WITH OVERVOLTAGE SAFETY CHECK
+            if (brakeRate > 0) {
+               motor1.setPark();
+            }
+            else {
+                motor1.setForward();
+            }
+           // switch (brakeRate) {
+//                case 0:     // NO BRAKING
+//                    motor1.brake(0.00f);
+////                    motor2.brake(0.00f);
+////                    contactBatt = 0;                    // Close battery contactor so all power comes from supercaps
+//                    pc.printf("Regen Braking set to 0%\r\n");
+//                    break;
+//                    
+//                case 1:
+//                    motor1.throttle(0.0f);
+//                    motor1.brake(0.33f);
+////                    motor2.brake(0.33f);
+////                    contactBatt = 0;                    // Open battery contactor so all power comes from supercaps
+//                    pc.printf("Regen Braking set to 33%\r\n");
+//                    break;
+//                
+//                case 2:
+//                    motor1.brake(0.66f);
+//                    motor1.throttle(0.0f);
+////                    motor2.brake(0.66f);
+////                    contactBatt = 0;                    // Open battery contactor so all power comes from supercaps
+//                    pc.printf("Regen Braking set to 66%\r\n");
+//                    break;
+//                
+//                case 3:
+//                    motor1.brake(1.0f);
+//                    motor1.throttle(0.0f);
+////                    motor2.brake(1.0f);
+//                    pc.printf("Regen Braking set to 100%\r\n");
+//                    break;
+//                                    
+//                default:
+//                    break;
+//            }
+        }
+        else {  // MECHANICAL BRAKING 
+            switch (brakeRate) {
+                case 0:     // NO BRAKING
+                    brakeValve32 = 1;
+                    brakeValve22 = 1;
+                    break;
+                
+                case 1:
+                    motor1.throttle(0.0f);
+                    brakeValve32 = 0;
+                    if (pressureSwitch1.read() == 0) {
+                        brakeValve22 = 0;
+                        pc.printf("Pressure 1 Reached");
+                    }
+                    else {
+                        brakeValve22 = 1;   
+                        pc.printf("Braking Level 1\r\n");
+                    }
+                    break;
+                    
+//                case 2:
+//                    motor1.throttle(0.0f);
+//                    brakeValve32 = 0;
+//                    if (pressureSwitch2.read() == 0) {
+//                        brakeValve22 = 0;
+//                        pc.printf("Pressure 2 Reached");
+//                    }
+//                    else {
+//                        brakeValve22 = 1;   
+//                        pc.printf("Braking Level 2\r\n");
+//                    }
+//                    
+//                    break;
+                    
+                case 2 ... 4:
+                    motor1.throttle(0.0f);
+                    brakeValve32 = 0;
+                    brakeValve22 = 1;
+                    
+//                    if (pressureSwitch3.read() == 0) {
+//                        brakeValve22 = 0;
+//                        pc.printf("Pressure 3 Reached");
+//                    }
+//                    else {
+//                        brakeValve22 = 1;  
+//                        pc.printf("Braking Level 3\r\n");
+//                    }
+                    break;
+                    
+                    
+                default:    // NO BRAKING
+                    brakeValve32 = 1;
+                    brakeValve22 = 1;
+                    break;
+            }
+        }
+    }   
+    return;
+}
+
+void speedControl(int commandedSpeed) {
+    if (dashboard.currentSpeed < 16.00) {  // IF SPEED LESS THAN LIMIT
+        switch (commandedSpeed) {
+            
+            default:
+//                motor1.throttle(0.0f);
+                break;
+                
+            case 0:
+                motor1.throttle(0.0f);
+                break;
+                
+            case 1 ... 2:
+                motor1.throttle(0.1f);
+                break;
+                
+            case 3 ... 4:
+                motor1.throttle(0.2f);
+                break;
+                
+            case 5 ... 6:
+                motor1.throttle(0.3f);
+                break;
+                
+            case 7 ... 8:
+                motor1.throttle(0.4f);
+                break;
+                
+            case 9 ... 10:
+                motor1.throttle(0.5f);
+                break;
+                
+            case 11:
+                motor1.throttle(0.6f);
+                break;
+                
+            case 12:
+                motor1.throttle(0.7f);
+                break;
+                
+            case 13:
+                motor1.throttle(0.8f);
+                break;
+                
+            case 14:
+                motor1.throttle(0.9f);
+                break;
+                
+            case 15:
+                motor1.throttle(1.0f);
+                break;
+        }
+    }
+    else {  // IF OVER 15KPH
+        if (dashboard.currentSpeed < 20.00) {   // If speed less than 20 (we cant physically go this fast so any faster is probably compressor noise), cut throttle, otherwise ignore
+            motor1.throttle(0.0f);    // COMMENTED AS ALREADY SET 0 IN BRAKECONTROL
+//          brakeControl(1);
+        }
+    }
+}
+
+/*void speedControl(int commandedSpeed) {
+    if (commandedSpeed > dashboard.currentSpeed) {  // IF THROTTLE REQUESTED
+        // Max possible difference is 15
+        // Motor Analog Voltage between 0 and 5
+        // 5 / 15 = 0.33333 = 0.4v / kph difference
+        
+        int difference = commandedSpeed - dashboard.currentSpeed;
+        
+        switch (difference) {
+            case 1:
+                motor1.throttle(0.1f);
+//              motor2.throttle(0.1f);
+                pc.printf("Throttle set to 10%\r\n");
+                break;
+                
+            case 2 ... 3:
+                motor1.throttle(0.2f);
+//                motor2.throttle(0.2f);
+                pc.printf("Throttle set to 20%\r\n");
+                break;
+            
+            case 4 ... 6:
+                motor1.throttle(0.4f);
+//                motor2.throttle(0.4f);
+                pc.printf("Throttle set to 40%\r\n");
+                break;
+            
+            case 7 ... 9:
+                motor1.throttle(0.6f);
+//                motor2.throttle(0.6f);
+                pc.printf("Throttle set to 60%\r\n");
+                break;
+                
+            case 10 ... 12:
+                motor1.throttle(0.8f);
+//                motor2.throttle(0.8f);
+                pc.printf("Throttle set to 80%\r\n");
+                break;
+                
+            case 13 ... 15:
+                motor1.throttle(1.0f);
+//                motor2.throttle(1.0f);
+                pc.printf("Throttle set to 100%\r\n");
+                break;
+                
+            default:
+                motor1.throttle(0.0f);
+                break;
+        }
+    }
+    else {  // COAST
+        motor1.throttle(0.0f);
+//        motor2.throttle(0.0f);
+    }
+}*/
+
+int main() {
+    pc.baud(115200);
+    
+    // CONFIGURE INTERRUPTS
+    rtc_output.rise(&emergencyStop);
+
+    millisStart();
+    
+    rtc_Trigger = 1;
+
+    // LOCAL VARIABLES
+    bool systemOn = false;   // On/Off status of loco
+    int lastKnownDirection = 2;
+    bool inParkMode = false;
+    
+    // Record last time error was sent
+    unsigned long lastErrorMillis = 0;
+
+    while(1) {
+     
+        while(remote.commsGood == true) {
+            
+            // PING
+            remote.commsCheck();
+            // GET SWITCH STATES
+            remote.getSwitchStates();
+            
+            // ALLOW BRAKES TO BE OPERATED
+            brakeControl(remote.braking);
+            
+            // Print Pressure Switch States (Debugging)
+//            pc.printf("Pressure Switch 1: %d\r\n", pressureSwitch1.read());
+//            pc.printf("Pressure Switch 2: %d\r\n", pressureSwitch2.read());
+//            pc.printf("Pressure Switch 3: %d\r\n", pressureSwitch3.read());
+            
+            // SOUND WHISTLE IF WHISTLE BUTTON PRESSED 
+            if (remote.whistle == 0) {
+                 whistleValve32 = 1;
+//                 wait(0.5);
+//                 whistleValve32 = 1;
+             }
+             else {
+                 whistleValve32 = 0;
+             }   
+
+
+            //  GET AND DISPLAY SPEED
+            dashboard.getCurrentSpeed();
+            remote.sendData(2, dashboard.currentSpeed);       // Send speed to remote
+                
+            // TOGGLE COMPRESSOR
+            remote.compressor == 0 ? contactCompressor = 1 : contactCompressor = 0;
+            
+            // TOGGLE MOTOR CONTROLLER DEADMAN (SEAT SWITCH AND FOOTBRAKE)
+            if (rtc.deadman == 0) { // IF DEADMAN PRESSED
+                motor1.closeDeadman();
+            }
+            else {
+                motor1.releaseDeadman();
+            }
+            
+            // TOGGLE REGEN THROTTLING
+            if (challenge.regenThrottleActive == false) {
+                if (remote.regenThrottle == 0 && remote.start == 0) {    // TURN OFF IF ON
+                    challenge.regenThrottleOn();
+                }
+            }
+            else {
+                remote.sendError('B');     // Send error to remote
+                if (remote.regenThrottle == 1) {    // TURN ON IF OFF
+                    challenge.regenThrottleOff();
+                }
+            }
+            
+            //  TOGGLE REGEN BRAKING
+            if (challenge.regenBrakingActive == false) {
+                if (remote.regenBrake == 0 && remote.start == 0) {    // TURN OFF IF ON
+                    if (challenge.regenBrakingOn() == 0) {
+                        remote.sendError('I');     // Send error to remote
+                        pc.printf("Regen Braking Off - SuperCaps are full\r\n");
+                    }
+                }
+            }
+            else {
+                remote.sendError('C');     // Send error to remote
+                if (remote.regenBrake == 1) {     // TURN OFF
+                    challenge.regenBrakingOff();
+                    if (superCapVoltage == 1) {
+                        pc.printf("Regen Braking Off - SuperCaps are full\r\n");
+                        remote.sendError('I');     // Send error to remote
+                    }
+                }
+            }
+            
+
+            //  TOGGLE AUTOSTOP
+            if (challenge.autoStopActive == 0) {
+                if (remote.autoStop == 0 && remote.start == 0) {    // TURN OFF IF ON
+                    challenge.autoStopOn();
+                }
+            }
+            else {
+                remote.sendError('D');     // Send error to remote
+                if (remote.autoStop == 1) {    // TURN ON IF OFF
+                    challenge.autoStopOff();
+                }
+            }
+
+            //  TOGGLE INNOVATION
+            if (challenge.innovationActive == 0) {
+                if (remote.innovation == 0 && remote.start == 0) {    // TURN OFF IF ON
+                    if (driveMode == 0) {
+                        challenge.innovationOn();
+                    }
+                    else {
+                        remote.sendError('J');     // Send error to remote
+                        pc.printf("Can only active innovation mode in forward direction\r\n");
+                    }
+                }
+            }
+            else {
+                remote.sendError('E');     // Send error to remote
+                
+                if (remote.innovation == 1) {    // TURN ON IF OFF
+                    challenge.innovationOff();
+                }
+            }
+            
+            
+            // CONTROL
+            
+           if (systemOn == false) {
+            
+                if (remote.start == 1) {
+                    
+                    if (millis() - lastErrorMillis > 500) {
+                        remote.sendError('A');   // SEND ERROR MESSAGE 'A' TO REMOTE
+                        lastErrorMillis = millis();
+                    }
+                
+                    motor1.turnOff();
+//                    motor2.turnOff();
+                }
+                else {
+                    systemOn = true;
+                    pc.printf("Start Switch is On\r\n");
+//                    startupHealthCheck();   // Run System Startup Health Check - Will stay in here until it passes
+                    
+                    motor1.turnOn();    // Turn on motors
+//                    motor2.turnOn();
+                    
+                }
+            }   // END IF SYSTEMON = FALSE
+            else {  // IF SYSTEMON == TRUE
+                if (remote.start == 1) {
+                    systemOn = false;       // WILL STOP ABOVE HERE NEXT LOOP
+                    pc.printf("Start Switch is Off\r\n");
+                }
+                
+                if (driveMode != 0 && remote.forward == 0) {
+                    driveMode = 0;
+                    motor1.setForward();
+//                    motor2.setForward();
+                }
+                if (driveMode != 1 && remote.reverse == 0) {
+                    driveMode = 1;
+                    motor1.setReverse();
+//                    motor2.setReverse();
+                }
+                if (driveMode != 2 && remote.park == 0) {
+                    driveMode = 2;
+                    motor1.setPark();
+                    motor1.throttle(0);
+//                    motor2.setPark();
+                }
+
+                if (driveMode == 2) {                             //place in park mode if selected by driver
+                
+//                    pc.printf("RTC Output is %d\r\n", rtc_output.read());
+//                    pc.printf("EM State Output is %d\r\n", emergencyStopActive);
+//                    pc.printf("ParkMode = %d", inParkMode);
+                    
+                    if (inParkMode == false) {
+                        pc.printf("Train in park mode.\r\n");
+                    }
+                    
+                    if (emergencyStopActive == true && rtc_output.read() == 0) {   // Clear emergency stop flag
+                        emergencyStopActive = false;
+                    }
+                    
+                    led_parkMode = 1;
+                    inParkMode = true;      // Stop above debug print from displaying more than once
+                    
+                    motor1.setPark();
+//                    motor2.setPark();
+                    
+                }
+                else{                                                   //else i.e if selected drive mode is forward or reverse
+//                    pc.printf("RTC Output is %d\r\n", rtc_output.read());
+//                    pc.printf("EM State Output is %d\r\n", emergencyStopActive);
+                    if (emergencyStopActive == false && rtc_output.read() == 0) {                                  // IF RTC FLAGGED AS SAFE
+                    
+//                        if (dashboard.currentSpeed < 1 || driveMode == lastKnownDirection) {      //do not allow motors to reverse if significant forward speed exists
+                            
+                            led_parkMode = 0;
+                            inParkMode = false;
+                            
+                            if (driveMode != lastKnownDirection) {
+                                pc.printf("Train enabled for direction %d\r\n", driveMode);
+                                
+                                lastKnownDirection = driveMode;
+                            }
+                           
+
+                            if (challenge.autoStopInProgress == true) { // IF AUTOSTOPPING, PASS THROTTLE CONTROL TO FUNCTION
+                                challenge.autoStopControl();
+                                pc.printf("Autostop in Control\r\n");
+                            }
+                            else {  // OTHERWISE INPUT THROTTLE FROM REMOTE
+                                if (remote.throttle > 0) {   // If joystick pushed upwards = throttle
+                                    
+                                    if (challenge.innovationActive == true) {
+                                        pc.printf("Collision Detection in Control\r\n");
+                                        int innovationThrottle = challenge.innovationControl(remote.throttle);
+                                        speedControl(innovationThrottle);
+                                        
+                                        if (innovationThrottle == 0) {
+                                             emergencyStop();   // emergency Brake if obstacle detected
+                                        }
+                                    }
+                                    else {
+                                        speedControl(remote.throttle);
+                                        pc.printf("Throttling: %d\r\n", remote.throttle);
+                                    }
+                                } // remote.throttle
+                                else {
+                                    speedControl(0);  
+                                }
+                            }
+
+//                        }
+//                        else {
+//                            pc.printf("Cannot change direction until train has stopped moving\r\n");
+//                            remote.sendError('F');     // Send error to remote
+//                        }
+                    }
+                    else {
+                        pc.printf("Cannot exit park mode until RTC is cleared\r\n");
+                        inParkMode = false;
+                        remote.sendError('G');     // Send error to remote
+                    }
+                }
+            }   // END IF (SYSTEMON == TRUE)
+
+            wait_ms(500);   // SLOW DOWN THE SYSTEM (REMOTE CANT KEEP UP)
+        }   // END WHILE(COMMSGOOD)
+        pc.printf("Main Loop Skipped Due To Emergency Status\r\n");
+        emergencyStop();    // Emergency stop if comms lost with remote controller 
+
+    }   //END WHILE(1)
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/millis.lib	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/hudakz/code/millis/#ac7586424119
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motor.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,143 @@
+#include <mbed.h>
+#include "definitions.h"
+#include "motor.h"
+
+Motor::Motor   (AnalogOut& motorAccelerator,
+                AnalogOut& motorBrake,
+                DigitalOut& keySwitch,
+                DigitalOut& directionFwd,
+                DigitalOut& directionRev,
+                DigitalOut& footSwitch,
+                DigitalOut& seatSwitch,
+                DigitalOut& inchFwd,
+                DigitalOut& speedLimit2,
+                DigitalOut& speedLimit3) : 
+                
+                _motorAccelerator(motorAccelerator),
+                _motorBrake(motorBrake),
+                _keySwitch(keySwitch),
+                _directionFwd(directionFwd),
+                _directionRev(directionRev),
+                _footSwitch(footSwitch),
+                _seatSwitch(seatSwitch),
+                _inchFwd(inchFwd),
+                _speedLimit2(speedLimit2),
+                _speedLimit3(speedLimit3)
+                {
+                    _motorAccelerator = 0;
+                    _motorBrake = 0;
+//                    _contactMtr = 0;
+                    _keySwitch = 0;
+                    _directionFwd = 0;
+                    _directionRev = 0;
+                    _footSwitch = 0;
+                    _seatSwitch = 0;
+                    _inchFwd = 1;
+                    _speedLimit2 = 1;
+                    _speedLimit3 = 0;   // SET MAX SPEED MODE BY DEFAULT
+                }
+
+
+void Motor::turnOn() {
+    _keySwitch = 1;
+//    pc.printf("Motor Switched On\r\n");  
+}
+
+void Motor::turnOff() {
+    _keySwitch = 0;
+//    pc.printf("Motor Switched Off\r\n");  
+}
+
+void Motor::closeDeadman() {
+    _footSwitch = 1;
+    _seatSwitch = 1;
+}
+
+void Motor::releaseDeadman() {
+    _footSwitch = 0;
+    _seatSwitch = 0;
+}
+
+void Motor::setForward() {
+    _directionFwd = 1;
+    _directionRev = 0;
+//    pc.printf("Motor Set to Forward\r\n");  
+}
+
+void Motor::setPark() {
+    _directionFwd = 0;
+    _directionRev = 0;
+    
+//    pc.printf("Motor Set to Park\r\n"); 
+}
+
+void Motor::setReverse() {
+    _directionFwd = 0;
+    _directionRev = 1;
+//    pc.printf("Motor Set to Reverse\r\n"); 
+}
+
+void Motor::engage() {
+//    _contactMtr = 1;    
+//    pc.printf("Motor Contactor Engaged\r\n");   
+}
+
+void Motor::disengage() {
+//    _contactMtr = 0;
+    
+    setPark();
+    
+//    pc.printf("Motor Disengaged\r\n");  
+}
+
+void Motor::setSpeedMode(int speed) {
+    switch (speed) {
+        case 0:     // Clear limits
+        
+            _inchFwd = 0;
+            _speedLimit2 = 0;
+            _speedLimit3 = 0;
+            
+//                    pc.printf("Motor Speed Cleared\r\n");
+            break;
+        
+        case 1:     // Inch Forward
+        
+            _inchFwd = 1;
+            _speedLimit2 = 0;
+            _speedLimit3 = 0;
+            
+//                    pc.printf("Motor Set to Inch Forward\r\n");
+            break;
+            
+        case 2:     // Speed 2
+            
+            _inchFwd = 0;
+            _speedLimit2 = 1;
+            _speedLimit3 = 0;
+            
+//                    pc.printf("Motor Set to Speed Limit 2\r\n");
+            break;
+            
+        case 3:     // Speed 3
+            
+            _inchFwd = 0;
+            _speedLimit2 = 0;
+            _speedLimit3 = 1;
+            
+//            pc.printf("Motor Set to Speed Limit 3\r\n");
+            break;   
+    }
+}
+
+void Motor::throttle(float throttleRate) {
+    // set the output voltage of the analog output pin specified as a percentage of Vcc (3.3V)
+    _motorAccelerator = throttleRate;   // Analog value between 0.0f and 1.0f
+//    pc.printf("Throttling\r\n");
+    
+}
+
+void Motor::brake(float brakeRate) {
+    _motorBrake = brakeRate;            // Analog value between 0.0f and 1.0f
+//    pc.printf("Motor Braking\r\n");
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motor.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,45 @@
+#ifndef MOTOR_H
+#define MOTOR_H
+
+#include <mbed.h>
+
+class Motor {
+    public:
+        Motor  (AnalogOut& motorAccelerator,
+                AnalogOut& motorBrake,
+                DigitalOut& keySwitch,
+                DigitalOut& directionFwd,
+                DigitalOut& directionRev,
+                DigitalOut& footSwitch,
+                DigitalOut& seatSwitch,
+                DigitalOut& inchFwd,
+                DigitalOut& speedLimit2,
+                DigitalOut& speedLimit3);
+                
+        void turnOn();
+        void turnOff();
+        void closeDeadman();
+        void releaseDeadman();
+        void setForward();
+        void setPark();
+        void setReverse();
+        void engage();
+        void disengage();
+        void setSpeedMode(int speed);
+        void throttle(float throttleRate);
+        void brake(float brakeRate);
+        
+    private:
+        AnalogOut& _motorAccelerator;
+        AnalogOut& _motorBrake;
+        DigitalOut& _keySwitch;
+        DigitalOut& _directionFwd;
+        DigitalOut& _directionRev;
+        DigitalOut& _footSwitch;
+        DigitalOut& _seatSwitch;
+        DigitalOut& _inchFwd;
+        DigitalOut& _speedLimit2;
+        DigitalOut& _speedLimit3;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remoteControl.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,181 @@
+#include <mbed.h>
+#include "remoteControl.h"
+#include "definitions.h"
+
+Remote::Remote(SPI& remoteControl, DigitalOut& remoteControlCS) : _remoteControl(remoteControl), _remoteControlCS(remoteControlCS) {
+    _remoteControl.format(8,0);    // FORMAT SPI AS 8-BIT DATA, SPI CLOCK MODE 0
+    const long arduinoClock = 16000000;
+    long spiFrequency = arduinoClock / 4;
+    _remoteControl.frequency(spiFrequency); // SET SPI CLOCK FREQUENCY
+    
+    _remoteControlCS = 1;   // DISABLE SLAVE
+    spiDelay = 600;    //DELAY BETWEEN SPI TRANSACTIONS (SO ARDUINO CAN KEEP UP WITH REQUESTS)
+    
+    commsGood = false;                 // Successful Comms Between Nucleo and Remote Control
+    commsFailures = 0;                      // Number of consecutive remote comms failures
+    errorIndex = 0;
+    
+//    remoteSwitchStateTicker.attach(this, &Remote::getSwitchStates, 0.2);
+    commsCheckTicker.attach(this, &Remote::commsCheck, 0.2);  // Run the commsCheck function every 0.1s with the commsCheckTicker. - &commsCheck = The address of the function to be attached and 0.1 = the interval
+}
+
+int Remote::sendData(int precursor, int data) {
+    int response  = 0;
+    
+    _remoteControlCS = 0;          // ENABLE REMOTE SPI
+//    pc.printf("Enabled \r\n");
+    _remoteControl.write(precursor);   // Prepare arduino to receive data
+    wait_us(spiDelay);
+    _remoteControl.write(data);          // SEND DATA
+    wait_us(spiDelay);
+    response = _remoteControl.write(255);
+    wait_us(spiDelay);
+    
+    _remoteControlCS = 1;         // DISABLE REMOTE SPI
+//    pc.printf("Disabling\r\n");
+
+    return response;
+}
+
+void Remote::commsCheck() {
+    // Send a random number to the controller and expect its square in return for valid operation.
+    
+    // Random number between 2 and 15. Reply should be the squared, and within the 1 byte size limit of 255 for SPI comms.
+    // Does not conflict with switch states as they use ASCII A, B C etc which are Decimal 65+
+    int randomNumber = rand() % (15 - 2 + 1) + 2;  // rand()%(max-min + 1) + min inclusive of max and min
+    int expectedResponse = randomNumber * randomNumber;
+    int actualResponse = 0;
+    
+    actualResponse = sendData(1, randomNumber);
+    
+//    pc.printf("Random Number: %d\r\n", randomNumber);
+//    pc.printf("Expected: %d\r\n", expectedResponse);
+//    pc.printf("Actual: %d\r\n", actualResponse);
+    
+    if (actualResponse == expectedResponse) {
+        commsGood = true;
+        commsFailures = 0;          // Reset consecutive failure count
+    }
+    else
+    {
+//        pc.printf("Failed at: \r\n");
+//        pc.printf("Random Number: %d\r\n", randomNumber);
+//        pc.printf("Expected: %d\r\n", expectedResponse);
+//        pc.printf("Actual: %d\r\n", actualResponse);
+        
+        if (commsFailures++ > 3) {            // Increment consecutive failure count
+            commsGood = false;              // Flag comms failure after 3 failures (> 0.3 seconds)
+//            pc.printf("Remote Comms Failure!\r\n");
+        }
+    }
+//    pc.printf("commsGood: %d\r\n", commsGood);
+}
+
+// CONVERT BYTE TO BITS
+/* 
+The received bytes from the remote control uses bitmapping.
+Each 0/1 bit represents the on/ off state of a switch.
+This function takes each bit and assigned it to a switch variable.
+*/
+void Remote::ByteToBits(unsigned char character, bool *boolArray)
+{
+    for (int i=0; i < 8; ++i) {
+        boolArray[i] = (character & (1<<i)) != 0;
+    }   
+}
+
+void Remote::getSwitchStates() {
+    // GET THE SWITCH STATES FROM THE REMOTE CONTROL
+
+    
+    bool bitGroupA[8] = {1, 1, 1, 1, 1, 1, 1, 1};
+    bool bitGroupB[8] = {1, 1, 1, 1, 1, 1, 1, 1};
+        
+    char slaveReceivedA, slaveReceivedB;  // BYTE RECEIVED FROM REMOTE CONTROL
+    
+    slaveReceivedA = sendData(3, 3);
+    slaveReceivedB = sendData(4, 4);
+    throttle = sendData(5, 5);
+    braking = sendData(6, 6);
+            
+    ByteToBits(slaveReceivedA, bitGroupA);    // CONVERT GROUP A BYTE TO BITS
+    ByteToBits(slaveReceivedB, bitGroupB);    // CONVERT GROUP B BYTE TO BITS
+    
+    // ASSIGN VARIABLES FROM BIT GROUPS
+
+    start         = bitGroupA[0];
+    forward       = bitGroupA[1];
+    park          = bitGroupA[2];
+    reverse       = bitGroupA[3];
+    compressor    = bitGroupA[4];
+    autoStop      = bitGroupA[5];
+    regenBrake    = bitGroupA[6];
+    regenThrottle = bitGroupA[7];
+    
+    whistle       = bitGroupB[0];
+    innovation    = bitGroupB[1];
+   
+//    pc.printf("Start: %d\n\r", start);
+//    pc.printf("Forward: %d\n\r", forward);
+//    pc.printf("Park: %d\n\r", park);
+//    pc.printf("Reverse: %d\n\r", reverse);
+//    pc.printf("Compressor: %d\n\r", compressor);
+//    pc.printf("AutoStop: %d\n\r", autoStop);
+//    pc.printf("Regen Brake: %d\n\r", regenBrake);
+//    pc.printf("Regen Throttle: %d\n\r", regenThrottle);
+//    pc.printf("Whistle: %d\n\r", whistle);
+//    pc.printf("Innovation: %d\n\r", innovation);
+//    pc.printf("Throttle: %d\n\r", throttle);
+//    pc.printf("Brake: %d\n\r", braking);
+        
+}
+        
+void Remote::setTime(int hr, int min, int sec, int day, int mon, int yr) {
+    _remoteControlCS = 0;
+    
+    _remoteControl.write(7);
+    wait_us(spiDelay);
+    _remoteControl.write(hr);
+    wait_us(spiDelay);
+    _remoteControl.write(min);
+    wait_us(spiDelay);
+    _remoteControl.write(sec);
+    wait_us(spiDelay);
+    _remoteControl.write(day);
+    wait_us(spiDelay);
+    _remoteControl.write(mon);
+    wait_us(spiDelay);
+    _remoteControl.write(yr);
+    wait_us(spiDelay);
+    _remoteControl.write(255);
+    
+    _remoteControlCS = 1;   // DISABLE REMOTE SPI
+}
+
+void Remote::sendError(int error) {
+
+    bool errorInBuffer = false;
+    
+    for (int index = 0; index < errorIndex; index++) {
+        if (errorBuffer[index] == error) {
+            errorInBuffer == true;
+            break;
+        }
+    }
+    
+    if (errorInBuffer == false) {
+        errorBuffer[errorIndex++] = error;
+    }
+    else {
+        errorInBuffer = false;  // reset
+    }
+    
+    sendData(8, errorBuffer[0]);
+
+    for (int index = 0; index < errorIndex; index++) {
+        errorBuffer[index] = errorBuffer[index + 1];
+    }
+    errorIndex--;
+    
+    wait_ms(100);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remoteControl.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,48 @@
+#ifndef REMOTECONTROL_H
+#define REMOTECONTROL_H
+
+#include <mbed.h>
+
+class Remote{
+    public:
+        // CONSTRUCTOR
+        Remote(SPI& remoteControl, DigitalOut& remoteControlCS);
+        
+        bool commsGood;                 // Successful Comms Between Nucleo and Remote Control
+        
+        volatile int throttle;
+        volatile int braking;
+        volatile bool start;
+        volatile bool forward;
+        volatile bool park;
+        volatile bool reverse;
+        volatile bool compressor;
+        volatile bool autoStop;
+        volatile bool regenBrake;
+        volatile bool regenThrottle;
+        volatile bool whistle;
+        volatile bool innovation;
+        
+        void initialiseRemoteComms();
+        int sendData(int precursor, int data);
+        void sendError(int error);
+        void commsCheck();
+        void getSwitchStates();
+        void setTime(int hr, int min, int sec, int day, int mon, int yr);
+        
+    private:
+        SPI& _remoteControl;
+        DigitalOut& _remoteControlCS;
+
+        int spiDelay;
+        int commsFailures;                      // Number of consecutive remote comms failures
+        int errorIndex;
+        int errorBuffer[27];
+        
+        void ByteToBits(unsigned char character, bool *boolArray);
+        
+        Ticker commsCheckTicker;                    //ticker for recurring comms check
+        Ticker remoteSwitchStateTicker;             //ticker for recurring remote switch state update
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rtc.cpp	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,61 @@
+#include <mbed.h>
+#include "definitions.h"
+//#include "remoteControl.h"    // Enable if you want error sent to remote
+#include "rtc.h"
+#include "motor.h"
+//
+RoundTrainCircuit::RoundTrainCircuit(
+                            DigitalIn rtc_1, 
+                            DigitalIn rtc_2,
+                            DigitalIn rtc_3,
+                            DigitalIn rtc_4,
+                            DigitalIn rtc_5,
+                            DigitalIn rtc_6,
+                            DigitalIn rtc_7,
+                            DigitalIn rtc_override) :
+                            
+                            deadman(rtc_1),
+                            emergencyButtonLeft(rtc_2),
+                            emergencyButtonRight(rtc_3),
+                            heatDetector(rtc_4),
+                            driverCord(rtc_5),
+                            superCapOverVoltage(rtc_6),
+                            spare(rtc_7),
+                            override(rtc_override)
+                            {
+
+}
+
+void RoundTrainCircuit::getTriggerCause() {
+
+    if (deadman == 1) {
+        pc.printf("Deadman Switch Triggered\r\n");
+//        DigitalOut footswitchM1(PD_4);
+//        DigitalOut seatM1(PD_5);
+    }
+    
+    if (emergencyButtonLeft == 1) {
+        pc.printf("Left Emergency Button Operated\r\n");
+    }
+    
+    if (emergencyButtonRight == 1) {
+        pc.printf("Right Emergency Button Operated\r\n");
+    }
+    
+    
+    if (heatDetector == 1) {
+        pc.printf("Heat Detector Triggered\r\n");
+    }
+    
+    if (driverCord == 1) {
+        pc.printf("Driver Cord Released\r\n");
+    }
+    
+    if (superCapOverVoltage == 1) {
+        pc.printf("Super Cap Reached Dangerous Levels\r\n");
+    }
+    
+    if (spare == 1) {
+        pc.printf("Spare Input Triggered\r\n");
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rtc.h	Fri Mar 13 11:48:04 2020 +0000
@@ -0,0 +1,27 @@
+#ifndef RTC_H
+#define RTC_H
+
+class RoundTrainCircuit {
+    public:
+        RoundTrainCircuit  (DigitalIn rtc_1, 
+                            DigitalIn rtc_2,
+                            DigitalIn rtc_3,
+                            DigitalIn rtc_4,
+                            DigitalIn rtc_5,
+                            DigitalIn rtc_6,
+                            DigitalIn rtc_7,
+                            DigitalIn rtc_override);
+        
+        DigitalIn deadman;
+        DigitalIn emergencyButtonLeft;
+        DigitalIn emergencyButtonRight;
+        DigitalIn heatDetector;
+        DigitalIn driverCord;
+        DigitalIn superCapOverVoltage;
+        DigitalIn spare;
+        DigitalIn override;
+                            
+        void getTriggerCause();
+};
+
+#endif
\ No newline at end of file