diff --git a/README.md b/README.md index df37497..6d1f1f5 100755 --- a/README.md +++ b/README.md @@ -515,6 +515,15 @@ const uint8_t shakerStop = 60; // Shaker power while engine stop (max. 255, abou ## Changelog (newest on top): +### New in V 9.9.0: +- New NEOPIXEL_UNION_JACK animation for Land Rover ;-) +- New MAX_POWER_MILLIAMPS setting for Neopixels. This and other optimizations is eliminating the flickering Neopixels issue +- 3_adjustmentsESC.h: globalAccelerationPercentage allows to adjust the acceleration, if vehicle setting is not OK +- 4_adjustmentsTransmission.h: lowRangePercentage allows to adjust the acceleration in low transmission (off road) range. Used for MODE1_SHIFTING and WPL 2 speed transmission +- Channel failsafe changed +- 2_adjustmentsRemote.h: External SBUS library not required anymore. See option #define EMBEDDED_SBUS. "sbusInverted" moved to remote configuration profiles, so you don't have to change it anymore +- SBUS still unstable with Flysky remotes! Especially in combination with WIRELESS_TRAILER. Use IBUS in this case! I'm thankful for hints about this bug. Differences: Micro RC is sending an SBUS packet every 14ms, Flysky every 7ms + ### New in V 9.8.0: - Adjustable RECOVERY_HYSTERESIS for battery protection - 8_adjustmentsSound.h (masterVolumeCrawlerThreshold) and 3_adjustmentsESC.h (crawlerEscRampTime): switchable crawler mode with just minimal inertia for gearbox protection. Allows to have a "show mode" and a "competition mode" diff --git a/data/trailer.txt b/data/calibration.txt similarity index 100% rename from data/trailer.txt rename to data/calibration.txt diff --git a/src/1_adjustmentsVehicle.h b/src/1_adjustmentsVehicle.h index 8ca571c..b00c66a 100644 --- a/src/1_adjustmentsVehicle.h +++ b/src/1_adjustmentsVehicle.h @@ -28,7 +28,7 @@ //#include "vehicles/ScaniaV8_50ton.h" // SCANIA V8 50 ton truck. Unknown model. Bad quality! //#include "vehicles/ScaniaV8.h" // SCANIA V8 truck, unknown model //#include "vehicles/1000HpScaniaV8.h" // 1000 HP SCANIA V8 truck with open pipes. Insane sound! Good bass speakers reqired -//#include "vehicles/Scania143.h" // SCANIA 143 V8 - the legend! The best sounding in my opinion +#include "vehicles/Scania143.h" // SCANIA 143 V8 - the legend! The best sounding in my opinion //#include "vehicles/ScaniaV8Firetruck.h" // SCANIA V8 firetruck, automatic Allison 6 speed transmission with torque converter, "Martinshorn" siren //#include "vehicles/VolvoFH16_750.h" // Volvo FH16 750 truck. Inline 6, 750 horses, open pipes! //#include "vehicles/VolvoFH16_OpenPipe.h" // Volvo FH truck. Inline 6, open pipes, alternative version @@ -84,7 +84,7 @@ // EU SUV -------- //#include "vehicles/DefenderV8Automatic.h" // Land Rover Defender 90 V8 automatic (very nice V8 with lots of bass) //#include "vehicles/DefenderV8OpenPipeAutomatic.h" // Land Rover Defender 90 V8 automatic, open pipes (optimised for smaller speakers) -#include "vehicles/DefenderV8OpenPipe.h" // Land Rover Defender 90 V8 manual, open pipes (optimised for smaller speakers) +//#include "vehicles/DefenderV8OpenPipe.h" // Land Rover Defender 90 V8 manual, open pipes (optimised for smaller speakers) //#include "vehicles/DefenderV8CrawlerAutomatic.h" // Land Rover Defender 90 V8 automatic crawler //#include "vehicles/DefenderTd5.h" // Land Rover Defender 90 Td5 R5 Diesel diff --git a/src/2_adjustmentsRemote.h b/src/2_adjustmentsRemote.h index 0c17c1a..bd07f65 100644 --- a/src/2_adjustmentsRemote.h +++ b/src/2_adjustmentsRemote.h @@ -7,7 +7,7 @@ //#define RGT_EX86100 // <------- MT-305 remote delivered with RGT EX86100 crawler (use PWM communication setting) //#define GRAUPNER_MZ_12 // <------- Graupner MZ-12 PRO #define MICRO_RC // <------- The car style DIY "Micro RC" remote. Don't use this with standard remotes! -//#define MICRO_RC_STICK // <------- The stick based DIY "Micro RC" remote. Don't use this with standard remotes! +//#define MICRO_RC_STICK // <------- The stick based DIY "Micro RC" remote. Don't use this with standard remotes! // For testing only! //#define FLYSKY_FS_I6S_EXCAVATOR_TEST // <------- Flysky FS-i6s for KABOLITE K336 hydraulic excavator @@ -23,9 +23,12 @@ // PWM mode active, if SBUS, IBUS, and PPM are disabled (// in front of #define) // SBUS communication (RX header, 13 channels. This is my preferred communication protocol)-------- +/* NOTE! SBUS is causing weird issues with Flysky remotes. Use IBUS instead! */ #define SBUS_COMMUNICATION // control signals are coming in via the SBUS interface (comment it out for classic PWM RC signals) -boolean sbusInverted = false; // false = wired to non standard (inverted) SBUS signal (for example from my "Micro RC" receiver) +// NOTE: "boolean sbusInverted = true / false" was moved to the remote configuration profiles, so you don't have to change it uint32_t sbusBaud = 100000; // Standard is 100000. Try to lower it, if your channels are coming in unstable. Working range is about 96000 - 104000. +#define EMBEDDED_SBUS // SBUS library not used, if defined (It is working fine with MICRO_RC, but still unstable with Flysky remotes, use IBUS for them) +uint16_t sbusFailsafeTimeout = 100; // Failsafe is triggered after this timeout in milliseconds (about 100, was 50) // IBUS communication (RX header, 13 channels not recommended, NO FAILSAFE, if bad contact in iBUS wiring!) -------- //#define IBUS_COMMUNICATION // control signals are coming in via the IBUS interface (comment it out for classic PWM RC signals) @@ -38,7 +41,7 @@ uint32_t sbusBaud = 100000; // Standard is 100000. Try to lower it, if your chan // CHANNEL LINEARITY SETTINGS **************************************************************************************************************** -#define EXPONENTIAL_THROTTLE // Exponential throttle curve. Ideal for enhanced slow speed control in crawlers +//#define EXPONENTIAL_THROTTLE // Exponential throttle curve. Ideal for enhanced slow speed control in crawlers //#define EXPONENTIAL_STEERING // Exponential steering curve. More steering accuracy around center position // CHANNEL AVERAGING (EXPERIMENTAL!) ********************************************************************************************************** @@ -145,6 +148,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF //#define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // Flysky FS-i6S remote configuration profile (for excavators only) --------------------------------------------------------------------------------- @@ -213,6 +219,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF //#define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // Flysky FS-i6S remote configuration profile (for excavators only) --------------------------------------------------------------------------------- @@ -281,6 +290,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF //#define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // Flysky GT5 / Reely GT6 EVO / Absima CR6P remote configuration profile (thanks to BlackbirdXL1 for making this profile)----------------------- @@ -373,6 +385,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF #define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // RGT MT-305 configuration profile (comes with EX86100) ----------------------- @@ -460,6 +475,9 @@ const uint16_t pulseSpan = 500; #define AUTO_ENGINE_ON_OFF #define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // Graupner mz-12 PRO remote configuration profile --------------------------------------------------------------------------------------------------- @@ -526,6 +544,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF #define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = true; // true = standard (non inverted) SBUS signal + #endif // "Micro RC" (the car style one) DIY Arduino remote configuration profile ------------------------------------------------------------------------------------------- @@ -592,6 +613,9 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF #define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = false; // false = non standard (inverted) SBUS signal + #endif // "Micro RC" (The stick based one) DIY Arduino remote configuration profile ------------------------------------------------------------------------------------------- @@ -658,4 +682,7 @@ const uint16_t pulseSpan = 480; //#define AUTO_ENGINE_ON_OFF #define AUTO_INDICATORS +// SBUS mode ---- +boolean sbusInverted = false; // false = non standard (inverted) SBUS signal + #endif diff --git a/src/3_adjustmentsESC.h b/src/3_adjustmentsESC.h index 13943b3..5b81d41 100644 --- a/src/3_adjustmentsESC.h +++ b/src/3_adjustmentsESC.h @@ -115,7 +115,10 @@ const uint16_t escReversePlus = 0; const uint16_t brakeMargin = 0; // For RZ7886 motor driver and 370 motor = 10 // Crawler mode escRampTime (see "8_adjustmentsSound.h") WARNING: a very low setting may damage your transmission! -const uint8_t crawlerEscRampTime = 10; // about 10, less = more direct control = less virtual inertia +const uint8_t crawlerEscRampTime = 10; // about 10 (15 for Jeep), less = more direct control = less virtual inertia + +// Allows to scale vehicle file dependent acceleration +uint16_t globalAccelerationPercentage = 100; // about 100 - 200% (200 for Jeep) Experimental, may cause automatic transmission shifting issues! /* Battery low discharge protection (only for boards with voltage divider resistors): * IMPORTANT: Enter used resistor values in Ohms (Ω) and THEN adjust DIODE_DROP, until your readings match the actual battery voltage! */ @@ -127,9 +130,9 @@ const float RECOVERY_HYSTERESIS = 0.2; // around 0.2 V * When selecting resistors, always use two of the same magnitude: Like, for example, 10k/2k, 20k/4k or 100k/20k. NEVER exceed a ratio LOWER than (4:1 = 4)! * WARNING: If the ratio is too LOW, like 10k/5k (2:1 = 2), the battery voltage will most likely DAMAGE the controller permanently! * Example calculation: 2000 / (2000 + 10000) = 0.166 666 666 7; 7.4 V * 0.167 = 1.2358 V (of 3.3 V maximum on GPIO Pin). */ -const uint16_t RESISTOR_TO_BATTTERY_PLUS = 10000; // Value in Ohms (Ω), for example 10000 -const uint16_t RESISTOR_TO_GND = 2000; // Value in Ohms (Ω), for example 1000. Measuring exact resistor values before soldering, if possible is recommended! -const float DIODE_DROP = 0.34; // Fine adjust measured value and/or consider diode voltage drop (about 0.34V for SS34 diode) +uint16_t RESISTOR_TO_BATTTERY_PLUS = 10000; // Value in Ohms (Ω), for example 10000 +uint16_t RESISTOR_TO_GND = 2000; // Value in Ohms (Ω), for example 2000. Measuring exact resistor values before soldering, if possible is recommended! +float DIODE_DROP = 0.34; // Fine adjust measured value and/or consider diode voltage drop (about 0.34V for SS34 diode) /* It is recommended to add a sticker to your ESP32, which includes the 3 calibration values above */ volatile int outOfFuelVolumePercentage = 80; // Adjust the message volume in % // Select the out of fuel message you want: diff --git a/src/4_adjustmentsTransmission.h b/src/4_adjustmentsTransmission.h index 864d179..09d30ca 100644 --- a/src/4_adjustmentsTransmission.h +++ b/src/4_adjustmentsTransmission.h @@ -25,6 +25,9 @@ // In some cases we want a different reverse acceleration for automatic transmission vehicles. uint16_t automaticReverseAccelerationPercentage = 100; +// Low range percentage is used for MODE1_SHIFTING (off road reducer) +uint16_t lowRangePercentage = 58;// WPL 2 speed ratios = 29:1, 17:1 = 58% in low range. You may want to change this for other 2 speed transmissions + // Transmission controls options =========================================================================================================== // #define SEMI_AUTOMATIC This will simulate a semi automatic transmission. Shifting is not controlled by the 3 position switch in this mode! //#define SEMI_AUTOMATIC // Works for VIRTUAL_3_SPEED or real 3 speed transmission. Don't select this @ the same time as VIRTUAL_16_SPEED_SEQUENTIAL diff --git a/src/6_adjustmentsLights.h b/src/6_adjustmentsLights.h index e608780..02c6c44 100644 --- a/src/6_adjustmentsLights.h +++ b/src/6_adjustmentsLights.h @@ -1,6 +1,6 @@ #include -/* General LIGHTS SETTINGS ************************************************************************************************ +/* General LIGHTS SETTINGS *********************************************************************************************************************** * * Most lights settings are done in the vehicle configuration files in the /vehicles/ directory. * @@ -10,12 +10,14 @@ //#define NEOPIXEL_ENABLED // GPIO0 used for WS2812 Neopixel control, if defined! #define NEOPIXEL_COUNT 8 // How many Neopixels? 8 for Knight Rider, 3 for B33lz3bub #define NEOPIXEL_BRIGHTNESS 127 // Brightness (255 is the maximum) +#define MAX_POWER_MILLIAMPS 100 // Maximum allowed current draw in mA (100 recommended, depending on your 5V supply) -// Choose the mode you want +// Choose the animation you want //#define NEOPIXEL_DEMO // Demo //#define NEOPIXEL_KNIGHT_RIDER // Knight Rider scanner animation for 8 LED (use it in combination with "kittScanner.h" "siren" sound in your vehicle file) -#define NEOPIXEL_BLUELIGHT // Bluelight animation for 8 LED -//#define NEOPIXEL_HIGHBEAM // Neopixel bar is used as high beam as well, if defined. Also usable in combination with NEOPIXEL_KNIGHT_RIDER & NEOPIXEL_BLUELIGHT +//#define NEOPIXEL_BLUELIGHT // Bluelight animation for 8 LED +#define NEOPIXEL_UNION_JACK // United Kingdom animation for 8 LED (use it in combination with "BritishNationalAnthemSiren.h" sound in your vehicle file) +#define NEOPIXEL_HIGHBEAM // Neopixel bar is used as high beam as well, if defined. Also usable in combination with NEOPIXEL_KNIGHT_RIDER & NEOPIXEL_BLUELIGHT //#define NEOPIXEL_B33LZ3BUB // B33lz3bub Austria animation for 3 LED: https://www.rc-modellbau-portal.de/index.php?threads/baubericht-mercedes-actros-1851-gigaspace-tamiya.14349/page-3 @@ -33,9 +35,9 @@ // Adjust the brightness of your lights here ----------------------------------------------------------------------------------------------------- // All brightness values 0 - 255 -uint8_t cabLightsBrightness = 255; // Usually 255, 100 for Actros +uint8_t cabLightsBrightness = 255; // Usually 255, 100 for Actros & Ural uint8_t sideLightsBrightness = 200; // Usually 200, 100 for WPL C44, 50 for Landy, 100 for P407, 150 for Actros uint8_t rearlightDimmedBrightness = 30; // tailligt brightness, if not braking, about 30 uint8_t rearlightParkingBrightness = 0; // 0, if you want the taillights being off, if side lights are on, or about 5 if you want them on (0 for US Mode) uint8_t headlightParkingBrightness = 0; // 0, if you want the headlights being off, if side lights are on, or about 5 if you want them on (0 for US Mode) -uint8_t reversingLightBrightness = 140; // Around 140, 50 for Landy +uint8_t reversingLightBrightness = 140; // Around 140, 50 for Landy & Ural diff --git a/src/7_adjustmentsServos.h b/src/7_adjustmentsServos.h index 1051b2b..7ef5e3a 100644 --- a/src/7_adjustmentsServos.h +++ b/src/7_adjustmentsServos.h @@ -77,7 +77,7 @@ const uint8_t SERVO_FREQUENCY = 50; // usually 50Hz, some servos may run smoothe // WARNING: never connect receiver PWM signals to the "CH" pins in BUS communication mode! // Servo limits -const uint16_t CH1L = 2000, CH1C = 1660, CH1R = 1190; // CH1 steering left, center, right +const uint16_t CH1L = 2100, CH1C = 1660, CH1R = 1190; // CH1 steering left 2000, center 1660, right 1190 const uint16_t CH2L = 1000, CH2C = 1500, CH2R = 2000; // CH2 transmission gear 1, 2, 3 const uint16_t CH3L = 1435, CH3C = 1495, CH3R = 1560; // CH3 winch pull, off, release const uint16_t CH4L = 1300, CH4R = 1700; // CH4 trailer coupler (5th. wheel) locked, unlocked diff --git a/src/src.ino b/src/src.ino index 1e59bec..7d0d7fa 100644 --- a/src/src.ino +++ b/src/src.ino @@ -18,7 +18,7 @@ Arduino IDE is supported as before, but stuff was renamed and moved to different folders! */ -char codeVersion[] = "9.8.0"; // Software revision. +char codeVersion[] = "9.9.0"; // Software revision. // This stuff is required for Visual Studio Code IDE, if .ino is renamed into .cpp! #include @@ -90,7 +90,9 @@ float batteryVolts(); // !! Do NOT install the libraries in the sketch folder. // No manual library download is required in Visual Studio Code IDE (see platformio.ini) #include // https://github.com/TheDIYGuy999/statusLED <<------- required for LED control +#if not defined EMBEDDED_SBUS // SBUS library only required, if not embedded SBUS code is used ----------- #include // https://github.com/TheDIYGuy999/SBUS <<------- you need to install my fork of this library! +#endif // ------------------------------------------------------------------------------------------------ #include // https://github.com/TheDIYGuy999/rcTrigger <<------- required for RC signal processing #include // https://github.com/bmellink/IBusBM <<------- required for IBUS interface #include // https://github.com/Bodmer/TFT_eSPI <<------- required for LCD dashboard. Use v2.3.70 @@ -103,6 +105,9 @@ float batteryVolts(); #include "src/helper.h" // Various stuff #include "src/dashboard.h" // For LCD dashboard. See: https://github.com/Gamadril/Rc_Engine_Sound_ESP32 #include "src/SUMD.h" // For Graupner SUMD interface. See: https://github.com/Gamadril/Rc_Engine_Sound_ESP32 +#if defined EMBEDDED_SBUS +#include "src/sbus.h" // For SBUS interface +#endif // No need to install these, they come with the ESP32 board definition #include "driver/rmt.h" // for PWM signal detection @@ -281,11 +286,16 @@ unsigned long timelastloop; uint32_t maxPpmRpmPercentage = 390; // Limit required to prevent controller from crashing @ high engine RPM // SBUS signal processing variables +#if not defined EMBEDDED_SBUS // ------------------------ SBUS sBus(Serial2); // SBUS object on Serial 2 port // channel, fail safe, and lost frames data uint16_t SBUSchannels[16]; bool SBUSfailSafe; bool SBUSlostFrame; +#else // ------------------------------------------------ +bfs::SbusRx sBus(&Serial2); +std::array SBUSchannels; +#endif // ----------------------------------------------- bool sbusInit; uint32_t maxSbusRpmPercentage = 390; // Limit required to prevent controller from crashing @ high engine RPM @@ -302,7 +312,7 @@ uint32_t maxSumdRpmPercentage = 390; // Limit required to prevent controller fro // IBUS signal processing variables IBusBM iBus; // IBUS object bool ibusInit; -uint32_t maxIbusRpmPercentage = 340; // Limit required to prevent controller from crashing @ high engine RPM (was 350, but sometimes crashing) +uint32_t maxIbusRpmPercentage = 320; // Limit required to prevent controller from crashing @ high engine RPM (was 350, but sometimes crashing) // Interrupt latches volatile boolean couplerSwitchInteruptLatch; // this is enabled, if the coupler switch pin change interrupt is detected @@ -426,6 +436,7 @@ boolean gearDownShiftingInProgress; // Active while shiftin boolean gearUpShiftingPulse; // Active, if shifting upwards begins boolean gearDownShiftingPulse; // Active, if shifting downwards begins volatile boolean neutralGear = false; // Transmission in neutral +boolean lowRange = false; // Transmission range (off road reducer) // ESC volatile boolean escIsBraking = false; // ESC is in a braking state @@ -1479,6 +1490,13 @@ void setup() { Serial.printf("Core %i reset reason: %i: %s\n", coreNum, rtc_get_reset_reason(coreNum), RESET_REASONS[resetReason - 1]); } } +#if defined BATTERY_PROTECTION + Serial.printf("Battery protection calibration data:\n"); + Serial.printf("RESISTOR_TO_BATTTERY_PLUS: %i Ω\n", RESISTOR_TO_BATTTERY_PLUS); + Serial.printf("RESISTOR_TO_GND: %i Ω\n", RESISTOR_TO_GND); + Serial.printf("DIODE_DROP: %.2f V\n", DIODE_DROP); +#endif + Serial.printf("**************************************************************************************************\n\n"); setupBattery(); @@ -1545,7 +1563,9 @@ void setup() { // Neopixel setup #ifdef NEOPIXEL_ENABLED FastLED.addLeds(rgbLEDs, NEOPIXEL_COUNT); + FastLED.setCorrection( TypicalLEDStrip ); FastLED.setBrightness(NEOPIXEL_BRIGHTNESS); + FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS); #endif // Communication setup -------------------------------------------- @@ -1802,36 +1822,52 @@ void readSbusCommands() { // Signals are coming in via SBUS protocol static unsigned long lastSbusFailsafe; + static unsigned long lastSbusRead; + + if (millis() - lastSbusRead > 20) { // TODO, test for Flysky SBUS bugfix. 20 is not bad, but still a bit unstable! USE IBUS for Flysky! + // look for a good SBUS packet from the receiver +#if not defined EMBEDDED_SBUS // ------------------------ + if (sBus.read(&SBUSchannels[0], &SBUSfailSafe, &SBUSlostFrame)) { +#else // ------------------------------------------------ + if (sBus.read() && !sBus.failsafe() && !sBus.lost_frame()) { +#endif // ----------------------------------------------- + sbusInit = true; + lastSbusFailsafe = millis(); + lastSbusRead = millis(); + } + } - // look for a good SBUS packet from the receiver - if (sBus.read(&SBUSchannels[0], &SBUSfailSafe, &SBUSlostFrame)) { - sbusInit = true; - lastSbusFailsafe = millis(); + // Failsafe triggering (works, if SBUS wire is unplugged, but SBUSfailSafe signal from the receiver is untested!) +#if not defined EMBEDDED_SBUS // ------------------------ + if (millis() - lastSbusFailsafe > sbusFailsafeTimeout && !SBUSfailSafe && !SBUSlostFrame) { +#else // ------------------------------------------------ + if (millis() - lastSbusFailsafe > sbusFailsafeTimeout) { +#endif // ----------------------------------------------- + failSafe = true; // if timeout (signal loss) } + else failSafe = false; //SBUSchannels[NONE - 1] = 991; // The NONE channel needs to be on neutral (991 = 1500ms) TODO // Proportional channels (in Microseconds) - pulseWidthRaw[1] = map(SBUSchannels[STEERING - 1], 172, 1811, 1000, 2000); // CH1 steering - pulseWidthRaw[2] = map(SBUSchannels[GEARBOX - 1], 172, 1811, 1000, 2000); // CH2 3 position switch for gearbox (left throttle in tracked mode) - pulseWidthRaw[3] = map(SBUSchannels[THROTTLE - 1], 172, 1811, 1000, 2000); // CH3 throttle & brake - pulseWidthRaw[4] = map(SBUSchannels[HORN - 1], 172, 1811, 1000, 2000); // CH5 jake brake, high / low beam, headlight flasher, engine on / off - pulseWidthRaw[5] = map(SBUSchannels[FUNCTION_R - 1], 172, 1811, 1000, 2000); // CH5 jake brake, high / low beam, headlight flasher, engine on / off - pulseWidthRaw[6] = map(SBUSchannels[FUNCTION_L - 1], 172, 1811, 1000, 2000); // CH6 indicators, hazards - pulseWidthRaw[7] = map(SBUSchannels[POT2 - 1], 172, 1811, 1000, 2000); // CH7 pot 2 - pulseWidthRaw[8] = map(SBUSchannels[MODE1 - 1], 172, 1811, 1000, 2000); // CH8 mode 1 switch - pulseWidthRaw[9] = map(SBUSchannels[MODE2 - 1], 172, 1811, 1000, 2000); // CH9 mode 2 switch - pulseWidthRaw[10] = map(SBUSchannels[MOMENTARY1 - 1], 172, 1811, 1000, 2000); // CH10 - pulseWidthRaw[11] = map(SBUSchannels[HAZARDS - 1], 172, 1811, 1000, 2000); // CH11 - pulseWidthRaw[12] = map(SBUSchannels[INDICATOR_LEFT - 1], 172, 1811, 1000, 2000); // CH12 - pulseWidthRaw[13] = map(SBUSchannels[INDICATOR_RIGHT - 1], 172, 1811, 1000, 2000); // CH13 - - // Failsafe triggering (works, if SBUS wire is unplugged, but SBUSfailSafe signal from the receiver is untested!) - if (millis() - lastSbusFailsafe > 50 && !SBUSfailSafe && !SBUSlostFrame) { - failSafe = true; // if timeout (signal loss) - //Serial.printf("SBUS failsafe!\n"); + if (!failSafe) { +#if defined EMBEDDED_SBUS // ---------------------------- + SBUSchannels = sBus.ch(); +#endif // ----------------------------------------------- + pulseWidthRaw[1] = map(SBUSchannels[STEERING - 1], 172, 1811, 1000, 2000); // CH1 steering + pulseWidthRaw[2] = map(SBUSchannels[GEARBOX - 1], 172, 1811, 1000, 2000); // CH2 3 position switch for gearbox (left throttle in tracked mode) + pulseWidthRaw[3] = map(SBUSchannels[THROTTLE - 1], 172, 1811, 1000, 2000); // CH3 throttle & brake + pulseWidthRaw[4] = map(SBUSchannels[HORN - 1], 172, 1811, 1000, 2000); // CH5 jake brake, high / low beam, headlight flasher, engine on / off + pulseWidthRaw[5] = map(SBUSchannels[FUNCTION_R - 1], 172, 1811, 1000, 2000); // CH5 jake brake, high / low beam, headlight flasher, engine on / off + pulseWidthRaw[6] = map(SBUSchannels[FUNCTION_L - 1], 172, 1811, 1000, 2000); // CH6 indicators, hazards + pulseWidthRaw[7] = map(SBUSchannels[POT2 - 1], 172, 1811, 1000, 2000); // CH7 pot 2 + pulseWidthRaw[8] = map(SBUSchannels[MODE1 - 1], 172, 1811, 1000, 2000); // CH8 mode 1 switch + pulseWidthRaw[9] = map(SBUSchannels[MODE2 - 1], 172, 1811, 1000, 2000); // CH9 mode 2 switch + pulseWidthRaw[10] = map(SBUSchannels[MOMENTARY1 - 1], 172, 1811, 1000, 2000); // CH10 + pulseWidthRaw[11] = map(SBUSchannels[HAZARDS - 1], 172, 1811, 1000, 2000); // CH11 + pulseWidthRaw[12] = map(SBUSchannels[INDICATOR_LEFT - 1], 172, 1811, 1000, 2000); // CH12 + pulseWidthRaw[13] = map(SBUSchannels[INDICATOR_RIGHT - 1], 172, 1811, 1000, 2000); // CH13 } - else failSafe = false; if (sbusInit) { // Normalize, auto zero and reverse channels @@ -1961,16 +1997,14 @@ void processRawChannels() { #ifdef AIRPLANE_MODE // If airplane mode: always disable CH3 auto zero adjustment channelAutoZero[3] = false; #endif - if (!autoZeroDone) { - Serial.printf("\nTransmitter channel offsets (calculated, if channelAutoZero[] = true):\n"); // Print offsets, if switching on the controller - } + if (millis() - lastOutOfRangeMillis > 500) { for (uint8_t i = 1; i < PULSE_ARRAY_SIZE; i++) { // For each channel: // Position valid for auto calibration? Must be between 1400 and 1600 microseconds if (channelAutoZero[i] && !autoZeroDone && (pulseWidthRaw[i] > 1600 || pulseWidthRaw[i] < 1400)) { channel = i; - Serial.printf("CH%i signal out of auto calibration range, check transmitter & receiver!\n", channel); + Serial.printf(" CH%i: signal out of auto calibration range, check transmitter & receiver!\n", channel); channelZero(); lastOutOfRangeMillis = millis(); i--; @@ -1980,7 +2014,7 @@ void processRawChannels() { // Exponential throttle compensation ------------------ #ifdef EXPONENTIAL_THROTTLE if (!exThrottlePrint) { - Serial.printf("EXPONENTIAL_THROTTLE mode configured\n"); + Serial.printf("EXPONENTIAL_THROTTLE mode enabled\n"); exThrottlePrint = true; } if (i == 3) { // Throttle CH only @@ -1996,7 +2030,7 @@ void processRawChannels() { // Exponential steering compensation ------------------ #ifdef EXPONENTIAL_STEERING if (!exSteeringPrint) { - Serial.printf("EXPONENTIAL_STEERING mode configured\n"); + Serial.printf("EXPONENTIAL_STEERING mode enabled\n"); exSteeringPrint = true; } if (i == 1) { // Throttle CH only @@ -2026,7 +2060,8 @@ void processRawChannels() { // Compensate pulsewidth with auto zero offset pulseWidthRaw3[i] += pulseOffset[i]; if (!autoZeroDone) { // Print offsets, if switching on the controller - Serial.printf(" CH%i: %i µs\n", i, pulseOffset[i]); + if (i == 1) Serial.printf("\nTransmitter channel offsets (calculated, if channelAutoZero[] = true):\n"); + if (channelAutoZero[i]) Serial.printf(" CH%i: %i µs\n", i, pulseOffset[i]); } // Set auto zero done flag @@ -2083,8 +2118,10 @@ void processRawChannels() { Serial.printf(" HAZARDS: %s\n", hazard ? "true" : "false"); Serial.printf(" INDICATOR_LEFT: %s\n", indicatorLon ? "true" : "false"); Serial.printf(" INDICATOR_RIGHT: %s\n", indicatorRon ? "true" : "false"); +#if not defined EMBEDDED_SBUS // ------------------------ Serial.printf(" SBUS Failsafe: %s\n", SBUSfailSafe ? "true" : "false"); Serial.printf(" SBUS Lost frames: %s\n", SBUSlostFrame ? "true" : "false"); +#endif // ----------------------------------------------- Serial.printf(" Failsafe state: %s\n", failSafe ? "true" : "false"); Serial.printf("Misc:\n"); Serial.printf(" MAX_RPM_PERCENTAGE: %i\n", MAX_RPM_PERCENTAGE); @@ -2110,7 +2147,11 @@ void channelZero() { void failsafeRcSignals() { // Failsafe actions -------- - if (failSafe) pulseWidth[3] = pulseZero[3]; // Throttle to zero position! + if (failSafe) { + for (uint8_t i = 1; i < PULSE_ARRAY_SIZE; i++) { + if (i != 1 && i != 2 && i != 8 && i != 9) pulseWidth[i] = pulseZero[i]; // Channels to zero position, but never for CH1 (Steering), CH8, CH9 + } + } } // @@ -2196,8 +2237,14 @@ void mcpwmOutput() { #else #undef TRANSMISSION_NEUTRAL // Not usable in this case! if (currentSpeed > 50 && currentSpeed < 150) { // Only shift WPL gearbox, if vehicle is moving slowly, so it's engaging properly - if (!mode1) shiftingServoMicros = CH2L; - else shiftingServoMicros = CH2C; + if (!mode1) { + shiftingServoMicros = CH2L; + lowRange = true; + } + else { + shiftingServoMicros = CH2C; + lowRange = false; + } } #endif mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, shiftingServoMicros); @@ -3176,7 +3223,7 @@ static unsigned long lastStateTime; static int8_t driveRampRate; static int8_t driveRampGain; static int8_t brakeRampRate; -uint8_t escRampTime; +uint16_t escRampTime; // ESC sub functions ============================================= // We always need the data up to date, so these comparators are programmed as sub functions! @@ -3243,6 +3290,12 @@ void esc() { // ESC main function ================================ if (escInReverse) escRampTime = escRampTime * 100 / automaticReverseAccelerationPercentage; // faster acceleration in automatic reverse, EXPERIMENTAL, TODO! } + // Allows to scale vehicle file dependent acceleration + escRampTime = escRampTime * 100 / globalAccelerationPercentage; + + // ESC ramp time compensation in low range + if (lowRange) escRampTime = escRampTime * lowRangePercentage / 100; + // Drive mode ------------------------------------------- // Crawler mode for direct control ----- crawlerMode = (masterVolume <= masterVolumeCrawlerThreshold); // Direct control, depending on master volume @@ -3280,6 +3333,7 @@ void esc() { // ESC main function ================================ Serial.printf("escPulseMaxNeutral: %i\n", escPulseMaxNeutral); Serial.printf("escPulseMax: %i\n", escPulseMax); Serial.printf("brakeRampRate: %i\n", brakeRampRate); + Serial.printf("lowRange: %s\n", lowRange ? "true" : "false"); Serial.printf("currentRpm: %i\n", currentRpm); Serial.printf("escPulseWidth: %i\n", escPulseWidth); Serial.printf("escPulseWidthOut: %i\n", escPulseWidthOut); @@ -4039,6 +4093,8 @@ void updateRGBLEDs() { static uint32_t lastNeopixelTime = millis(); static bool knightRiderLatch = false; + static bool unionJackLatch = false; + static bool neopixelShow = false; #ifdef NEOPIXEL_DEMO // Demo ------------------------------------------------------------- if (millis() - lastNeopixelTime > 20) { // Every 20 ms @@ -4052,6 +4108,7 @@ void updateRGBLEDs() { rgbLEDs[3] = CRGB::Yellow; rgbLEDs[4] = CRGB::Blue; rgbLEDs[5] = CRGB::Green; + neopixelShow = true; } #endif @@ -4075,6 +4132,7 @@ void updateRGBLEDs() { for (int i = 0; i < NEOPIXEL_COUNT; i++) { rgbLEDs[i].nscale8(160); //160 } + neopixelShow = true; } #endif @@ -4111,6 +4169,70 @@ void updateRGBLEDs() { } } else fill_solid(rgbLEDs, NEOPIXEL_COUNT, CRGB::Black); // Off + neopixelShow = true; + } +#endif + +#ifdef NEOPIXEL_UNION_JACK // United Kingdom animation --------------------------------------- + static uint32_t lastNeopixelUnionJackTime = millis(); + static uint8_t animationStep = 1; + + if (sirenTrigger || unionJackLatch) { + unionJackLatch = true; + if (millis() - lastNeopixelUnionJackTime > 789) { // Every 789 ms (must match with sound "BritishNationalAnthemSiren.h") + lastNeopixelUnionJackTime = millis(); + if (animationStep == 1 || animationStep == 9) { // Step 1 or 9 + rgbLEDs[0] = CRGB::Red; + rgbLEDs[1] = CRGB::Blue; + rgbLEDs[2] = CRGB::Blue; + rgbLEDs[3] = CRGB::Red; + rgbLEDs[4] = CRGB::Red; + rgbLEDs[5] = CRGB::Blue; + rgbLEDs[6] = CRGB::Blue; + rgbLEDs[7] = CRGB::Red; + } + if (animationStep == 2 || animationStep == 8) { // Step 2 or 8 + rgbLEDs[0] = CRGB::White; + rgbLEDs[1] = CRGB::Red; + rgbLEDs[2] = CRGB::Blue; + rgbLEDs[3] = CRGB::Red; + rgbLEDs[4] = CRGB::Red; + rgbLEDs[5] = CRGB::Blue; + rgbLEDs[6] = CRGB::Red; + rgbLEDs[7] = CRGB::White; + } + if (animationStep == 3 || animationStep == 7) { // Step 3 or 7 + rgbLEDs[0] = CRGB::Blue; + rgbLEDs[1] = CRGB::White; + rgbLEDs[2] = CRGB::Red; + rgbLEDs[3] = CRGB::Red; + rgbLEDs[4] = CRGB::Red; + rgbLEDs[5] = CRGB::Red; + rgbLEDs[6] = CRGB::White; + rgbLEDs[7] = CRGB::Blue; + } + if (animationStep == 4 || animationStep == 5 || animationStep == 6) { // Step 4 + rgbLEDs[0] = CRGB::Red; + rgbLEDs[1] = CRGB::Red; + rgbLEDs[2] = CRGB::Red; + rgbLEDs[3] = CRGB::Red; + rgbLEDs[4] = CRGB::Red; + rgbLEDs[5] = CRGB::Red; + rgbLEDs[6] = CRGB::Red; + rgbLEDs[7] = CRGB::Red; + } + if (animationStep == 10) { // Step 10 + fill_solid(rgbLEDs, NEOPIXEL_COUNT, CRGB::Black); + animationStep = 0; + unionJackLatch = false; + } + animationStep ++; + neopixelShow = true; + } + } + else { + animationStep = 1; + lastNeopixelUnionJackTime = millis(); } #endif @@ -4119,10 +4241,11 @@ void updateRGBLEDs() { if (millis() - lastNeopixelHighbeamTime > 20) { // Every 20 ms lastNeopixelHighbeamTime = millis(); - if (!knightRiderLatch && !sirenTrigger && !blueLightTrigger) { + if (!knightRiderLatch && !sirenTrigger && !blueLightTrigger && !unionJackLatch) { if (headLightsHighBeamOn || headLightsFlasherOn) fill_solid(rgbLEDs, NEOPIXEL_COUNT, CRGB::White); else fill_solid(rgbLEDs, NEOPIXEL_COUNT, CRGB::Black); } + neopixelShow = true; } #endif @@ -4147,14 +4270,16 @@ void updateRGBLEDs() { else { fill_solid(rgbLEDs, NEOPIXEL_COUNT, CRGB::White); // only white } + neopixelShow = true; } #endif - // Neopixel refresh for all option above ------------------------------------------------ + // Neopixel refresh for all options above ------------------------------------------------ static uint32_t lastNeopixelRefreshTime = millis(); - if (millis() - lastNeopixelRefreshTime > 20) { // Every 20 ms + if (millis() - lastNeopixelRefreshTime > 20 && neopixelShow) { // Every 20 ms lastNeopixelRefreshTime = millis(); FastLED.show(); + neopixelShow = false; } } diff --git a/src/src/sbus.cpp b/src/src/sbus.cpp new file mode 100644 index 0000000..adba529 --- /dev/null +++ b/src/src/sbus.cpp @@ -0,0 +1,121 @@ +/* + * Brian R Taylor + * brian.taylor@bolderflight.com + * + * Copyright (c) 2021 Bolder Flight Systems Inc (modified by TheDIYGuy999) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the “Software”), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "sbus.h" // NOLINT +#if defined(ARDUINO) +#include +#else +#include "core/core.h" +#endif +#include +#include +#include +#include + +namespace bfs { + +// ----------------------------------------------------------------------------------- +void SbusRx::begin(const int8_t rxpin, const int8_t txpin, bool inverted, uint32_t baud) { + BAUD_ = baud; // Set baudrate (allows fine tuning, if you have troubles) + uart_->begin(BAUD_, SERIAL_8E2, rxpin, txpin, inverted); // Start the bus + uart_->flush(); // flush the bus +} + +// ----------------------------------------------------------------------------------- +bool SbusRx::read() { + /* Read through all available packets to get the newest */ + new_data_ = false; + do { + if (parse()) { + new_data_ = true; + } + } while (uart_->available()); + /* Parse new data, if available */ + if (new_data_) { + /* Grab the channel data */ + ch_[0] = static_cast(buf_[1] | buf_[2] << 8 & 0x07FF); + ch_[1] = static_cast(buf_[2] >> 3 | buf_[3] << 5 & 0x07FF); + ch_[2] = static_cast(buf_[3] >> 6 | buf_[4] << 2 | + buf_[5] << 10 & 0x07FF); + ch_[3] = static_cast(buf_[5] >> 1 | buf_[6] << 7 & 0x07FF); + ch_[4] = static_cast(buf_[6] >> 4 | buf_[7] << 4 & 0x07FF); + ch_[5] = static_cast(buf_[7] >> 7 | buf_[8] << 1 | + buf_[9] << 9 & 0x07FF); + ch_[6] = static_cast(buf_[9] >> 2 | buf_[10] << 6 & 0x07FF); + ch_[7] = static_cast(buf_[10] >> 5 | buf_[11] << 3 & 0x07FF); + ch_[8] = static_cast(buf_[12] | buf_[13] << 8 & 0x07FF); + ch_[9] = static_cast(buf_[13] >> 3 | buf_[14] << 5 & 0x07FF); + ch_[10] = static_cast(buf_[14] >> 6 | buf_[15] << 2 | + buf_[16] << 10 & 0x07FF); + ch_[11] = static_cast(buf_[16] >> 1 | buf_[17] << 7 & 0x07FF); + ch_[12] = static_cast(buf_[17] >> 4 | buf_[18] << 4 & 0x07FF); + ch_[13] = static_cast(buf_[18] >> 7 | buf_[19] << 1 | + buf_[20] << 9 & 0x07FF); + ch_[14] = static_cast(buf_[20] >> 2 | buf_[21] << 6 & 0x07FF); + ch_[15] = static_cast(buf_[21] >> 5 | buf_[22] << 3 & 0x07FF); + /* CH 17 */ + ch17_ = buf_[23] & CH17_MASK_; + /* CH 18 */ + ch18_ = buf_[23] & CH18_MASK_; + /* Grab the lost frame */ + lost_frame_ = buf_[23] & LOST_FRAME_MASK_; + /* Grab the failsafe */ + failsafe_ = buf_[23] & FAILSAFE_MASK_; + } + return new_data_; +} + +// ----------------------------------------------------------------------------------- +bool SbusRx::parse() { + /* Parse messages */ + while (uart_->available()) { + cur_byte_ = uart_->read(); + if (state_ == 0) { + if ((cur_byte_ == HEADER_) && ((prev_byte_ == FOOTER_) || + ((prev_byte_ & 0x0F) == FOOTER2_))) { + buf_[state_++] = cur_byte_; + } else { + state_ = 0; + } + } else { + if (state_ < BUF_LEN_) { + buf_[state_++] = cur_byte_; + } else { + state_ = 0; + if ((buf_[BUF_LEN_ - 1] == FOOTER_) || + ((buf_[BUF_LEN_ - 1] & 0x0F) == FOOTER2_)) { + return true; + } else { + return false; + } + } + } + prev_byte_ = cur_byte_; + } + return false; +} + + +} // namespace bfs diff --git a/src/src/sbus.h b/src/src/sbus.h new file mode 100644 index 0000000..22f860f --- /dev/null +++ b/src/src/sbus.h @@ -0,0 +1,83 @@ +/* +* Brian R Taylor +* brian.taylor@bolderflight.com +* +* Copyright (c) 2021 Bolder Flight Systems Inc (modified by TheDIYGuy999) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the “Software”), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + +#ifndef SRC_SBUS_H_ +#define SRC_SBUS_H_ + +#if defined(ARDUINO) +#include +#else +#include "core/core.h" +#endif +#include +#include +#include +#include + +namespace bfs { + +class SbusRx { + private: + /* Communication */ + HardwareSerial *uart_; + uint32_t BAUD_ = 100000; + /* Message len */ + static constexpr int8_t BUF_LEN_ = 25; + /* SBUS message defs */ + static constexpr int8_t NUM_SBUS_CH_ = 16; + static constexpr uint8_t HEADER_ = 0x0F; + static constexpr uint8_t FOOTER_ = 0x00; + static constexpr uint8_t FOOTER2_ = 0x04; + static constexpr uint8_t CH17_MASK_ = 0x01; + static constexpr uint8_t CH18_MASK_ = 0x02; + static constexpr uint8_t LOST_FRAME_MASK_ = 0x04; + static constexpr uint8_t FAILSAFE_MASK_ = 0x08; + /* Parsing state tracking */ + int8_t state_ = 0; + uint8_t prev_byte_ = FOOTER_; + uint8_t cur_byte_; + /* Buffer for storing messages */ + uint8_t buf_[BUF_LEN_]; + /* Data */ + bool new_data_; + std::array ch_; + bool failsafe_ = false, lost_frame_ = false, ch17_ = false, ch18_ = false; + bool parse(); + + public: + explicit SbusRx(HardwareSerial *bus) : uart_(bus) {} + void begin(const int8_t rxpin = 16, const int8_t txpin = 17, bool inverted = true, uint32_t baud = 100000); // 16, 17 = UART 2, if not specified + bool read(); + static constexpr int8_t NUM_CH() {return NUM_SBUS_CH_;} + inline std::array ch() const {return ch_;} + inline bool failsafe() const {return failsafe_;} + inline bool lost_frame() const {return lost_frame_;} + inline bool ch17() const {return ch17_;} + inline bool ch18() const {return ch18_;} +}; + +} // namespace bfs + +#endif // SRC_SBUS_H_