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
Revision 8:93203f473f6e, committed 2018-08-18
- Comitter:
- JonFreeman
- Date:
- Sat Aug 18 12:51:35 2018 +0000
- Parent:
- 7:6deaeace9a3e
- Child:
- 9:ac2412df01be
- Commit message:
- Work underway to drive brushed motors.; Code as supplied to Rob
Changed in this revision
--- a/DualBLS.h Sun Jun 17 06:59:37 2018 +0000
+++ b/DualBLS.h Sat Aug 18 12:51:35 2018 +0000
@@ -6,20 +6,23 @@
const int TIMEOUT_SECONDS = 30;
/* Please Do Not Alter these */
-const int VOLTAGE_READ_INTERVAL_US = 50, // Interrupts timed every 50 micro sec, runs around loop performing 1 A-D conversion per pass
+const int PWM_PRESECALER_DEFAULT = 5,
+ VOLTAGE_READ_INTERVAL_US = 50, // Interrupts timed every 50 micro sec, runs around loop performing 1 A-D conversion per pass
MAIN_LOOP_REPEAT_TIME_US = 31250, // 31250 us, with TACHO_TAB_SIZE = 32 means tacho_ticks_per_time is tacho_ticks_per_second
MAIN_LOOP_ITERATION_Hz = 1000000 / MAIN_LOOP_REPEAT_TIME_US,
CURRENT_SAMPLES_AVERAGED = 100, // Current is spikey. Reading smoothed by using average of this many latest current readings
- PWM_HZ = 16000, // chosen to be above cutoff frequency of average human ear
- MAX_PWM_TICKS = (SystemCoreClock / PWM_HZ),
+ PWM_HZ = 15000, // chosen to be above cutoff frequency of average human ear
+ MAX_PWM_TICKS = (SystemCoreClock / (PWM_HZ * PWM_PRESECALER_DEFAULT)),
TICKLE_TIMES = 100 ,
WATCHDOG_RELOAD = (TIMEOUT_SECONDS * 8); // WatchDog counter ticked down in 8Hz loop
/* End of Please Do Not Alter these */
const double PI = 4.0 * atan(1.0),
TWOPI = 8.0 * atan(1.0);
+const double Pot_Brake_Range = 0.33;
-enum {MOTADIR, MOTBDIR, GANG, SVO1, SVO2, COMM_SRC, ID, WHEELDIA, MOTPIN, WHEELGEAR} ; // Identical in TS and DualBLS
+//enum {MOTADIR, MOTBDIR, GANG, SVO1, SVO2, COMM_SRC, ID, WHEELDIA, MOTPIN, WHEELGEAR} ; // Identical in TS and DualBLS
+enum {MOTADIR, MOTBDIR, GANG, SVO1, SVO2, COMM_SRC, ID, WHEELDIA, MOTPIN, WHEELGEAR, BOGHUNWAT, FUT1, FUT2, FUT3, FUT4, FUT5} ; // Identical in TS and DualBLS
struct optpar {
int min, max, def; // min, max, default
const char * t; // description
@@ -32,9 +35,15 @@
{0, 2, 2, "Servo2 0, 1, 2 = Not used, Input, Output"},
{1, 5, 2, "Command source 0 Invalid, 1 COM1, 2 COM2, 3 Pot, 4 Servo1, 5 Servo2"},
{'1', '9', '0', "Alternative ID ascii '1' to '9'"}, // defaults to '0' before eerom setup for first time
- {20, 253, 98, "Wheel diameter mm"}, // New 01/06/2018
+ {50, 253, 98, "Wheel diameter mm"}, // New 01/06/2018
{10, 253, 27, "Motor pinion"}, // New 01/06/2018
- {20, 253, 85, "Wheel gear"}, // New 01/06/2018
+ {50, 253, 85, "Wheel gear"}, // New 01/06/2018
+ {1, 20, 4, "Bogie power closest hundreds of Watt"}, // New 22/06/2018
+ {0, 100, 0, "Future 1"},
+ {0, 100, 0, "Future 2"},
+ {0, 100, 0, "Future 3"},
+ {0, 100, 0, "Future 4"},
+ {0, 100, 0, "Future 5"},
} ;
const int numof_eeprom_options = sizeof(option_list) / sizeof (struct optpar);
--- a/F401RE.h Sun Jun 17 06:59:37 2018 +0000 +++ b/F401RE.h Sat Aug 18 12:51:35 2018 +0000 @@ -91,8 +91,8 @@ DigitalOut T3 (PB_15); // Pin 36 // BufferedSerial com2 pins 37 Tx, 38 Rx BufferedSerial com2 (PC_6, PC_7); // Pins 37, 38 tx, rx to XBee module -FastPWM A_MAX_V_PWM (PC_8, 1), // Pin 39 pwm3/3 - A_MAX_I_PWM (PC_9, 1); // pin 40, prescaler value pwm3/4 +FastPWM A_MAX_V_PWM (PC_8, PWM_PRESECALER_DEFAULT), // Pin 39 pwm3/3 + A_MAX_I_PWM (PC_9, PWM_PRESECALER_DEFAULT); // pin 40, prescaler value pwm3/4 //InterruptIn MotB_Hall (PA_8); // Pin 41 // Pin 41 Port_A AWH // BufferedSerial com3 pins 42 Tx, 43 Rx @@ -126,8 +126,8 @@ InterruptIn MAH3 (PC_12); // Pin 53 InterruptIn MBH1 (PD_2); // Pin 54 DigitalOut T6 (PB_3); // Pin 55 -FastPWM B_MAX_V_PWM (PB_4, 1), // Pin 56 pwm3/3 - B_MAX_I_PWM (PB_5, 1); // pin 57, prescaler value pwm3/4 +FastPWM B_MAX_V_PWM (PB_4, PWM_PRESECALER_DEFAULT), // Pin 56 pwm3/3 + B_MAX_I_PWM (PB_5, PWM_PRESECALER_DEFAULT); // pin 57, prescaler value pwm3/4 I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom // Pin 60 BOOT0
--- a/F446ZE.h Sun Jun 17 06:59:37 2018 +0000 +++ b/F446ZE.h Sat Aug 18 12:51:35 2018 +0000 @@ -1,16 +1,14 @@ // 5TH JUNE 2018 NONE OF THIS IS RIGHT YET !! - // Hoped to select servo functions from user info stored on EEROM. Too difficult. Do not define servo as in and out - // Port A -> MotorA, Port B -> MotorB const uint16_t -AUL = 1 << 0, // Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers -AVL = 1 << 6, // These are which port bits connect to which mosfet driver -AWL = 1 << 4, +AUL = 1 << 1, // Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers +AVL = 1 << 2, // These are which port bits connect to which mosfet driver +AWL = 1 << 3, -AUH = 1 << 1, -AVH = 1 << 7, -AWH = 1 << 8, +AUH = 1 << 4, +AVH = 1 << 5, +AWH = 1 << 6, AUV = AUH | AVL, // Each of 6 possible output energisations made up of one hi and one low AVU = AVH | AUL, @@ -29,8 +27,8 @@ BWL = 1 << 2, BUH = 1 << 10, -BVH = 1 << 12, -BWH = 1 << 13, +BVH = 1 << 11, +BWH = 1 << 3, BUV = BUH | BVL, BVU = BVH | BUL, @@ -46,14 +44,14 @@ PORT_A_MASK = AUL | AVL | AWL | AUH | AVH | AWH, // NEW METHOD FOR DGD21032 MOSFET DRIVERS PORT_B_MASK = BUL | BVL | BWL | BUH | BVH | BWH; - -PortOut MotA (PortA, PORT_A_MASK); // Activate output ports to motor drivers -PortOut MotB (PortB, PORT_B_MASK); +// Use Ports E and G - best first guess July 2018 +PortOut MotA (PortE, PORT_A_MASK); // Activate output ports to motor drivers +PortOut MotB (PortG, PORT_B_MASK); // Pin 1 VBAT NET +3V3 //DigitalIn J3 (PC_13, PullUp);// Pin 2 Jumper pulls to GND, R floats Hi -InterruptIn Temperature_pin (PC_13);// Pin 2 June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn +InterruptIn Temperature_pin (PD_7);// Pin ?? June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn // Pin 3 PC14-OSC32_IN NET O32I @@ -70,16 +68,16 @@ // Pin 14 Port_A AUL // Pin 15 Port_A AUH // Pins 16, 17 BufferedSerial pc -BufferedSerial pc (PA_2, PA_3, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead +BufferedSerial pc (PD_8, PD_9, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead // Pin 18 VSS NET GND // Pin 19 VDD NET +3V3 // Pin 20 Port_A AWL // Pin 21 DigitalOut led1(LED1); -DigitalOut LED (PA_5); // Pin 21 +DigitalOut LED (PB_0); // Pin ?? as fitted to Nucleo board. Other leds use PB_7 and PB_14 // Pin 22 Port_A AVL // Pin 23 Port_A AVH -InterruptIn MBH2 (PC_4); // Pin 24 -InterruptIn MBH3 (PC_5); // Pin 25 +InterruptIn MBH2 (PD_1); // Pin ?? +InterruptIn MBH3 (PD_3); // Pin ?? // Pin 26 Port_B BUL // Pin 27 Port_B BVL // Pin 28 Port_B BWL @@ -89,17 +87,21 @@ // Pin 32 VDD // Pin 33 Port_B BVH // Pin 34 Port_B BWH -DigitalOut T4 (PB_14); // Pin 35 -DigitalOut T3 (PB_15); // Pin 36 + +//DigitalOut T4 (PB_14); // Pin ** +//DigitalOut T3 (PB_15); // Pin ** + // BufferedSerial com2 pins 37 Tx, 38 Rx -BufferedSerial com2 (PC_6, PC_7); // Pins 37, 38 tx, rx to XBee module -FastPWM A_MAX_V_PWM (PC_8, 1), // Pin 39 pwm3/3 - A_MAX_I_PWM (PC_9, 1); // pin 40, prescaler value pwm3/4 +BufferedSerial com2 (PC_10, PC_11); // Pins 37, 38 tx, rx to XBee module +FastPWM A_MAX_V_PWM (PC_8, PWM_PRESECALER_DEFAULT), // Pin 39 pwm3/3 + A_MAX_I_PWM (PC_9, PWM_PRESECALER_DEFAULT); // pin 40, prescaler value pwm3/4 //InterruptIn MotB_Hall (PA_8); // Pin 41 // Pin 41 Port_A AWH // BufferedSerial com3 pins 42 Tx, 43 Rx //InterruptIn tryseredge (PA_9); -BufferedSerial com3 (PA_9, PA_10); // Pins 42, 43 tx, rx to any aux module + +BufferedSerial com3 (PC_12, PD_2); // Pins 42, 43 tx, rx to any aux module + // PA_9 is Tx. I wonder, can we also use InterruptIn on this pin to generate interrupts on tx bit transitions ? Let's find out ! // No. @@ -111,7 +113,7 @@ //InterruptIn T1 (PA_12); // Pin 45 now input counting pulses from LMT01 temperature sensor // InterruptIn DOES NOT WORK ON PA_12. Boards are being made, will have to wire link PA12 to PC13 -DigitalIn T1 (PA_12); +//DigitalIn T1 (PA_12); ////InterruptIn T1 (PC_13); // Pin 45 now input counting pulses from LMT01 temperature sensor @@ -123,21 +125,21 @@ //Was DigitalOut T5 (PA_15); // Pin 50 DigitalIn T5 (PA_15); // Pin 50 now fwd/rev from remote control box if fitted -InterruptIn MAH1 (PC_10); // Pin 51 -InterruptIn MAH2 (PC_11); // Pin 52 -InterruptIn MAH3 (PC_12); // Pin 53 -InterruptIn MBH1 (PD_2); // Pin 54 +InterruptIn MAH1 (PD_4); // Pin 51 +InterruptIn MAH2 (PD_5); // Pin 52 +InterruptIn MAH3 (PD_6); // Pin 53 +InterruptIn MBH1 (PD_0); // Pin 54 DigitalOut T6 (PB_3); // Pin 55 -FastPWM B_MAX_V_PWM (PB_4, 1), // Pin 56 pwm3/3 - B_MAX_I_PWM (PB_5, 1); // pin 57, prescaler value pwm3/4 +FastPWM B_MAX_V_PWM (PE_13, PWM_PRESECALER_DEFAULT), // Pin 56 pwm3/3 + B_MAX_I_PWM (PE_14, PWM_PRESECALER_DEFAULT); // pin 57, prescaler value pwm3/4 -I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom +I2C i2c (PB_9, PB_8); // Pins 58, 59 For 24LC64 eeprom // Pin 60 BOOT0 // Servo pins, 2 off. Configured as Input to read radio control receiver // If used as servo output, code gives pin to 'Servo' - seems to work -InterruptIn Servo1_i (PB_8); // Pin 61 to read output from rc rx -InterruptIn Servo2_i (PB_9); // Pin 62 to read output from rc rx +InterruptIn Servo1_i (PF_14); // Pin 61 to read output from rc rx +InterruptIn Servo2_i (PF_15); // Pin 62 to read output from rc rx // Pin 63 VSS // Pin 64 VDD
--- a/cli_BLS_nortos.cpp Sun Jun 17 06:59:37 2018 +0000
+++ b/cli_BLS_nortos.cpp Sat Aug 18 12:51:35 2018 +0000
@@ -7,7 +7,9 @@
using namespace std;
extern int I_Am () ; // Returns boards id number as ASCII char '0', '1' etc. Code for Broadcast = '\r'
-extern int WatchDog;
+extern int WatchDog;
+extern bool WatchDogEnable;
+extern char mode_bytes[];
const int BROADCAST = '\r';
const int MAX_PARAMS = 20;
@@ -31,6 +33,11 @@
extern void read_last_VI (double * val) ; // only for test from cli
//BufferedSerial * com;
+extern double Read_DriverPot ();
+void pot_cmd (struct parameters & a)
+{
+ pc.printf ("Driver's pot %.3f\r\n", Read_DriverPot ());
+}
void null_cmd (struct parameters & a)
{
@@ -38,7 +45,45 @@
a.com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
}
-extern void mode_set (int mode, double val) ; // called from cli to set fw, re, rb, hb
+// {"wden", "enable watchdog if modes allow", wden_lococmd},
+// {"wddi", "disable watchdog always", wddi_lococmd},
+
+void wden_lococmd (struct parameters & a)
+{
+ if (mode_bytes[COMM_SRC] != 3) // When not hand pot control, allow watchdog enable
+ WatchDogEnable = true;
+}
+void wden_pccmd (struct parameters & a)
+{
+ wden_lococmd (a);
+ a.com->printf ("Watchdog %sabled\r\n", WatchDogEnable ? "En":"Dis");
+}
+
+void wddi_lococmd (struct parameters & a)
+{
+ WatchDogEnable = false;
+}
+void wddi_pccmd (struct parameters & a)
+{
+ wddi_lococmd (a);
+ a.com->printf ("Watchdog %sabled\r\n", WatchDogEnable ? "En":"Dis");
+}
+
+extern void prscfuck (int);
+void pf_cmd (struct parameters & a)
+{
+ prscfuck ((int)a.dbl[0]);
+}
+
+extern void report_motor_types () ;
+void mt_cmd (struct parameters & a)
+{
+ report_motor_types ();
+// if (a.respond)
+// a.com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
+}
+
+extern void mode_set_both_motors (int mode, double val) ; // called from cli to set fw, re, rb, hb
extern void read_supply_vi (double * val) ;
void rdi_cmd (struct parameters & a) // read motor currents
@@ -61,19 +106,19 @@
void fw_cmd (struct parameters & a) // Forward command
{
- mode_set (FORWARD, 0.0);
+ mode_set_both_motors (FORWARD, 0.0);
}
void re_cmd (struct parameters & a) // Reverse command
{
- mode_set (REVERSE, 0.0);
+ mode_set_both_motors (REVERSE, 0.0);
}
void rb_cmd (struct parameters & a) // Regen brake command
{
double b = a.dbl[0] / 100.0;
// a.com->printf ("Applying brake %.3f\r\n", b);
- mode_set (REGENBRAKE, b);
+ mode_set_both_motors (REGENBRAKE, b);
// apply_brake (b);
}
@@ -105,7 +150,25 @@
// last;
} ;
*/
-extern char mode_bytes[];
+
+// New 22 June 2018
+// get bogie bytes - report back to touch controller
+void gbb_cmd (struct parameters & a) //
+{
+ if (a.target_unit == BROADCAST || !a.resp_always) {
+// a.com->printf ("At mode_cmd, can not use BROADCAST with mode_cmd\r\n");
+ } else {
+ pc.printf ("At gbb\r\n");
+ char eeprom_contents[36]; // might need to be unsigned?
+ memset (eeprom_contents, 0, 36);
+ a.com->printf ("gbb");
+ rd_24LC64 (0, eeprom_contents, 32);
+ for (int i = 0; i < numof_eeprom_options; i++)
+ a.com->printf (" %d", eeprom_contents[i]);
+ a.com->putc ('\r');
+ a.com->putc ('\n');
+ }
+}
void mode_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents
{
@@ -154,7 +217,7 @@
a.com->printf ("numof params = %d\r\n", a.numof_dbls);
a.com->printf ("Hand Brake : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
}
- mode_set (HANDBRAKE, 0.0);
+ mode_set_both_motors (HANDBRAKE, 0.0);
}
extern uint32_t last_temp_count;
@@ -183,9 +246,11 @@
extern double rpm2mph ;
void mph_cmd (struct parameters & a) // to report miles per hour
{
+ if (a.respond) {
uint32_t dest[3];
read_RPM (dest); // gets rpm for each motor
- a.com->printf ("mph%c %.3f\r\n", mode_bytes[ID], (double)(dest[0] + dest[1]) * rpm2mph / 2.0);
+ a.com->printf ("mph%c %.3f\r", mode_bytes[ID], (double)(dest[0] + dest[1]) * rpm2mph / 2.0);
+ }
}
void menucmd (struct parameters & a);
@@ -240,15 +305,19 @@
{"v", "set motors V percent RANGE 0 to 100", v_cmd},
{"i", "set motors I percent RANGE 0 to 100", i_cmd},
{"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
- {"who", "search for connected units, e.g. 3who returs 'Hi there' if found", who_cmd},
+ {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
{"mode", "read or set params in eeprom", mode_cmd},
{"erase", "set eeprom contents to all 0xff", erase_cmd},
{"tem", "report temperature", temperature_cmd},
{"kd", "kick the dog, reloads WatchDog", kd_cmd},
+ {"wden", "enable watchdog if modes allow", wden_lococmd},
+ {"wddi", "disable watchdog always", wddi_lococmd},
{"rpm", "read motor pair speeds", rpm_cmd},
+ {"mph", "read loco speed miles per hour", mph_cmd},
{"rvi", "read most recent values sent to pwms", rvi_cmd},
{"rdi", "read motor currents and power voltage", rdi_cmd},
- {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd},
+ {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd}, // OBSOLETE, replaced by 'gbb'
+ {"gbb", "get bogie bytes from eeprom and report", gbb_cmd},
{"nu", "do nothing", null_cmd},
};
@@ -258,6 +327,9 @@
struct kb_command const pc_command_list[] = {
{"ls", "Lists available commands", menucmd},
{"?", "Lists available commands, same as ls", menucmd},
+ {"mtypes", "report types of motors found", mt_cmd},
+ {"pf", "try changing FastPWM prescaler values", pf_cmd},
+ {"pot", "read drivers control pot", pot_cmd},
{"fw", "forward", fw_cmd},
{"re", "reverse", re_cmd},
{"rb", "regen brake 0 to 99 %", rb_cmd},
@@ -265,16 +337,19 @@
{"v", "set motors V percent RANGE 0 to 100", v_cmd},
{"i", "set motors I percent RANGE 0 to 100", i_cmd},
{"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
- {"who", "search for connected units, e.g. 3who returs 'Hi there' if found", who_cmd},
+ {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
{"mode", "read or set params in eeprom", mode_cmd},
{"erase", "set eeprom contents to all 0xff", erase_cmd},
{"tem", "report temperature", temperature_cmd},
{"kd", "kick the dog, reloads WatchDog", kd_cmd},
+ {"wden", "enable watchdog if modes allow", wden_pccmd},
+ {"wddi", "disable watchdog always", wddi_pccmd},
{"rpm", "read motor pair speeds", rpm_cmd},
{"mph", "read loco speed miles per hour", mph_cmd},
{"rvi", "read most recent values sent to pwms", rvi_cmd},
{"rdi", "read motor currents and power voltage", rdi_cmd},
{"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd},
+ {"gbb", "get bogie bytes from eeprom and report", gbb_cmd}, // OBSOLETE, replaced by 'gbb'
{"nu", "do nothing", null_cmd},
};
--- a/main.cpp Sun Jun 17 06:59:37 2018 +0000
+++ b/main.cpp Sat Aug 18 12:51:35 2018 +0000
@@ -1,4 +1,6 @@
#include "mbed.h"
+//#include "users/mbed_official/code/mbed-dev/file/707f6e361f3e/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F401xE/device/stm32f401xe.h"
+#include "stm32f401xe.h"
#include "DualBLS.h"
#include "BufferedSerial.h"
#include "FastPWM.h"
@@ -28,6 +30,7 @@
*/
+
#if defined (TARGET_NUCLEO_F401RE) // CPU in 64 pin LQFP
#include "F401RE.h"
#endif
@@ -37,6 +40,7 @@
/* Global variable declarations */
volatile uint32_t fast_sys_timer = 0; // gets incremented by our Ticker ISR every VOLTAGE_READ_INTERVAL_US
int WatchDog = WATCHDOG_RELOAD + 80; // Allow extra few seconds at powerup
+bool WatchDogEnable = false; // Must recieve explicit instruction from pc or controller to enable
uint32_t volt_reading = 0, // Global updated by interrupt driven read of Battery Volts
driverpot_reading = 0, // Global updated by interrupt driven read of Drivers Pot
sys_timer = 0, // gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
@@ -51,17 +55,20 @@
uint32_t temp_sensor_count = 0, // incremented by every rising edge from LMT01
last_temp_count = 0; // global updated approx every 100ms after each LMT01 conversion completes
-// struct single_bogie_options bogie;
- double rpm2mph = 0.0; // gets calculated from eeprom mode entries if present
+// struct single_bogie_options bogie;
+double rpm2mph = 0.0; // gets calculated from eeprom mode entries if present
/* End of Global variable declarations */
Ticker tick_vread; // Device to cause periodic interrupts, used to time voltage readings etc
Ticker loop_timer; // Device to cause periodic interrupts, used to sync iterations of main programme loop
Ticker temperature_find_ticker;
Timer temperature_timer;
+Timer dc_motor_kicker_timer;
+Timeout motors_restore;
// Interrupt Service Routines
-void ISR_temperature_find_ticker () { // every 960 us, i.e. slightly faster than once per milli sec
+void ISR_temperature_find_ticker () // every 960 us, i.e. slightly faster than once per milli sec
+{
static bool readflag = false;
int t = temperature_timer.read_ms ();
if ((t == 5) && (!readflag)) {
@@ -100,7 +107,8 @@
class RControl_In
-{ // Read servo style pwm input
+{
+ // Read servo style pwm input
Timer t;
int32_t clock_old, clock_new;
int32_t pulse_width_us, period_us;
@@ -117,11 +125,13 @@
bool rx_active;
} ;
-uint32_t RControl_In::pulsewidth () {
+uint32_t RControl_In::pulsewidth ()
+{
return pulse_width_us;
}
-uint32_t RControl_In::period () {
+uint32_t RControl_In::period ()
+{
return period_us;
}
@@ -162,12 +172,19 @@
4 1 0 0 0 1 1 -___---___-- Hall3
UV WV WU VU VW UW OUTPUT SEQUENCE
+
+8th July 2018
+Added drive to DC brushed motors.
+Connect U and W to dc motor, leave V open.
+
+Hall codes 0 and 7 not used for brushless motors. Without Hall sensors connected pullup resistors give code 7. Use this for dc motors
+
*/
const uint16_t A_tabl[] = { // Origial table
0, 0, 0, 0, 0, 0, 0, 0, // Handbrake
- 0, AWV,AVU,AWU,AUW,AUV,AVW, 0, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
- 0, AVW,AUV,AUW,AWU,AVU,AWV, 0, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
- 0, BRA,BRA,BRA,BRA,BRA,BRA,0, // Regenerative Braking
+ 0, AWV,AVU,AWU,AUW,AUV,AVW,AUW, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
+ 0, AVW,AUV,AUW,AWU,AVU,AWV,AWU, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
+ 0, BRA,BRA,BRA,BRA,BRA,BRA,BRA, // Regenerative Braking
KEEP_L_MASK_A, KEEP_H_MASK_A // [32 and 33]
} ;
InterruptIn * AHarr[] = {
@@ -177,9 +194,9 @@
} ;
const uint16_t B_tabl[] = {
0, 0, 0, 0, 0, 0, 0, 0, // Handbrake
- 0, BWV,BVU,BWU,BUW,BUV,BVW, 0, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
- 0, BVW,BUV,BUW,BWU,BVU,BWV, 0, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
- 0, BRB,BRB,BRB,BRB,BRB,BRB,0, // Regenerative Braking
+ 0, BWV,BVU,BWU,BUW,BUV,BVW,BUW, // Forward 0, WV1, VU1, WU1, UW1, UV1, VW1, 0, // JP, FR, SG, PWM = 1 0 1 1 Forward1
+ 0, BVW,BUV,BUW,BWU,BVU,BWV,BWU, // Reverse 0, VW1, UV1, UW1, WU1, VU1, WV1, 0, // JP, FR, SG, PWM = 1 1 0 1 Reverse1
+ 0, BRB,BRB,BRB,BRB,BRB,BRB,BRB, // Regenerative Braking
KEEP_L_MASK_B, KEEP_H_MASK_B
} ;
InterruptIn * BHarr[] = {
@@ -198,6 +215,7 @@
PortOut * Motor_Port;
InterruptIn * Hall1, * Hall2, * Hall3;
public:
+ bool dc_motor;
struct currents {
uint32_t max, min, ave;
} I;
@@ -218,7 +236,10 @@
void current_calc () ; // Updates 3 uint32_t I.min, I.ave, I.max
uint32_t pulses_per_sec () ; // call this once per main loop pass to keep count = edges per sec
int read_Halls () ; // Returns 3 bits of latest Hall sensor outputs
+ bool motor_is_brushless ();
void high_side_off () ;
+ void low_side_on () ;
+ void raw_V_pwm (int);
} ; //MotorA, MotorB, or even Motor[2];
motor MotorA (&MotA, &A_MAX_V_PWM, &A_MAX_I_PWM, A_tabl, AHarr);
@@ -227,7 +248,8 @@
//motor * MotPtr[8]; // Array of pointers to some number of motor objects
motor::motor (PortOut * P , FastPWM * _maxV_ , FastPWM * _maxI_ , const uint16_t * lutptr, InterruptIn ** Hall) // Constructor
-{ // Constructor
+{
+ // Constructor
maxV = _maxV_;
maxI = _maxI_;
Hall_total = 0; // mode can be only 0, 8, 16 or 24, lut row select for Handbrake, Forward, Reverse, or Regen Braking
@@ -258,19 +280,36 @@
PPS = 0;
RPM = 0;
last_V = last_I = 0.0;
+ int x = read_Halls ();
+ if (x == 7)
+ dc_motor = true;
+ else
+ dc_motor = false;
+}
+
+bool motor::motor_is_brushless ()
+{
+ /* int x = read_Halls ();
+ if (x < 1 || x > 6)
+ return false;
+ return true;
+ */
+ return !dc_motor;
}
/**
void motor::direction_set (int dir) {
Used to set direction according to mode data from eeprom
*/
-void motor::direction_set (int dir) {
+void motor::direction_set (int dir)
+{
if (dir != 0)
dir = FORWARD | REVERSE; // bits used in eor
direction = dir;
}
-int motor::read_Halls () {
+int motor::read_Halls ()
+{
int x = 0;
if (*Hall1 != 0) x |= 1;
if (*Hall2 != 0) x |= 2;
@@ -278,12 +317,20 @@
return x;
}
-void motor::high_side_off () {
+void motor::high_side_off ()
+{
uint16_t p = *Motor_Port;
p &= lut[32]; // KEEP_L_MASK_A or B
*Motor_Port = p;
}
+void motor::low_side_on ()
+{
+// uint16_t p = *Motor_Port;
+// p &= lut[31]; // KEEP_L_MASK_A or B
+ *Motor_Port = lut[31];
+}
+
void motor::current_calc ()
{
I.min = 0x0fffffff; // samples are 16 bit
@@ -301,7 +348,15 @@
I.ave /= CURRENT_SAMPLES_AVERAGED;
}
-void motor::set_V_limit (double p) // Sets max motor voltage
+
+void motor::raw_V_pwm (int v)
+{
+ if (v < 1) v = 1;
+ if (v > MAX_PWM_TICKS) v = MAX_PWM_TICKS;
+ maxV->pulsewidth_ticks (v);
+}
+
+void motor::set_V_limit (double p) // Sets max motor voltage. Use set_V_limit (last_V) to restore previous setting
{
if (p < 0.0)
p = 0.0;
@@ -330,12 +385,15 @@
}
uint32_t motor::pulses_per_sec () // call this once per 'MAIN_LOOP_REPEAT_TIME_US= 31250' main loop pass to keep count = edges per sec
-{ // Can also test for motor running or not here
+{
+ // Can also test for motor running or not here
+ if (dc_motor)
+ return 0;
if (ppstmp == Hall_total) {
+// if (dc_motor || ppstmp == Hall_total) {
moving_flag = false; // Zero Hall transitions since previous call - motor not moving
tickleon = TICKLE_TIMES;
- }
- else {
+ } else {
moving_flag = true;
ppstmp = Hall_total;
}
@@ -378,17 +436,16 @@
void motor::Hall_change ()
{
- const int32_t delta_theta_lut[] = // Looks up -1 for forward move detected, +1 for reverse move detected, 0 for error or unknown
- {
- 0, 0, 0, 0, 0, 0, 0, 0, // Previous Hindex was 0
- 0, 0, 0,-1, 0, 1, 0, 0, // Previous Hindex was 1
- 0, 0, 0, 1, 0, 0,-1, 0, // Previous Hindex was 2
- 0, 1,-1, 0, 0, 0, 0, 0, // Previous Hindex was 3
- 0, 0, 0, 0, 0,-1, 1, 0, // Previous Hindex was 4
- 0,-1, 0, 0, 1, 0, 0, 0, // Previous Hindex was 5
- 0, 0, 1, 0,-1, 0, 0, 0, // Previous Hindex was 6
- 0, 0, 0, 0, 0, 0, 0, 0, // Previous Hindex was 7
- } ;
+ const int32_t delta_theta_lut[] = { // Looks up -1 for forward move detected, +1 for reverse move detected, 0 for error or unknown
+ 0, 0, 0, 0, 0, 0, 0, 0, // Previous Hindex was 0
+ 0, 0, 0,-1, 0, 1, 0, 0, // Previous Hindex was 1
+ 0, 0, 0, 1, 0, 0,-1, 0, // Previous Hindex was 2
+ 0, 1,-1, 0, 0, 0, 0, 0, // Previous Hindex was 3
+ 0, 0, 0, 0, 0,-1, 1, 0, // Previous Hindex was 4
+ 0,-1, 0, 0, 1, 0, 0, 0, // Previous Hindex was 5
+ 0, 0, 1, 0,-1, 0, 0, 0, // Previous Hindex was 6
+ 0, 0, 0, 0, 0, 0, 0, 0, // Previous Hindex was 7
+ } ;
int32_t delta_theta = delta_theta_lut[(Hindex[1] << 3) | Hindex[0]];
if (delta_theta == 0)
encoder_error_cnt++;
@@ -400,7 +457,13 @@
}
-void temp_sensor_isr () { // got rising edge from LMT01. ALMOST CERTAIN this misses some
+void report_motor_types () // not very good test, shows 'Brushless' if Hall inputs read 1 to 6, 'DC' otherwise
+{
+ pc.printf ("Mot A is %s, Mot B is %s\r\n", MotorA.motor_is_brushless() ? "Brushless":"DC", MotorB.motor_is_brushless() ? "Brushless":"DC");
+}
+
+void temp_sensor_isr () // got rising edge from LMT01. ALMOST CERTAIN this misses some
+{
int t = temperature_timer.read_us (); // Must be being overrun by something, most likely culprit A-D reading ?
temperature_timer.reset ();
temp_sensor_count++;
@@ -409,11 +472,12 @@
// T2 = !T2; // scope hanger
}
+
void MAH_isr ()
{
uint32_t x = 0;
MotorA.high_side_off ();
- T3 = !T3;
+// T3 = !T3;
if (MAH1 != 0) x |= 1;
if (MAH2 != 0) x |= 2;
if (MAH3 != 0) x |= 4;
@@ -441,32 +505,38 @@
*Motor_Port = lut[inner_mode | Hindex[0]];
}
-void setVI (double v, double i) {
+void setVI (double v, double i)
+{
MotorA.set_V_limit (v); // Sets max motor voltage
MotorA.set_I_limit (i); // Sets max motor current
MotorB.set_V_limit (v);
MotorB.set_I_limit (i);
}
-void setV (double v) {
+void setV (double v)
+{
MotorA.set_V_limit (v);
MotorB.set_V_limit (v);
}
-void setI (double i) {
+void setI (double i)
+{
MotorA.set_I_limit (i);
MotorB.set_I_limit (i);
}
-void read_RPM (uint32_t * dest) {
+void read_RPM (uint32_t * dest)
+{
dest[0] = MotorA.RPM;
dest[1] = MotorB.RPM;
}
-void read_PPS (uint32_t * dest) {
+void read_PPS (uint32_t * dest)
+{
dest[0] = MotorA.PPS;
dest[1] = MotorB.PPS;
}
-void read_last_VI (double * d) { // only for test from cli
+void read_last_VI (double * d) // only for test from cli
+{
d[0] = MotorA.last_V;
d[1] = MotorA.last_I;
d[2] = MotorB.last_V;
@@ -481,13 +551,22 @@
void AtoD_reader () // Call to here every VOLTAGE_READ_INTERVAL_US = 50 once loop responds to flag set in isr
{
static uint32_t i = 0, tab_ptr = 0;
-
+// if (MotorA.dc_motor) {
+// MotorA.low_side_on ();
+// }
+// else {
if (MotorA.tickleon)
MotorA.high_side_off ();
+// }
+// if (MotorB.dc_motor) {
+// MotorB.low_side_on ();
+// }
+// else {
if (MotorB.tickleon)
MotorB.high_side_off ();
+// }
if (AtoD_Semaphore > 20) {
- pc.printf ("WARNING - silly semaphore count %d, limiting to sensible\r\n", AtoD_Semaphore);
+ pc.printf ("WARNING - sema cnt %d\r\n", AtoD_Semaphore);
AtoD_Semaphore = 20;
}
while (AtoD_Semaphore > 0) {
@@ -516,10 +595,12 @@
i = 0;
} // end of while (AtoD_Semaphore > 0) {
if (MotorA.tickleon) {
+// if (MotorA.dc_motor || MotorA.tickleon) {
MotorA.tickleon--;
MotorA.motor_set (); // Reactivate any high side switches turned off above
}
if (MotorB.tickleon) {
+// if (MotorB.dc_motor || MotorB.tickleon) {
MotorB.tickleon--;
MotorB.motor_set ();
}
@@ -540,13 +621,15 @@
return ((double) volt_reading) / 951.0; // divisor fiddled to make voltage reading correct !
}
-void read_supply_vi (double * val) { // called from cli
+void read_supply_vi (double * val) // called from cli
+{
val[0] = MotorA.I.ave;
val[1] = MotorB.I.ave;
val[2] = Read_BatteryVolts ();
}
-void mode_set (int mode, double val) { // called from cli to set fw, re, rb, hb
+void mode_set_both_motors (int mode, double val) // called from cli to set fw, re, rb, hb
+{
MotorA.set_mode (mode);
MotorB.set_mode (mode);
if (mode == REGENBRAKE) {
@@ -577,17 +660,140 @@
last;
} ;
*/
-int I_Am () { // Returns boards id number as ASCII char
+int I_Am () // Returns boards id number as ASCII char
+{
return IAm;
}
-double mph (int rpm) {
+double mph (int rpm)
+{
if (mode_good_flag) {
return rpm2mph * (double) rpm;
}
return -1.0;
}
+void restorer ()
+{
+ motors_restore.detach ();
+ if (MotorA.dc_motor) {
+ MotorA.set_V_limit (MotorA.last_V);
+ MotorA.set_I_limit (MotorA.last_I);
+ MotorA.motor_set ();
+ }
+ if (MotorB.dc_motor) {
+ MotorB.set_V_limit (MotorB.last_V);
+ MotorB.set_I_limit (MotorB.last_I);
+ MotorB.motor_set ();
+ }
+}
+
+//int ttime = 3; // resettable via cli 'stt', used to determine suitable force low on period for driving dc motor
+bool worth_the_bother (double a, double b) {
+ double c = a - b;
+ if (c < 0.0)
+ c = 0.0 - c;
+ if (c > 0.02) {
+// pc.printf ("%.3f\r\n", c);
+ return true;
+ }
+ return false;
+}
+
+void prscfuck (int v) {
+/*
+int prescaler ( int value )
+
+Set the PWM prescaler.
+
+The period of all PWM pins on the same PWM unit have to be reset after using this!
+
+Parameters:
+ value - The required prescaler. Special values: 0 = lock current prescaler, -1 = use dynamic prescaler
+ return - The prescaler which was set (can differ from requested prescaler if not possible)
+
+Definition at line 82 of file FastPWM_common.cpp.
+*/
+ if (v < 1)
+ v = 1;
+ int w = A_MAX_V_PWM.prescaler (v);
+ pc.printf ("Attempt setting prescaler %d returned %d\r\n", v, w);
+}
+
+enum { HAND_CONT_STATE_BEGIN,
+ HAND_CONT_STATE_POWER_CYCLE_TO_EXIT,
+ HAND_CONT_STATE_INTO_BRAKING,
+ HAND_CONT_STATE_INTO_DRIVING,
+ HAND_CONT_STATE_BRAKING,
+ HAND_CONT_STATE_DRIVING
+ } ;
+
+void hand_control_state_machine () {
+ static int new_hand_controller_state = HAND_CONT_STATE_BEGIN;
+// static int old_hand_controller_state = HAND_CONT_STATE_BEGIN;
+ static int old_hand_controller_direction = T5, t = 0;
+ static double brake_effort, drive_effort, pot_position, old_pot_position = 0.0;
+ if (T5 != old_hand_controller_direction) { // 1 Forward, 0 Reverse
+ pc.printf ("Direction change! Power off then on again to resume\r\n");
+ mode_set_both_motors (REGENBRAKE, 1.0);
+// old_hand_controller_state = new_hand_controller_state;
+ new_hand_controller_state = HAND_CONT_STATE_POWER_CYCLE_TO_EXIT;
+ }
+ pot_position = Read_DriverPot (); // gets to here on first pass before pot has been read
+ switch (new_hand_controller_state) {
+ case HAND_CONT_STATE_BEGIN:
+ pot_position = Read_DriverPot ();
+ if (t++ > 2 && pot_position < 0.02) {
+ pc.printf ("In BEGIN, pot %.2f\r\n", pot_position);
+ new_hand_controller_state = HAND_CONT_STATE_INTO_BRAKING;
+ }
+ break;
+ case HAND_CONT_STATE_POWER_CYCLE_TO_EXIT:
+ break;
+ case HAND_CONT_STATE_INTO_BRAKING:
+ brake_effort = (Pot_Brake_Range - pot_position) / Pot_Brake_Range;
+ mode_set_both_motors (REGENBRAKE, brake_effort);
+ old_pot_position = pot_position;
+ new_hand_controller_state = HAND_CONT_STATE_BRAKING;
+ pc.printf ("Brake\r\n");
+ break;
+ case HAND_CONT_STATE_INTO_DRIVING:
+ new_hand_controller_state = HAND_CONT_STATE_DRIVING;
+ pc.printf ("Drive\r\n");
+ if (T5)
+ mode_set_both_motors (FORWARD, 0.0); // sets both motors
+ else
+ mode_set_both_motors (REVERSE, 0.0);
+ break;
+ case HAND_CONT_STATE_BRAKING:
+ if (pot_position > Pot_Brake_Range) // escape braking into drive
+ new_hand_controller_state = HAND_CONT_STATE_INTO_DRIVING;
+ else {
+ if (worth_the_bother(pot_position, old_pot_position)) {
+ old_pot_position = pot_position;
+ brake_effort = (Pot_Brake_Range - pot_position) / Pot_Brake_Range;
+ mode_set_both_motors (REGENBRAKE, brake_effort);
+// pc.printf ("Brake %.2f\r\n", brake_effort);
+ }
+ }
+ break;
+ case HAND_CONT_STATE_DRIVING:
+ if (pot_position < Pot_Brake_Range) // escape braking into drive
+ new_hand_controller_state = HAND_CONT_STATE_INTO_BRAKING;
+ else {
+ if (worth_the_bother(pot_position, old_pot_position)) {
+ old_pot_position = pot_position;
+ drive_effort = (pot_position - Pot_Brake_Range) / (1.0 - Pot_Brake_Range);
+ setVI (drive_effort, drive_effort); // Wind volts and amps up and down together ???
+ pc.printf ("Drive %.2f\r\n", drive_effort);
+ }
+ }
+ break;
+ default:
+ break;
+ } // endof switch (hand_controller_state) {
+}
+
int main()
{
int eighth_sec_count = 0;
@@ -596,7 +802,7 @@
MotB = 0;
// MotPtr[0] = &MotorA; // Pointers to motor class objects
// MotPtr[1] = &MotorB;
-
+
Temperature_pin.fall (&temp_sensor_isr);
Temperature_pin.mode (PullUp);
@@ -642,41 +848,47 @@
pc.printf ("Check for 24LC64 eeprom FAILED\r\n");
com2.printf ("Check for 24LC64 eeprom FAILED\r\n");
eeprom_flag = false;
- }
- else { // Found 24LC64 memory on I2C
+ } else { // Found 24LC64 memory on I2C
eeprom_flag = true;
bool k;
k = rd_24LC64 (0, mode_bytes, 32);
if (!k)
com2.printf ("Error reading from eeprom\r\n");
- int err = 0;
+// int err = 0;
for (int i = 0; i < numof_eeprom_options; i++) {
if ((mode_bytes[i] < option_list[i].min) || (mode_bytes[i] > option_list[i].max)) {
com2.printf ("EEROM error with %s\r\n", option_list[i].t);
- err++;
+ pc.printf ("EEROM error with %s\r\n", option_list[i].t);
+ if (i == ID) { // need to force id to '0'
+ pc.printf ("Bad board ID value %d, forcing to \'0\'\r\n");
+ mode_bytes[ID] = '0';
+ }
+// err++;
}
// else
// com2.printf ("%2x Good %s\r\n", buff[i], option_list[i].t);
}
rpm2mph = 0.0;
- if (err == 0) {
- mode_good_flag = true;
- MotorA.direction_set (mode_bytes[MOTADIR]);
- MotorB.direction_set (mode_bytes[MOTBDIR]);
- IAm = mode_bytes[ID];
- rpm2mph = 60.0 // to Motor Revs per hour;
- * ((double)mode_bytes[MOTPIN] / (double)mode_bytes[WHEELGEAR]) // Wheel revs per hour
- * PI * ((double)mode_bytes[WHEELDIA] / 1000.0) // metres per hour
- * 39.37 / (1760.0 * 36.0); // miles per hour
- }
- // Alternative ID 1 to 9
+ if (mode_bytes[WHEELGEAR] == 0) // avoid making div0 error
+ mode_bytes[WHEELGEAR]++;
+// if (err == 0) {
+ mode_good_flag = true;
+ MotorA.direction_set (mode_bytes[MOTADIR]);
+ MotorB.direction_set (mode_bytes[MOTBDIR]);
+ IAm = mode_bytes[ID];
+ rpm2mph = 60.0 // to Motor Revs per hour;
+ * ((double)mode_bytes[MOTPIN] / (double)mode_bytes[WHEELGEAR]) // Wheel revs per hour
+ * PI * ((double)mode_bytes[WHEELDIA] / 1000.0) // metres per hour
+ * 39.37 / (1760.0 * 36.0); // miles per hour
+// }
+ // Alternative ID 1 to 9
// com2.printf ("Alternative ID = 0x%2x\r\n", buff[6]);
}
// T1 = 0; Now WRONGLY hoped to be InterruptIn counting pulses from LMT01 temperature sensor
T2 = 0; // T2, T3, T4 As yet unused pins
- T3 = 0;
- T4 = 0;
+// T3 = 0;
+// T4 = 0;
// T5 = 0; now input from fw/re on remote control box
T6 = 0;
// MotPtr[0]->set_mode (REGENBRAKE);
@@ -684,6 +896,8 @@
MotorB.set_mode (REGENBRAKE);
setVI (0.9, 0.5);
+// prscfuck (PWM_PRESECALER_DEFAULT); // Test fucking with fastpwm prescaler
+
Servos[0] = Servos[1] = NULL;
// NOTE The ONLY way to get both servos working properly is to NOT use any if (bla) Servo ervo1(PB_8);
// Only works with unconditional inline code
@@ -693,17 +907,17 @@
Servos[0] = & Servo1;
Servo Servo2 (PB_9) ;
Servos[1] = & Servo2;
-
+
// pc.printf ("last_temp_count = %d\r\n", last_temp_count); // Has had time to do at least 1 conversion
if ((last_temp_count > 160) && (last_temp_count < 2400)) // in range -40 to +100 degree C
temp_sensor_exists = true;
-/*
- // Setup Complete ! Can now start main control forever loop.
- // March 16th 2018 thoughts !!!
- // Control from one of several sources and types as selected in options bytes in eeprom.
- // Control could be from e.g. Pot, Com2, Servos etc.
- // Suggest e.g.
-*/ /*
+ /*
+ // Setup Complete ! Can now start main control forever loop.
+ // March 16th 2018 thoughts !!!
+ // Control from one of several sources and types as selected in options bytes in eeprom.
+ // Control could be from e.g. Pot, Com2, Servos etc.
+ // Suggest e.g.
+ */ /*
switch (mode_byte) { // executed once only upon startup
case POT:
while (1) { // forever loop
@@ -720,7 +934,18 @@
}
*/
// pc.printf ("Ready to go!, wheel gear in position %d\r\n", WHEELGEAR);
- pc.printf ("About to start!\r\n");
+ dc_motor_kicker_timer.start ();
+ int old_hand_controller_direction = T5;
+ if (mode_bytes[COMM_SRC] == 3) { // Read fwd/rev switch 'T5', PA15 on 401
+ pc.printf ("Pot control\r\n");
+ if (T5)
+ mode_set_both_motors (FORWARD, 0.0); // sets both motors
+ else
+ mode_set_both_motors (REVERSE, 0.0);
+ }
+
+ pc.printf ("About to start!, mode_bytes[COMM_SRC]= %d\r\n", mode_bytes[COMM_SRC]);
+
while (1) { // Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
while (!loop_flag) { // Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
command_line_interpreter_pc () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
@@ -728,31 +953,66 @@
AtoD_reader (); // Performs A to D conversions at rate set by ticker interrupts
}
loop_flag = false; // Clear flag set by ticker interrupt handler
+ switch (mode_bytes[COMM_SRC]) { // Look to selected source of driving command, act on commands from wherever
+ case 0: // Invalid
+ break;
+ case 1: // COM1 - Primarily for testing, bypassed by command line interpreter
+ break;
+ case 2: // COM2 - Primarily for testing, bypassed by command line interpreter
+ break;
+ case 3: // Put all hand controller input stuff here
+ hand_control_state_machine ();
+ break; // endof hand controller stuff
+ case 4: // Servo1
+ break;
+ case 5: // Servo2
+ break;
+ default:
+ pc.printf ("Unrecognised state %d\r\n", mode_bytes[COMM_SRC]);
+ break;
+ } // endof switch (mode_bytes[COMM_SRC]) {
+
+ dc_motor_kicker_timer.reset ();
MotorA.pulses_per_sec (); // Needed to keep table updated to give reading in Hall transitions per second
MotorB.pulses_per_sec (); // Read MotorX.PPS to read pulses per sec or MotorX.RPM to read motor RPM
- T4 = !T4; // toggle to hang scope on to verify loop execution
+// T4 = !T4; // toggle to hang scope on to verify loop execution
// do stuff
+ if (MotorA.dc_motor) {
+ MotorA.raw_V_pwm (1);
+ MotorA.low_side_on ();
+ }
+ if (MotorB.dc_motor) {
+ MotorB.raw_V_pwm (1);
+ MotorB.low_side_on ();
+ }
+ if (MotorA.dc_motor || MotorB.dc_motor) {
+// motors_restore.attach_us (&restorer, ttime);
+ motors_restore.attach_us (&restorer, 25);
+ }
+
if (flag_8Hz) { // do slower stuff
flag_8Hz = false;
LED = !LED; // Toggle LED on board, should be seen to fast flash
- WatchDog--;
- if (WatchDog == 0) { // Deal with WatchDog timer timeout here
- setVI (0.0, 0.0); // set motor volts and amps to zero
- com2.printf ("TIMEOUT %2x\r\n", (I_Am() & 0x0f)); // Potential problem of multiple units reporting at same time overcome by adding board number to WATCHDOG_RELOAD
- } // End of dealing with WatchDog timer timeout
- if (WatchDog < 0)
- WatchDog = 0;
+ if (WatchDogEnable) {
+ WatchDog--;
+ if (WatchDog == 0) { // Deal with WatchDog timer timeout here
+ setVI (0.0, 0.0); // set motor volts and amps to zero
+ com2.printf ("TIMEOUT %2x\r\n", (I_Am() & 0x0f)); // Potential problem of multiple units reporting at same time overcome by adding board number to WATCHDOG_RELOAD
+ } // End of dealing with WatchDog timer timeout
+ if (WatchDog < 0)
+ WatchDog = 0;
+ }
eighth_sec_count++;
if (eighth_sec_count > 6) { // Send some status info out of serial port every second and a bit or thereabouts
eighth_sec_count = 0;
MotorA.current_calc (); // Updates readings in MotorA.I.min, MotorA.I.ave and MotorA.I.max
MotorB.current_calc ();
-/* if (temp_sensor_exists) {
- double tmprt = (double) last_temp_count;
- tmprt /= 16.0;
- tmprt -= 50.0;
- pc.printf ("Temp %.2f\r\n", tmprt);
- }*/
+ /* if (temp_sensor_exists) {
+ double tmprt = (double) last_temp_count;
+ tmprt /= 16.0;
+ tmprt -= 50.0;
+ pc.printf ("Temp %.2f\r\n", tmprt);
+ }*/
// com2.printf ("V=%+.2f, Pot=%+.2f, HA %d, HB %d, IAmin %d, IAave %d, IAmax %d, IB %d, Arpm %d, Brpm %d\r\n", Read_BatteryVolts(), Read_DriverPot(), MotorA.read_Halls (), MotorB.read_Halls (), MotorA.I.min, MotorA.I.ave, MotorA.I.max, MotorB.I.ave, (Apps * 60) / 24, (Bpps * 60) / 24);
}
} // End of if(flag_8Hz)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sud.cpp Sat Aug 18 12:51:35 2018 +0000
@@ -0,0 +1,117 @@
+//sudoku
+#include "mbed.h"
+#include "BufferedSerial.h"
+#include "DualBLS.h"
+extern BufferedSerial com2, pc;
+using namespace std;
+
+struct cell {
+ uint16_t confirmed;
+ uint16_t dominoes;
+ uint16_t must_be;
+} matrix[82];
+/*
+Cell Map
+
+0 1 2 3 4 5 6 7 8
+9 10 11 12 13 14 15 16 17
+18 19 20 21 22 23 24 25 26
+
+27 28 29 30 31 32 33 34 35
+36 37 38 39 40 41 42 43 44
+45 46 47 48 49 50 51 52 53
+
+54 55 56 57 58 59 60 61 62
+63 64 65 66 67 68 69 70 71
+72 73 74 75 76 77 78 79 80
+
+*/
+
+static const uint16_t
+ box1[] = { 0, 1, 2, 9, 10, 11, 18, 19, 20},
+ box2[] = { 3, 4, 5, 12, 13, 14, 21, 22, 23},
+ box3[] = { 6, 7, 8, 15, 16, 17, 24, 25, 26},
+ box4[] = {27, 28, 29, 36, 37, 38, 45, 46, 47},
+ box5[] = {30, 31, 32, 39, 40, 41, 48, 49, 50},
+ box6[] = {33, 34, 35, 42, 43, 44, 51, 52, 53},
+ box7[] = {54, 55, 56, 63, 64, 65, 72, 73, 74},
+ box8[] = {57, 58, 59, 66, 67, 68, 75, 76, 77},
+ box9[] = {60, 61, 62, 69, 70, 71, 78, 79, 80},
+
+ col1[] = { 0, 9, 18, 27, 36, 45, 54, 63, 72},
+ col2[] = { 1, 10, 19, 28, 37, 46, 55, 64, 73},
+ col3[] = { 2, 11, 20, 29, 38, 47, 56, 65, 74},
+ col4[] = { 3, 12, 21, 30, 39, 48, 57, 66, 75},
+ col5[] = { 4, 13, 22, 31, 40, 49, 58, 67, 76},
+ col6[] = { 5, 14, 23, 32, 41, 50, 59, 68, 77},
+ col7[] = { 6, 15, 24, 33, 42, 51, 60, 69, 78},
+ col8[] = { 7, 16, 25, 34, 43, 52, 61, 70, 79},
+ col9[] = { 8, 17, 26, 35, 44, 53, 62, 71, 80},
+
+ row1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8},
+ row2[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17},
+ row3[] = {18, 19, 20, 21, 22, 23, 24, 25, 26},
+ row4[] = {27, 28, 29, 30, 31, 32, 33, 34, 35},
+ row5[] = {36, 37, 38, 39, 40, 41, 42, 43, 44},
+ row6[] = {45, 46, 47, 48, 49, 50, 51, 52, 53},
+ row7[] = {54, 55, 56, 57, 58, 59, 60, 61, 62},
+ row8[] = {63, 64, 65, 66, 67, 68, 69, 70, 71},
+ row9[] = {72, 73, 74, 75, 76, 77, 78, 79, 80},
+
+ *box[] = {box1, box2, box3, box4, box5, box6, box7, box8, box9},
+ *row[] = {row1, row2, row3, row4, row5, row6, row7, row8, row9},
+ *col[] = {col1, col2, col3, col4, col5, col6, col7, col8, col9},
+
+ examp1[] = {5,0,0,0,9,0,7,0,0, // Hard puzzle 2,706,560,598
+ 0,0,8,2,0,0,5,3,0,
+ 0,6,0,8,0,0,0,0,0,
+ 0,0,0,3,7,9,0,0,2,
+ 0,2,0,0,0,0,0,9,0,
+ 3,0,0,5,8,2,0,0,0,
+ 0,0,0,0,0,6,0,8,0,
+ 0,7,4,0,0,8,3,0,0,
+ 0,0,6,0,1,0,0,0,7};
+
+void clear_matrix () {
+ for (int i = 0; i < 81; i++) {
+ matrix[i].confirmed = matrix[i].must_be = 0;
+ matrix[i].dominoes = 0x3fe;
+ }
+}
+void load_matrix (const uint16_t * p) {
+ for (int i = 0; i < 81; i++)
+ matrix[i].confirmed = p[i];
+}
+bool ranged (uint16_t a) {
+ if ((a > 0) && (a < 10))
+ return true;
+ return false;
+}
+void knock_down_dominoes (const uint16_t * brc) { // param points to list of 9 matrix offsets. May refer to row, col, or box
+ int d, mask;
+ for (int i = 0; i < 9; i++) {
+ d = matrix[brc[i]].confirmed;
+ pc.printf ("matrix cell %d\r\n", brc[i]);
+ if (ranged(d)) {
+ mask = (~(1 << d)) & 0x3fe;
+ for (int j = 0; j < 9; j++) {
+ if (i == j)
+ matrix[brc[j]].dominoes |= 1 << d;
+ else
+ matrix[brc[j]].dominoes &= mask;
+ }
+ }
+ }
+}
+void update_matrix () {
+ for (int i = 0; i < 9; i++) {
+ knock_down_dominoes (row[i]);
+ knock_down_dominoes (col[i]);
+ knock_down_dominoes (box[i]);
+ }
+}
+void sudo () {
+ clear_matrix ();
+ load_matrix (examp1);
+ pc.printf ("Row 3 col 7 = %d\r\n", matrix[row[3][7]].dominoes);
+}