rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
electronic_throttle_impl.h
Go to the documentation of this file.
1/**
2 * @file electronic_throttle_impl.h
3 *
4 * @date Dec 7, 2013
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8#pragma once
9
10// include the "public" ETB interface
11#include "electronic_throttle.h"
12
13#include "sensor.h"
14#include "efi_pid.h"
15#include "error_accumulator.h"
18
19/**
20 * Hard code ETB update speed.
21 * Since this is a safety critical system with no real reason for a user to ever need to change the update rate,
22 * it's locked to 500hz, along with the ADC.
23 * https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem
24 */
25#define ETB_LOOP_FREQUENCY 500
26#define DEFAULT_ETB_PWM_FREQUENCY 800
27
29public:
30 bool init(dc_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D* pedalMap) override;
31 void setIdlePosition(percent_t pos) override;
32 void setWastegatePosition(percent_t pos) override;
33 void reset(const char *reason) override;
34
35 // Update the controller's state: read sensors, send output, etc
36 void update() override;
37
38 // Called when the configuration may have changed. Controller will
39 // reset if necessary.
40 void onConfigurationChange(pid_s* previousConfiguration);
41
42 // Print this throttle's status.
43 void showStatus();
44
45 // Helpers for individual parts of throttle control
46 expected<percent_t> observePlant() override;
47
48 expected<percent_t> getSetpoint() override;
49 expected<percent_t> getSetpointEtb();
50 expected<percent_t> getSetpointWastegate() const;
51 expected<percent_t> getSetpointIdleValve() const;
52
53 expected<percent_t> getOpenLoop(percent_t target) override;
54 expected<percent_t> getClosedLoop(percent_t setpoint, percent_t observation) override;
55 expected<percent_t> getClosedLoopAutotune(percent_t setpoint, percent_t actualThrottlePosition);
56
58
59 void checkJam(percent_t setpoint, percent_t observation);
60
61 void setOutput(expected<percent_t> outputValue) override;
62
63 // Used to inspect the internal PID controller's state
64 const pid_state_s& getPidState() const override { return m_pid; };
65
66 // Override if this throttle needs special per-throttle adjustment (bank-to-bank trim, for example)
67 virtual percent_t getThrottleTrim(float /*rpm*/, percent_t /*targetPosition*/) const {
68 return 0;
69 }
70
71 // pedal-based part of ETB target, without idle and other interventions
72 float getCurrentTarget() const override {
73 return etbCurrentTarget;
74 }
75
76 bool isEtbMode() const override {
77 return m_function == DC_Throttle1 || m_function == DC_Throttle2;
78 }
79
80 // Lua throttle adjustment
81 void setLuaAdjustment(percent_t adjustment) override;
82 float getLuaAdjustment() const;
83
84 float prevOutput = 0;
85
86protected:
87 bool hadTpsError = false;
88 bool hadPpsError = false;
89
90 DcMotor* getMotor() { return m_motor; }
91
92private:
95 DcMotor *m_motor = nullptr;
97 bool m_shouldResetPid = false;
98
100
101 /**
102 * @return true if OK, false if should be disabled
103 */
104 bool checkStatus();
105
107
108 // Pedal -> target map
110
111 float m_idlePosition = 0;
112
113 // This is set if automatic PID cal should be run
114 bool m_isAutotune = false;
115
116 // Autotune helpers
117 bool m_lastIsPositive = false;
119 float m_minCycleTps = 0;
120 float m_maxCycleTps = 0;
121 // Autotune measured parameters: gain and ultimate period
122 // These are set to correct order of magnitude starting points
123 // so we converge more quickly on the correct values
124 float m_a = 8;
125 float m_tu = 0.1f;
126
127#if EFI_TUNER_STUDIO
128 uint8_t m_autotuneCounter = 0;
130#endif
131
133
134 efitimeus_t lastTickUs;
135};
136
137void etbPidReset();
138
139class EtbController1 : public EtbController { };
140
142public:
147
148 percent_t getThrottleTrim(float rpm, percent_t /*targetPosition*/) const override;
149
150private:
152};
153
154template <typename TBase>
155class EtbImpl final : public TBase {
156private:
157 enum class ACPhase {
158 Stopped,
159
160 Start,
161
162 // Drive the motor open
163 Open,
164
165 // Drive the motor closed
166 Close,
167
168 // Write learned values to TS
173 };
174
175public:
176 template <typename... TArgs>
177 EtbImpl(TArgs&&... args) : TBase(std::forward<TArgs>(args)...) { }
178
179 void update() override {
180#if EFI_TUNER_STUDIO
181 if (m_benchTestActive) {
182 if (m_benchTestTimer.hasElapsedMs(300)) {
183 auto motor = TBase::getMotor();
184 if (motor) {
185 motor->disable("bench test");
186 }
187 m_benchTestActive = false;
188 efiPrintf("ETB bench test done");
189 }
190 } else if (m_autocalPhase != ACPhase::Stopped) {
191 ACPhase nextPhase = doAutocal(m_autocalPhase);
192
193 // if we changed phase, reset the phase timer
194 if (m_autocalPhase != nextPhase) {
195 m_autocalTimer.reset();
196 m_autocalPhase = nextPhase;
197 }
198 } else
199#endif /* EFI_TUNER_STUDIO */
200
201 {
202 TBase::update();
203 }
204 }
205
206 void startBenchTest() override {
207 auto motor = TBase::getMotor();
208 if (!motor) {
209 efiPrintf("ETB bench test: no motor configured");
210 return;
211 }
212 if (TBase::getFunction() != DC_Throttle1 && TBase::getFunction() != DC_Throttle2) {
213 efiPrintf("ETB bench test: not a throttle");
214 return;
215 }
216 motor->set(0.5f);
217 motor->enable();
218 m_benchTestTimer.reset();
219 m_benchTestActive = true;
220 efiPrintf("ETB bench test: opening for 300ms");
221 }
222
223 void autoCalibrateTps(bool reportToTs) override {
224 // Only auto calibrate throttles
225 if (TBase::getFunction() == DC_Throttle1 || TBase::getFunction() == DC_Throttle2 || TBase::getFunction() == DC_Wastegate) {
226 m_isAutocalTs = reportToTs;
228 }
229 }
230
232 // Don't allow if engine is running!
234 efiPrintf(" ****************** ERROR: Not while RPM ********************");
235 return ACPhase::Stopped;
236 }
237
238 auto motor = TBase::getMotor();
239 if (!motor) {
240 efiPrintf(" ****************** ERROR: No DC motor ********************");
241 return ACPhase::Stopped;
242 }
243
244 TBase::etbErrorCode = (uint8_t)EtbStatus::AutoCalibrate;
245
246 auto myFunction = TBase::getFunction();
247
248 switch (phase) {
249 case ACPhase::Start:
250 // Open the throttle
251 motor->set(0.5f);
252 motor->enable();
253 return ACPhase::Open;
254 case ACPhase::Open:
255 if (m_autocalTimer.hasElapsedMs(1000)) {
256 // Capture open position
259
260 // Next: close the throttle
261 motor->set(-0.5f);
262 return ACPhase::Close;
263 }
264 break;
265 case ACPhase::Close:
266 if (m_autocalTimer.hasElapsedMs(1000)) {
267 // Capture closed position
270
271 // Disable the motor, we're done
272 motor->disable("autotune");
273
274 // Check that the calibrate actually moved the throttle
275 if (std::abs(m_primaryMax - m_primaryMin) < 0.5f) {
276 firmwareError(ObdCode::OBD_TPS_Configuration, "Auto calibrate failed, check your wiring!\r\nClosed voltage: %.1fv Open voltage: %.1fv", m_primaryMin, m_primaryMax);
277 return ACPhase::Stopped;
278 }
279
280 if (!m_isAutocalTs) {
281 // configuration on ECU side is in ADC, TS sees Volts, see "tps_limit_t"
282 if (myFunction == DC_Throttle1) {
287 } else if (myFunction == DC_Throttle2) {
292 } else if (myFunction == DC_Wastegate) {
295 } else {
296 /* TODO */
297 }
298 return ACPhase::Stopped;
299 }
300
301 // Next: start transmitting results
304 }
305 break;
307 if (tsCalibrationIsIdle()) {
310 }
311 break;
313 if (tsCalibrationIsIdle()) {
315 // No secondary sensor?
317 return ACPhase::Stopped;
319 }
320 break;
322 if (tsCalibrationIsIdle()) {
325 }
326 break;
328 if (tsCalibrationIsIdle()) {
329 // Done!
330 return ACPhase::Stopped;
331 }
332 break;
333 case ACPhase::Stopped: break;
334 }
335
336 // by default, stay in the same phase
337 return phase;
338 }
339
340private:
343 // Report calibrated values to TS, if false - set directly to config
345
346 bool m_benchTestActive = false;
348
353};
354
357
358static constexpr electronic_throttle_s const* etbData1_ptr = &etb1;
359static constexpr electronic_throttle_s const* etbData2_ptr = &etb2;
360
361// To be used by LogFields, for LiveData fragments see non constexpr getLiveData() in electronic_throttle.cpp
362template<typename T, size_t idx>
363consteval electronic_throttle_s const* getLiveDataConstexpr() requires std::is_same_v<T, electronic_throttle_s> {
364#if EFI_ELECTRONIC_THROTTLE_BODY
365
366 static_assert(idx < ETB_COUNT);
367
368 if constexpr (idx == 0) {
369 return etbData1_ptr;
370 }
371
372 return etbData2_ptr;
373#else
374 return nullptr;
375#endif
376}
Brushed or brushless DC motor interface.
Definition dc_motor.h:20
const ValueProvider3D & m_throttle2Trim
percent_t getThrottleTrim(float rpm, percent_t) const override
EtbController2(const ValueProvider3D &throttle2TrimTable)
void setWastegatePosition(percent_t pos) override
float getLuaAdjustment() const
bool isEtbMode() const override
const pid_state_s & getPidState() const override
expected< percent_t > getSetpointIdleValve() const
expected< percent_t > getSetpointEtb()
void setIdlePosition(percent_t pos) override
void checkJam(percent_t setpoint, percent_t observation)
expected< percent_t > getSetpoint() override
ErrorAccumulator m_targetErrorAccumulator
virtual percent_t getThrottleTrim(float, percent_t) const
expected< percent_t > getClosedLoopAutotune(percent_t setpoint, percent_t actualThrottlePosition)
void update() override
dc_function_e getFunction() const
bool init(dc_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D *pedalMap) override
void setLuaAdjustment(percent_t adjustment) override
expected< percent_t > getClosedLoop(percent_t setpoint, percent_t observation) override
expected< percent_t > getOpenLoop(percent_t target) override
void reset(const char *reason) override
void onConfigurationChange(pid_s *previousConfiguration)
const ValueProvider3D * m_pedalProvider
expected< percent_t > observePlant() override
expected< percent_t > getSetpointWastegate() const
float getCurrentTarget() const override
void setOutput(expected< percent_t > outputValue) override
void autoCalibrateTps(bool reportToTs) override
EtbImpl(TArgs &&... args)
ACPhase doAutocal(ACPhase phase)
void startBenchTest() override
void update() override
Definition efi_pid.h:34
virtual float getRaw() const
Definition sensor.h:152
static float getOrZero(SensorType type)
Definition sensor.h:87
static TsCalMode functionToCalModePriMin(dc_function_e func)
static Map3D< ETB2_TRIM_RPM_SIZE, ETB2_TRIM_SIZE, int8_t, uint8_t, uint8_t > throttle2TrimTable
static TsCalMode functionToCalModeSecMin(dc_function_e func)
static SensorType functionToTpsSensorPrimary(dc_function_e func)
static TsCalMode functionToCalModePriMax(dc_function_e func)
static SensorType functionToTpsSensorSecondary(dc_function_e func)
static TsCalMode functionToCalModeSecMax(dc_function_e func)
static constexpr electronic_throttle_s const * etbData2_ptr
static constexpr electronic_throttle_s const * etbData1_ptr
consteval electronic_throttle_s const * getLiveDataConstexpr()
void etbPidReset()
EtbImpl< EtbController1 > etb1
EtbImpl< EtbController2 > etb2
static constexpr engine_configuration_s * engineConfiguration
void firmwareError(ObdCode code, const char *fmt,...)
@ OBD_TPS_Configuration
dc_function_e
float percent_t
Base class for sensors. Inherit this class to implement a new type of sensor.
SensorType
Definition sensor_type.h:18
constexpr int convertVoltageTo10bitADC(float voltage)
Definition tps.h:21
void tsCalibrationSetData(TsCalMode mode, float value, float value2, float timeoutMs)
maintainConstantValue implementation header