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
Diff: Radio_Control_In.cpp
- 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