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:
16:d1e4b9ad3b8b
Parent:
14:acaa1add097b
--- a/Radio_Control_In.cpp	Sat Nov 30 18:40:30 2019 +0000
+++ b/Radio_Control_In.cpp	Tue Jun 09 09:20:19 2020 +0000
@@ -1,6 +1,7 @@
 #include "mbed.h"
 #include "BufferedSerial.h"
 #include "Radio_Control_In.h"
+#include "STM3_ESC.h"
 /**class   RControl_In
     Jon Freeman
     Jan 2019
@@ -9,6 +10,7 @@
     Checks repetition rate in range 5-25ms
 */
 extern  BufferedSerial  pc;
+//extern  eeprom_settings     user_settings     ;
 
 //    RControl_In::RControl_In   ()   {    //  Default Constructor
 //        pulse_width_us = period_us = pulse_count = 0;
@@ -39,29 +41,103 @@
     return  period_us;
 }
 
-void    RControl_In::reset ()
-{
-    pulse_width_us = period_us = pulse_count = 0;
-    t.reset ();
-}
-
 bool    RControl_In::validate_rx ()
 {   //  Tests for pulse width and repetition rates being believable
     return  !((period_us < 5000) || (period_us > 25000) || (pulse_width_us < 800) || (pulse_width_us > 2200));
 }
 
-double  RControl_In::normalised  ()  {
-    if  (!validate_rx())    {
-        pc.printf   ("Invalid RCin\r\n");
-        return  lost_chan_return_value;     //  ** WHAT TO RETURN WHEN RC NOT ACTIVE ? ** This is now user settable
-    }                                       //  Defaults to returning 0.0, user should call set_lost_chan_value (value) to alter
-    double norm = (double) (pulse_width_us - 1000);  //  left with -200 to + 1200 allowing for some margin
-    norm /= 1000.0;
-    if  (norm > 1.0)
-        norm = 1.0;
-    if  (norm < 0.0)
-        norm = 0.0;
-    return  norm;
+bool        RControl_In::energise    (struct  RC_stick_info & stick, struct brushless_motor & motor)  {     //  December 2019
+    if  (stick.active)   {
+        if  (stick.zone == ZONE_DRIVE)   {
+            motor.set_mode (stick.stick_implied_motor_direction == 1 ? MOTOR_FORWARD : MOTOR_REVERSE);
+            motor.set_V_limit  (stick.drive_effort);
+            motor.set_I_limit  (stick.drive_effort);    //  This could be 1.0, or other options
+        }
+        if  (stick.zone == ZONE_BRAKE)   {
+            motor.brake    (stick.brake_effort);
+        }
+    }
+    return  stick.active;
+}
+
+bool        RControl_In::read    (class  RC_stick_info & stick)  {      //  December 2019
+    double  dtmp;
+    uint32_t    old_zone = stick.zone;
+    stick.chan_mode = get_chanmode(); //  0 disabled, 1 uni-dir, or 2 bi-dir
+    stick.active = validate_rx();     //  True if RC Rx delivering believable pulse duration and timing
+    if  (stick.active && (stick.chan_mode < 1 || stick.chan_mode > 2))    {   //  Should signal an error here
+        stick.active = false;
+    }
+    if  (stick.active)    {
+        stick.raw = (double) (pulse_width_us - 1000);  //  Read pulse width from Rx, left with -200.0 to + 1200.0 allowing for some margin
+        stick.raw /= 1000.0;        //  pulse width varies between typ 1000 to 2000 micro seconds
+        stick.raw += range_offset;  //  range now normalised to 0.0 <= raw <= 1.0
+        if  (stick.raw > 1.0)        stick.raw = 1.0;
+        if  (stick.raw < 0.0)        stick.raw = 0.0;   //  clipped to strict limits 0.0 and 1.0
+        if  (stick_sense != 0)
+            stick.raw = 1.0 - stick.raw;    //  user setting allows for stick sense reversal
+        stick.deflection = stick.raw;
+        stick.stick_implied_motor_direction = +1;     //  -1 Reverse, 0 Stopped, +1 Forward
+        if  (stick.chan_mode == 2)  {       //  Bi-directional centre zero stick mode selected by user
+            stick.deflection = (stick.raw * 2.0) - 1.0;     //  range here -1.0 <= deflection <= +1.0
+            if  (stick.deflection < 0.0)    {
+                stick.deflection = 0.0 - stick.deflection;  //  range inverted if negative, direction info separated out
+                stick.stick_implied_motor_direction = -1;     //  -1 Reverse, 0 Stopped, +1 Forward (almost never 0)
+            }   //  endof deflection < 0.0
+        }       //  endof if chan_mode == 2
+        //  Now find zone from deflection
+        stick.zone = ZONE_COAST;
+        if  (stick.deflection < (brake_segment - 0.02))     //  size of brake_segment user settable
+            stick.zone = ZONE_BRAKE;
+        if  (stick.deflection > (brake_segment + 0.02))     //  Tiny 'freewheel' COAST band between drive and brake
+            stick.zone = ZONE_DRIVE;
+        if  (old_zone != ZONE_COAST && old_zone != stick.zone)    //
+            stick.zone = ZONE_COAST;        //  Ensures transitions between BRAKE and DRIVE go via COAST
+        switch  (stick.zone)    {
+            case    ZONE_COAST:
+                stick.drive_effort = 0.0;
+                stick.brake_effort = 0.0;
+                break;
+            case    ZONE_BRAKE:
+                stick.brake_effort = (brake_segment - stick.deflection) / brake_segment;    //  1.0 at zero deflection, reducing to 0.0 on boundary with DRIVE
+                stick.drive_effort = 0.0;
+                break;
+            case    ZONE_DRIVE:
+                stick.brake_effort = 0.0;
+                dtmp = (stick.deflection - brake_segment) / (1.0 - brake_segment);
+                if  (dtmp > stick.drive_effort) {       //  Stick has moved in increasing demand direction
+                    stick.drive_effort *= (1.0 - stick_attack);     //  Apply 'viscous damping' to demand increases for smoother operation
+                    stick.drive_effort += (dtmp * stick_attack);    //  Low pass filter, time constant variable by choosing 'stick_attack' value %age
+                }
+                else    //  Reduction or no increase in demanded drive effort
+                    stick.drive_effort = dtmp;      //  Reduce demand immediately, i.e. no viscous damping on reduced demand
+                break;
+        }       //  endof switch
+    }           //  endof if active
+    else    {   //  stick Not active
+        stick.zone = ZONE_BRAKE;
+        stick.raw = 0.0;
+        stick.deflection = 0.0;
+    }           //  endof not active
+    return  stick.active;
+}
+
+
+void    RControl_In::set_offset (signed char offs, char brake_pcent, char attack)   {   //  Takes user_settings[RCIx_TRIM]
+    brake_segment = ((double) brake_pcent) / 100.0;
+    stick_attack = ((double) attack) / 100.0;
+    range_offset = (double) offs;
+    range_offset /= 1000.0;         //  This is where to set range_offset sensitivity
+//    pc.printf   ("In RControl_In::set_offset, input signed char = %d, out f %.3f\r\n", offs, range_offset);
+}
+
+uint32_t    RControl_In::get_chanmode    () {
+    return  chan_mode;
+}
+
+void    RControl_In::set_chanmode    (char c, char polarity) {
+    chan_mode = ((uint32_t) c);
+    stick_sense = (uint32_t) polarity;
 }
 
 void    RControl_In::RadC_fall    ()     //  December 2018 - Could not make Servo port bidirectional, fix by using PC_14 and 15 as inputs