diff --git a/firmware/CHANGELOG.md b/firmware/CHANGELOG.md index 293242e1cf..c97c5e819d 100644 --- a/firmware/CHANGELOG.md +++ b/firmware/CHANGELOG.md @@ -28,6 +28,8 @@ All notable user-facing or behavior-altering changes will be documented in this ## XXX 2021 Release ### Breaking Changes + - Closed loop idle timing behavior changed to no longer fall off control as entering/leaving the idle region. It now sharply engages/disengages upon entering/leaving the idle area. + - Idle phase logic uses the same idle detection thresholds as the main idle controller instead of its own thresholds. ### Added @@ -42,6 +44,7 @@ All notable user-facing or behavior-altering changes will be documented in this - Basic fueling-only flex fuel implementation. Automatic adjustment of stoichiometric ratio based on ethanol content, compatible with the common GM/Continental 50-150hz flex fuel sensor 🎉 🎉 🎉 ### Fixed + - Simplify idle control dialog in TunerStudio - microRusEFI outputs are in trouble on configuration change - CLT gauge no longer erroneously shows "deg F" by default. diff --git a/firmware/config/engines/mazda_miata_1_6.cpp b/firmware/config/engines/mazda_miata_1_6.cpp index fd14250365..d58dd7f22f 100644 --- a/firmware/config/engines/mazda_miata_1_6.cpp +++ b/firmware/config/engines/mazda_miata_1_6.cpp @@ -423,11 +423,8 @@ void setMiataNA6_MAP_MRE(DECLARE_CONFIG_PARAMETER_SIGNATURE) { engineConfiguration->idleTimingPid.dFactor = 0.0; engineConfiguration->idleTimingPid.minValue = -13; engineConfiguration->idleTimingPid.maxValue = 13; - engineConfiguration->idleTimingPidWorkZone = 150; - engineConfiguration->idlePidFalloffDeltaRpm = 50; engineConfiguration->idleTimingPidDeadZone = 10; - // EFI_ADC_3: "22 - AN temp 4" engineConfiguration->acSwitch = GPIOA_6; diff --git a/firmware/controllers/actuators/idle_thread.cpp b/firmware/controllers/actuators/idle_thread.cpp index 13d230c62f..a3284f86a3 100644 --- a/firmware/controllers/actuators/idle_thread.cpp +++ b/firmware/controllers/actuators/idle_thread.cpp @@ -193,6 +193,10 @@ void setManualIdleValvePosition(int positionPercent) { #endif /* EFI_UNIT_TEST */ +void IdleController::init(pid_s* idlePidConfig) { + m_timingPid.initPidClass(idlePidConfig); +} + int IdleController::getTargetRpm(float clt) const { // TODO: bump target rpm based on AC and/or fan(s)? @@ -269,6 +273,32 @@ float IdleController::getOpenLoop(Phase phase, float clt, SensorResult tps) cons return interpolateClamped(0, cranking, CONFIG(afterCrankingIACtaperDuration), running, revsSinceStart); } +float IdleController::getIdleTimingAdjustment(int rpm) { + return getIdleTimingAdjustment(rpm, m_lastTargetRpm, m_lastPhase); +} + +float IdleController::getIdleTimingAdjustment(int rpm, int targetRpm, Phase phase) { + // if not enabled, do nothing + if (!CONFIG(useIdleTimingPidControl)) { + return 0; + } + + // If not idling, do nothing + if (phase != Phase::Idling) { + m_timingPid.reset(); + return 0; + } + + // If inside the deadzone, do nothing + if (absI(rpm - targetRpm) < CONFIG(idleTimingPidDeadZone)) { + m_timingPid.reset(); + return 0; + } + + // We're now in the idle mode, and RPM is inside the Timing-PID regulator work zone! + return m_timingPid.getOutput(targetRpm, rpm, FAST_CALLBACK_PERIOD_MS / 1000.0f); +} + static percent_t manualIdleController(float cltCorrection DECLARE_ENGINE_PARAMETER_SUFFIX) { percent_t correctedPosition = cltCorrection * CONFIG(manIdlePosition); @@ -432,9 +462,11 @@ static percent_t automaticIdleController(float tpsPos, float rpm, int targetRpm, // Compute the target we're shooting for auto targetRpm = getTargetRpm(clt); + m_lastTargetRpm = targetRpm; // Determine what operation phase we're in - idling or not auto phase = determinePhase(rpm, targetRpm, tps); + m_lastPhase = phase; engine->engineState.isAutomaticIdle = tps.Valid && engineConfiguration->idleMode == IM_AUTO; @@ -529,6 +561,10 @@ void updateIdleControl() idleControllerInstance.update(); } +float getIdleTimingAdjustment(int rpm) { + return idleControllerInstance.getIdleTimingAdjustment(rpm); +} + static void applyPidSettings(DECLARE_ENGINE_PARAMETER_SIGNATURE) { getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->updateFactors(engineConfiguration->idleRpmPid.pFactor, engineConfiguration->idleRpmPid.iFactor, engineConfiguration->idleRpmPid.dFactor); iacPidMultMap.init(CONFIG(iacPidMultTable), CONFIG(iacPidMultLoadBins), CONFIG(iacPidMultRpmBins)); @@ -605,6 +641,7 @@ void startIdleBench(void) { void startIdleThread(Logging*sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) { logger = sharedLogger; INJECT_ENGINE_REFERENCE(&idleControllerInstance); + idleControllerInstance.init(&CONFIG(idleTimingPid)); INJECT_ENGINE_REFERENCE(&industrialWithOverrideIdlePid); ENGINE(idleController) = &idleControllerInstance; diff --git a/firmware/controllers/actuators/idle_thread.h b/firmware/controllers/actuators/idle_thread.h index ac8413e3fb..c3a0ec5f9c 100644 --- a/firmware/controllers/actuators/idle_thread.h +++ b/firmware/controllers/actuators/idle_thread.h @@ -11,6 +11,7 @@ #include "engine_ptr.h" #include "rusefi_types.h" #include "periodic_task.h" +#include "pid.h" struct IIdleController { enum class Phase : uint8_t { @@ -28,13 +29,13 @@ struct IIdleController { }; class Logging; -class Pid; - class IdleController : public IIdleController { public: DECLARE_ENGINE_PTR; + void init(pid_s* idlePidConfig); + float getIdlePosition(); void update(); @@ -48,11 +49,23 @@ public: float getCrankingOpenLoop(float clt) const override; float getRunningOpenLoop(float clt, SensorResult tps) const override; float getOpenLoop(Phase phase, float clt, SensorResult tps) const override; + + float getIdleTimingAdjustment(int rpm); + float getIdleTimingAdjustment(int rpm, int targetRpm, Phase phase); + +private: + // These are stored by getIdlePosition() and used by getIdleTimingAdjustment() + Phase m_lastPhase = Phase::Cranking; + int m_lastTargetRpm = 0; + + Pid m_timingPid; }; void updateIdleControl(); percent_t getIdlePosition(); +float getIdleTimingAdjustment(int rpm); + void applyIACposition(percent_t position DECLARE_ENGINE_PARAMETER_SUFFIX); void setManualIdleValvePosition(int positionPercent); diff --git a/firmware/controllers/algo/advance_map.cpp b/firmware/controllers/algo/advance_map.cpp index 4c703377f9..9d3c474e3d 100644 --- a/firmware/controllers/algo/advance_map.cpp +++ b/firmware/controllers/algo/advance_map.cpp @@ -37,10 +37,6 @@ static ign_Map3D_t advanceMap("advance"); // This coeff in ctor parameter is sufficient for int16<->float conversion! static ign_Map3D_t iatAdvanceCorrectionMap("iat corr"); -// Init PID later (make it compatible with unit-tests) -static Pid idleTimingPid; -static bool shouldResetTimingPid = false; - static int minCrankingRpm = 0; #if IGN_LOAD_COUNT == DEFAULT_IGN_LOAD_COUNT @@ -122,41 +118,10 @@ angle_t getAdvanceCorrections(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) { if (!iatValid) { iatCorrection = 0; } else { - iatCorrection = iatAdvanceCorrectionMap.getValue((float) rpm, iat); + iatCorrection = iatAdvanceCorrectionMap.getValue(rpm, iat); } - // PID Ignition Advance angle correction - float pidTimingCorrection = 0.0f; - if (CONFIG(useIdleTimingPidControl)) { - int targetRpm = ENGINE(idleController)->getTargetRpm(Sensor::get(SensorType::Clt).value_or(0)); - int rpmDelta = absI(rpm - targetRpm); - - auto [valid, tps] = Sensor::get(SensorType::Tps1); - - // If TPS is invalid, or we aren't in the region, so reset state and don't apply PID - if (!valid || tps >= CONFIG(idlePidDeactivationTpsThreshold)) { - // we are not in the idle mode anymore, so the 'reset' flag will help us when we return to the idle. - shouldResetTimingPid = true; - } - else if (rpmDelta > CONFIG(idleTimingPidDeadZone) && rpmDelta < CONFIG(idleTimingPidWorkZone) + CONFIG(idlePidFalloffDeltaRpm)) { - // We're now in the idle mode, and RPM is inside the Timing-PID regulator work zone! - // So if we need to reset the PID, let's do it now - if (shouldResetTimingPid) { - idleTimingPid.reset(); - shouldResetTimingPid = false; - } - // get PID value (this is not an actual Advance Angle, but just a additive correction!) - percent_t timingRawCorr = idleTimingPid.getOutput(targetRpm, rpm, FAST_CALLBACK_PERIOD_MS / 1000.0f); - // tps idle-running falloff - pidTimingCorrection = interpolateClamped(0.0f, timingRawCorr, CONFIG(idlePidDeactivationTpsThreshold), 0.0f, tps); - // rpm falloff - pidTimingCorrection = interpolateClamped(0.0f, pidTimingCorrection, CONFIG(idlePidFalloffDeltaRpm), 0.0f, rpmDelta - CONFIG(idleTimingPidWorkZone)); - } else { - shouldResetTimingPid = true; - } - } else { - shouldResetTimingPid = true; - } + float pidTimingCorrection = getIdleTimingAdjustment(rpm); if (engineConfiguration->debugMode == DBG_IGNITION_TIMING) { #if EFI_TUNER_STUDIO @@ -291,8 +256,6 @@ void initTimingMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) { config->ignitionRpmBins); iatAdvanceCorrectionMap.init(config->ignitionIatCorrTable, config->ignitionIatCorrLoadBins, config->ignitionIatCorrRpmBins); - // init timing PID - idleTimingPid = Pid(&CONFIG(idleTimingPid)); } /** diff --git a/firmware/controllers/bench_test.cpp b/firmware/controllers/bench_test.cpp index f283abb9b7..b52811662b 100644 --- a/firmware/controllers/bench_test.cpp +++ b/firmware/controllers/bench_test.cpp @@ -290,8 +290,12 @@ static void handleBenchCategory(uint16_t index) { case CMD_TS_BENCH_AC_COMPRESSOR_RELAY: acRelayBench(); return; + case CMD_TS_BENCH_FAN_RELAY: + fanBench(); + return; + default: + firmwareError(OBD_PCM_Processor_Fault, "Unexpected bench function %d", index); } - } static void handleCommandX14(uint16_t index) { @@ -347,6 +351,8 @@ static void handleCommandX14(uint16_t index) { case 0x12: widebandUpdatePending = true; return; + default: + firmwareError(OBD_PCM_Processor_Fault, "Unexpected bench x14 %d", index); } } @@ -377,7 +383,7 @@ void executeTSCommand(uint16_t subsystem, uint16_t index) { } break; - case CMD_TS_INJECTOR_CATEGORY: + case CMD_TS_INJECTOR_CATEGORY: if (!running) { doRunFuel(index, "300", "4", "400", "3"); } @@ -398,11 +404,6 @@ void executeTSCommand(uint16_t subsystem, uint16_t index) { case CMD_TS_X14: handleCommandX14(index); break; - - case CMD_TS_X15: - fanBench(); - break; - case CMD_TS_BENCH_CATEGORY: handleBenchCategory(index); break; @@ -452,6 +453,8 @@ void executeTSCommand(uint16_t subsystem, uint16_t index) { rebootNow(); #endif /* EFI_PROD_CODE */ break; + default: + firmwareError(OBD_PCM_Processor_Fault, "Unexpected bench subsystem %d %d", subsystem, index); } } diff --git a/firmware/controllers/generated/fsio_enums_generated.def b/firmware/controllers/generated/fsio_enums_generated.def index 44a05ecd14..64afee0968 100644 --- a/firmware/controllers/generated/fsio_enums_generated.def +++ b/firmware/controllers/generated/fsio_enums_generated.def @@ -1,4 +1,4 @@ -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jan 06 18:57:11 UTC 2021 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jan 07 13:24:50 UTC 2021 // by class com.rusefi.output.FileFsioSettingsConsumer FSIO_SETTING_FANONTEMPERATURE = 1000, diff --git a/firmware/controllers/generated/fsio_getters.def b/firmware/controllers/generated/fsio_getters.def index 197fa559f8..5c37c29d3a 100644 --- a/firmware/controllers/generated/fsio_getters.def +++ b/firmware/controllers/generated/fsio_getters.def @@ -1,4 +1,4 @@ -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jan 06 18:57:11 UTC 2021 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jan 07 13:24:50 UTC 2021 // by class com.rusefi.output.FileFsioSettingsConsumer case FSIO_SETTING_FANONTEMPERATURE: diff --git a/firmware/controllers/generated/fsio_names.def b/firmware/controllers/generated/fsio_names.def index 52f6b25a8e..78a67a3868 100644 --- a/firmware/controllers/generated/fsio_names.def +++ b/firmware/controllers/generated/fsio_names.def @@ -1,4 +1,4 @@ -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jan 06 18:57:11 UTC 2021 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jan 07 13:24:50 UTC 2021 // by class com.rusefi.output.FileFsioSettingsConsumer static LENameOrdinalPair lefanOnTemperature(FSIO_SETTING_FANONTEMPERATURE, "cfg_fanOnTemperature"); diff --git a/firmware/controllers/generated/fsio_strings.def b/firmware/controllers/generated/fsio_strings.def index 680e8a8343..8bfb93cf7c 100644 --- a/firmware/controllers/generated/fsio_strings.def +++ b/firmware/controllers/generated/fsio_strings.def @@ -1,4 +1,4 @@ -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jan 06 18:57:11 UTC 2021 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jan 07 13:24:50 UTC 2021 // by class com.rusefi.output.FileFsioSettingsConsumer case FSIO_SETTING_FANONTEMPERATURE: diff --git a/firmware/controllers/generated/signature_all.h b/firmware/controllers/generated/signature_all.h index 41317d81ee..ceb4b66b12 100644 --- a/firmware/controllers/generated/signature_all.h +++ b/firmware/controllers/generated/signature_all.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD all -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 3975866578 -#define TS_SIGNATURE "rusEFI 2021.01.06.all.3975866578" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 118283022 +#define TS_SIGNATURE "rusEFI 2021.01.07.all.118283022" diff --git a/firmware/controllers/generated/signature_frankenso_na6.h b/firmware/controllers/generated/signature_frankenso_na6.h index 5cacabc83d..a410369039 100644 --- a/firmware/controllers/generated/signature_frankenso_na6.h +++ b/firmware/controllers/generated/signature_frankenso_na6.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD frankenso_na6 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 2055887145 -#define TS_SIGNATURE "rusEFI 2021.01.06.frankenso_na6.2055887145" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 2440850165 +#define TS_SIGNATURE "rusEFI 2021.01.07.frankenso_na6.2440850165" diff --git a/firmware/controllers/generated/signature_hellen_cypress.h b/firmware/controllers/generated/signature_hellen_cypress.h index 4334e5ae9d..5687bf3677 100644 --- a/firmware/controllers/generated/signature_hellen_cypress.h +++ b/firmware/controllers/generated/signature_hellen_cypress.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD hellen_cypress -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 621497873 -#define TS_SIGNATURE "rusEFI 2021.01.06.hellen_cypress.621497873" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 3472719309 +#define TS_SIGNATURE "rusEFI 2021.01.07.hellen_cypress.3472719309" diff --git a/firmware/controllers/generated/signature_kin.h b/firmware/controllers/generated/signature_kin.h index 3d976bc812..c35087fdf5 100644 --- a/firmware/controllers/generated/signature_kin.h +++ b/firmware/controllers/generated/signature_kin.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD kin -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 1947694315 -#define TS_SIGNATURE "rusEFI 2021.01.06.kin.1947694315" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 2682341175 +#define TS_SIGNATURE "rusEFI 2021.01.07.kin.2682341175" diff --git a/firmware/controllers/generated/signature_mre_f4.h b/firmware/controllers/generated/signature_mre_f4.h index 21c0a834be..dbcdf6b863 100644 --- a/firmware/controllers/generated/signature_mre_f4.h +++ b/firmware/controllers/generated/signature_mre_f4.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD mre_f4 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 4213847723 -#define TS_SIGNATURE "rusEFI 2021.01.06.mre_f4.4213847723" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 282854775 +#define TS_SIGNATURE "rusEFI 2021.01.07.mre_f4.282854775" diff --git a/firmware/controllers/generated/signature_mre_f7.h b/firmware/controllers/generated/signature_mre_f7.h index c1d67e805c..3ad431da99 100644 --- a/firmware/controllers/generated/signature_mre_f7.h +++ b/firmware/controllers/generated/signature_mre_f7.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD mre_f7 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 4213847723 -#define TS_SIGNATURE "rusEFI 2021.01.06.mre_f7.4213847723" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 282854775 +#define TS_SIGNATURE "rusEFI 2021.01.07.mre_f7.282854775" diff --git a/firmware/controllers/generated/signature_prometheus_405.h b/firmware/controllers/generated/signature_prometheus_405.h index b51f2040a5..bc5703f6d0 100644 --- a/firmware/controllers/generated/signature_prometheus_405.h +++ b/firmware/controllers/generated/signature_prometheus_405.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD prometheus_405 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 2921524867 -#define TS_SIGNATURE "rusEFI 2021.01.06.prometheus_405.2921524867" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 1171578207 +#define TS_SIGNATURE "rusEFI 2021.01.07.prometheus_405.1171578207" diff --git a/firmware/controllers/generated/signature_prometheus_469.h b/firmware/controllers/generated/signature_prometheus_469.h index d14c944f57..dc7ad3ed58 100644 --- a/firmware/controllers/generated/signature_prometheus_469.h +++ b/firmware/controllers/generated/signature_prometheus_469.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD prometheus_469 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 2921524867 -#define TS_SIGNATURE "rusEFI 2021.01.06.prometheus_469.2921524867" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 1171578207 +#define TS_SIGNATURE "rusEFI 2021.01.07.prometheus_469.1171578207" diff --git a/firmware/controllers/generated/signature_proteus_f4.h b/firmware/controllers/generated/signature_proteus_f4.h index 2306585fc2..22b0de5d31 100644 --- a/firmware/controllers/generated/signature_proteus_f4.h +++ b/firmware/controllers/generated/signature_proteus_f4.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD proteus_f4 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 626041356 -#define TS_SIGNATURE "rusEFI 2021.01.06.proteus_f4.626041356" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 3467022800 +#define TS_SIGNATURE "rusEFI 2021.01.07.proteus_f4.3467022800" diff --git a/firmware/controllers/generated/signature_proteus_f7.h b/firmware/controllers/generated/signature_proteus_f7.h index cd3b0d408e..7880075673 100644 --- a/firmware/controllers/generated/signature_proteus_f7.h +++ b/firmware/controllers/generated/signature_proteus_f7.h @@ -3,6 +3,6 @@ // #define SIGNATURE_BOARD proteus_f7 -#define SIGNATURE_DATE 2021.01.06 -#define SIGNATURE_HASH 626041356 -#define TS_SIGNATURE "rusEFI 2021.01.06.proteus_f7.626041356" +#define SIGNATURE_DATE 2021.01.07 +#define SIGNATURE_HASH 3467022800 +#define TS_SIGNATURE "rusEFI 2021.01.07.proteus_f7.3467022800" diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index db4c2c5857..ff19340c23 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1409,9 +1409,10 @@ tChargeMode_e tChargeMode; uint8_t[4] unused1059;;"units", 1, 0, -20, 100, 0 pid_s idleTimingPid;See useIdleTimingPidControl - int16_t idleTimingPidWorkZone;+When the current RPM is closer than this value to the target, closed-loop idle timing control is enabled.;"RPM", 1, 0, 0, 1000, 0 + uint8_t[2] unused3988;;"units", 1, 0, -20, 100, 0 int16_t idleTimingPidDeadZone;+If the RPM closer to target than this value, disable timing correction to prevent oscillation;"RPM", 1, 0, 0, 1000, 0 - int16_t idlePidFalloffDeltaRpm;+Taper out idle timing control over this range as the engine leaves idle conditions;"RPM", 1, 0, 0, 1000, 0 + uint8_t[2] unused3942;;"units", 1, 0, -20, 100, 0 + int16_t tpsAccelFractionPeriod;+A delay in cycles between fuel-enrich. portions;"cycles", 1, 0, 0, 500, 0 float tpsAccelFractionDivisor;+A fraction divisor: 1 or less = entire portion at once, or split into diminishing fractions;"coef", 1, 0, 0, 100, 2 @@ -1747,7 +1748,6 @@ end_struct #define CMD_TS_IGNITION_CATEGORY 18 #define CMD_TS_INJECTOR_CATEGORY 19 #define CMD_TS_X14 20 -#define CMD_TS_X15 21 // 0x16 #define CMD_TS_BENCH_CATEGORY 22 #define CMD_TS_X17 23 diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index c8e406442b..32f144bbba 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -2567,6 +2567,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = idleTimingPidCorrDialog, "", yAxis field = "" field = "Enable closed loop idle ignition timing", useIdleTimingPidControl + field = "RPM deadzone", idleTimingPidDeadZone field = "" field = "#Gain is in degrees advance per rpm away from target" field = "#A good starting point is 0.1 = 10 deg per 100 rpm" diff --git a/unit_tests/tests/test_idle_controller.cpp b/unit_tests/tests/test_idle_controller.cpp index afddfb796c..134700543b 100644 --- a/unit_tests/tests/test_idle_controller.cpp +++ b/unit_tests/tests/test_idle_controller.cpp @@ -62,76 +62,42 @@ TEST(idle, fsioPidParameters) { // ASSERT_EQ(1, engine->acSwitchState); } -// see also util.pid test -TEST(idle, timingPid) { +using ICP = IIdleController::Phase; + +TEST(idle_v2, timingPid) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + IdleController dut; + INJECT_ENGINE_REFERENCE(&dut); - // set PID settings - pid_s pidS; - pidS.pFactor = 0.1; - pidS.iFactor = 0; - pidS.dFactor = 0; - pidS.offset = 0; - pidS.minValue = -20; - pidS.maxValue = +20; - pidS.periodMs = 1; - - // setup TimingPid settings - engineConfiguration->idleTimingPidDeadZone = 10; - engineConfiguration->idleTimingPidWorkZone = 100; - engineConfiguration->idlePidFalloffDeltaRpm = 30; - - // setup target rpm curve - const int idleRpmTarget = 700; - setArrayValues(engineConfiguration->cltIdleRpm, idleRpmTarget); - - // setup other settings - engineConfiguration->idleTimingPid = pidS; - eth.engine.fsioState.fsioTimingAdjustment = 0; - eth.engine.fsioState.fsioIdleTargetRPMAdjustment = 0; - eth.engine.engineState.cltTimingCorrection = 0; - - // configure TPS - engineConfiguration->idlePidDeactivationTpsThreshold = 10; - Sensor::setMockValue(SensorType::Tps1, 0); - - // all corrections disabled, should be 0 - engineConfiguration->useIdleTimingPidControl = false; - angle_t corr = getAdvanceCorrections(idleRpmTarget PASS_ENGINE_PARAMETER_SUFFIX); - ASSERT_EQ(0, corr) << "getAdvanceCorrections#1"; - - // basic IDLE PID correction test engineConfiguration->useIdleTimingPidControl = true; - int baseTestRpm = idleRpmTarget + engineConfiguration->idleTimingPidWorkZone; - corr = getAdvanceCorrections(baseTestRpm PASS_ENGINE_PARAMETER_SUFFIX); - // (delta_rpm=-100) * (p-factor=0.1) = -10 degrees - ASSERT_EQ(-10, corr) << "getAdvanceCorrections#2"; - // check if rpm is too close to the target - corr = getAdvanceCorrections((idleRpmTarget + engineConfiguration->idleTimingPidDeadZone) PASS_ENGINE_PARAMETER_SUFFIX); - ASSERT_EQ(0, corr) << "getAdvanceCorrections#3"; + pid_s pidCfg{}; + pidCfg.pFactor = 0.1; + pidCfg.minValue = -10; + pidCfg.maxValue = 10; + dut.init(&pidCfg); - // check if rpm is too high (just outside the workzone and even falloff) so we disable the PID correction - int tooHighRpm = idleRpmTarget + engineConfiguration->idleTimingPidWorkZone + engineConfiguration->idlePidFalloffDeltaRpm; - corr = getAdvanceCorrections(tooHighRpm PASS_ENGINE_PARAMETER_SUFFIX); - ASSERT_EQ(0, corr) << "getAdvanceCorrections#4"; + // Check that out of idle mode it doesn't do anything + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Cranking)); + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Coasting)); + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Running)); - // check if rpm is within the falloff zone - int falloffRpm = idleRpmTarget + engineConfiguration->idleTimingPidWorkZone + (engineConfiguration->idlePidFalloffDeltaRpm / 2); - corr = getAdvanceCorrections(falloffRpm PASS_ENGINE_PARAMETER_SUFFIX); - // -(100+30/2) * 0.1 / 2 = -5.75 - ASSERT_FLOAT_EQ(-5.75f, corr) << "getAdvanceCorrections#5"; + // Check that it works in idle mode + EXPECT_FLOAT_EQ(-5, dut.getIdleTimingAdjustment(1050, 1000, ICP::Idling)); - // check if PID correction is disabled in running mode (tps > threshold): - Sensor::setMockValue(SensorType::Tps1, engineConfiguration->idlePidDeactivationTpsThreshold + 1); - corr = getAdvanceCorrections(idleRpmTarget PASS_ENGINE_PARAMETER_SUFFIX); - ASSERT_EQ(0, corr) << "getAdvanceCorrections#6"; + // ...but not when disabled + engineConfiguration->useIdleTimingPidControl = false; + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Idling)); - // check if PID correction is interpolated for transient idle-running TPS positions - Sensor::setMockValue(SensorType::Tps1, engineConfiguration->idlePidDeactivationTpsThreshold / 2); - corr = getAdvanceCorrections(baseTestRpm PASS_ENGINE_PARAMETER_SUFFIX); - ASSERT_FLOAT_EQ(-5.0f, corr) << "getAdvanceCorrections#7"; + engineConfiguration->useIdleTimingPidControl = true; + // Now check that the deadzone works + engineConfiguration->idleTimingPidDeadZone = 50; + EXPECT_FLOAT_EQ(5.1, dut.getIdleTimingAdjustment(949, 1000, ICP::Idling)); + EXPECT_EQ(0, dut.getIdleTimingAdjustment(951, 1000, ICP::Idling)); + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1000, 1000, ICP::Idling)); + EXPECT_EQ(0, dut.getIdleTimingAdjustment(1049, 1000, ICP::Idling)); + EXPECT_FLOAT_EQ(-5.1, dut.getIdleTimingAdjustment(1051, 1000, ICP::Idling)); } TEST(idle_v2, testTargetRpm) { @@ -148,8 +114,6 @@ TEST(idle_v2, testTargetRpm) { EXPECT_FLOAT_EQ(500, dut.getTargetRpm(50)); } -using ICP = IIdleController::Phase; - TEST(idle_v2, testDeterminePhase) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); IdleController dut;