mirror of https://github.com/rusefi/rusefi-1.git
Gate closed loop idle on road speed (#2901)
* implement * test * b * config
This commit is contained in:
parent
90e43040c7
commit
007a390f2b
|
@ -39,6 +39,7 @@
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
#include "periodic_task.h"
|
#include "periodic_task.h"
|
||||||
#include "allsensors.h"
|
#include "allsensors.h"
|
||||||
|
#include "vehicle_speed.h"
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#include "dc_motors.h"
|
#include "dc_motors.h"
|
||||||
|
|
||||||
|
@ -207,7 +208,7 @@ int IdleController::getTargetRpm(float clt) const {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, SensorResult tps) const {
|
IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, SensorResult tps, float vss) const {
|
||||||
if (!engine->rpmCalculator.isRunning()) {
|
if (!engine->rpmCalculator.isRunning()) {
|
||||||
return Phase::Cranking;
|
return Phase::Cranking;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +229,12 @@ IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, Se
|
||||||
return Phase::Coasting;
|
return Phase::Coasting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the vehicle is moving too quickly, disable CL idle
|
||||||
|
auto maxVss = CONFIG(maxIdleVss);
|
||||||
|
if (maxVss != 0 && vss > maxVss) {
|
||||||
|
return Phase::Running;
|
||||||
|
}
|
||||||
|
|
||||||
// No other conditions met, we are idling!
|
// No other conditions met, we are idling!
|
||||||
return Phase::Idling;
|
return Phase::Idling;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +474,7 @@ float IdleController::getClosedLoop(IIdleController::Phase phase, float tpsPos,
|
||||||
m_lastTargetRpm = targetRpm;
|
m_lastTargetRpm = targetRpm;
|
||||||
|
|
||||||
// Determine what operation phase we're in - idling or not
|
// Determine what operation phase we're in - idling or not
|
||||||
auto phase = determinePhase(rpm, targetRpm, tps);
|
auto phase = determinePhase(rpm, targetRpm, tps, getVehicleSpeed());
|
||||||
m_lastPhase = phase;
|
m_lastPhase = phase;
|
||||||
|
|
||||||
engine->engineState.isAutomaticIdle = tps.Valid && engineConfiguration->idleMode == IM_AUTO;
|
engine->engineState.isAutomaticIdle = tps.Valid && engineConfiguration->idleMode == IM_AUTO;
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct IIdleController {
|
||||||
Running, // On throttle
|
Running, // On throttle
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual Phase determinePhase(int rpm, int targetRpm, SensorResult tps) const = 0;
|
virtual Phase determinePhase(int rpm, int targetRpm, SensorResult tps, float vss) const = 0;
|
||||||
virtual int getTargetRpm(float clt) const = 0;
|
virtual int getTargetRpm(float clt) const = 0;
|
||||||
virtual float getCrankingOpenLoop(float clt) const = 0;
|
virtual float getCrankingOpenLoop(float clt) const = 0;
|
||||||
virtual float getRunningOpenLoop(float clt, SensorResult tps) const = 0;
|
virtual float getRunningOpenLoop(float clt, SensorResult tps) const = 0;
|
||||||
|
@ -42,7 +42,7 @@ public:
|
||||||
int getTargetRpm(float clt) const override;
|
int getTargetRpm(float clt) const override;
|
||||||
|
|
||||||
// PHASE DETERMINATION: what is the driver trying to do right now?
|
// PHASE DETERMINATION: what is the driver trying to do right now?
|
||||||
Phase determinePhase(int rpm, int targetRpm, SensorResult tps) const override;
|
Phase determinePhase(int rpm, int targetRpm, SensorResult tps, float vss) const override;
|
||||||
|
|
||||||
// OPEN LOOP CORRECTIONS
|
// OPEN LOOP CORRECTIONS
|
||||||
float getCrankingOpenLoop(float clt) const override;
|
float getCrankingOpenLoop(float clt) const override;
|
||||||
|
|
|
@ -628,7 +628,7 @@ custom ignition_mode_e 4 bits, U32, @OFFSET@, [0:1], "Single Coil", "Individual
|
||||||
ignition_mode_e ignitionMode;+Single coil = distributor\nIndividual coils = one coil per cylinder (COP, coil-near-plug), requires sequential mode\nWasted spark = Fires pairs of cylinders together, either one coil per pair of cylinders or one coil per cylinder\nTwo distributors = A pair of distributors, found on some BMW, Toyota and other engines\nset ignition_mode X
|
ignition_mode_e ignitionMode;+Single coil = distributor\nIndividual coils = one coil per cylinder (COP, coil-near-plug), requires sequential mode\nWasted spark = Fires pairs of cylinders together, either one coil per pair of cylinders or one coil per cylinder\nTwo distributors = A pair of distributors, found on some BMW, Toyota and other engines\nset ignition_mode X
|
||||||
|
|
||||||
int8_t gapTrackingLengthOverride;;"count", 1, 0, 0, @@GAP_TRACKING_LENGTH@@, 0
|
int8_t gapTrackingLengthOverride;;"count", 1, 0, 0, @@GAP_TRACKING_LENGTH@@, 0
|
||||||
int8_t[1] unusedOldIgnitionOffset;;"unused", 1, 0, 0, 1, 0
|
uint8_t maxIdleVss;+Above this speed, disable closed loop idle control. Set to 0 to disable (allow closed loop idle at any speed).;"kph", 1, 0, 0, 100, 0
|
||||||
uint16_t minOilPressureAfterStart;+Expected oil pressure after starting the engine. If oil pressure does not reach this level within 5 seconds of engine start, fuel will be cut. Set to 0 to disable and always allow starting.;"kPa", 1, 0, 0, 1000, 0
|
uint16_t minOilPressureAfterStart;+Expected oil pressure after starting the engine. If oil pressure does not reach this level within 5 seconds of engine start, fuel will be cut. Set to 0 to disable and always allow starting.;"kPa", 1, 0, 0, 1000, 0
|
||||||
|
|
||||||
custom timing_mode_e 4 bits, U32, @OFFSET@, [0:0], "dynamic", "fixed"
|
custom timing_mode_e 4 bits, U32, @OFFSET@, [0:0], "dynamic", "fixed"
|
||||||
|
|
|
@ -2650,6 +2650,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00"
|
||||||
field = "TPS threshold", idlePidDeactivationTpsThreshold
|
field = "TPS threshold", idlePidDeactivationTpsThreshold
|
||||||
field = "RPM upper limit", idlePidRpmUpperLimit
|
field = "RPM upper limit", idlePidRpmUpperLimit
|
||||||
field = "RPM deadzone", idlePidRpmDeadZone
|
field = "RPM deadzone", idlePidRpmDeadZone
|
||||||
|
field = "Max vehicle speed", maxIdleVss
|
||||||
|
|
||||||
dialog = idleExtra, "Extra Idle Features"
|
dialog = idleExtra, "Extra Idle Features"
|
||||||
field = "Use idle ignition table", useSeparateAdvanceForIdle
|
field = "Use idle ignition table", useSeparateAdvanceForIdle
|
||||||
|
|
|
@ -123,33 +123,38 @@ TEST(idle_v2, testDeterminePhase) {
|
||||||
CONFIG(idlePidDeactivationTpsThreshold) = 5;
|
CONFIG(idlePidDeactivationTpsThreshold) = 5;
|
||||||
// RPM window is 100 RPM above target
|
// RPM window is 100 RPM above target
|
||||||
CONFIG(idlePidRpmUpperLimit) = 100;
|
CONFIG(idlePidRpmUpperLimit) = 100;
|
||||||
|
// Max VSS for idle is 10kph
|
||||||
|
CONFIG(maxIdleVss) = 10;
|
||||||
|
|
||||||
// First test stopped engine
|
// First test stopped engine
|
||||||
engine->rpmCalculator.setRpmValue(0);
|
engine->rpmCalculator.setRpmValue(0);
|
||||||
EXPECT_EQ(ICP::Cranking, dut.determinePhase(0, 1000, unexpected));
|
EXPECT_EQ(ICP::Cranking, dut.determinePhase(0, 1000, unexpected, 0));
|
||||||
|
|
||||||
// Now engine is running!
|
// Now engine is running!
|
||||||
// Controller doesn't need this other than for isCranking()
|
// Controller doesn't need this other than for isCranking()
|
||||||
engine->rpmCalculator.setRpmValue(1000);
|
engine->rpmCalculator.setRpmValue(1000);
|
||||||
|
|
||||||
// Test invalid TPS, but inside the idle window
|
// Test invalid TPS, but inside the idle window
|
||||||
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, unexpected));
|
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, unexpected, 0));
|
||||||
|
|
||||||
// Valid TPS should now be inside the zone
|
// Valid TPS should now be inside the zone
|
||||||
EXPECT_EQ(ICP::Idling, dut.determinePhase(1000, 1000, 0));
|
EXPECT_EQ(ICP::Idling, dut.determinePhase(1000, 1000, 0, 0));
|
||||||
|
|
||||||
|
// Inside the zone, but vehicle speed too fast
|
||||||
|
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 0, 25));
|
||||||
|
|
||||||
// Above TPS threshold should be outside the zone
|
// Above TPS threshold should be outside the zone
|
||||||
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 10));
|
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 10, 0));
|
||||||
|
|
||||||
// Above target, below (target + upperLimit) should be in idle zone
|
// Above target, below (target + upperLimit) should be in idle zone
|
||||||
EXPECT_EQ(ICP::Idling, dut.determinePhase(1099, 1000, 0));
|
EXPECT_EQ(ICP::Idling, dut.determinePhase(1099, 1000, 0, 0));
|
||||||
|
|
||||||
// above upper limit and on throttle should be out of idle zone
|
// above upper limit and on throttle should be out of idle zone
|
||||||
EXPECT_EQ(ICP::Running, dut.determinePhase(1101, 1000, 10));
|
EXPECT_EQ(ICP::Running, dut.determinePhase(1101, 1000, 10, 0));
|
||||||
|
|
||||||
// Below TPS but above RPM should be outside the zone
|
// Below TPS but above RPM should be outside the zone
|
||||||
EXPECT_EQ(ICP::Coasting, dut.determinePhase(1101, 1000, 0));
|
EXPECT_EQ(ICP::Coasting, dut.determinePhase(1101, 1000, 0, 0));
|
||||||
EXPECT_EQ(ICP::Coasting, dut.determinePhase(5000, 1000, 0));
|
EXPECT_EQ(ICP::Coasting, dut.determinePhase(5000, 1000, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(idle_v2, crankingOpenLoop) {
|
TEST(idle_v2, crankingOpenLoop) {
|
||||||
|
@ -383,7 +388,7 @@ TEST(idle_v2, closedLoopDeadzone) {
|
||||||
|
|
||||||
struct IntegrationIdleMock : public IdleController {
|
struct IntegrationIdleMock : public IdleController {
|
||||||
MOCK_METHOD(int, getTargetRpm, (float clt), (const, override));
|
MOCK_METHOD(int, getTargetRpm, (float clt), (const, override));
|
||||||
MOCK_METHOD(ICP, determinePhase, (int rpm, int targetRpm, SensorResult tps), (const, override));
|
MOCK_METHOD(ICP, determinePhase, (int rpm, int targetRpm, SensorResult tps, float vss), (const, override));
|
||||||
MOCK_METHOD(float, getOpenLoop, (ICP phase, float clt, SensorResult tps), (const, override));
|
MOCK_METHOD(float, getOpenLoop, (ICP phase, float clt, SensorResult tps), (const, override));
|
||||||
MOCK_METHOD(float, getClosedLoop, (ICP phase, float tps, int rpm, int target), (override));
|
MOCK_METHOD(float, getClosedLoop, (ICP phase, float tps, int rpm, int target), (override));
|
||||||
};
|
};
|
||||||
|
@ -404,7 +409,7 @@ TEST(idle_v2, IntegrationManual) {
|
||||||
.WillOnce(Return(1000));
|
.WillOnce(Return(1000));
|
||||||
|
|
||||||
// Determine phase will claim we're idling
|
// Determine phase will claim we're idling
|
||||||
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps))
|
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps, 0))
|
||||||
.WillOnce(Return(ICP::Idling));
|
.WillOnce(Return(ICP::Idling));
|
||||||
|
|
||||||
// Open loop should be asked for an open loop position
|
// Open loop should be asked for an open loop position
|
||||||
|
@ -434,7 +439,7 @@ TEST(idle_v2, IntegrationAutomatic) {
|
||||||
.WillOnce(Return(1000));
|
.WillOnce(Return(1000));
|
||||||
|
|
||||||
// Determine phase will claim we're idling
|
// Determine phase will claim we're idling
|
||||||
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps))
|
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps, 0))
|
||||||
.WillOnce(Return(ICP::Idling));
|
.WillOnce(Return(ICP::Idling));
|
||||||
|
|
||||||
// Open loop should be asked for an open loop position
|
// Open loop should be asked for an open loop position
|
||||||
|
@ -467,7 +472,7 @@ TEST(idle_v2, IntegrationClamping) {
|
||||||
.WillOnce(Return(1000));
|
.WillOnce(Return(1000));
|
||||||
|
|
||||||
// Determine phase will claim we're idling
|
// Determine phase will claim we're idling
|
||||||
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps))
|
EXPECT_CALL(dut, determinePhase(950, 1000, expectedTps, 0))
|
||||||
.WillOnce(Return(ICP::Idling));
|
.WillOnce(Return(ICP::Idling));
|
||||||
|
|
||||||
// Open loop should be asked for an open loop position
|
// Open loop should be asked for an open loop position
|
||||||
|
|
Loading…
Reference in New Issue