From 46e38447e51f26c3224d2553faf6532bfc6d8fe9 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Mon, 5 Apr 2021 12:57:03 -0700 Subject: [PATCH] Ford redundant ETB tps (#2519) * ford tps * configurable maximum * initialization * check consistency when in the low range * print info * default * config field * config parameter * test Co-authored-by: Matthew Kennedy --- .../sensors/redundant_ford_tps.cpp | 53 +++++++ .../controllers/sensors/redundant_ford_tps.h | 34 +++++ .../sensors/sensor_info_printing.cpp | 5 + firmware/controllers/sensors/sensors.mk | 1 + firmware/init/sensor/init_tps.cpp | 30 +++- firmware/integration/rusefi_config.txt | 2 +- firmware/tunerstudio/rusefi.input | 1 + unit_tests/tests/sensor/redundant.cpp | 141 ++++++++++++++++++ 8 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 firmware/controllers/sensors/redundant_ford_tps.cpp create mode 100644 firmware/controllers/sensors/redundant_ford_tps.h diff --git a/firmware/controllers/sensors/redundant_ford_tps.cpp b/firmware/controllers/sensors/redundant_ford_tps.cpp new file mode 100644 index 0000000000..ca5714087c --- /dev/null +++ b/firmware/controllers/sensors/redundant_ford_tps.cpp @@ -0,0 +1,53 @@ +#include "redundant_ford_tps.h" + +#include "efilib.h" + +RedundantFordTps::RedundantFordTps(SensorType outputType, SensorType first, SensorType second) + : Sensor(outputType) + , m_first(first) + , m_second(second) +{ +} + +void RedundantFordTps::configure(float maxDifference, float secondaryMaximum) { + m_maxDifference = maxDifference; + m_secondaryMaximum = secondaryMaximum; +} + +SensorResult RedundantFordTps::get() const { + // Sensor 1 is "plain linear" and has the full range + auto tps1 = Sensor::get(m_first); + + // Sensor 2 is compressed in to 0 -> 50% + auto tps2 = Sensor::get(m_second); + + // If either result is invalid, return invalid. + if (!tps1 || !tps2) { + return unexpected; + } + + // The "actual" position resolved by the second throttle - this tops out at m_secondaryMaximum instead of 100% + float tps2Actual = tps2.Value * m_secondaryMaximum / 100; + + // Switch modes slightly below the maximum of the secondary, to avoid misbehavior near 100% + float avgThreshold = m_secondaryMaximum * 0.9f; + + // Case 1: both sensors show low position, average result + if (tps1.Value < avgThreshold && tps2Actual < avgThreshold) { + // Check that the resolved positions are close + float delta = absF(tps1.Value - tps2Actual); + if (delta > m_maxDifference) { + return unexpected; + } + + return (tps1.Value + tps2Actual) / 2; + } + + // Case 2: both sensors show high position, return "full scale" sensor's position + if (tps1.Value > avgThreshold && tps2Actual > (avgThreshold - 3)) { + return tps1; + } + + // Any other condition indicates an mismatch, and therefore an error + return unexpected; +} diff --git a/firmware/controllers/sensors/redundant_ford_tps.h b/firmware/controllers/sensors/redundant_ford_tps.h new file mode 100644 index 0000000000..0e3f2da361 --- /dev/null +++ b/firmware/controllers/sensors/redundant_ford_tps.h @@ -0,0 +1,34 @@ +#pragma once + +#include "sensor.h" + +class RedundantFordTps final : public Sensor +{ +public: + RedundantFordTps( + SensorType outputType, + SensorType firstSensor, + SensorType secondSensor + ); + + void configure(float maxDifference, float secondaryMaximum); + + SensorResult get() const override; + + bool isRedundant() const override { + return true; + } + + void showInfo(Logging* logger, const char* sensorName) const override; + +private: + // The two sensors we interpret to form one redundant sensor + const SensorType m_first; + const SensorType m_second; + + // How far apart do we allow the sensors to be before reporting an issue? + float m_maxDifference = 0; + + // At what primary % does the secondary hit 100%? + float m_secondaryMaximum = 0; +}; diff --git a/firmware/controllers/sensors/sensor_info_printing.cpp b/firmware/controllers/sensors/sensor_info_printing.cpp index 033c28d0ba..de5b304e72 100644 --- a/firmware/controllers/sensors/sensor_info_printing.cpp +++ b/firmware/controllers/sensors/sensor_info_printing.cpp @@ -2,6 +2,7 @@ #include "proxy_sensor.h" #include "functional_sensor.h" #include "redundant_sensor.h" +#include "redundant_ford_tps.h" #include "rpm_calculator.h" #include "Lps25Sensor.h" #include "linear_func.h" @@ -37,6 +38,10 @@ void RedundantSensor::showInfo(Logging* logger, const char* sensorName) const { scheduleMsg(logger, "Sensor \"%s\" is redundant combining \"%s\" and \"%s\"", sensorName, getSensorName(m_first), getSensorName(m_second)); } +void RedundantFordTps::showInfo(Logging* logger, const char* sensorName) const { + scheduleMsg(logger, "Sensor \"%s\" is Ford-type redundant TPS combining \"%s\" and \"%s\"", sensorName, getSensorName(m_first), getSensorName(m_second)); +} + void RpmCalculator::showInfo(Logging* logger, const char* /*sensorName*/) const { scheduleMsg(logger, "RPM sensor: stopped: %d spinning up: %d cranking: %d running: %d rpm: %f", isStopped(), diff --git a/firmware/controllers/sensors/sensors.mk b/firmware/controllers/sensors/sensors.mk index 2286c353d0..77dc10d0eb 100644 --- a/firmware/controllers/sensors/sensors.mk +++ b/firmware/controllers/sensors/sensors.mk @@ -11,6 +11,7 @@ CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cp $(PROJECT_DIR)/controllers/sensors/sensor_info_printing.cpp \ $(PROJECT_DIR)/controllers/sensors/functional_sensor.cpp \ $(PROJECT_DIR)/controllers/sensors/redundant_sensor.cpp \ + $(PROJECT_DIR)/controllers/sensors/redundant_ford_tps.cpp \ $(PROJECT_DIR)/controllers/sensors/AemXSeriesLambda.cpp \ $(PROJECT_DIR)/cotnrollers/sensors/flex_sensor.cpp \ $(PROJECT_DIR)/controllers/sensors/software_knock.cpp \ diff --git a/firmware/init/sensor/init_tps.cpp b/firmware/init/sensor/init_tps.cpp index f96b3056f9..bac07dd870 100644 --- a/firmware/init/sensor/init_tps.cpp +++ b/firmware/init/sensor/init_tps.cpp @@ -5,6 +5,7 @@ #include "error_handling.h" #include "functional_sensor.h" #include "redundant_sensor.h" +#include "redundant_ford_tps.h" #include "proxy_sensor.h" #include "linear_func.h" #include "tps.h" @@ -21,9 +22,14 @@ FunctionalSensor tpsSens1s(SensorType::Tps1Secondary, MS2NT(10)); FunctionalSensor tpsSens2p(SensorType::Tps2Primary, MS2NT(10)); FunctionalSensor tpsSens2s(SensorType::Tps2Secondary, MS2NT(10)); +// Used in case of "normal", non-Ford ETB TPS RedundantSensor tps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary); RedundantSensor tps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary); +// Used only in case of weird Ford-style ETB TPS +RedundantFordTps fordTps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary); +RedundantFordTps fordTps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary); + LinearFunc pedalFuncPrimary; LinearFunc pedalFuncSecondary; FunctionalSensor pedalSensorPrimary(SensorType::AcceleratorPedalPrimary, MS2NT(10)); @@ -81,12 +87,16 @@ static bool initTpsFunc(LinearFunc& func, FunctionalSensor& sensor, adc_channel_ return sensor.Register(); } -static void initTpsFuncAndRedund(RedundantSensor& redund, LinearFunc& func, FunctionalSensor& sensor, adc_channel_e channel, float closed, float open, float min, float max) { +static void initTpsFuncAndRedund(RedundantSensor& redund, RedundantFordTps* fordTps, bool isFordTps, LinearFunc& func, FunctionalSensor& sensor, adc_channel_e channel, float closed, float open, float min, float max) { bool hasSecond = initTpsFunc(func, sensor, channel, closed, open, min, max); - redund.configure(5.0f, !hasSecond); - - redund.Register(); + if (isFordTps && fordTps) { + fordTps->configure(5.0f, 52.6f); + fordTps->Register(); + } else { + redund.configure(5.0f, !hasSecond); + redund.Register(); + } } void initTps(DECLARE_CONFIG_PARAMETER_SIGNATURE) { @@ -94,12 +104,18 @@ void initTps(DECLARE_CONFIG_PARAMETER_SIGNATURE) { percent_t max = CONFIG(tpsErrorDetectionTooHigh); if (!CONFIG(consumeObdSensors)) { + // primary TPS sensors initTpsFunc(tpsFunc1p, tpsSens1p, CONFIG(tps1_1AdcChannel), CONFIG(tpsMin), CONFIG(tpsMax), min, max); - initTpsFuncAndRedund(tps1, tpsFunc1s, tpsSens1s, CONFIG(tps1_2AdcChannel), CONFIG(tps1SecondaryMin), CONFIG(tps1SecondaryMax), min, max); initTpsFunc(tpsFunc2p, tpsSens2p, CONFIG(tps2_1AdcChannel), CONFIG(tps2Min), CONFIG(tps2Max), min, max); - initTpsFuncAndRedund(tps2, tpsFunc2s, tpsSens2s, CONFIG(tps2_2AdcChannel), CONFIG(tps2SecondaryMin), CONFIG(tps2SecondaryMax), min, max); + + // Secondary TPS sensors (and redundant combining) + bool isFordTps = CONFIG(useFordRedundantTps); + initTpsFuncAndRedund(tps1, &fordTps1, isFordTps, tpsFunc1s, tpsSens1s, CONFIG(tps1_2AdcChannel), CONFIG(tps1SecondaryMin), CONFIG(tps1SecondaryMax), min, max); + initTpsFuncAndRedund(tps2, &fordTps2, isFordTps, tpsFunc2s, tpsSens2s, CONFIG(tps2_2AdcChannel), CONFIG(tps2SecondaryMin), CONFIG(tps2SecondaryMax), min, max); + + // Pedal sensors initTpsFunc(pedalFuncPrimary, pedalSensorPrimary, CONFIG(throttlePedalPositionAdcChannel), CONFIG(throttlePedalUpVoltage), CONFIG(throttlePedalWOTVoltage), min, max); - initTpsFuncAndRedund(pedal, pedalFuncSecondary, pedalSensorSecondary, CONFIG(throttlePedalPositionSecondAdcChannel), CONFIG(throttlePedalSecondaryUpVoltage), CONFIG(throttlePedalSecondaryWOTVoltage), min, max); + initTpsFuncAndRedund(pedal, nullptr, false, pedalFuncSecondary, pedalSensorSecondary, CONFIG(throttlePedalPositionSecondAdcChannel), CONFIG(throttlePedalSecondaryUpVoltage), CONFIG(throttlePedalSecondaryWOTVoltage), min, max); // TPS-like stuff that isn't actually a TPS initTpsFunc(wastegateFunc, wastegateSens, CONFIG(wastegatePositionSensor), CONFIG(wastegatePositionMin), CONFIG(wastegatePositionMax), min, max); diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 40644361d7..ff1b96929b 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -506,7 +506,7 @@ end_struct injector_s injector bit isForcedInduction; -bit unused_294_1; +bit useFordRedundantTps; bit isVerboseAuxPid1; bit unused_294_3; bit unused_294_4; diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index a1fe8cc393..b79d0cfc16 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -3491,6 +3491,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" field = "Ignition Math Logic @", ignMathCalculateAtIndex field = "MAP Averaging Logic @", mapAveragingSchedulingAtIndex field = "showHumanReadableWarning (affects Burn)", showHumanReadableWarning + field = "Ford redundant TPS mode", useFordRedundantTps help = helpGeneral, "rusEFI General Help" diff --git a/unit_tests/tests/sensor/redundant.cpp b/unit_tests/tests/sensor/redundant.cpp index eb2ddbf24b..11c84f5be4 100644 --- a/unit_tests/tests/sensor/redundant.cpp +++ b/unit_tests/tests/sensor/redundant.cpp @@ -1,4 +1,5 @@ #include "redundant_sensor.h" +#include "redundant_ford_tps.h" #include @@ -220,3 +221,143 @@ TEST_F(SensorRedundantIgnoreSecond, SetBothIgnoreSecond) EXPECT_FLOAT_EQ(result.Value, 74.0f); } } + +class SensorFordRedundantTps : public ::testing::Test +{ +protected: + RedundantFordTps dut; + MockSensor m1, m2; + + SensorFordRedundantTps() + : dut(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary) + , m1(SensorType::Tps1Primary) + , m2(SensorType::Tps1Secondary) + { + } + + void SetUp() override + { + Sensor::resetRegistry(); + + // Other tests verify registry function - don't re-test it here + ASSERT_TRUE(dut.Register()); + ASSERT_TRUE(m1.Register()); + ASSERT_TRUE(m2.Register()); + + dut.configure(5.0f, 50); + } + + void TearDown() override + { + Sensor::resetRegistry(); + } +}; + +TEST_F(SensorFordRedundantTps, SetOnlyOneSensor) +{ + // Don't set any sensors - expect invalid + { + auto result = dut.get(); + EXPECT_FALSE(result.Valid); + } + + // Set one sensor + m1.set(24.0f); + + // Should still be invalid - only one is set! + { + auto result = dut.get(); + EXPECT_FALSE(result.Valid); + } +} + +TEST_F(SensorFordRedundantTps, SetTwoSensors) +{ + // Don't set any sensors - expect invalid + { + auto result = dut.get(); + EXPECT_FALSE(result.Valid); + } + + // Set one sensor + m1.set(12.0f); + // Set the other sensor at double the first + m2.set(28.0f); + + // Should now be valid - and the average of the two input + { + auto result = dut.get(); + EXPECT_TRUE(result.Valid); + EXPECT_FLOAT_EQ(result.Value, 13.0f); + + EXPECT_TRUE(dut.isRedundant()); + } +} + +TEST_F(SensorFordRedundantTps, DifferenceNone) +{ + // Set both sensors to the same value + m1.set(10); + m2.set(20); + + // Expect valid, and 10 output + { + auto result = dut.get(); + EXPECT_TRUE(result.Valid); + EXPECT_FLOAT_EQ(result.Value, 10.0f); + } +} + +TEST_F(SensorFordRedundantTps, DifferenceNearLimit) +{ + // Set both sensors to nearly the limit (4.998 apart) + m1.set(7.501f); + m2.set(2 * 12.499f); + + // Expect valid, and 10 output + { + auto result = dut.get(); + EXPECT_TRUE(result.Valid); + EXPECT_FLOAT_EQ(result.Value, 10.0f); + } +} + +TEST_F(SensorFordRedundantTps, DifferenceOverLimit) +{ + // Set both sensors barely over the limit (5.002 apart) + m1.set(7.499f); + m2.set(2 * 12.501f); + + // Expect invalid + { + auto result = dut.get(); + EXPECT_FALSE(result.Valid); + } +} + +TEST_F(SensorFordRedundantTps, DifferenceOverLimitSwapped) +{ + // Now try it the other way (m1 > m2) + m1.set(12.501f); + m2.set(2 * 7.499f); + + // Expect invalid + { + auto result = dut.get(); + EXPECT_FALSE(result.Valid); + } +} + +TEST_F(SensorFordRedundantTps, HighRange) +{ + // Set the throttle like it's at 75% + m1.set(75); + m2.set(100); + + // expect valid, at 75% + { + auto result = dut.get(); + EXPECT_TRUE(result.Valid); + EXPECT_FLOAT_EQ(result.Value, 75.0f); + } +}