Dual Brushless Motor ESC, 10-62V, up to 50A per motor. Motors ganged or independent, multiple control input methods, cycle-by-cycle current limit, speed mode and torque mode control. Motors tiny to kW. Speed limit and other parameters easily set in firmware. As used in 'The Brushless Brutalist' locomotive - www.jons-workshop.com. See also Model Engineer magazine June-October 2019.

Dependencies:   mbed BufferedSerial Servo PCT2075 FastPWM

Update 17th August 2020 Radio control inputs completed

Committer:
JonFreeman
Date:
Sun Sep 29 16:34:37 2019 +0000
Revision:
13:ef7a06fa11de
Parent:
12:d1d21a2941ef
Child:
15:2591e2008323
Stable code as at end of 2019 running season

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 13:ef7a06fa11de 1 /*
JonFreeman 13:ef7a06fa11de 2 STM3_ESC Electronic Speed Controller board, drives Two Brushless Motors, full Four Quadrant Control.
JonFreeman 13:ef7a06fa11de 3 Jon Freeman B. Eng Hons
JonFreeman 13:ef7a06fa11de 4 2015 - 2019
JonFreeman 13:ef7a06fa11de 5 */
JonFreeman 0:435bf84ce48a 6 #include "mbed.h"
JonFreeman 13:ef7a06fa11de 7 #include "STM3_ESC.h"
JonFreeman 0:435bf84ce48a 8 #include "BufferedSerial.h"
JonFreeman 0:435bf84ce48a 9 #include "FastPWM.h"
JonFreeman 4:21d91465e4b1 10 #include "Servo.h"
JonFreeman 10:e40d8724268a 11 #include "brushless_motor.h"
JonFreeman 11:bfb73f083009 12 #include "Radio_Control_In.h"
JonFreeman 13:ef7a06fa11de 13 //#ifdef TARGET_NUCLEO_F401RE //
JonFreeman 5:ca86a7848d54 14
JonFreeman 13:ef7a06fa11de 15 //#endif
JonFreeman 5:ca86a7848d54 16 /*
JonFreeman 13:ef7a06fa11de 17 Brushless_STM3_ESC board
JonFreeman 12:d1d21a2941ef 18 Jan 2019 * WatchDog implemented. Default is disabled, 'kd' command from TS controller enables and reloads
JonFreeman 12:d1d21a2941ef 19 * Tidied brushless_motor class, parameter passing now done properly
JonFreeman 12:d1d21a2941ef 20 * class RControl_In created. Inputs now routed to new pins, can now use two chans both class RControl_In and Servo out
JonFreeman 13:ef7a06fa11de 21 (buggery board required for new inputs on June 2018 issue boards)
JonFreeman 12:d1d21a2941ef 22 * Added version string
JonFreeman 12:d1d21a2941ef 23 * Error handler written and included
JonFreeman 12:d1d21a2941ef 24 * Realised Nanotec motors are 6 pole, all others are 8 pole. Modified 'mode' to include 'motor poles' in EEPROM data, now speed reading correct for all
JonFreeman 12:d1d21a2941ef 25 * Reorganised EEPROM data - mode setting now much easier, less error prone
JonFreeman 13:ef7a06fa11de 26 * Maximum speed now one EEPROM option, range 1.0 to 25.0 MPH in 0.1 MPH steps
JonFreeman 12:d1d21a2941ef 27
JonFreeman 10:e40d8724268a 28 New 29th May 2018 **
JonFreeman 10:e40d8724268a 29 LMT01 temperature sensor routed to T1 - and rerouted to PC_13 as InterruptIn on T1 (ports A and B I think) not workable
JonFreeman 13:ef7a06fa11de 30 March 2019 temp sensor only included with TEMP_SENSOR_ENABLE defined. Temp reading not essential, LMT01 was not a good choice due to
JonFreeman 13:ef7a06fa11de 31 significant loading of interrupts, threatening integrity of Real Time System
JonFreeman 5:ca86a7848d54 32 */
JonFreeman 5:ca86a7848d54 33
JonFreeman 5:ca86a7848d54 34
JonFreeman 0:435bf84ce48a 35 /* STM32F401RE - compile using NUCLEO-F401RE
JonFreeman 12:d1d21a2941ef 36 // PROJECT - STM3_ESC Dual Brushless Motor Controller - Jon Freeman June 2018.
JonFreeman 0:435bf84ce48a 37
JonFreeman 0:435bf84ce48a 38 AnalogIn to read each motor current
JonFreeman 0:435bf84ce48a 39
JonFreeman 0:435bf84ce48a 40 ____________________________________________________________________________________
JonFreeman 0:435bf84ce48a 41 CONTROL PHILOSOPHY
JonFreeman 13:ef7a06fa11de 42 This STM3_ESC Bogie drive board software should ensure sensible control when commands supplied are not sensible !
JonFreeman 0:435bf84ce48a 43
JonFreeman 0:435bf84ce48a 44 That is, smooth transition between Drive, Coast and Brake to be implemented here.
JonFreeman 0:435bf84ce48a 45 The remote controller must not be relied upon to deliver sensible command sequences.
JonFreeman 0:435bf84ce48a 46
JonFreeman 0:435bf84ce48a 47 So much the better if the remote controller does issue sensible commands, but ...
JonFreeman 0:435bf84ce48a 48
JonFreeman 0:435bf84ce48a 49 ____________________________________________________________________________________
JonFreeman 0:435bf84ce48a 50
JonFreeman 0:435bf84ce48a 51
JonFreeman 0:435bf84ce48a 52 */
JonFreeman 8:93203f473f6e 53
JonFreeman 7:6deaeace9a3e 54 #if defined (TARGET_NUCLEO_F401RE) // CPU in 64 pin LQFP
JonFreeman 9:ac2412df01be 55 #include "F401RE.h" // See here for warnings about Servo InterruptIn not working
JonFreeman 6:f289a49c1eae 56 #endif
JonFreeman 13:ef7a06fa11de 57 #if defined (TARGET_NUCLEO_F411RE) // CPU in 64 pin LQFP
JonFreeman 13:ef7a06fa11de 58 #include "F411RE.h" // See here for warnings about Servo InterruptIn not working
JonFreeman 13:ef7a06fa11de 59 #endif
JonFreeman 7:6deaeace9a3e 60 #if defined (TARGET_NUCLEO_F446ZE) // CPU in 144 pin LQFP
JonFreeman 10:e40d8724268a 61 #include "F446ZE.h" // A thought for future version
JonFreeman 6:f289a49c1eae 62 #endif
JonFreeman 0:435bf84ce48a 63 /* Global variable declarations */
JonFreeman 13:ef7a06fa11de 64 char const_version_string[] = {"1.0.y2019.m09.d29\0"}; // Version string, readable from serial ports
JonFreeman 3:ecb00e0e8d68 65 volatile uint32_t fast_sys_timer = 0; // gets incremented by our Ticker ISR every VOLTAGE_READ_INTERVAL_US
JonFreeman 13:ef7a06fa11de 66 //int WatchDog = WATCHDOG_RELOAD + 80; // Allow extra few seconds at powerup
JonFreeman 13:ef7a06fa11de 67 int WatchDog = 0; // Set this up in main once pre-flight checks done. Allow extra few seconds at powerup
JonFreeman 8:93203f473f6e 68 bool WatchDogEnable = false; // Must recieve explicit instruction from pc or controller to enable
JonFreeman 0:435bf84ce48a 69 uint32_t volt_reading = 0, // Global updated by interrupt driven read of Battery Volts
JonFreeman 0:435bf84ce48a 70 driverpot_reading = 0, // Global updated by interrupt driven read of Drivers Pot
JonFreeman 13:ef7a06fa11de 71 sys_timer = 0, // gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US, 31250us at Sept 2019
JonFreeman 5:ca86a7848d54 72 AtoD_Semaphore = 0;
JonFreeman 12:d1d21a2941ef 73
JonFreeman 11:bfb73f083009 74 bool loop_flag = false; // made true in ISR_loop_timer, picked up and made false again in main programme loop
JonFreeman 11:bfb73f083009 75 bool flag_8Hz = false; // As loop_flag but repeats 8 times per sec
JonFreeman 6:f289a49c1eae 76 bool temp_sensor_exists = false;
JonFreeman 12:d1d21a2941ef 77 double rpm2mph;
JonFreeman 3:ecb00e0e8d68 78
JonFreeman 13:ef7a06fa11de 79 double Current_Scaler_Sep_2019 = 1.0; // New idea - Sept 2019. Plan is to scale down motor current limit when voltage lower than nom.
JonFreeman 13:ef7a06fa11de 80 // See schematic for full details, but cycle-by-cycle current limit has the effect of allowing larger average I
JonFreeman 13:ef7a06fa11de 81 // at lower voltages. This is simply because current takes longer to build in motor inductance when voltage
JonFreeman 13:ef7a06fa11de 82 // is low. Conversely, at high supply voltages, motor current reaches limit quickly, cutting drive, meaning
JonFreeman 13:ef7a06fa11de 83 // similar current flows for shorter times at higher voltages.
JonFreeman 13:ef7a06fa11de 84
JonFreeman 13:ef7a06fa11de 85 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 6:f289a49c1eae 86 uint32_t temp_sensor_count = 0, // incremented by every rising edge from LMT01
JonFreeman 12:d1d21a2941ef 87 last_temperature_count = 0; // global updated approx every 100ms after each LMT01 conversion completes
JonFreeman 13:ef7a06fa11de 88 #endif
JonFreeman 0:435bf84ce48a 89 /* End of Global variable declarations */
JonFreeman 0:435bf84ce48a 90
JonFreeman 0:435bf84ce48a 91 Ticker tick_vread; // Device to cause periodic interrupts, used to time voltage readings etc
JonFreeman 0:435bf84ce48a 92 Ticker loop_timer; // Device to cause periodic interrupts, used to sync iterations of main programme loop
JonFreeman 13:ef7a06fa11de 93 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 6:f289a49c1eae 94 Ticker temperature_find_ticker;
JonFreeman 6:f289a49c1eae 95 Timer temperature_timer;
JonFreeman 13:ef7a06fa11de 96 #endif
JonFreeman 12:d1d21a2941ef 97 #ifdef USING_DC_MOTORS
JonFreeman 8:93203f473f6e 98 Timer dc_motor_kicker_timer;
JonFreeman 8:93203f473f6e 99 Timeout motors_restore;
JonFreeman 12:d1d21a2941ef 100 #endif
JonFreeman 12:d1d21a2941ef 101
JonFreeman 11:bfb73f083009 102 RControl_In RC_chan_1 (PC_14);
JonFreeman 11:bfb73f083009 103 RControl_In RC_chan_2 (PC_15); // Instantiate two radio control input channels and specify which InterruptIn pin
JonFreeman 12:d1d21a2941ef 104 error_handling_Jan_2019 ESC_Error ; // Provides array usable to store error codes.
JonFreeman 0:435bf84ce48a 105
JonFreeman 12:d1d21a2941ef 106 eeprom_settings mode (SDA_PIN, SCL_PIN) ; // This MUST come before Motors setup
JonFreeman 4:21d91465e4b1 107
JonFreeman 0:435bf84ce48a 108 //uint32_t HAtot = 0, HBtot = 0, A_Offset = 0, B_Offset = 0;
JonFreeman 0:435bf84ce48a 109 /*
JonFreeman 0:435bf84ce48a 110 5 1 3 2 6 4 SENSOR SEQUENCE
JonFreeman 0:435bf84ce48a 111
JonFreeman 3:ecb00e0e8d68 112 1 1 1 1 0 0 0 ---___---___ Hall1
JonFreeman 3:ecb00e0e8d68 113 2 0 0 1 1 1 0 __---___---_ Hall2
JonFreeman 3:ecb00e0e8d68 114 4 1 0 0 0 1 1 -___---___-- Hall3
JonFreeman 0:435bf84ce48a 115
JonFreeman 0:435bf84ce48a 116 UV WV WU VU VW UW OUTPUT SEQUENCE
JonFreeman 8:93203f473f6e 117
JonFreeman 8:93203f473f6e 118 8th July 2018
JonFreeman 8:93203f473f6e 119 Added drive to DC brushed motors.
JonFreeman 8:93203f473f6e 120 Connect U and W to dc motor, leave V open.
JonFreeman 8:93203f473f6e 121
JonFreeman 8:93203f473f6e 122 Hall codes 0 and 7 not used for brushless motors. Without Hall sensors connected pullup resistors give code 7. Use this for dc motors
JonFreeman 8:93203f473f6e 123
JonFreeman 0:435bf84ce48a 124 */
JonFreeman 3:ecb00e0e8d68 125 const uint16_t A_tabl[] = { // Origial table
JonFreeman 0:435bf84ce48a 126 0, 0, 0, 0, 0, 0, 0, 0, // Handbrake
JonFreeman 10:e40d8724268a 127 0, AWHVL,AVHUL,AWHUL,AUHWL,AUHVL,AVHWL,AUHWL, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
JonFreeman 10:e40d8724268a 128 0, AVHWL,AUHVL,AUHWL,AWHUL,AVHUL,AWHVL,AWHUL, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
JonFreeman 8:93203f473f6e 129 0, BRA,BRA,BRA,BRA,BRA,BRA,BRA, // Regenerative Braking
JonFreeman 4:21d91465e4b1 130 KEEP_L_MASK_A, KEEP_H_MASK_A // [32 and 33]
JonFreeman 3:ecb00e0e8d68 131 } ;
JonFreeman 11:bfb73f083009 132
JonFreeman 0:435bf84ce48a 133 const uint16_t B_tabl[] = {
JonFreeman 0:435bf84ce48a 134 0, 0, 0, 0, 0, 0, 0, 0, // Handbrake
JonFreeman 10:e40d8724268a 135 0, BWHVL,BVHUL,BWHUL,BUHWL,BUHVL,BVHWL,BUHWL, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
JonFreeman 10:e40d8724268a 136 0, BVHWL,BUHVL,BUHWL,BWHUL,BVHUL,BWHVL,BWHUL, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
JonFreeman 8:93203f473f6e 137 0, BRB,BRB,BRB,BRB,BRB,BRB,BRB, // Regenerative Braking
JonFreeman 4:21d91465e4b1 138 KEEP_L_MASK_B, KEEP_H_MASK_B
JonFreeman 3:ecb00e0e8d68 139 } ;
JonFreeman 0:435bf84ce48a 140
JonFreeman 12:d1d21a2941ef 141 brushless_motor MotorA (MOT_A_I_ADC, APWMV, APWMI, A_tabl, _MAH1, _MAH2, _MAH3, PortA, PORT_A_MASK, ISHUNTA);
JonFreeman 12:d1d21a2941ef 142 brushless_motor MotorB (MOT_B_I_ADC, BPWMV, BPWMI, B_tabl, _MBH1, _MBH2, _MBH3, PortB, PORT_B_MASK, ISHUNTB);
JonFreeman 2:04761b196473 143
JonFreeman 5:ca86a7848d54 144
JonFreeman 12:d1d21a2941ef 145 extern cli_2019 pcc, tsc; // command line interpreters from pc and touch screen
JonFreeman 12:d1d21a2941ef 146
JonFreeman 12:d1d21a2941ef 147 // Interrupt Service Routines
JonFreeman 13:ef7a06fa11de 148 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 12:d1d21a2941ef 149 void ISR_temperature_find_ticker () // every 960 us, i.e. slightly faster than once per milli sec
JonFreeman 12:d1d21a2941ef 150 {
JonFreeman 12:d1d21a2941ef 151 static bool readflag = false;
JonFreeman 12:d1d21a2941ef 152 int t = temperature_timer.read_ms ();
JonFreeman 12:d1d21a2941ef 153 if ((t == 5) && (!readflag)) {
JonFreeman 12:d1d21a2941ef 154 last_temperature_count = temp_sensor_count;
JonFreeman 12:d1d21a2941ef 155 temp_sensor_count = 0;
JonFreeman 12:d1d21a2941ef 156 readflag = true;
JonFreeman 12:d1d21a2941ef 157 }
JonFreeman 12:d1d21a2941ef 158 if (t == 6)
JonFreeman 12:d1d21a2941ef 159 readflag = false;
JonFreeman 12:d1d21a2941ef 160 }
JonFreeman 13:ef7a06fa11de 161 #endif
JonFreeman 12:d1d21a2941ef 162 /** void ISR_loop_timer ()
JonFreeman 12:d1d21a2941ef 163 * This ISR responds to Ticker interrupts at a rate of (probably) 32 times per second (check from constant declarations above)
JonFreeman 12:d1d21a2941ef 164 * This ISR sets global flag 'loop_flag' used to synchronise passes around main programme control loop.
JonFreeman 12:d1d21a2941ef 165 * Increments global 'sys_timer', usable anywhere as general measure of elapsed time
JonFreeman 12:d1d21a2941ef 166 */
JonFreeman 12:d1d21a2941ef 167 void ISR_loop_timer () // This is Ticker Interrupt Service Routine - loop timer - MAIN_LOOP_REPEAT_TIME_US
JonFreeman 8:93203f473f6e 168 {
JonFreeman 12:d1d21a2941ef 169 loop_flag = true; // set flag to allow main programme loop to proceed
JonFreeman 12:d1d21a2941ef 170 sys_timer++; // Just a handy measure of elapsed time for anything to use
JonFreeman 12:d1d21a2941ef 171 if ((sys_timer & 0x03) == 0)
JonFreeman 12:d1d21a2941ef 172 flag_8Hz = true;
JonFreeman 8:93203f473f6e 173 }
JonFreeman 8:93203f473f6e 174
JonFreeman 12:d1d21a2941ef 175 /** void ISR_voltage_reader ()
JonFreeman 12:d1d21a2941ef 176 * This ISR responds to Ticker interrupts every 'VOLTAGE_READ_INTERVAL_US' micro seconds
JonFreeman 12:d1d21a2941ef 177 *
JonFreeman 12:d1d21a2941ef 178 * AtoD_reader() called from convenient point in code to take readings outside of ISRs
JonFreeman 12:d1d21a2941ef 179 */
JonFreeman 12:d1d21a2941ef 180 void ISR_voltage_reader () // This is Ticker Interrupt Service Routine ; few us between readings ; VOLTAGE_READ_INTERVAL_US = 50
JonFreeman 12:d1d21a2941ef 181 {
JonFreeman 12:d1d21a2941ef 182 AtoD_Semaphore++;
JonFreeman 12:d1d21a2941ef 183 fast_sys_timer++; // Just a handy measure of elapsed time for anything to use
JonFreeman 12:d1d21a2941ef 184 }
JonFreeman 12:d1d21a2941ef 185
JonFreeman 13:ef7a06fa11de 186 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 12:d1d21a2941ef 187 void temp_sensor_isr () // got rising edge from LMT01. ALMOST CERTAIN this misses some
JonFreeman 12:d1d21a2941ef 188 {
JonFreeman 12:d1d21a2941ef 189 int t = temperature_timer.read_us (); // Must be being overrun by something, most likely culprit A-D reading ?
JonFreeman 12:d1d21a2941ef 190 temperature_timer.reset ();
JonFreeman 12:d1d21a2941ef 191 temp_sensor_count++;
JonFreeman 12:d1d21a2941ef 192 if (t > 18) // Yes proved some interrupts get missed, this fixes temperature reading
JonFreeman 12:d1d21a2941ef 193 temp_sensor_count++;
JonFreeman 12:d1d21a2941ef 194 // T2 = !T2; // scope hanger
JonFreeman 12:d1d21a2941ef 195 }
JonFreeman 13:ef7a06fa11de 196 #endif
JonFreeman 12:d1d21a2941ef 197 // End of Interrupt Service Routines
JonFreeman 12:d1d21a2941ef 198
JonFreeman 12:d1d21a2941ef 199
JonFreeman 8:93203f473f6e 200 void setVI (double v, double i)
JonFreeman 8:93203f473f6e 201 {
JonFreeman 4:21d91465e4b1 202 MotorA.set_V_limit (v); // Sets max motor voltage
JonFreeman 4:21d91465e4b1 203 MotorA.set_I_limit (i); // Sets max motor current
JonFreeman 4:21d91465e4b1 204 MotorB.set_V_limit (v);
JonFreeman 4:21d91465e4b1 205 MotorB.set_I_limit (i);
JonFreeman 4:21d91465e4b1 206 }
JonFreeman 11:bfb73f083009 207
JonFreeman 3:ecb00e0e8d68 208
JonFreeman 5:ca86a7848d54 209 /**
JonFreeman 12:d1d21a2941ef 210 * void AtoD_reader () // Call to here every VOLTAGE_READ_INTERVAL_US = 50 once loop responds to flag set in isr
JonFreeman 12:d1d21a2941ef 211 * Not part of ISR
JonFreeman 5:ca86a7848d54 212 */
JonFreeman 3:ecb00e0e8d68 213 void AtoD_reader () // Call to here every VOLTAGE_READ_INTERVAL_US = 50 once loop responds to flag set in isr
JonFreeman 0:435bf84ce48a 214 {
JonFreeman 11:bfb73f083009 215 static uint32_t i = 0;
JonFreeman 3:ecb00e0e8d68 216 if (MotorA.tickleon)
JonFreeman 3:ecb00e0e8d68 217 MotorA.high_side_off ();
JonFreeman 3:ecb00e0e8d68 218 if (MotorB.tickleon)
JonFreeman 3:ecb00e0e8d68 219 MotorB.high_side_off ();
JonFreeman 0:435bf84ce48a 220 if (AtoD_Semaphore > 20) {
JonFreeman 8:93203f473f6e 221 pc.printf ("WARNING - sema cnt %d\r\n", AtoD_Semaphore);
JonFreeman 0:435bf84ce48a 222 AtoD_Semaphore = 20;
JonFreeman 0:435bf84ce48a 223 }
JonFreeman 0:435bf84ce48a 224 while (AtoD_Semaphore > 0) {
JonFreeman 0:435bf84ce48a 225 AtoD_Semaphore--;
JonFreeman 0:435bf84ce48a 226 // Code here to sequence through reading voltmeter, demand pot, ammeters
JonFreeman 0:435bf84ce48a 227 switch (i) { //
JonFreeman 0:435bf84ce48a 228 case 0:
JonFreeman 0:435bf84ce48a 229 volt_reading += Ain_SystemVolts.read_u16 (); // Result = Result + New Reading
JonFreeman 0:435bf84ce48a 230 volt_reading >>= 1; // Result = Result / 2
JonFreeman 0:435bf84ce48a 231 break; // i.e. Very simple digital low pass filter
JonFreeman 0:435bf84ce48a 232 case 1:
JonFreeman 0:435bf84ce48a 233 driverpot_reading += Ain_DriverPot.read_u16 ();
JonFreeman 0:435bf84ce48a 234 driverpot_reading >>= 1;
JonFreeman 0:435bf84ce48a 235 break;
JonFreeman 0:435bf84ce48a 236 case 2:
JonFreeman 12:d1d21a2941ef 237 MotorA.sniff_current (); // Initiate ADC current reading
JonFreeman 0:435bf84ce48a 238 break;
JonFreeman 0:435bf84ce48a 239 case 3:
JonFreeman 11:bfb73f083009 240 MotorB.sniff_current ();
JonFreeman 0:435bf84ce48a 241 break;
JonFreeman 0:435bf84ce48a 242 }
JonFreeman 0:435bf84ce48a 243 i++; // prepare to read the next input in response to the next interrupt
JonFreeman 0:435bf84ce48a 244 if (i > 3)
JonFreeman 0:435bf84ce48a 245 i = 0;
JonFreeman 3:ecb00e0e8d68 246 } // end of while (AtoD_Semaphore > 0) {
JonFreeman 3:ecb00e0e8d68 247 if (MotorA.tickleon) {
JonFreeman 3:ecb00e0e8d68 248 MotorA.tickleon--;
JonFreeman 5:ca86a7848d54 249 MotorA.motor_set (); // Reactivate any high side switches turned off above
JonFreeman 3:ecb00e0e8d68 250 }
JonFreeman 3:ecb00e0e8d68 251 if (MotorB.tickleon) {
JonFreeman 3:ecb00e0e8d68 252 MotorB.tickleon--;
JonFreeman 3:ecb00e0e8d68 253 MotorB.motor_set ();
JonFreeman 0:435bf84ce48a 254 }
JonFreeman 0:435bf84ce48a 255 }
JonFreeman 0:435bf84ce48a 256
JonFreeman 10:e40d8724268a 257 /** double Read_Servo1_In ()
JonFreeman 10:e40d8724268a 258 * driverpot_reading is a global 16 bit unsigned int updated in interrupt service routine
JonFreeman 10:e40d8724268a 259 * ISR also filters signal
JonFreeman 10:e40d8724268a 260 * This function returns normalised double (range 0.0 to 1.0) representation of driver pot position
JonFreeman 10:e40d8724268a 261 */
JonFreeman 10:e40d8724268a 262 double Read_Servo1_In ()
JonFreeman 10:e40d8724268a 263 {
JonFreeman 10:e40d8724268a 264 const double xjoin = 0.5,
JonFreeman 10:e40d8724268a 265 yjoin = 0.35,
JonFreeman 10:e40d8724268a 266 slope_a = yjoin / xjoin,
JonFreeman 10:e40d8724268a 267 slope_b = (1.0 - yjoin)/(1.0 - xjoin);
JonFreeman 10:e40d8724268a 268 // centre = 0.35, // For pot, first (1/3)ish in braking area, position = 1/3 drift, > (1/3)ish drive
JonFreeman 10:e40d8724268a 269 // halfish = 0.5; // RC stick in the centre value
JonFreeman 10:e40d8724268a 270 // Bottom half of RC stick movement maps to lowest (1/3)ish pot movement
JonFreeman 10:e40d8724268a 271 // Higher half of RC stick movement maps to highest (2/3)ish pot movement
JonFreeman 10:e40d8724268a 272 double t;
JonFreeman 10:e40d8724268a 273 double demand = RC_chan_1.normalised();
JonFreeman 10:e40d8724268a 274 // apply demand = 1.0 - demand here to swap stick move polarity
JonFreeman 10:e40d8724268a 275 // return pow (demand, SERVOIN_PWR_BENDER);
JonFreeman 10:e40d8724268a 276 if (demand < 0.0) demand = 0.0;
JonFreeman 10:e40d8724268a 277 if (demand > 1.0) demand = 1.0;
JonFreeman 10:e40d8724268a 278 if (demand < xjoin) {
JonFreeman 10:e40d8724268a 279 demand *= slope_a;
JonFreeman 10:e40d8724268a 280 }
JonFreeman 10:e40d8724268a 281 else {
JonFreeman 10:e40d8724268a 282 t = yjoin + ((demand - xjoin) * slope_b);
JonFreeman 10:e40d8724268a 283 demand = t;
JonFreeman 10:e40d8724268a 284 }
JonFreeman 10:e40d8724268a 285 return demand;
JonFreeman 10:e40d8724268a 286 }
JonFreeman 10:e40d8724268a 287
JonFreeman 0:435bf84ce48a 288 /** double Read_DriverPot ()
JonFreeman 0:435bf84ce48a 289 * driverpot_reading is a global 16 bit unsigned int updated in interrupt service routine
JonFreeman 10:e40d8724268a 290 * ISR also filters signal by returning average of most recent two readings
JonFreeman 0:435bf84ce48a 291 * This function returns normalised double (range 0.0 to 1.0) representation of driver pot position
JonFreeman 0:435bf84ce48a 292 */
JonFreeman 0:435bf84ce48a 293 double Read_DriverPot ()
JonFreeman 0:435bf84ce48a 294 {
JonFreeman 5:ca86a7848d54 295 return ((double) driverpot_reading) / 65536.0; // Normalise 0.0 <= control pot <= 1.0
JonFreeman 0:435bf84ce48a 296 }
JonFreeman 0:435bf84ce48a 297
JonFreeman 0:435bf84ce48a 298 double Read_BatteryVolts ()
JonFreeman 0:435bf84ce48a 299 {
JonFreeman 5:ca86a7848d54 300 return ((double) volt_reading) / 951.0; // divisor fiddled to make voltage reading correct !
JonFreeman 0:435bf84ce48a 301 }
JonFreeman 0:435bf84ce48a 302
JonFreeman 12:d1d21a2941ef 303
JonFreeman 13:ef7a06fa11de 304 void Update_Current_Scaler () { // ***NEW Sept 2019*** Called at 8Hz
JonFreeman 13:ef7a06fa11de 305 const double Vnom = 48.0,
JonFreeman 13:ef7a06fa11de 306 Vmin = Vnom / 3.0,
JonFreeman 13:ef7a06fa11de 307 Voff = Vnom / 4.0;
JonFreeman 13:ef7a06fa11de 308
JonFreeman 13:ef7a06fa11de 309 double v = Read_BatteryVolts ();
JonFreeman 13:ef7a06fa11de 310 if (v > Vnom)
JonFreeman 13:ef7a06fa11de 311 v = Vnom;
JonFreeman 13:ef7a06fa11de 312 if (v < Voff)
JonFreeman 13:ef7a06fa11de 313 v = Voff;
JonFreeman 13:ef7a06fa11de 314 if (v > Vmin) { // In expected normal operating voltage range
JonFreeman 13:ef7a06fa11de 315 Current_Scaler_Sep_2019 = v / Vnom; // May need to revisit law
JonFreeman 13:ef7a06fa11de 316 }
JonFreeman 13:ef7a06fa11de 317 else { // In very low voltage region
JonFreeman 13:ef7a06fa11de 318 Current_Scaler_Sep_2019 = 0.5 * (v / Vnom);
JonFreeman 13:ef7a06fa11de 319 }
JonFreeman 13:ef7a06fa11de 320 }
JonFreeman 13:ef7a06fa11de 321
JonFreeman 8:93203f473f6e 322 void mode_set_both_motors (int mode, double val) // called from cli to set fw, re, rb, hb
JonFreeman 8:93203f473f6e 323 {
JonFreeman 2:04761b196473 324 MotorA.set_mode (mode);
JonFreeman 2:04761b196473 325 MotorB.set_mode (mode);
JonFreeman 12:d1d21a2941ef 326 if (mode == MOTOR_REGENBRAKE) {
JonFreeman 5:ca86a7848d54 327 if (val > 1.0)
JonFreeman 5:ca86a7848d54 328 val = 1.0;
JonFreeman 5:ca86a7848d54 329 if (val < 0.0)
JonFreeman 5:ca86a7848d54 330 val = 0.0;
JonFreeman 5:ca86a7848d54 331 val *= 0.9; // set upper limit, this is essential
JonFreeman 5:ca86a7848d54 332 val = sqrt (val); // to linearise effect
JonFreeman 5:ca86a7848d54 333 setVI (val, 1.0);
JonFreeman 2:04761b196473 334 }
JonFreeman 2:04761b196473 335 }
JonFreeman 0:435bf84ce48a 336
JonFreeman 12:d1d21a2941ef 337
JonFreeman 0:435bf84ce48a 338
JonFreeman 12:d1d21a2941ef 339 #ifdef USING_DC_MOTORS
JonFreeman 8:93203f473f6e 340 void restorer ()
JonFreeman 8:93203f473f6e 341 {
JonFreeman 8:93203f473f6e 342 motors_restore.detach ();
JonFreeman 8:93203f473f6e 343 if (MotorA.dc_motor) {
JonFreeman 8:93203f473f6e 344 MotorA.set_V_limit (MotorA.last_V);
JonFreeman 8:93203f473f6e 345 MotorA.set_I_limit (MotorA.last_I);
JonFreeman 8:93203f473f6e 346 MotorA.motor_set ();
JonFreeman 8:93203f473f6e 347 }
JonFreeman 8:93203f473f6e 348 if (MotorB.dc_motor) {
JonFreeman 8:93203f473f6e 349 MotorB.set_V_limit (MotorB.last_V);
JonFreeman 8:93203f473f6e 350 MotorB.set_I_limit (MotorB.last_I);
JonFreeman 8:93203f473f6e 351 MotorB.motor_set ();
JonFreeman 8:93203f473f6e 352 }
JonFreeman 8:93203f473f6e 353 }
JonFreeman 12:d1d21a2941ef 354 #endif
JonFreeman 8:93203f473f6e 355
JonFreeman 10:e40d8724268a 356 void rcin_report () {
JonFreeman 10:e40d8724268a 357 double c1 = RC_chan_1.normalised();
JonFreeman 10:e40d8724268a 358 double c2 = RC_chan_2.normalised();
JonFreeman 10:e40d8724268a 359 uint32_t pc1 = RC_chan_1.pulsecount();
JonFreeman 10:e40d8724268a 360 uint32_t pc2 = RC_chan_2.pulsecount();
JonFreeman 10:e40d8724268a 361 pc.printf ("At rcin_report, Ch1=%.3f, Ch2=%.3f, cnt1 %d, cnt2 %d\r\n", c1, c2, pc1, pc2);
JonFreeman 10:e40d8724268a 362 // if (c1 < -0.0001)
JonFreeman 10:e40d8724268a 363 pc.printf ("\t1 period %d, pulsewidth %d\r\n", RC_chan_1.period(), RC_chan_1.pulsewidth());
JonFreeman 10:e40d8724268a 364 // if (c2 < -0.0001)
JonFreeman 10:e40d8724268a 365 pc.printf ("\t2 period %d, pulsewidth %d\r\n", RC_chan_2.period(), RC_chan_2.pulsewidth());
JonFreeman 10:e40d8724268a 366 }
JonFreeman 8:93203f473f6e 367
JonFreeman 11:bfb73f083009 368 bool worth_the_bother (double a, double b) { // Tests size of change. No point updating tiny demand changes
JonFreeman 10:e40d8724268a 369 double c = a - b;
JonFreeman 10:e40d8724268a 370 if (c < 0.0)
JonFreeman 10:e40d8724268a 371 c = 0.0 - c;
JonFreeman 10:e40d8724268a 372 if (c > 0.02)
JonFreeman 10:e40d8724268a 373 return true;
JonFreeman 10:e40d8724268a 374 return false;
JonFreeman 10:e40d8724268a 375 }
JonFreeman 10:e40d8724268a 376
JonFreeman 10:e40d8724268a 377 void hand_control_state_machine (int source) { // if hand control mode '3', get here @ approx 30Hz to read drivers control pot
JonFreeman 10:e40d8724268a 378 // if servo1 mode '4', reads input from servo1 instead
JonFreeman 10:e40d8724268a 379 enum { // states used in hand_control_state_machine()
JonFreeman 10:e40d8724268a 380 HAND_CONT_IDLE,
JonFreeman 10:e40d8724268a 381 HAND_CONT_BRAKE_WAIT,
JonFreeman 10:e40d8724268a 382 HAND_CONT_BRAKE_POT,
JonFreeman 10:e40d8724268a 383 HAND_CONT_STATE_INTO_BRAKING,
JonFreeman 10:e40d8724268a 384 HAND_CONT_STATE_BRAKING,
JonFreeman 10:e40d8724268a 385 HAND_CONT_STATE_INTO_DRIVING,
JonFreeman 10:e40d8724268a 386 HAND_CONT_STATE_DRIVING
JonFreeman 10:e40d8724268a 387 } ;
JonFreeman 10:e40d8724268a 388
JonFreeman 10:e40d8724268a 389 static int hand_controller_state = HAND_CONT_IDLE;
JonFreeman 10:e40d8724268a 390 // static int old_hand_controller_direction = T5; // Nov 2018 reworked thanks to feedback from Rob and Quentin
JonFreeman 8:93203f473f6e 391 static double brake_effort, drive_effort, pot_position, old_pot_position = 0.0;
JonFreeman 10:e40d8724268a 392 static int dirbuf[5] = {100,100,100,100,100}; // Initialised with invalid direction such that 'change' is read from switch
JonFreeman 10:e40d8724268a 393 static int dirbufptr = 0, direction_old = -1, direction_new = -1;
JonFreeman 10:e40d8724268a 394 const int buflen = sizeof(dirbuf) / sizeof(int);
JonFreeman 10:e40d8724268a 395 const double Pot_Brake_Range = 0.35; //pow (0.5, SERVOIN_PWR_BENDER); //0.353553 for SERVOIN_PWR_BENDER = 1.5;
JonFreeman 10:e40d8724268a 396
JonFreeman 13:ef7a06fa11de 397 direction_old = direction_new;
JonFreeman 10:e40d8724268a 398
JonFreeman 10:e40d8724268a 399 // Test for change in direction switch setting.
JonFreeman 10:e40d8724268a 400 // If whole buffer NEWLY filled with all Fwd or all Rev, state = brake_wait
JonFreeman 10:e40d8724268a 401 int diracc = 0;
JonFreeman 10:e40d8724268a 402 if (dirbufptr >= buflen)
JonFreeman 10:e40d8724268a 403 dirbufptr = 0;
JonFreeman 10:e40d8724268a 404 dirbuf[dirbufptr++] = T5; // Read direction switch into circular debounce buffer
JonFreeman 10:e40d8724268a 405 for (int i = 0; i < buflen; i++)
JonFreeman 10:e40d8724268a 406 diracc += dirbuf[i]; // will = 0 or buflen if direction switch stable
JonFreeman 10:e40d8724268a 407 if (diracc == buflen || diracc == 0) // if was all 0 or all 1
JonFreeman 10:e40d8724268a 408 direction_new = diracc / buflen;
JonFreeman 10:e40d8724268a 409 if (direction_new != direction_old)
JonFreeman 10:e40d8724268a 410 hand_controller_state = HAND_CONT_BRAKE_WAIT; // validated change of direction switch
JonFreeman 10:e40d8724268a 411
JonFreeman 10:e40d8724268a 412 switch (source) {
JonFreeman 10:e40d8724268a 413 case 3: // driver pot is control input
JonFreeman 10:e40d8724268a 414 pot_position = Read_DriverPot (); // Only place read in the loop, rteads normalised 0.0 to 1.0
JonFreeman 10:e40d8724268a 415 break;
JonFreeman 10:e40d8724268a 416 case 4: // servo 1 input is control input
JonFreeman 10:e40d8724268a 417 break;
JonFreeman 10:e40d8724268a 418 default:
JonFreeman 10:e40d8724268a 419 pot_position = 0.0;
JonFreeman 10:e40d8724268a 420 break;
JonFreeman 8:93203f473f6e 421 }
JonFreeman 10:e40d8724268a 422
JonFreeman 10:e40d8724268a 423 switch (hand_controller_state) {
JonFreeman 10:e40d8724268a 424 case HAND_CONT_IDLE: // Here for first few passes until validated direction switch reading
JonFreeman 10:e40d8724268a 425 break;
JonFreeman 10:e40d8724268a 426
JonFreeman 11:bfb73f083009 427 case HAND_CONT_BRAKE_WAIT: // Only get here after direction input changed or newly validated at power on
JonFreeman 10:e40d8724268a 428 pc.printf ("At HAND_CONT_BRAKE_WAIT\r\n");
JonFreeman 10:e40d8724268a 429 brake_effort = 0.05; // Apply braking not too fiercely
JonFreeman 12:d1d21a2941ef 430 mode_set_both_motors (MOTOR_REGENBRAKE, brake_effort); // Direction change
JonFreeman 10:e40d8724268a 431 hand_controller_state = HAND_CONT_BRAKE_POT;
JonFreeman 10:e40d8724268a 432 break;
JonFreeman 10:e40d8724268a 433
JonFreeman 11:bfb73f083009 434 case HAND_CONT_BRAKE_POT: // Only get here after one pass through HAND_CONT_BRAKE_WAIT but
JonFreeman 11:bfb73f083009 435 if (brake_effort < 0.9) { // remain in this state until driver has turned pott fully anticlockwise
JonFreeman 11:bfb73f083009 436 brake_effort += 0.05; // ramp braking up to max over about one sec after direction change or validation
JonFreeman 12:d1d21a2941ef 437 mode_set_both_motors (MOTOR_REGENBRAKE, brake_effort); // Direction change or testing at power on
JonFreeman 10:e40d8724268a 438 pc.printf ("Brake effort %.2f\r\n", brake_effort);
JonFreeman 10:e40d8724268a 439 }
JonFreeman 10:e40d8724268a 440 else { // once braking up to quite hard
JonFreeman 10:e40d8724268a 441 if (pot_position < 0.02) { // Driver has turned pot fully anticlock
JonFreeman 10:e40d8724268a 442 hand_controller_state = HAND_CONT_STATE_BRAKING;
JonFreeman 10:e40d8724268a 443 }
JonFreeman 8:93203f473f6e 444 }
JonFreeman 8:93203f473f6e 445 break;
JonFreeman 10:e40d8724268a 446
JonFreeman 8:93203f473f6e 447 case HAND_CONT_STATE_INTO_BRAKING:
JonFreeman 8:93203f473f6e 448 brake_effort = (Pot_Brake_Range - pot_position) / Pot_Brake_Range;
JonFreeman 10:e40d8724268a 449 if (brake_effort < 0.0)
JonFreeman 10:e40d8724268a 450 brake_effort = 0.5;
JonFreeman 12:d1d21a2941ef 451 mode_set_both_motors (MOTOR_REGENBRAKE, brake_effort);
JonFreeman 8:93203f473f6e 452 old_pot_position = pot_position;
JonFreeman 10:e40d8724268a 453 hand_controller_state = HAND_CONT_STATE_BRAKING;
JonFreeman 8:93203f473f6e 454 pc.printf ("Brake\r\n");
JonFreeman 8:93203f473f6e 455 break;
JonFreeman 10:e40d8724268a 456
JonFreeman 8:93203f473f6e 457 case HAND_CONT_STATE_BRAKING:
JonFreeman 8:93203f473f6e 458 if (pot_position > Pot_Brake_Range) // escape braking into drive
JonFreeman 10:e40d8724268a 459 hand_controller_state = HAND_CONT_STATE_INTO_DRIVING;
JonFreeman 8:93203f473f6e 460 else {
JonFreeman 8:93203f473f6e 461 if (worth_the_bother(pot_position, old_pot_position)) {
JonFreeman 8:93203f473f6e 462 old_pot_position = pot_position;
JonFreeman 8:93203f473f6e 463 brake_effort = (Pot_Brake_Range - pot_position) / Pot_Brake_Range;
JonFreeman 12:d1d21a2941ef 464 mode_set_both_motors (MOTOR_REGENBRAKE, brake_effort);
JonFreeman 8:93203f473f6e 465 // pc.printf ("Brake %.2f\r\n", brake_effort);
JonFreeman 8:93203f473f6e 466 }
JonFreeman 8:93203f473f6e 467 }
JonFreeman 8:93203f473f6e 468 break;
JonFreeman 10:e40d8724268a 469
JonFreeman 11:bfb73f083009 470 case HAND_CONT_STATE_INTO_DRIVING: // Only get here after HAND_CONT_STATE_BRAKING
JonFreeman 10:e40d8724268a 471 pc.printf ("Drive\r\n");
JonFreeman 10:e40d8724268a 472 if (direction_new == 1)
JonFreeman 12:d1d21a2941ef 473 mode_set_both_motors (MOTOR_FORWARD, 0.0); // sets both motors
JonFreeman 10:e40d8724268a 474 else
JonFreeman 12:d1d21a2941ef 475 mode_set_both_motors (MOTOR_REVERSE, 0.0);
JonFreeman 10:e40d8724268a 476 hand_controller_state = HAND_CONT_STATE_DRIVING;
JonFreeman 10:e40d8724268a 477 break;
JonFreeman 10:e40d8724268a 478
JonFreeman 8:93203f473f6e 479 case HAND_CONT_STATE_DRIVING:
JonFreeman 8:93203f473f6e 480 if (pot_position < Pot_Brake_Range) // escape braking into drive
JonFreeman 10:e40d8724268a 481 hand_controller_state = HAND_CONT_STATE_INTO_BRAKING;
JonFreeman 8:93203f473f6e 482 else {
JonFreeman 8:93203f473f6e 483 if (worth_the_bother(pot_position, old_pot_position)) {
JonFreeman 8:93203f473f6e 484 old_pot_position = pot_position;
JonFreeman 8:93203f473f6e 485 drive_effort = (pot_position - Pot_Brake_Range) / (1.0 - Pot_Brake_Range);
JonFreeman 8:93203f473f6e 486 setVI (drive_effort, drive_effort); // Wind volts and amps up and down together ???
JonFreeman 8:93203f473f6e 487 pc.printf ("Drive %.2f\r\n", drive_effort);
JonFreeman 8:93203f473f6e 488 }
JonFreeman 8:93203f473f6e 489 }
JonFreeman 8:93203f473f6e 490 break;
JonFreeman 10:e40d8724268a 491
JonFreeman 8:93203f473f6e 492 default:
JonFreeman 10:e40d8724268a 493 pc.printf ("Unhandled Hand Controller state %d\r\n", hand_controller_state);
JonFreeman 8:93203f473f6e 494 break;
JonFreeman 8:93203f473f6e 495 } // endof switch (hand_controller_state) {
JonFreeman 8:93203f473f6e 496 }
JonFreeman 8:93203f473f6e 497
JonFreeman 0:435bf84ce48a 498 int main()
JonFreeman 0:435bf84ce48a 499 {
JonFreeman 4:21d91465e4b1 500 int eighth_sec_count = 0;
JonFreeman 0:435bf84ce48a 501 // Setup system timers to cause periodic interrupts to synchronise and automate volt and current readings, loop repeat rate etc
JonFreeman 0:435bf84ce48a 502 tick_vread.attach_us (&ISR_voltage_reader, VOLTAGE_READ_INTERVAL_US); // Start periodic interrupt generator
JonFreeman 0:435bf84ce48a 503 loop_timer.attach_us (&ISR_loop_timer, MAIN_LOOP_REPEAT_TIME_US); // Start periodic interrupt generator
JonFreeman 13:ef7a06fa11de 504 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 6:f289a49c1eae 505 temperature_find_ticker.attach_us (&ISR_temperature_find_ticker, 960);
JonFreeman 13:ef7a06fa11de 506 Temperature_pin.fall (&temp_sensor_isr);
JonFreeman 13:ef7a06fa11de 507 Temperature_pin.mode (PullUp);
JonFreeman 13:ef7a06fa11de 508 temperature_timer.start ();
JonFreeman 13:ef7a06fa11de 509 #endif
JonFreeman 0:435bf84ce48a 510 // Done setting up system interrupt timers
JonFreeman 0:435bf84ce48a 511
JonFreeman 12:d1d21a2941ef 512 pc.baud (9600); // COM port to pc
JonFreeman 12:d1d21a2941ef 513 com3.baud (1200); // Once had an idea to use this for IR comms, never tried
JonFreeman 12:d1d21a2941ef 514 com2.baud (19200); // Opto isolated serial bus connecting 'n' STM3_ESC boards to 1 Brute Touch Screen controller
JonFreeman 6:f289a49c1eae 515
JonFreeman 12:d1d21a2941ef 516 rpm2mph = 60.0 // to Motor Revs per hour;
JonFreeman 12:d1d21a2941ef 517 * ((double)mode.rd(MOTPIN) / (double)mode.rd(WHEELGEAR)) // Wheel revs per hour
JonFreeman 12:d1d21a2941ef 518 * PI * ((double)mode.rd(WHEELDIA) / 1000.0) // metres per hour
JonFreeman 12:d1d21a2941ef 519 * 39.37 / (1760.0 * 36.0); // miles per hour
JonFreeman 5:ca86a7848d54 520
JonFreeman 12:d1d21a2941ef 521 MotorA.direction_set (mode.rd(MOTADIR)); // modes all setup in class eeprom_settings {} mode ; constructor
JonFreeman 12:d1d21a2941ef 522 MotorB.direction_set (mode.rd(MOTBDIR));
JonFreeman 12:d1d21a2941ef 523 MotorA.poles (mode.rd(MOTAPOLES)); // Returns true if poles 4, 6 or 8. Returns false otherwise
JonFreeman 12:d1d21a2941ef 524 MotorB.poles (mode.rd(MOTBPOLES)); // Only two calls are here
JonFreeman 12:d1d21a2941ef 525 MotorA.set_mode (MOTOR_REGENBRAKE);
JonFreeman 12:d1d21a2941ef 526 MotorB.set_mode (MOTOR_REGENBRAKE);
JonFreeman 12:d1d21a2941ef 527 setVI (0.9, 0.5); // Power up with moderate regen braking applied
JonFreeman 12:d1d21a2941ef 528
JonFreeman 6:f289a49c1eae 529 // T1 = 0; Now WRONGLY hoped to be InterruptIn counting pulses from LMT01 temperature sensor
JonFreeman 5:ca86a7848d54 530 T2 = 0; // T2, T3, T4 As yet unused pins
JonFreeman 8:93203f473f6e 531 // T3 = 0;
JonFreeman 8:93203f473f6e 532 // T4 = 0;
JonFreeman 5:ca86a7848d54 533 // T5 = 0; now input from fw/re on remote control box
JonFreeman 0:435bf84ce48a 534 T6 = 0;
JonFreeman 5:ca86a7848d54 535
JonFreeman 13:ef7a06fa11de 536 #ifdef TEMP_SENSOR_ENABLE
JonFreeman 12:d1d21a2941ef 537 if ((last_temperature_count > 160) && (last_temperature_count < 2400)) // in range -40 to +100 degree C
JonFreeman 6:f289a49c1eae 538 temp_sensor_exists = true;
JonFreeman 13:ef7a06fa11de 539 #endif
JonFreeman 12:d1d21a2941ef 540 #ifdef USING_DC_MOTORS
JonFreeman 8:93203f473f6e 541 dc_motor_kicker_timer.start ();
JonFreeman 12:d1d21a2941ef 542 #endif
JonFreeman 8:93203f473f6e 543 int old_hand_controller_direction = T5;
JonFreeman 12:d1d21a2941ef 544 if (mode.rd(COMM_SRC) == 3) { // Read fwd/rev switch 'T5', PA15 on 401
JonFreeman 8:93203f473f6e 545 pc.printf ("Pot control\r\n");
JonFreeman 8:93203f473f6e 546 if (T5)
JonFreeman 12:d1d21a2941ef 547 mode_set_both_motors (MOTOR_FORWARD, 0.0); // sets both motors
JonFreeman 8:93203f473f6e 548 else
JonFreeman 12:d1d21a2941ef 549 mode_set_both_motors (MOTOR_REVERSE, 0.0);
JonFreeman 8:93203f473f6e 550 }
JonFreeman 8:93203f473f6e 551
JonFreeman 12:d1d21a2941ef 552 pc.printf ("About to start %s!, mode_bytes[COMM_SRC]= %d\r\n", const_version_string, mode.rd(COMM_SRC));
JonFreeman 12:d1d21a2941ef 553 pc.printf ("ESC_Error.all_good() ret'd %s\r\n", ESC_Error.all_good() ? "true" : "false");
JonFreeman 12:d1d21a2941ef 554 // pc.printf ("SystemCoreClock=%d, MAX_PWM_TICKS=%d\r\n", SystemCoreClock, MAX_PWM_TICKS);
JonFreeman 12:d1d21a2941ef 555 // pcc.test () ;
JonFreeman 12:d1d21a2941ef 556 // tsc.test () ;
JonFreeman 13:ef7a06fa11de 557
JonFreeman 13:ef7a06fa11de 558 WatchDog = WATCHDOG_RELOAD + 80; // Allow extra few seconds at powerup
JonFreeman 13:ef7a06fa11de 559
JonFreeman 13:ef7a06fa11de 560
JonFreeman 0:435bf84ce48a 561 while (1) { // Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
JonFreeman 0:435bf84ce48a 562 while (!loop_flag) { // Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
JonFreeman 12:d1d21a2941ef 563 pcc.core () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
JonFreeman 12:d1d21a2941ef 564 tsc.core () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
JonFreeman 0:435bf84ce48a 565 AtoD_reader (); // Performs A to D conversions at rate set by ticker interrupts
JonFreeman 11:bfb73f083009 566 } // 32Hz original setting for loop repeat rate
JonFreeman 10:e40d8724268a 567 loop_flag = false; // Clear flag set by ticker interrupt handler. WHEN LAST CHECKED this was about every 32ms
JonFreeman 10:e40d8724268a 568
JonFreeman 13:ef7a06fa11de 569 RC_chan_1.validate_rx(); // Tests for pulse width and repetition rates being believable signal from radio control
JonFreeman 13:ef7a06fa11de 570 RC_chan_2.validate_rx(); // bool return values not noted here, these 2 lines are pointless.
JonFreeman 10:e40d8724268a 571
JonFreeman 12:d1d21a2941ef 572 switch (mode.rd(COMM_SRC)) { // Look to selected source of driving command, act on commands from wherever
JonFreeman 8:93203f473f6e 573 case 0: // Invalid
JonFreeman 8:93203f473f6e 574 break;
JonFreeman 11:bfb73f083009 575 case COM1: // COM1 - Primarily for testing, bypassed by command line interpreter
JonFreeman 8:93203f473f6e 576 break;
JonFreeman 11:bfb73f083009 577 case COM2: // COM2 - Primarily for testing, bypassed by command line interpreter
JonFreeman 8:93203f473f6e 578 break;
JonFreeman 11:bfb73f083009 579 case HAND: // Put all hand controller input stuff here
JonFreeman 10:e40d8724268a 580 hand_control_state_machine (3);
JonFreeman 8:93203f473f6e 581 break; // endof hand controller stuff
JonFreeman 11:bfb73f083009 582 case RC_IN1: // RC_chan_1
JonFreeman 10:e40d8724268a 583 hand_control_state_machine (4);
JonFreeman 8:93203f473f6e 584 break;
JonFreeman 11:bfb73f083009 585 case RC_IN2: // RC_chan_2
JonFreeman 8:93203f473f6e 586 break;
JonFreeman 8:93203f473f6e 587 default:
JonFreeman 12:d1d21a2941ef 588 if (ESC_Error.read(FAULT_UNRECOGNISED_STATE)) {
JonFreeman 12:d1d21a2941ef 589 pc.printf ("Unrecognised state %d\r\n", mode.rd(COMM_SRC)); // set error flag instead here
JonFreeman 12:d1d21a2941ef 590 ESC_Error.set (FAULT_UNRECOGNISED_STATE, 1);
JonFreeman 12:d1d21a2941ef 591 }
JonFreeman 8:93203f473f6e 592 break;
JonFreeman 8:93203f473f6e 593 } // endof switch (mode_bytes[COMM_SRC]) {
JonFreeman 8:93203f473f6e 594
JonFreeman 12:d1d21a2941ef 595 #ifdef USING_DC_MOTORS
JonFreeman 8:93203f473f6e 596 dc_motor_kicker_timer.reset ();
JonFreeman 12:d1d21a2941ef 597 #endif
JonFreeman 12:d1d21a2941ef 598 MotorA.speed_monitor_and_control (); // Needed to keep table updated to give reading in Hall transitions per second
JonFreeman 12:d1d21a2941ef 599 MotorB.speed_monitor_and_control (); // Read MotorX.PPS to read pulses per sec or MotorX.RPM to read motor RPM
JonFreeman 12:d1d21a2941ef 600
JonFreeman 12:d1d21a2941ef 601 #ifdef USING_DC_MOTORS
JonFreeman 8:93203f473f6e 602 if (MotorA.dc_motor) {
JonFreeman 12:d1d21a2941ef 603 // MotorA.raw_V_pwm (1);
JonFreeman 8:93203f473f6e 604 MotorA.low_side_on ();
JonFreeman 8:93203f473f6e 605 }
JonFreeman 8:93203f473f6e 606 if (MotorB.dc_motor) {
JonFreeman 12:d1d21a2941ef 607 // MotorB.raw_V_pwm (1);
JonFreeman 8:93203f473f6e 608 MotorB.low_side_on ();
JonFreeman 8:93203f473f6e 609 }
JonFreeman 8:93203f473f6e 610 if (MotorA.dc_motor || MotorB.dc_motor) {
JonFreeman 8:93203f473f6e 611 // motors_restore.attach_us (&restorer, ttime);
JonFreeman 8:93203f473f6e 612 motors_restore.attach_us (&restorer, 25);
JonFreeman 8:93203f473f6e 613 }
JonFreeman 12:d1d21a2941ef 614 #endif
JonFreeman 8:93203f473f6e 615
JonFreeman 0:435bf84ce48a 616 if (flag_8Hz) { // do slower stuff
JonFreeman 0:435bf84ce48a 617 flag_8Hz = false;
JonFreeman 3:ecb00e0e8d68 618 LED = !LED; // Toggle LED on board, should be seen to fast flash
JonFreeman 8:93203f473f6e 619 if (WatchDogEnable) {
JonFreeman 8:93203f473f6e 620 WatchDog--;
JonFreeman 13:ef7a06fa11de 621 if (WatchDog < 1) { // Deal with WatchDog timer timeout here
JonFreeman 13:ef7a06fa11de 622 WatchDog = 0;
JonFreeman 8:93203f473f6e 623 setVI (0.0, 0.0); // set motor volts and amps to zero
JonFreeman 12:d1d21a2941ef 624 // com2.printf ("TIMEOUT %c\r\n", mode.rd(BOARD_ID)); // Potential problem of multiple units reporting at same time overcome by adding board number to WATCHDOG_RELOAD
JonFreeman 12:d1d21a2941ef 625 pc.printf ("TIMEOUT %c\r\n", mode.rd(BOARD_ID)); // Brute touch screen controller can do nothing with this
JonFreeman 8:93203f473f6e 626 } // End of dealing with WatchDog timer timeout
JonFreeman 8:93203f473f6e 627 }
JonFreeman 13:ef7a06fa11de 628 Update_Current_Scaler ();
JonFreeman 4:21d91465e4b1 629 eighth_sec_count++;
JonFreeman 4:21d91465e4b1 630 if (eighth_sec_count > 6) { // Send some status info out of serial port every second and a bit or thereabouts
JonFreeman 4:21d91465e4b1 631 eighth_sec_count = 0;
JonFreeman 12:d1d21a2941ef 632 ESC_Error.report_any (false); // retain = false - reset error after reporting once
JonFreeman 8:93203f473f6e 633 /* if (temp_sensor_exists) {
JonFreeman 8:93203f473f6e 634 double tmprt = (double) last_temp_count;
JonFreeman 8:93203f473f6e 635 tmprt /= 16.0;
JonFreeman 8:93203f473f6e 636 tmprt -= 50.0;
JonFreeman 8:93203f473f6e 637 pc.printf ("Temp %.2f\r\n", tmprt);
JonFreeman 8:93203f473f6e 638 }*/
JonFreeman 0:435bf84ce48a 639 }
JonFreeman 13:ef7a06fa11de 640 //#define SERVO_OUT_TEST
JonFreeman 11:bfb73f083009 641 #ifdef SERVO_OUT_TEST
JonFreeman 13:ef7a06fa11de 642 static double servo_angle = 0.0; // For testing servo outs
JonFreeman 10:e40d8724268a 643 // servo out test here December 2018
JonFreeman 10:e40d8724268a 644 servo_angle += 0.01;
JonFreeman 10:e40d8724268a 645 if (servo_angle > TWOPI)
JonFreeman 10:e40d8724268a 646 servo_angle -= TWOPI;
JonFreeman 10:e40d8724268a 647 Servo1 = ((sin(servo_angle)+1.0) / 2.0);
JonFreeman 10:e40d8724268a 648 Servo2 = ((cos(servo_angle)+1.0) / 2.0);
JonFreeman 10:e40d8724268a 649 // Yep! Both servo outs work lovely December 2018
JonFreeman 11:bfb73f083009 650 #endif
JonFreeman 0:435bf84ce48a 651 } // End of if(flag_8Hz)
JonFreeman 0:435bf84ce48a 652 } // End of main programme loop
JonFreeman 0:435bf84ce48a 653 }
JonFreeman 11:bfb73f083009 654