Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:4788e1df7b55, committed 2020-03-13
- 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
--- /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