From ad368b20311a33e56a36da0b46829d010d7041ad Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Wed, 6 Apr 2022 13:15:58 -0700 Subject: [PATCH] Gear detection improvements (#4047) * gear detect improvements * ui * ui for gear ratios * ui --- firmware/console/status_loop.cpp | 7 ++-- firmware/controllers/algo/algo.mk | 1 + firmware/controllers/algo/engine.h | 4 +++ firmware/controllers/algo/gear_detector.cpp | 33 +++++++++++++++++ firmware/controllers/algo/gear_detector.h | 12 +++++++ firmware/integration/rusefi_config.txt | 8 ++--- firmware/tunerstudio/rusefi.input | 40 +++++++++++++-------- unit_tests/tests/test_gear_detector.cpp | 28 +++++++++++++++ unit_tests/tests/tests.mk | 1 + 9 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 firmware/controllers/algo/gear_detector.cpp create mode 100644 firmware/controllers/algo/gear_detector.h create mode 100644 unit_tests/tests/test_gear_detector.cpp diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index 0a60a10d88..30b40804e5 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -548,11 +548,8 @@ static void updateVvtSensors() { static void updateVehicleSpeed(int rpm) { #if EFI_VEHICLE_SPEED - float vehicleSpeedKph = Sensor::getOrZero(SensorType::VehicleSpeed); - float wheelRPM = vehicleSpeedKph * 1000 / 60 / (2 * CONST_PI * engineConfiguration->wheelDiameter); - float driveshaftRpm = wheelRPM * engineConfiguration->finalGearRatio; - engine->outputChannels.vehicleSpeedKph = vehicleSpeedKph; - engine->outputChannels.speedToRpmRatio = rpm / driveshaftRpm; + engine->outputChannels.vehicleSpeedKph = Sensor::getOrZero(SensorType::VehicleSpeed); + engine->outputChannels.speedToRpmRatio = engine->module()->getGearboxRatio(); #endif /* EFI_VEHICLE_SPEED */ } diff --git a/firmware/controllers/algo/algo.mk b/firmware/controllers/algo/algo.mk index a868664e1e..f0e4b0ed14 100644 --- a/firmware/controllers/algo/algo.mk +++ b/firmware/controllers/algo/algo.mk @@ -13,6 +13,7 @@ CONTROLLERS_ALGO_SRC_CPP = $(PROJECT_DIR)/controllers/algo/advance_map.cpp \ $(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \ $(PROJECT_DIR)/controllers/algo/engine.cpp \ $(PROJECT_DIR)/controllers/algo/engine2.cpp \ + $(PROJECT_DIR)/controllers/algo/gear_detector.cpp \ $(PROJECT_DIR)/controllers/gauges/lcd_menu_tree.cpp \ $(PROJECT_DIR)/controllers/algo/event_registry.cpp \ $(PROJECT_DIR)/controllers/algo/airmass/airmass.cpp \ diff --git a/firmware/controllers/algo/engine.h b/firmware/controllers/algo/engine.h index e4f80ff154..0f50597022 100644 --- a/firmware/controllers/algo/engine.h +++ b/firmware/controllers/algo/engine.h @@ -37,6 +37,7 @@ #include "ignition_controller.h" #include "alternator_controller.h" #include "dfco.h" +#include "gear_detector.h" #ifndef EFI_UNIT_TEST #error EFI_UNIT_TEST must be defined! @@ -185,6 +186,9 @@ public: PrimeController, DfcoController, Mockable, +#if EFI_VEHICLE_SPEED + GearDetector, +#endif // EFI_VEHICLE_SPEED EngineModule // dummy placeholder so the previous entries can all have commas > engineModules; diff --git a/firmware/controllers/algo/gear_detector.cpp b/firmware/controllers/algo/gear_detector.cpp new file mode 100644 index 0000000000..db760d6c76 --- /dev/null +++ b/firmware/controllers/algo/gear_detector.cpp @@ -0,0 +1,33 @@ +#include "pch.h" + +void GearDetector::onSlowCallback() { + m_gearboxRatio = computeGearboxRatio(); + + // TODO: solve for which gear this is +} + +float GearDetector::computeGearboxRatio() const { + auto vssKph = Sensor::getOrZero(SensorType::VehicleSpeed); + + if (vssKph < 5) { + // Vehicle too slow to determine gearbox ratio, avoid div/0 + return 0; + } + + auto engineRpm = Sensor::getOrZero(SensorType::Rpm); + + // Convert to wheel RPM + // km rev 1 hr + // ------ * ------------ * __________ + // hr km 60 min + float wheelRpm = vssKph * engineConfiguration->driveWheelRevPerKm * (1 / 60.0f); + + // Convert to driveshaft RPM + auto driveshaftRpm = wheelRpm * engineConfiguration->finalGearRatio; + + return engineRpm / driveshaftRpm; +} + +float GearDetector::getGearboxRatio() const { + return m_gearboxRatio; +} diff --git a/firmware/controllers/algo/gear_detector.h b/firmware/controllers/algo/gear_detector.h new file mode 100644 index 0000000000..7d8d2b3ce2 --- /dev/null +++ b/firmware/controllers/algo/gear_detector.h @@ -0,0 +1,12 @@ + +class GearDetector : public EngineModule { +public: + void onSlowCallback() override; + + float getGearboxRatio() const; + +private: + float computeGearboxRatio() const; + + float m_gearboxRatio = 0; +}; diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index f893e4acd9..e05fcb582c 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -724,8 +724,8 @@ custom adc_channel_mode_e 4 bits, U32, @OFFSET@, [0:1], "Off", "Slow", "Fast" pin_input_mode_e throttlePedalUpPinMode; uint8_t acIdleExtraOffset;+Additional idle % while A/C is active;"%", 1, 0, 0, 100, 0 - uint16_t autoscale finalGearRatio;;"ratio", 0.1, 0, 0, 100, 2 - uint16_t autoscale wheelDiameter;;"m", 0.001, 0, 0, 20, 2 + uint16_t autoscale finalGearRatio;Ratio between the wheels and your transmission output. ;"ratio", 0.01, 0, 0, 10, 2 + uint16_t autoscale unused722;;"", 1, 0, 0, 0, 0 uint16_t wastegatePositionMin;+Voltage when the wastegate is closed.\nYou probably don't have one of these!;"mv", 1, 0, 0, 5000, 0 uint16_t wastegatePositionMax;+Voltage when the wastegate is fully open.\nYou probably don't have one of these!\n1 volt = 1000 units;"mv", 1, 0, 0, 5000, 0 uint16_t idlePositionMin;+Voltage when the idle valve is closed.\nYou probably don't have one of these!;"mv", 1, 0, 0, 5000, 0 @@ -1177,7 +1177,7 @@ int16_t tps2Max;Full throttle#2. tpsMax value as 10 bit ADC value. Not Voltage!\ float tpsAccelEnrichmentThreshold;+Maximum change delta of TPS percentage over the 'length'. Actual TPS change has to be above this value in order for TPS/TPS acceleration to kick in.;"roc", 1, 0, 0, 200, 1 brain_input_pin_e[2 iterate] auxSpeedSensorInputPin; - uint8_t totalGearsCount;;"", 1, 0, 0, 1, 0 + uint8_t totalGearsCount;;"", 1, 0, 1, @@GEARS_COUNT@@, 0 uint8_t unused16962;;"", 1, 0, 0, 1, 0 uint32_t uartConsoleSerialSpeed;Band rate for primary TTL;"BPs", 1, 0, 0, 1000000, 0 @@ -1500,7 +1500,7 @@ int8_t[MAX_CYLINDER_COUNT iterate] fuelTrim;;"Percent", @@PERCENT_TRIM_BYTE_PACK output_pin_e[4 iterate] stepper_raw_output; - uint16_t[GEARS_COUNT iterate] autoscale gearRatio;;"ratio", 0.01, 0, 0, 650, 0 + uint16_t[GEARS_COUNT iterate] autoscale gearRatio;;"ratio", 0.01, 0, 0, 10, 2 uint16_t vvtActivationDelayMs;We need to give engine time to build oil pressure without diverting it to VVT;"ms", 1, 0, 0, 65000, 0 uint16_t unusedShort;;"RPM", 1, 0, 0, 65000, 0 diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index 1923ccbdd5..809f15d31b 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -1463,6 +1463,7 @@ menuDialog = main menu = "&Advanced" subMenu = ignitionCylExtra, "Cylinder offsets", 0 + subMenu = gearDetection, "Gear detection", 0 subMenu = std_separator subMenu = boostDialog, "Boost Control" @@ -3102,30 +3103,41 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" panel = alternator panel = startStopDialog - dialog = speedSensorAnalog + dialog = speedSensorAnalog, "Speed sensor" field = "Input pin", vehicleSpeedSensorInputPin - field = "Wheel revolutions per kilometer", driveWheelRevPerKm + field = "Filter Reciprocal", vssFilterReciprocal, { vehicleSpeedSensorInputPin != @@ADC_CHANNEL_NONE@@ } + ; ; We prefer quantities that users can actually measure or inspect without math, so we have ; two separate natural settings here without one 'sensor tooth to wheel revolution' ratio ; - field = "Speed sensor gear ratio", vssGearRatio - field = "Speed sensor tooth count", vssToothCount + field = "Wheel revolutions per kilometer", driveWheelRevPerKm + field = "Speed sensor gear ratio", vssGearRatio, { vehicleSpeedSensorInputPin != @@ADC_CHANNEL_NONE@@ } + field = "Speed sensor tooth count", vssToothCount, { vehicleSpeedSensorInputPin != @@ADC_CHANNEL_NONE@@ } - dialog = speedSensorCan - field = "Vss Car Type", canVssNbcType, { enableCanVss } + dialog = speedSensorCan, "CAN Vehicle Speed" + field = "Enable CAN VSS", enableCanVss, { canReadEnabled } + field = "VSS CAN message type", canVssNbcType, { enableCanVss } - dialog = vssFilter - field = "Filter Reciprocal", vssFilterReciprocal - - dialog = speedSensorLeft, "Speed sensor config", yAxis - panel = speedSensorCan, { enableCanVss } + dialog = speedSensorLeft, "", yAxis panel = speedSensorAnalog, { enableCanVss == 0 } - field = "Enable CANbus VSS values", enableCanVss, { canReadEnabled } + panel = speedSensorCan panel = vssFilter - field = "finalGearRatio", finalGearRatio - field = "wheelDiameter", wheelDiameter + dialog = gearDetection, "Gear Detection" + field = "Wheel revolutions per kilometer", driveWheelRevPerKm + field = "Final drive ratio", finalGearRatio + field = "" + field = "Forward gear count", totalGearsCount + field = "" + field = "1st gear", gearRatio1, { totalGearsCount >= 1 } + field = "2nd gear", gearRatio2, { totalGearsCount >= 2 } + field = "3rd gear", gearRatio3, { totalGearsCount >= 3 } + field = "4th gear", gearRatio4, { totalGearsCount >= 4 } + field = "5th gear", gearRatio5, { totalGearsCount >= 5 } + field = "6th gear", gearRatio6, { totalGearsCount >= 6 } + field = "7th gear", gearRatio6, { totalGearsCount >= 7 } + field = "8th gear", gearRatio6, { totalGearsCount >= 8 } dialog = speedSensor, "Speed sensor", xAxis panel = speedSensorLeft diff --git a/unit_tests/tests/test_gear_detector.cpp b/unit_tests/tests/test_gear_detector.cpp new file mode 100644 index 0000000000..214137083e --- /dev/null +++ b/unit_tests/tests/test_gear_detector.cpp @@ -0,0 +1,28 @@ +#include "pch.h" + +float GetGearRatioFor(float revPerKm, float axle, float kph, float rpm) { + EngineTestHelper eth(TEST_ENGINE); + + engineConfiguration->driveWheelRevPerKm = revPerKm; + engineConfiguration->finalGearRatio = axle; + + Sensor::setMockValue(SensorType::VehicleSpeed, kph); + Sensor::setMockValue(SensorType::Rpm, rpm); + + GearDetector dut; + dut.onSlowCallback(); + + return dut.getGearboxRatio(); +} + +TEST(GearDetector, ComputeGearRatio) { + // real gears from Volvo racecar + EXPECT_NEAR_M3(3.35f, GetGearRatioFor(507, 4.1, 29.45f / 0.6214f, 5500)); + EXPECT_NEAR_M3(1.99f, GetGearRatioFor(507, 4.1, 49.57f / 0.6214f, 5500)); + EXPECT_NEAR_M3(1.33f, GetGearRatioFor(507, 4.1, 74.18f / 0.6214f, 5500)); + EXPECT_NEAR_M3(1.00f, GetGearRatioFor(507, 4.1, 98.65f / 0.6214f, 5500)); + EXPECT_NEAR_M3(0.72f, GetGearRatioFor(507, 4.1, 137.02f / 0.6214f, 5500)); + + // Idling, car stopped, check no div/0 + EXPECT_EQ(0, GetGearRatioFor(507, 4.1, 0, 800)); +} diff --git a/unit_tests/tests/tests.mk b/unit_tests/tests/tests.mk index 1d5915638a..ed2ebe7bd9 100644 --- a/unit_tests/tests/tests.mk +++ b/unit_tests/tests/tests.mk @@ -49,6 +49,7 @@ TESTS_SRC_CPP = \ tests/test_scattered_outputs.cpp \ tests/test_launch.cpp \ tests/test_fuel_map.cpp \ + tests/test_gear_detector.cpp \ tests/ignition_injection/test_fuel_wall_wetting.cpp \ tests/test_one_cylinder_logic.cpp \ tests/test_tunerstudio.cpp \