2015-07-10 06:01:56 -07:00
|
|
|
|
/**
|
|
|
|
|
* @file electronic_throttle.cpp
|
2019-04-24 17:47:38 -07:00
|
|
|
|
* @brief Electronic Throttle driver
|
2015-07-10 06:01:56 -07:00
|
|
|
|
*
|
2020-02-22 20:18:02 -08:00
|
|
|
|
* @see test test_etb.cpp
|
|
|
|
|
*
|
2024-09-24 06:36:07 -07:00
|
|
|
|
* PPS=pedal position sensor=AcceleratorPedal
|
|
|
|
|
* TPS=throttle position sensor, this one is inside ETB=electronic throttle body
|
2019-12-30 07:25:52 -08:00
|
|
|
|
*
|
2020-04-29 15:41:40 -07:00
|
|
|
|
* Limited user documentation at https://github.com/rusefi/rusefi/wiki/HOWTO_electronic_throttle_body
|
2019-12-30 07:25:52 -08:00
|
|
|
|
*
|
2017-01-27 18:04:23 -08:00
|
|
|
|
*
|
2017-05-24 20:53:07 -07:00
|
|
|
|
* ETB is controlled according to pedal position input (pedal position sensor is a potentiometer)
|
2019-02-10 16:52:06 -08:00
|
|
|
|
* pedal 0% means pedal not pressed / idle
|
2017-05-24 20:53:07 -07:00
|
|
|
|
* pedal 100% means pedal all the way down
|
2017-05-25 09:09:07 -07:00
|
|
|
|
* (not TPS - not the one you can calibrate in TunerStudio)
|
2017-05-24 20:53:07 -07:00
|
|
|
|
*
|
|
|
|
|
*
|
2017-05-25 09:09:07 -07:00
|
|
|
|
* See also pid.cpp
|
|
|
|
|
*
|
2017-05-29 20:36:08 -07:00
|
|
|
|
* Relevant console commands:
|
|
|
|
|
*
|
2015-07-10 06:01:56 -07:00
|
|
|
|
* @date Dec 7, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
|
*
|
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
|
*
|
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
|
#include "pch.h"
|
2019-04-09 19:52:03 -07:00
|
|
|
|
|
2022-11-30 16:29:22 -08:00
|
|
|
|
#include "electronic_throttle_impl.h"
|
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
|
#if EFI_ELECTRONIC_THROTTLE_BODY
|
2019-04-09 19:52:03 -07:00
|
|
|
|
|
2019-03-29 06:11:13 -07:00
|
|
|
|
#include "dc_motor.h"
|
2020-03-03 14:56:50 -08:00
|
|
|
|
#include "dc_motors.h"
|
2022-10-29 20:04:24 -07:00
|
|
|
|
#include "defaults.h"
|
2024-10-03 17:00:01 -07:00
|
|
|
|
#include "tunerstudio.h"
|
2019-07-05 16:00:44 -07:00
|
|
|
|
|
|
|
|
|
#if defined(HAS_OS_ACCESS)
|
|
|
|
|
#error "Unexpected OS ACCESS HERE"
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-05-04 14:05:08 -07:00
|
|
|
|
#if HW_PROTEUS
|
|
|
|
|
#include "proteus_meta.h"
|
|
|
|
|
#endif // HW_PROTEUS
|
|
|
|
|
|
2019-11-21 10:35:57 -08:00
|
|
|
|
#ifndef ETB_MAX_COUNT
|
2019-07-05 16:00:44 -07:00
|
|
|
|
#define ETB_MAX_COUNT 2
|
2019-11-21 10:35:57 -08:00
|
|
|
|
#endif /* ETB_MAX_COUNT */
|
2019-07-05 16:00:44 -07:00
|
|
|
|
|
2024-05-03 19:13:30 -07:00
|
|
|
|
static pedal2tps_t pedal2tpsMap{"p2t"};
|
|
|
|
|
static Map3D<ETB2_TRIM_SIZE, ETB2_TRIM_SIZE, int8_t, uint8_t, uint8_t> throttle2TrimTable{"t2t"};
|
|
|
|
|
static Map3D<TRACTION_CONTROL_ETB_DROP_SIZE, TRACTION_CONTROL_ETB_DROP_SIZE, int8_t, uint16_t, uint8_t> tcEtbDropTable{"tce"};
|
2019-02-10 16:52:06 -08:00
|
|
|
|
|
2021-03-08 16:18:35 -08:00
|
|
|
|
constexpr float etbPeriodSeconds = 1.0f / ETB_LOOP_FREQUENCY;
|
|
|
|
|
|
2023-07-02 09:14:54 -07:00
|
|
|
|
//static bool startupPositionError = false;
|
2019-09-22 20:28:11 -07:00
|
|
|
|
|
2023-10-30 19:13:29 -07:00
|
|
|
|
//#define STARTUP_NEUTRAL_POSITION_ERROR_THRESHOLD 5
|
2019-09-22 20:28:11 -07:00
|
|
|
|
|
2020-12-25 21:57:23 -08:00
|
|
|
|
static const float hardCodedetbHitachiBiasBins[8] = {0.0, 19.0, 21.0, 22.0, 23.0, 25.0, 30.0, 100.0};
|
|
|
|
|
|
|
|
|
|
static const float hardCodedetbHitachiBiasValues[8] = {-18.0, -17.0, -15.0, 0.0, 16.0, 20.0, 20.0, 20.0};
|
|
|
|
|
|
|
|
|
|
/* Generated by TS2C on Thu Aug 20 21:10:02 EDT 2020*/
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setHitachiEtbBiasBins() {
|
2022-05-02 02:04:58 -07:00
|
|
|
|
copyArray(config->etbBiasBins, hardCodedetbHitachiBiasBins);
|
|
|
|
|
copyArray(config->etbBiasValues, hardCodedetbHitachiBiasValues);
|
2020-12-25 21:57:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static SensorType functionToPositionSensor(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch(func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return SensorType::Tps1;
|
|
|
|
|
case DC_Throttle2: return SensorType::Tps2;
|
|
|
|
|
case DC_IdleValve: return SensorType::IdlePosition;
|
|
|
|
|
case DC_Wastegate: return SensorType::WastegatePosition;
|
2020-09-28 13:33:07 -07:00
|
|
|
|
default: return SensorType::Invalid;
|
2020-04-02 18:33:49 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-22 10:41:43 -08:00
|
|
|
|
static SensorType functionToTpsSensor(dc_function_e func) {
|
|
|
|
|
switch(func) {
|
|
|
|
|
case DC_Throttle1: return SensorType::Tps1;
|
|
|
|
|
default: return SensorType::Tps2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static SensorType functionToTpsSensorPrimary(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch(func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return SensorType::Tps1Primary;
|
2020-05-18 11:32:00 -07:00
|
|
|
|
default: return SensorType::Tps2Primary;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static SensorType functionToTpsSensorSecondary(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch(func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return SensorType::Tps1Secondary;
|
2020-05-18 11:32:00 -07:00
|
|
|
|
default: return SensorType::Tps2Secondary;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-23 20:46:33 -07:00
|
|
|
|
#if EFI_TUNER_STUDIO
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static TsCalMode functionToCalModePriMin(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch (func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return TsCalMode::Tps1Min;
|
2020-08-23 20:41:35 -07:00
|
|
|
|
default: return TsCalMode::Tps2Min;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static TsCalMode functionToCalModePriMax(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch (func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return TsCalMode::Tps1Max;
|
2020-08-23 20:41:35 -07:00
|
|
|
|
default: return TsCalMode::Tps2Max;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static TsCalMode functionToCalModeSecMin(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch (func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return TsCalMode::Tps1SecondaryMin;
|
2020-08-23 20:41:35 -07:00
|
|
|
|
default: return TsCalMode::Tps2SecondaryMin;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 19:39:45 -08:00
|
|
|
|
static TsCalMode functionToCalModeSecMax(dc_function_e func) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch (func) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1: return TsCalMode::Tps1SecondaryMax;
|
2020-08-23 20:41:35 -07:00
|
|
|
|
default: return TsCalMode::Tps2SecondaryMax;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-23 20:46:33 -07:00
|
|
|
|
#endif // EFI_TUNER_STUDIO
|
2020-08-23 20:41:35 -07:00
|
|
|
|
|
2019-05-04 21:42:50 -07:00
|
|
|
|
#define ETB_DUTY_LIMIT 0.9
|
2019-07-12 04:48:28 -07:00
|
|
|
|
// this macro clamps both positive and negative percentages from about -100% to 100%
|
2020-04-20 10:52:20 -07:00
|
|
|
|
#define ETB_PERCENT_TO_DUTY(x) (clampF(-ETB_DUTY_LIMIT, 0.01f * (x), ETB_DUTY_LIMIT))
|
2019-02-27 14:54:25 -08:00
|
|
|
|
|
2024-10-26 09:00:41 -07:00
|
|
|
|
PUBLIC_API_WEAK bool isBoardAllowingLackOfPps() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-11 17:44:11 -08:00
|
|
|
|
bool EtbController::init(dc_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D* pedalProvider) {
|
2024-11-08 15:53:40 -08:00
|
|
|
|
state = (uint8_t)EtbState::InInit;
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (function == DC_None) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
// if not configured, don't init.
|
2024-11-08 15:53:40 -08:00
|
|
|
|
state = (uint8_t)EtbState::NotEbt;
|
2023-02-14 03:38:24 -08:00
|
|
|
|
etbErrorCode = (int8_t)TpsState::None;
|
2020-09-28 13:33:07 -07:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_function = function;
|
|
|
|
|
m_positionSensor = functionToPositionSensor(function);
|
2020-12-08 03:24:20 -08:00
|
|
|
|
|
|
|
|
|
// If we are a throttle, require redundant TPS sensor
|
2023-01-17 01:14:30 -08:00
|
|
|
|
if (isEtbMode()) {
|
2021-08-11 14:45:44 -07:00
|
|
|
|
// If no sensor is configured for this throttle, skip initialization.
|
2023-02-22 10:41:43 -08:00
|
|
|
|
if (!Sensor::hasSensor(functionToTpsSensor(function))) {
|
2022-11-29 19:39:55 -08:00
|
|
|
|
etbErrorCode = (int8_t)TpsState::TpsError;
|
2021-08-11 14:45:44 -07:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-08 03:24:20 -08:00
|
|
|
|
if (!Sensor::isRedundant(m_positionSensor)) {
|
2022-11-29 19:39:55 -08:00
|
|
|
|
etbErrorCode = (int8_t)TpsState::Redundancy;
|
2020-12-08 03:24:20 -08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 16:37:04 -08:00
|
|
|
|
m_motor = motor;
|
|
|
|
|
m_pid.initPidClass(pidParameters);
|
2024-06-17 18:08:10 -07:00
|
|
|
|
m_pedalProvider = pedalProvider;
|
2020-09-28 13:33:07 -07:00
|
|
|
|
|
2020-10-14 19:02:09 -07:00
|
|
|
|
reset();
|
|
|
|
|
|
2024-11-08 15:53:40 -08:00
|
|
|
|
state = (uint8_t)EtbState::SuccessfulInit;
|
2020-09-28 13:33:07 -07:00
|
|
|
|
return true;
|
2019-12-10 16:37:04 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EtbController::reset() {
|
|
|
|
|
m_shouldResetPid = true;
|
2022-11-30 19:20:09 -08:00
|
|
|
|
etbTpsErrorCounter = 0;
|
|
|
|
|
etbPpsErrorCounter = 0;
|
2019-12-10 16:37:04 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EtbController::onConfigurationChange(pid_s* previousConfiguration) {
|
2020-04-28 13:52:40 -07:00
|
|
|
|
if (m_motor && !m_pid.isSame(previousConfiguration)) {
|
2019-12-10 16:37:04 -08:00
|
|
|
|
m_shouldResetPid = true;
|
|
|
|
|
}
|
2023-06-01 11:09:30 -07:00
|
|
|
|
doInitElectronicThrottle();
|
2019-12-10 16:37:04 -08:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 17:02:32 -07:00
|
|
|
|
void EtbController::showStatus() {
|
|
|
|
|
m_pid.showPidStatus("ETB");
|
2019-11-22 17:53:54 -08:00
|
|
|
|
}
|
2019-11-20 21:49:38 -08:00
|
|
|
|
|
2023-10-19 18:06:09 -07:00
|
|
|
|
expected<percent_t> EtbController::observePlant() {
|
2024-11-08 17:21:59 -08:00
|
|
|
|
expected<percent_t> plant = Sensor::get(m_positionSensor);
|
2024-11-08 17:37:17 -08:00
|
|
|
|
validPlantPosition = plant.Valid;
|
2024-11-08 17:21:59 -08:00
|
|
|
|
return plant;
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
2019-09-22 20:28:11 -07:00
|
|
|
|
|
2020-04-20 13:26:35 -07:00
|
|
|
|
void EtbController::setIdlePosition(percent_t pos) {
|
|
|
|
|
m_idlePosition = pos;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-18 18:57:04 -07:00
|
|
|
|
void EtbController::setWastegatePosition(percent_t pos) {
|
|
|
|
|
m_wastegatePosition = pos;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-23 12:52:43 -08:00
|
|
|
|
expected<percent_t> EtbController::getSetpoint() {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
switch (m_function) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Throttle1:
|
|
|
|
|
case DC_Throttle2:
|
2020-09-28 13:33:07 -07:00
|
|
|
|
return getSetpointEtb();
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_IdleValve:
|
2020-09-28 13:33:07 -07:00
|
|
|
|
return getSetpointIdleValve();
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Wastegate:
|
2023-02-17 19:17:09 -08:00
|
|
|
|
return getSetpointWastegate();
|
2020-09-28 13:33:07 -07:00
|
|
|
|
default:
|
|
|
|
|
return unexpected;
|
2019-11-22 17:53:54 -08:00
|
|
|
|
}
|
2020-09-28 13:33:07 -07:00
|
|
|
|
}
|
2019-04-26 10:46:58 -07:00
|
|
|
|
|
2020-09-28 13:33:07 -07:00
|
|
|
|
expected<percent_t> EtbController::getSetpointIdleValve() const {
|
2020-07-26 02:55:35 -07:00
|
|
|
|
// VW ETB idle mode uses an ETB only for idle (a mini-ETB sets the lower stop, and a normal cable
|
|
|
|
|
// can pull the throttle up off the stop.), so we directly control the throttle with the idle position.
|
2023-01-10 12:31:04 -08:00
|
|
|
|
#if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.etbTarget = m_idlePosition;
|
2020-07-26 12:07:45 -07:00
|
|
|
|
#endif // EFI_TUNER_STUDIO
|
2024-04-06 06:00:15 -07:00
|
|
|
|
return clampPercentValue(m_idlePosition);
|
2020-09-28 13:33:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-17 19:17:09 -08:00
|
|
|
|
expected<percent_t> EtbController::getSetpointWastegate() const {
|
2024-04-06 06:00:15 -07:00
|
|
|
|
return clampPercentValue(m_wastegatePosition);
|
2020-09-28 13:33:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 05:23:14 -07:00
|
|
|
|
float getSanitizedPedal() {
|
|
|
|
|
auto pedalPosition = Sensor::get(SensorType::AcceleratorPedal);
|
|
|
|
|
// If the pedal has failed, just use 0 position.
|
|
|
|
|
// This is safer than disabling throttle control - we can at least push the throttle closed
|
|
|
|
|
// and let the engine idle.
|
|
|
|
|
return clampPercentValue(pedalPosition.value_or(0));
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-27 09:36:35 -07:00
|
|
|
|
PUBLIC_API_WEAK float boardAdjustEtbTarget(float currentEtbTarget) {
|
2024-07-06 10:02:45 -07:00
|
|
|
|
return currentEtbTarget;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-14 12:25:01 -07:00
|
|
|
|
expected<percent_t> EtbController::getSetpointEtb() {
|
2021-03-15 05:54:55 -07:00
|
|
|
|
// Autotune runs with 50% target position
|
|
|
|
|
if (m_isAutotune) {
|
|
|
|
|
return 50.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-02 09:14:54 -07:00
|
|
|
|
// // A few extra preconditions if throttle control is invalid
|
|
|
|
|
// if (startupPositionError) {
|
|
|
|
|
// return unexpected;
|
|
|
|
|
// }
|
2020-07-26 02:55:35 -07:00
|
|
|
|
|
2020-04-20 11:34:45 -07:00
|
|
|
|
// If the pedal map hasn't been set, we can't provide a setpoint.
|
2024-06-17 18:08:10 -07:00
|
|
|
|
if (!m_pedalProvider) {
|
2024-11-08 15:24:56 -08:00
|
|
|
|
state = (uint8_t)EtbState::NoPedal;
|
2020-04-20 11:34:45 -07:00
|
|
|
|
return unexpected;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 05:23:14 -07:00
|
|
|
|
float sanitizedPedal = getSanitizedPedal();
|
2023-12-18 13:27:44 -08:00
|
|
|
|
|
2022-01-20 19:40:15 -08:00
|
|
|
|
float rpm = Sensor::getOrZero(SensorType::Rpm);
|
2024-06-17 18:08:10 -07:00
|
|
|
|
etbCurrentTarget = m_pedalProvider->getValue(rpm, sanitizedPedal);
|
2020-04-20 13:26:35 -07:00
|
|
|
|
|
2024-04-06 06:00:15 -07:00
|
|
|
|
percent_t etbIdlePosition = clampPercentValue(m_idlePosition);
|
2021-12-26 09:33:32 -08:00
|
|
|
|
percent_t etbIdleAddition = PERCENT_DIV * engineConfiguration->etbIdleThrottleRange * etbIdlePosition;
|
2019-11-22 17:53:54 -08:00
|
|
|
|
|
2020-04-20 14:29:03 -07:00
|
|
|
|
// Interpolate so that the idle adder just "compresses" the throttle's range upward.
|
|
|
|
|
// [0, 100] -> [idle, 100]
|
|
|
|
|
// 0% target from table -> idle position as target
|
|
|
|
|
// 100% target from table -> 100% target position
|
2024-06-17 18:28:57 -07:00
|
|
|
|
targetWithIdlePosition = interpolateClamped(0, etbIdleAddition, 100, 100, etbCurrentTarget);
|
2020-04-19 14:18:47 -07:00
|
|
|
|
|
2024-07-06 10:02:45 -07:00
|
|
|
|
percent_t targetPosition = boardAdjustEtbTarget(targetWithIdlePosition + getLuaAdjustment());
|
2024-09-03 06:49:59 -07:00
|
|
|
|
// just an additional logging data point
|
|
|
|
|
adjustedEtbTarget = targetPosition;
|
2022-03-15 17:04:49 -07:00
|
|
|
|
|
2023-12-18 13:27:44 -08:00
|
|
|
|
#if EFI_ANTILAG_SYSTEM
|
2023-06-01 11:09:30 -07:00
|
|
|
|
if (engine->antilagController.isAntilagCondition) {
|
|
|
|
|
targetPosition += engineConfiguration->ALSEtbAdd;
|
|
|
|
|
}
|
2022-12-24 06:41:34 -08:00
|
|
|
|
#endif /* EFI_ANTILAG_SYSTEM */
|
|
|
|
|
|
2023-12-31 15:04:39 -08:00
|
|
|
|
float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed);
|
|
|
|
|
float wheelSlip = Sensor::getOrZero(SensorType::WheelSlipRatio);
|
2024-03-04 15:23:48 -08:00
|
|
|
|
tcEtbDrop = tcEtbDropTable.getValue(wheelSlip, vehicleSpeed);
|
2023-12-31 15:04:39 -08:00
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
// Apply any adjustment that this throttle alone needs
|
|
|
|
|
// Clamped to +-10 to prevent anything too wild
|
2022-04-14 12:25:01 -07:00
|
|
|
|
trim = clampF(-10, getThrottleTrim(rpm, targetPosition), 10);
|
2023-12-31 15:04:39 -08:00
|
|
|
|
targetPosition += trim + tcEtbDrop;
|
2022-03-15 17:04:49 -07:00
|
|
|
|
|
2022-07-09 19:46:28 -07:00
|
|
|
|
// Clamp before rev limiter to avoid ineffective rev limit due to crazy out of range position target
|
2024-04-06 06:00:15 -07:00
|
|
|
|
targetPosition = clampPercentValue(targetPosition);
|
2022-07-09 19:46:28 -07:00
|
|
|
|
|
2021-06-16 05:44:48 -07:00
|
|
|
|
// Lastly, apply ETB rev limiter
|
2021-11-17 00:54:21 -08:00
|
|
|
|
auto etbRpmLimit = engineConfiguration->etbRevLimitStart;
|
2021-06-16 05:44:48 -07:00
|
|
|
|
if (etbRpmLimit != 0) {
|
2021-11-17 00:54:21 -08:00
|
|
|
|
auto fullyLimitedRpm = etbRpmLimit + engineConfiguration->etbRevLimitRange;
|
2022-08-25 17:49:21 -07:00
|
|
|
|
|
|
|
|
|
float targetPositionBefore = targetPosition;
|
2021-06-16 05:44:48 -07:00
|
|
|
|
// Linearly taper throttle to closed from the limit across the range
|
|
|
|
|
targetPosition = interpolateClamped(etbRpmLimit, targetPosition, fullyLimitedRpm, 0, rpm);
|
2022-08-25 17:49:21 -07:00
|
|
|
|
|
|
|
|
|
// rev limit active if the position was changed by rev limiter
|
2024-09-24 23:47:37 -07:00
|
|
|
|
etbRevLimitActive = std::abs(targetPosition - targetPositionBefore) > 0.1f;
|
2021-06-16 05:44:48 -07:00
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
2022-05-02 02:24:50 -07:00
|
|
|
|
float minPosition = engineConfiguration->etbMinimumPosition;
|
|
|
|
|
|
2021-11-05 15:16:19 -07:00
|
|
|
|
// Keep the throttle just barely off the lower stop, and less than the user-configured maximum
|
2021-11-17 00:54:21 -08:00
|
|
|
|
float maxPosition = engineConfiguration->etbMaximumPosition;
|
2023-12-25 17:50:47 -08:00
|
|
|
|
// Don't allow max position over 100
|
2024-09-25 14:00:33 -07:00
|
|
|
|
maxPosition = std::min(maxPosition, 100.0f);
|
2021-11-05 15:16:19 -07:00
|
|
|
|
|
2022-05-02 02:24:50 -07:00
|
|
|
|
targetPosition = clampF(minPosition, targetPosition, maxPosition);
|
2022-11-22 17:20:45 -08:00
|
|
|
|
etbCurrentAdjustedTarget = targetPosition;
|
2022-03-15 17:04:49 -07:00
|
|
|
|
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (m_function == DC_Throttle1) {
|
2022-03-15 17:04:49 -07:00
|
|
|
|
engine->outputChannels.etbTarget = targetPosition;
|
|
|
|
|
}
|
|
|
|
|
#endif // EFI_TUNER_STUDIO
|
|
|
|
|
|
|
|
|
|
return targetPosition;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 19:46:28 -07:00
|
|
|
|
void EtbController::setLuaAdjustment(float adjustment) {
|
|
|
|
|
luaAdjustment = adjustment;
|
|
|
|
|
m_luaAdjustmentTimer.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-15 15:17:57 -07:00
|
|
|
|
/**
|
|
|
|
|
* positive adjustment opens TPS, negative closes TPS
|
|
|
|
|
*/
|
2022-07-09 19:46:28 -07:00
|
|
|
|
float EtbController::getLuaAdjustment() const {
|
|
|
|
|
// If the lua position hasn't been set in 0.2 second, don't adjust!
|
|
|
|
|
// This avoids a stuck throttle due to hung/rogue/etc Lua script
|
|
|
|
|
if (m_luaAdjustmentTimer.getElapsedSeconds() > 0.2f) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
return luaAdjustment;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-28 05:28:20 -07:00
|
|
|
|
percent_t EtbController2::getThrottleTrim(float rpm, percent_t targetPosition) const {
|
|
|
|
|
return m_throttle2Trim.getValue(rpm, targetPosition);
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
2017-11-16 11:44:34 -08:00
|
|
|
|
|
2021-11-23 12:52:43 -08:00
|
|
|
|
expected<percent_t> EtbController::getOpenLoop(percent_t target) {
|
2020-11-19 17:51:30 -08:00
|
|
|
|
// Don't apply open loop for wastegate/idle valve, only real ETB
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (m_function != DC_Wastegate
|
|
|
|
|
&& m_function != DC_IdleValve) {
|
2022-06-29 00:27:51 -07:00
|
|
|
|
etbFeedForward = interpolate2d(target, config->etbBiasBins, config->etbBiasValues);
|
2022-06-29 00:33:06 -07:00
|
|
|
|
} else {
|
2023-06-01 11:09:30 -07:00
|
|
|
|
etbFeedForward = 0;
|
2020-11-19 17:51:30 -08:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 00:27:51 -07:00
|
|
|
|
return etbFeedForward;
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 05:54:55 -07:00
|
|
|
|
expected<percent_t> EtbController::getClosedLoopAutotune(percent_t target, percent_t actualThrottlePosition) {
|
|
|
|
|
// Estimate gain at current position - this should be well away from the spring and in the linear region
|
|
|
|
|
// GetSetpoint sets this to 50%
|
|
|
|
|
bool isPositive = actualThrottlePosition > target;
|
2020-04-22 19:22:28 -07:00
|
|
|
|
|
|
|
|
|
float autotuneAmplitude = 20;
|
|
|
|
|
|
|
|
|
|
// End of cycle - record & reset
|
|
|
|
|
if (!isPositive && m_lastIsPositive) {
|
|
|
|
|
efitick_t now = getTimeNowNt();
|
|
|
|
|
|
|
|
|
|
// Determine period
|
2024-04-25 15:07:21 -07:00
|
|
|
|
float tu = m_autotuneCycleStart.getElapsedSecondsAndReset(now);
|
2020-04-22 19:22:28 -07:00
|
|
|
|
|
|
|
|
|
// Determine amplitude
|
|
|
|
|
float a = m_maxCycleTps - m_minCycleTps;
|
|
|
|
|
|
|
|
|
|
// Filter - it's pretty noisy since the ultimate period is not very many loop periods
|
|
|
|
|
constexpr float alpha = 0.05;
|
|
|
|
|
m_a = alpha * a + (1 - alpha) * m_a;
|
|
|
|
|
m_tu = alpha * tu + (1 - alpha) * m_tu;
|
|
|
|
|
|
|
|
|
|
// Reset bounds
|
|
|
|
|
m_minCycleTps = 100;
|
|
|
|
|
m_maxCycleTps = 0;
|
|
|
|
|
|
|
|
|
|
// Math is for Åström–Hägglund (relay) auto tuning
|
|
|
|
|
// https://warwick.ac.uk/fac/cross_fac/iatl/reinvention/archive/volume5issue2/hornsey
|
|
|
|
|
|
|
|
|
|
// Publish to TS state
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
2020-05-06 05:39:02 -07:00
|
|
|
|
// Amplitude of input (duty cycle %)
|
|
|
|
|
float b = 2 * autotuneAmplitude;
|
|
|
|
|
|
|
|
|
|
// Ultimate gain per A-H relay tuning rule
|
2022-01-14 18:18:51 -08:00
|
|
|
|
float ku = 4 * b / (CONST_PI * m_a);
|
2020-05-06 05:39:02 -07:00
|
|
|
|
|
2023-12-18 13:27:44 -08:00
|
|
|
|
// The multipliers below are somewhere near the "no overshoot"
|
2020-05-06 05:39:02 -07:00
|
|
|
|
// and "some overshoot" flavors of the Ziegler-Nichols method
|
|
|
|
|
// Kp
|
|
|
|
|
float kp = 0.35f * ku;
|
|
|
|
|
float ki = 0.25f * ku / m_tu;
|
|
|
|
|
float kd = 0.08f * ku * m_tu;
|
|
|
|
|
|
|
|
|
|
// Every 5 cycles (of the throttle), cycle to the next value
|
2023-02-13 07:31:37 -08:00
|
|
|
|
if (m_autotuneCounter >= 5) {
|
2020-05-06 05:39:02 -07:00
|
|
|
|
m_autotuneCounter = 0;
|
2023-02-13 07:31:37 -08:00
|
|
|
|
m_autotuneCurrentParam = (m_autotuneCurrentParam + 1) % 3; // three ETB calibs: P-I-D
|
2020-05-06 05:39:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_autotuneCounter++;
|
|
|
|
|
|
|
|
|
|
// Multiplex 3 signals on to the {mode, value} format
|
2023-02-13 07:31:37 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)static_cast<TsCalMode>((uint8_t)TsCalMode::EtbKp + m_autotuneCurrentParam);
|
2020-05-06 05:39:02 -07:00
|
|
|
|
|
|
|
|
|
switch (m_autotuneCurrentParam) {
|
|
|
|
|
case 0:
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationValue = kp;
|
2020-05-06 05:39:02 -07:00
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationValue = ki;
|
2020-05-06 05:39:02 -07:00
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationValue = kd;
|
2020-05-06 05:39:02 -07:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Also output to debug channels if configured
|
2020-04-22 19:22:28 -07:00
|
|
|
|
if (engineConfiguration->debugMode == DBG_ETB_AUTOTUNE) {
|
|
|
|
|
// a - amplitude of output (TPS %)
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.debugFloatField1 = m_a;
|
2020-04-22 19:22:28 -07:00
|
|
|
|
// b - amplitude of input (Duty cycle %)
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.debugFloatField2 = b;
|
2020-04-22 19:22:28 -07:00
|
|
|
|
// Tu - oscillation period (seconds)
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.debugFloatField3 = m_tu;
|
2020-04-22 19:22:28 -07:00
|
|
|
|
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.debugFloatField4 = ku;
|
|
|
|
|
engine->outputChannels.debugFloatField5 = kp;
|
|
|
|
|
engine->outputChannels.debugFloatField6 = ki;
|
|
|
|
|
engine->outputChannels.debugFloatField7 = kd;
|
2020-04-22 19:22:28 -07:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_lastIsPositive = isPositive;
|
|
|
|
|
|
|
|
|
|
// Find the min/max of each cycle
|
|
|
|
|
if (actualThrottlePosition < m_minCycleTps) {
|
|
|
|
|
m_minCycleTps = actualThrottlePosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (actualThrottlePosition > m_maxCycleTps) {
|
|
|
|
|
m_maxCycleTps = actualThrottlePosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bang-bang control the output to induce oscillation
|
|
|
|
|
return autotuneAmplitude * (isPositive ? -1 : 1);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 02:22:31 -07:00
|
|
|
|
expected<percent_t> EtbController::getClosedLoop(percent_t target, percent_t observation) {
|
2020-04-19 14:18:47 -07:00
|
|
|
|
if (m_shouldResetPid) {
|
|
|
|
|
m_pid.reset();
|
|
|
|
|
m_shouldResetPid = false;
|
|
|
|
|
}
|
2019-03-03 12:27:49 -08:00
|
|
|
|
|
2021-03-15 05:54:55 -07:00
|
|
|
|
if (m_isAutotune) {
|
2024-11-08 15:24:56 -08:00
|
|
|
|
state = (uint8_t)EtbState::Autotune;
|
2021-03-15 05:54:55 -07:00
|
|
|
|
return getClosedLoopAutotune(target, observation);
|
2020-04-11 19:15:49 -07:00
|
|
|
|
} else {
|
2024-09-17 16:39:16 -07:00
|
|
|
|
checkJam(target, observation);
|
2024-09-17 18:33:32 -07:00
|
|
|
|
|
2020-04-11 19:15:49 -07:00
|
|
|
|
// Normal case - use PID to compute closed loop part
|
2022-11-30 12:25:50 -08:00
|
|
|
|
return m_pid.getOutput(target, observation, etbPeriodSeconds);
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EtbController::setOutput(expected<percent_t> outputValue) {
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
|
// Only report first-throttle stats
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (m_function == DC_Throttle1) {
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.etb1DutyCycle = outputValue.value_or(0);
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-11-29 19:39:55 -08:00
|
|
|
|
if (!m_motor) {
|
2024-11-08 15:24:56 -08:00
|
|
|
|
state = (uint8_t)EtbState::NoMotor;
|
2022-11-29 19:39:55 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-04-19 14:18:47 -07:00
|
|
|
|
|
2024-11-08 15:24:56 -08:00
|
|
|
|
bool isEnabled;
|
|
|
|
|
if (!isEtbMode()) {
|
|
|
|
|
// technical debt: non-ETB usages of DC motor are still mixed into ETB controller?
|
|
|
|
|
state = (uint8_t)EtbState::NotEbt;
|
|
|
|
|
isEnabled = true;
|
|
|
|
|
} else if (!getLimpManager()->allowElectronicThrottle()) {
|
|
|
|
|
state = (uint8_t)EtbState::LimpProhibited;
|
|
|
|
|
isEnabled = false;
|
|
|
|
|
} else if (engineConfiguration->pauseEtbControl) {
|
|
|
|
|
state = (uint8_t)EtbState::Paused;
|
|
|
|
|
isEnabled = false;
|
|
|
|
|
} else if (!outputValue) {
|
|
|
|
|
state = (uint8_t)EtbState::NoOutput;
|
|
|
|
|
isEnabled = false;
|
|
|
|
|
} else {
|
|
|
|
|
state = (uint8_t)EtbState::Active;
|
|
|
|
|
isEnabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-17 10:13:46 -08:00
|
|
|
|
// If not ETB, or ETB is allowed, output is valid, and we aren't paused, output to motor.
|
2024-11-08 15:24:56 -08:00
|
|
|
|
if (isEnabled) {
|
2020-04-19 14:18:47 -07:00
|
|
|
|
m_motor->enable();
|
|
|
|
|
m_motor->set(ETB_PERCENT_TO_DUTY(outputValue.Value));
|
|
|
|
|
} else {
|
2020-12-26 18:47:27 -08:00
|
|
|
|
// Otherwise disable the motor.
|
2023-10-30 05:45:41 -07:00
|
|
|
|
m_motor->disable("no-ETB");
|
2020-04-19 14:18:47 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-17 01:14:30 -08:00
|
|
|
|
bool EtbController::checkStatus() {
|
2020-04-19 14:18:47 -07:00
|
|
|
|
#if EFI_TUNER_STUDIO
|
2020-09-28 13:33:07 -07:00
|
|
|
|
// Only debug throttle #1
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (m_function == DC_Throttle1) {
|
2022-03-24 05:58:55 -07:00
|
|
|
|
m_pid.postState(engine->outputChannels.etbStatus);
|
2023-02-18 19:39:45 -08:00
|
|
|
|
} else if (m_function == DC_Wastegate) {
|
2023-02-18 19:33:44 -08:00
|
|
|
|
m_pid.postState(engine->outputChannels.wastegateDcStatus);
|
2020-04-11 19:15:49 -07:00
|
|
|
|
}
|
2020-04-19 14:18:47 -07:00
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
2020-04-11 19:15:49 -07:00
|
|
|
|
|
2023-02-18 21:36:03 -08:00
|
|
|
|
if (!isEtbMode()) {
|
2023-06-01 11:09:30 -07:00
|
|
|
|
// no validation for h-bridge or idle mode
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// ETB-specific code belo. The whole mix-up between DC and ETB is shameful :(
|
2023-02-18 21:36:03 -08:00
|
|
|
|
|
|
|
|
|
m_pid.iTermMin = engineConfiguration->etb_iTermMin;
|
|
|
|
|
m_pid.iTermMax = engineConfiguration->etb_iTermMax;
|
|
|
|
|
|
2022-11-30 19:20:09 -08:00
|
|
|
|
// Only allow autotune with stopped engine, and on the first throttle
|
|
|
|
|
// Update local state about autotune
|
|
|
|
|
m_isAutotune = Sensor::getOrZero(SensorType::Rpm) == 0
|
|
|
|
|
&& engine->etbAutoTune
|
2023-02-18 19:39:45 -08:00
|
|
|
|
&& m_function == DC_Throttle1;
|
2022-11-30 19:20:09 -08:00
|
|
|
|
|
|
|
|
|
bool shouldCheckSensorFunction = engine->module<SensorChecker>()->analogSensorsShouldWork();
|
|
|
|
|
|
|
|
|
|
if (!m_isAutotune && shouldCheckSensorFunction) {
|
|
|
|
|
bool isTpsError = !Sensor::get(m_positionSensor).Valid;
|
|
|
|
|
|
|
|
|
|
// If we have an error that's new, increment the counter
|
|
|
|
|
if (isTpsError && !hadTpsError) {
|
|
|
|
|
etbTpsErrorCounter++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hadTpsError = isTpsError;
|
|
|
|
|
|
|
|
|
|
bool isPpsError = !Sensor::get(SensorType::AcceleratorPedal).Valid;
|
|
|
|
|
|
|
|
|
|
// If we have an error that's new, increment the counter
|
|
|
|
|
if (isPpsError && !hadPpsError) {
|
|
|
|
|
etbPpsErrorCounter++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hadPpsError = isPpsError;
|
|
|
|
|
} else {
|
|
|
|
|
// Either sensors are expected to not work, or autotune is running, so reset the error counter
|
|
|
|
|
etbTpsErrorCounter = 0;
|
|
|
|
|
etbPpsErrorCounter = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 20:29:49 -07:00
|
|
|
|
#ifndef ETB_INTERMITTENT_LIMIT
|
|
|
|
|
#define ETB_INTERMITTENT_LIMIT 50
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-11-29 19:39:55 -08:00
|
|
|
|
TpsState localReason = TpsState::None;
|
2024-04-22 20:29:49 -07:00
|
|
|
|
if (etbTpsErrorCounter > ETB_INTERMITTENT_LIMIT) {
|
2022-11-30 19:20:09 -08:00
|
|
|
|
localReason = TpsState::IntermittentTps;
|
2022-12-17 11:36:27 -08:00
|
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
|
|
|
|
} else if (engineConfiguration->disableEtbWhenEngineStopped && !engine->triggerCentral.engineMovedRecently()) {
|
|
|
|
|
localReason = TpsState::EngineStopped;
|
|
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
2024-04-22 20:29:49 -07:00
|
|
|
|
} else if (etbPpsErrorCounter > ETB_INTERMITTENT_LIMIT) {
|
2022-11-30 19:20:09 -08:00
|
|
|
|
localReason = TpsState::IntermittentPps;
|
2022-11-29 19:39:55 -08:00
|
|
|
|
} else if (engine->engineState.lua.luaDisableEtb) {
|
|
|
|
|
localReason = TpsState::Lua;
|
2024-11-08 12:04:36 -08:00
|
|
|
|
} else if (!getLimpManager()->allowElectronicThrottle()) {
|
|
|
|
|
localReason = TpsState::JamDetected;
|
2024-11-13 06:40:57 -08:00
|
|
|
|
} else if(!isBoardAllowingLackOfPps() && !Sensor::isRedundant(SensorType::AcceleratorPedal)) {
|
|
|
|
|
etbErrorCode = (int8_t)TpsState::Redundancy;
|
2022-11-29 19:39:55 -08:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 19:20:09 -08:00
|
|
|
|
etbErrorCode = (int8_t)localReason;
|
|
|
|
|
|
2023-06-01 11:09:30 -07:00
|
|
|
|
return localReason == TpsState::None;
|
2023-01-17 01:14:30 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EtbController::update() {
|
|
|
|
|
#if !EFI_UNIT_TEST
|
|
|
|
|
// If we didn't get initialized, fail fast
|
|
|
|
|
if (!m_motor) {
|
2024-11-08 15:24:56 -08:00
|
|
|
|
state = (uint8_t)EtbState::FailFast;
|
2023-01-17 01:14:30 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif // EFI_UNIT_TEST
|
|
|
|
|
|
2023-06-01 11:09:30 -07:00
|
|
|
|
bool isOk = checkStatus();
|
2023-01-17 01:14:30 -08:00
|
|
|
|
|
|
|
|
|
if (!isOk) {
|
2022-11-15 08:01:56 -08:00
|
|
|
|
// If engine is stopped and so configured, skip the ETB update entirely
|
|
|
|
|
// This is quieter and pulls less power than leaving it on all the time
|
2023-01-17 10:46:54 -08:00
|
|
|
|
m_motor->disable("etb status");
|
2022-11-15 08:01:56 -08:00
|
|
|
|
return;
|
2021-02-05 15:19:57 -08:00
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 22:04:46 -07:00
|
|
|
|
ClosedLoopController::update();
|
2024-11-08 17:37:17 -08:00
|
|
|
|
|
|
|
|
|
if (isEtbMode() && !validPlantPosition) {
|
|
|
|
|
etbErrorCode = (int8_t)TpsState::TpsError;
|
|
|
|
|
}
|
2023-01-10 12:31:04 -08:00
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 16:39:16 -07:00
|
|
|
|
void EtbController::checkJam(percent_t setpoint, percent_t observation) {
|
|
|
|
|
float absError = std::abs(setpoint - observation);
|
2023-01-10 12:31:04 -08:00
|
|
|
|
|
2024-09-17 19:11:41 -07:00
|
|
|
|
auto jamDetectThreshold = engineConfiguration->etbJamDetectThreshold;
|
2024-10-20 14:09:28 -07:00
|
|
|
|
auto jamTimeout = engineConfiguration->etbJamTimeout;
|
2023-01-10 12:31:04 -08:00
|
|
|
|
|
2024-10-20 14:09:28 -07:00
|
|
|
|
if (jamDetectThreshold != 0 && jamTimeout != 0) {
|
2023-01-10 12:31:04 -08:00
|
|
|
|
auto nowNt = getTimeNowNt();
|
|
|
|
|
|
2024-09-17 18:33:32 -07:00
|
|
|
|
if (absError > jamDetectThreshold && engine->module<IgnitionController>()->getIgnState()) {
|
2024-10-20 14:09:28 -07:00
|
|
|
|
if (m_jamDetectTimer.hasElapsedSec(jamTimeout)) {
|
2024-11-08 12:04:36 -08:00
|
|
|
|
efiPrintf(" ************* ETB is jammed! ***************");
|
2023-01-10 12:31:04 -08:00
|
|
|
|
jamDetected = true;
|
|
|
|
|
|
2024-09-17 18:33:32 -07:00
|
|
|
|
getLimpManager()->reportEtbProblem();
|
2023-01-10 12:31:04 -08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2024-09-17 18:05:32 -07:00
|
|
|
|
m_jamDetectTimer.reset(nowNt);
|
2023-01-10 12:31:04 -08:00
|
|
|
|
jamDetected = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jamTimer = m_jamDetectTimer.getElapsedSeconds(nowNt);
|
|
|
|
|
}
|
2022-11-30 12:25:50 -08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 16:31:41 -07:00
|
|
|
|
void EtbController::autoCalibrateTps() {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
// Only auto calibrate throttles
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (m_function == DC_Throttle1 || m_function == DC_Throttle2) {
|
2020-09-28 13:33:07 -07:00
|
|
|
|
m_isAutocal = true;
|
2024-10-26 07:31:02 -07:00
|
|
|
|
efiPrintf("m_isAutocal");
|
2020-09-28 13:33:07 -07:00
|
|
|
|
}
|
2020-04-28 16:31:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 04:22:31 -07:00
|
|
|
|
#if !EFI_UNIT_TEST
|
2020-04-28 05:05:18 -07:00
|
|
|
|
/**
|
|
|
|
|
* Things running on a timer (instead of a thread) don't participate it the RTOS's thread priority system,
|
|
|
|
|
* and operate essentially "first come first serve", which risks starvation.
|
|
|
|
|
* Since ETB is a safety critical device, we need the hard RTOS guarantee that it will be scheduled over other less important tasks.
|
|
|
|
|
*/
|
2020-04-28 04:22:31 -07:00
|
|
|
|
#include "periodic_thread_controller.h"
|
2022-11-28 20:22:08 -08:00
|
|
|
|
#else
|
|
|
|
|
#define chThdSleepMilliseconds(x) {}
|
|
|
|
|
#endif // EFI_UNIT_TEST
|
2022-03-15 17:04:49 -07:00
|
|
|
|
|
2022-08-28 05:28:20 -07:00
|
|
|
|
#include <utility>
|
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
template <typename TBase>
|
|
|
|
|
struct EtbImpl final : public TBase {
|
2022-08-28 05:28:20 -07:00
|
|
|
|
template <typename... TArgs>
|
|
|
|
|
EtbImpl(TArgs&&... args) : TBase(std::forward<TArgs>(args)...) { }
|
|
|
|
|
|
2020-09-18 10:47:49 -07:00
|
|
|
|
void update() override {
|
2020-04-28 16:31:41 -07:00
|
|
|
|
#if EFI_TUNER_STUDIO
|
2022-03-15 17:04:49 -07:00
|
|
|
|
if (TBase::m_isAutocal) {
|
2020-04-28 16:31:41 -07:00
|
|
|
|
// Don't allow if engine is running!
|
2022-01-20 19:40:15 -08:00
|
|
|
|
if (Sensor::getOrZero(SensorType::Rpm) > 0) {
|
2024-10-26 07:31:02 -07:00
|
|
|
|
efiPrintf(" ****************** ERROR: Not while RPM ********************");
|
2022-03-15 17:04:49 -07:00
|
|
|
|
TBase::m_isAutocal = false;
|
2020-04-28 16:31:41 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
auto motor = TBase::getMotor();
|
2020-04-28 16:31:41 -07:00
|
|
|
|
if (!motor) {
|
2024-10-26 07:31:02 -07:00
|
|
|
|
efiPrintf(" ****************** ERROR: No motor ********************");
|
2022-03-15 17:04:49 -07:00
|
|
|
|
TBase::m_isAutocal = false;
|
2020-04-28 16:31:41 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
auto myFunction = TBase::getFunction();
|
2020-04-28 16:31:41 -07:00
|
|
|
|
|
|
|
|
|
// First grab open
|
2024-10-26 07:31:02 -07:00
|
|
|
|
efiPrintf("Opening!");
|
2020-04-28 16:31:41 -07:00
|
|
|
|
motor->set(0.5f);
|
|
|
|
|
motor->enable();
|
|
|
|
|
chThdSleepMilliseconds(1000);
|
2021-08-14 23:10:28 -07:00
|
|
|
|
float primaryMax = Sensor::getRaw(functionToTpsSensorPrimary(myFunction));
|
|
|
|
|
float secondaryMax = Sensor::getRaw(functionToTpsSensorSecondary(myFunction));
|
2024-10-26 07:31:02 -07:00
|
|
|
|
efiPrintf("Opened %f %f", primaryMax, secondaryMax);
|
2020-04-28 16:31:41 -07:00
|
|
|
|
|
|
|
|
|
// Let it return
|
|
|
|
|
motor->set(0);
|
|
|
|
|
chThdSleepMilliseconds(200);
|
|
|
|
|
|
|
|
|
|
// Now grab closed
|
|
|
|
|
motor->set(-0.5f);
|
|
|
|
|
chThdSleepMilliseconds(1000);
|
2021-08-14 23:10:28 -07:00
|
|
|
|
float primaryMin = Sensor::getRaw(functionToTpsSensorPrimary(myFunction));
|
|
|
|
|
float secondaryMin = Sensor::getRaw(functionToTpsSensorSecondary(myFunction));
|
2020-04-28 16:31:41 -07:00
|
|
|
|
|
|
|
|
|
// Finally disable and reset state
|
2023-01-17 10:46:54 -08:00
|
|
|
|
motor->disable("autotune");
|
2020-04-28 16:31:41 -07:00
|
|
|
|
|
2020-12-28 05:03:10 -08:00
|
|
|
|
// Check that the calibrate actually moved the throttle
|
2024-09-24 23:47:37 -07:00
|
|
|
|
if (std::abs(primaryMax - primaryMin) < 0.5f) {
|
2023-04-11 17:01:34 -07:00
|
|
|
|
firmwareError(ObdCode::OBD_TPS_Configuration, "Auto calibrate failed, check your wiring!\r\nClosed voltage: %.1fv Open voltage: %.1fv", primaryMin, primaryMax);
|
2022-03-15 17:04:49 -07:00
|
|
|
|
TBase::m_isAutocal = false;
|
2020-12-28 05:03:10 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 11:32:00 -07:00
|
|
|
|
// Write out the learned values to TS, waiting briefly after setting each to let TS grab it
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)functionToCalModePriMax(myFunction);
|
2024-06-14 11:44:50 -07:00
|
|
|
|
engine->outputChannels.calibrationValue = convertVoltageTo10bitADC(primaryMax);
|
2020-05-18 11:32:00 -07:00
|
|
|
|
chThdSleepMilliseconds(500);
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)functionToCalModePriMin(myFunction);
|
2024-06-14 11:44:50 -07:00
|
|
|
|
engine->outputChannels.calibrationValue = convertVoltageTo10bitADC(primaryMin);
|
2020-05-18 11:32:00 -07:00
|
|
|
|
chThdSleepMilliseconds(500);
|
|
|
|
|
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)functionToCalModeSecMax(myFunction);
|
2024-06-14 11:44:50 -07:00
|
|
|
|
engine->outputChannels.calibrationValue = convertVoltageTo10bitADC(secondaryMax);
|
2020-04-28 16:31:41 -07:00
|
|
|
|
chThdSleepMilliseconds(500);
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)functionToCalModeSecMin(myFunction);
|
2024-06-14 11:44:50 -07:00
|
|
|
|
engine->outputChannels.calibrationValue = convertVoltageTo10bitADC(secondaryMin);
|
2020-05-18 11:32:00 -07:00
|
|
|
|
chThdSleepMilliseconds(500);
|
|
|
|
|
|
2021-12-07 17:18:47 -08:00
|
|
|
|
engine->outputChannels.calibrationMode = (uint8_t)TsCalMode::None;
|
2020-04-28 16:31:41 -07:00
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
TBase::m_isAutocal = false;
|
2020-04-28 16:31:41 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
|
|
|
|
|
2022-03-15 17:04:49 -07:00
|
|
|
|
TBase::update();
|
2020-04-28 04:22:31 -07:00
|
|
|
|
}
|
2020-09-18 10:47:49 -07:00
|
|
|
|
};
|
2020-04-28 04:22:31 -07:00
|
|
|
|
|
2020-09-18 10:47:49 -07:00
|
|
|
|
// real implementation (we mock for some unit tests)
|
2022-03-15 17:04:49 -07:00
|
|
|
|
static EtbImpl<EtbController1> etb1;
|
2022-08-28 05:28:20 -07:00
|
|
|
|
static EtbImpl<EtbController2> etb2(throttle2TrimTable);
|
2022-03-15 17:04:49 -07:00
|
|
|
|
|
|
|
|
|
static_assert(ETB_COUNT == 2);
|
2022-07-09 19:46:28 -07:00
|
|
|
|
static EtbController* etbControllers[] = { &etb1, &etb2 };
|
2020-09-18 10:47:49 -07:00
|
|
|
|
|
2024-10-31 18:48:01 -07:00
|
|
|
|
void blinkEtbErrorCodes(bool blinkPhase) {
|
|
|
|
|
for (int i = 0;i<ETB_COUNT;i++) {
|
2024-11-08 11:41:58 -08:00
|
|
|
|
int8_t etbErrorCode = etbControllers[i]->etbErrorCode;
|
|
|
|
|
if (etbErrorCode && engine->etbAutoTune) {
|
|
|
|
|
etbErrorCode = (int8_t)TpsState::AutoTune;
|
|
|
|
|
}
|
|
|
|
|
etbControllers[i]->etbErrorCodeBlinker = blinkPhase ? 0 : etbErrorCode;
|
2024-10-31 18:48:01 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-28 20:22:08 -08:00
|
|
|
|
#if !EFI_UNIT_TEST
|
|
|
|
|
|
2023-01-16 13:02:29 -08:00
|
|
|
|
struct DcThread final : public PeriodicController<512> {
|
|
|
|
|
DcThread() : PeriodicController("DC", PRIO_ETB, ETB_LOOP_FREQUENCY) {}
|
2020-09-18 10:47:49 -07:00
|
|
|
|
|
|
|
|
|
void PeriodicTask(efitick_t) override {
|
|
|
|
|
// Simply update all controllers
|
2020-10-18 17:49:42 -07:00
|
|
|
|
for (int i = 0 ; i < ETB_COUNT; i++) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
auto controller = engine->etbControllers[i];
|
|
|
|
|
assertNotNullVoid(controller);
|
2022-03-15 17:04:49 -07:00
|
|
|
|
etbControllers[i]->update();
|
2020-09-18 10:47:49 -07:00
|
|
|
|
}
|
2020-04-28 04:22:31 -07:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-01-16 13:02:29 -08:00
|
|
|
|
static DcThread dcThread CCM_OPTIONAL;
|
2020-09-18 10:47:49 -07:00
|
|
|
|
|
2023-12-18 13:27:44 -08:00
|
|
|
|
#endif // !EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
2022-11-29 11:59:08 -08:00
|
|
|
|
void etbPidReset() {
|
2020-10-18 17:49:42 -07:00
|
|
|
|
for (int i = 0 ; i < ETB_COUNT; i++) {
|
|
|
|
|
if (auto controller = engine->etbControllers[i]) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
assertNotNullVoid(controller);
|
2020-10-18 17:49:42 -07:00
|
|
|
|
controller->reset();
|
|
|
|
|
}
|
2019-11-28 12:24:30 -08:00
|
|
|
|
}
|
2019-11-27 19:07:36 -08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 16:31:41 -07:00
|
|
|
|
void etbAutocal(size_t throttleIndex) {
|
|
|
|
|
if (throttleIndex >= ETB_COUNT) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-18 18:57:04 -07:00
|
|
|
|
if (auto etb = engine->etbControllers[throttleIndex]) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
assertNotNullVoid(etb);
|
2020-04-28 16:31:41 -07:00
|
|
|
|
etb->autoCalibrateTps();
|
2024-10-26 10:23:39 -07:00
|
|
|
|
// todo fix root cause! work-around: make sure not to write bad tune since that would brick requestBurn();
|
2020-04-28 16:31:41 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 05:12:16 -07:00
|
|
|
|
/**
|
|
|
|
|
* This specific throttle has default position of about 7% open
|
|
|
|
|
*/
|
|
|
|
|
static const float boschBiasBins[] = {
|
|
|
|
|
0, 1, 5, 7, 14, 65, 66, 100
|
|
|
|
|
};
|
|
|
|
|
static const float boschBiasValues[] = {
|
|
|
|
|
-15, -15, -10, 0, 19, 20, 26, 28
|
|
|
|
|
};
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setBoschVAGETB() {
|
2021-10-10 19:23:33 -07:00
|
|
|
|
engineConfiguration->tpsMin = 890; // convert 12to10 bit (ADC/4)
|
|
|
|
|
engineConfiguration->tpsMax = 70; // convert 12to10 bit (ADC/4)
|
|
|
|
|
|
|
|
|
|
engineConfiguration->tps1SecondaryMin = 102;
|
|
|
|
|
engineConfiguration->tps1SecondaryMax = 891;
|
|
|
|
|
|
|
|
|
|
engineConfiguration->etb.pFactor = 5.12;
|
|
|
|
|
engineConfiguration->etb.iFactor = 47;
|
|
|
|
|
engineConfiguration->etb.dFactor = 0.088;
|
|
|
|
|
engineConfiguration->etb.offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setBoschVNH2SP30Curve() {
|
2022-05-02 02:04:58 -07:00
|
|
|
|
copyArray(config->etbBiasBins, boschBiasBins);
|
|
|
|
|
copyArray(config->etbBiasValues, boschBiasValues);
|
2019-08-31 17:17:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setDefaultEtbParameters() {
|
2023-06-18 20:02:51 -07:00
|
|
|
|
engineConfiguration->etbIdleThrottleRange = 15;
|
2019-06-15 10:33:14 -07:00
|
|
|
|
|
2019-11-22 20:27:24 -08:00
|
|
|
|
setLinearCurve(config->pedalToTpsPedalBins, /*from*/0, /*to*/100, 1);
|
2023-11-13 15:30:30 -08:00
|
|
|
|
setRpmTableBin(config->pedalToTpsRpmBins);
|
2019-06-10 20:38:44 -07:00
|
|
|
|
|
2019-06-10 20:57:35 -07:00
|
|
|
|
for (int pedalIndex = 0;pedalIndex<PEDAL_TO_TPS_SIZE;pedalIndex++) {
|
|
|
|
|
for (int rpmIndex = 0;rpmIndex<PEDAL_TO_TPS_SIZE;rpmIndex++) {
|
|
|
|
|
config->pedalToTpsTable[pedalIndex][rpmIndex] = config->pedalToTpsPedalBins[pedalIndex];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-14 19:02:09 -07:00
|
|
|
|
// Default is to run each throttle off its respective hbridge
|
2023-02-18 19:39:45 -08:00
|
|
|
|
engineConfiguration->etbFunctions[0] = DC_Throttle1;
|
|
|
|
|
engineConfiguration->etbFunctions[1] = DC_Throttle2;
|
2020-10-14 19:02:09 -07:00
|
|
|
|
|
2020-04-28 04:22:31 -07:00
|
|
|
|
engineConfiguration->etbFreq = DEFAULT_ETB_PWM_FREQUENCY;
|
2019-06-10 20:57:35 -07:00
|
|
|
|
|
2020-04-28 04:22:31 -07:00
|
|
|
|
// voltage, not ADC like with TPS
|
2022-11-26 11:08:59 -08:00
|
|
|
|
setPPSCalibration(0, 5, 5, 0);
|
2017-05-29 19:35:24 -07:00
|
|
|
|
|
2020-04-10 05:12:16 -07:00
|
|
|
|
engineConfiguration->etb = {
|
|
|
|
|
1, // Kp
|
|
|
|
|
10, // Ki
|
|
|
|
|
0.05, // Kd
|
|
|
|
|
0, // offset
|
2020-04-28 04:22:31 -07:00
|
|
|
|
0, // Update rate, unused
|
2020-04-10 05:12:16 -07:00
|
|
|
|
-100, 100 // min/max
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-28 04:22:31 -07:00
|
|
|
|
engineConfiguration->etb_iTermMin = -30;
|
|
|
|
|
engineConfiguration->etb_iTermMax = 30;
|
2024-09-17 18:50:06 -07:00
|
|
|
|
|
2024-09-17 19:11:41 -07:00
|
|
|
|
engineConfiguration->etbJamDetectThreshold = 10;
|
2024-09-17 18:50:06 -07:00
|
|
|
|
engineConfiguration->etbJamTimeout = 1;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-27 20:01:41 -07:00
|
|
|
|
void onConfigurationChangeElectronicThrottleCallback(engine_configuration_s *previousConfiguration) {
|
2019-12-10 16:37:04 -08:00
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
2022-03-15 17:04:49 -07:00
|
|
|
|
etbControllers[i]->onConfigurationChange(&previousConfiguration->etb);
|
2019-11-28 12:24:30 -08:00
|
|
|
|
}
|
2017-05-27 20:01:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 05:12:16 -07:00
|
|
|
|
static const float defaultBiasBins[] = {
|
|
|
|
|
0, 1, 2, 4, 7, 98, 99, 100
|
|
|
|
|
};
|
|
|
|
|
static const float defaultBiasValues[] = {
|
|
|
|
|
-20, -18, -17, 0, 20, 21, 22, 25
|
|
|
|
|
};
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setDefaultEtbBiasCurve() {
|
2022-05-02 02:04:58 -07:00
|
|
|
|
copyArray(config->etbBiasBins, defaultBiasBins);
|
|
|
|
|
copyArray(config->etbBiasValues, defaultBiasValues);
|
2018-12-09 10:50:13 -08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-10 09:58:27 -07:00
|
|
|
|
void unregisterEtbPins() {
|
2019-12-13 10:52:34 -08:00
|
|
|
|
// todo: we probably need an implementation here?!
|
2019-03-10 09:58:27 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-18 21:15:12 -08:00
|
|
|
|
static pid_s* getPidForDcFunction(dc_function_e function) {
|
2020-10-19 05:04:27 -07:00
|
|
|
|
switch (function) {
|
2023-02-18 19:39:45 -08:00
|
|
|
|
case DC_Wastegate: return &engineConfiguration->etbWastegatePid;
|
2021-11-17 00:54:21 -08:00
|
|
|
|
default: return &engineConfiguration->etb;
|
2020-10-19 05:04:27 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-27 09:36:35 -07:00
|
|
|
|
PUBLIC_API_WEAK ValueProvider3D* pedal2TpsProvider() {
|
2024-05-04 21:58:55 -07:00
|
|
|
|
return &pedal2tpsMap;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 14:33:10 -07:00
|
|
|
|
void doInitElectronicThrottle() {
|
2022-11-29 19:39:55 -08:00
|
|
|
|
bool hasPedal = Sensor::hasSensor(SensorType::AcceleratorPedalPrimary);
|
2022-11-28 23:21:36 -08:00
|
|
|
|
|
|
|
|
|
|
2024-08-05 11:38:49 -07:00
|
|
|
|
bool anyEtbConfigured = false;
|
2020-10-14 19:02:09 -07:00
|
|
|
|
|
2021-11-08 09:44:37 -08:00
|
|
|
|
// todo: technical debt: we still have DC motor code initialization in ETB-specific file while DC motors are used not just as ETB
|
2023-02-12 21:56:54 -08:00
|
|
|
|
// like DC motor wastegate code flow should probably NOT go through electronic_throttle.cpp right?
|
2021-11-08 09:44:37 -08:00
|
|
|
|
// todo: rename etbFunctions to something-without-etb for same reason?
|
2020-10-18 14:26:38 -07:00
|
|
|
|
for (int i = 0 ; i < ETB_COUNT; i++) {
|
2021-11-17 00:54:21 -08:00
|
|
|
|
auto func = engineConfiguration->etbFunctions[i];
|
2023-02-18 19:39:45 -08:00
|
|
|
|
if (func == DC_None) {
|
2021-11-08 09:44:37 -08:00
|
|
|
|
// do not touch HW pins if function not selected, this way Lua can use DC motor hardware pins directly
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-03-27 08:00:01 -07:00
|
|
|
|
auto motor = initDcMotor("ETB disable",
|
|
|
|
|
engineConfiguration->etbIo[i], i, engineConfiguration->etb_use_two_wires);
|
2020-03-03 14:56:50 -08:00
|
|
|
|
|
2022-11-03 06:40:44 -07:00
|
|
|
|
auto controller = engine->etbControllers[i];
|
2023-12-18 13:32:35 -08:00
|
|
|
|
criticalAssertVoid(controller != nullptr, "null ETB");
|
2020-10-14 19:02:09 -07:00
|
|
|
|
|
2023-02-18 21:15:12 -08:00
|
|
|
|
auto pid = getPidForDcFunction(func);
|
2020-09-28 13:33:07 -07:00
|
|
|
|
|
2024-11-11 17:44:11 -08:00
|
|
|
|
bool dcConfigured = controller->init(func, motor, pid, pedal2TpsProvider());
|
2023-02-18 20:58:06 -08:00
|
|
|
|
bool etbConfigured = dcConfigured && controller->isEtbMode();
|
2024-08-05 11:38:49 -07:00
|
|
|
|
anyEtbConfigured |= etbConfigured;
|
2020-03-03 14:56:50 -08:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-05 11:38:49 -07:00
|
|
|
|
if (!anyEtbConfigured) {
|
2020-10-15 19:04:42 -07:00
|
|
|
|
// It's not valid to have a PPS without any ETBs - check that at least one ETB was enabled along with the pedal
|
2022-11-29 19:39:55 -08:00
|
|
|
|
if (hasPedal) {
|
2023-08-20 19:23:44 -07:00
|
|
|
|
criticalError("A pedal position sensor was configured, but no electronic throttles are configured.");
|
2020-10-15 19:04:42 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 11:00:04 -07:00
|
|
|
|
#if 0 && ! EFI_UNIT_TEST
|
2021-11-16 01:15:29 -08:00
|
|
|
|
percent_t startupThrottlePosition = getTPS();
|
2024-09-24 23:47:37 -07:00
|
|
|
|
if (std::abs(startupThrottlePosition - engineConfiguration->etbNeutralPosition) > STARTUP_NEUTRAL_POSITION_ERROR_THRESHOLD) {
|
2019-09-22 20:28:11 -07:00
|
|
|
|
/**
|
2020-03-28 17:56:58 -07:00
|
|
|
|
* Unexpected electronic throttle start-up position is worth a critical error
|
2019-09-22 20:28:11 -07:00
|
|
|
|
*/
|
2023-04-11 17:01:34 -07:00
|
|
|
|
firmwareError(ObdCode::OBD_Throttle_Actuator_Control_Range_Performance_Bank_1, "startup ETB position %.2f not %d",
|
2019-09-22 20:28:11 -07:00
|
|
|
|
startupThrottlePosition,
|
|
|
|
|
engineConfiguration->etbNeutralPosition);
|
|
|
|
|
startupPositionError = true;
|
|
|
|
|
}
|
2019-09-22 21:41:35 -07:00
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
2019-09-22 20:28:11 -07:00
|
|
|
|
|
2020-09-18 10:47:49 -07:00
|
|
|
|
#if !EFI_UNIT_TEST
|
2022-11-06 02:42:41 -08:00
|
|
|
|
static bool started = false;
|
|
|
|
|
if (started == false) {
|
2023-01-16 13:02:29 -08:00
|
|
|
|
dcThread.start();
|
2022-11-06 02:42:41 -08:00
|
|
|
|
started = true;
|
|
|
|
|
}
|
2020-09-18 10:47:49 -07:00
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void initElectronicThrottle() {
|
2020-04-01 21:32:03 -07:00
|
|
|
|
if (hasFirmwareError()) {
|
2020-04-02 05:04:12 -07:00
|
|
|
|
return;
|
2020-04-01 21:32:03 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
2022-03-15 17:04:49 -07:00
|
|
|
|
engine->etbControllers[i] = etbControllers[i];
|
2020-04-01 21:32:03 -07:00
|
|
|
|
}
|
2020-04-02 05:04:12 -07:00
|
|
|
|
|
2022-10-26 14:33:10 -07:00
|
|
|
|
#if EFI_PROD_CODE
|
2024-10-26 07:31:02 -07:00
|
|
|
|
addConsoleAction("etbautocal", [](){
|
|
|
|
|
efiPrintf("etbAutocal invoked");
|
|
|
|
|
etbAutocal(0);
|
|
|
|
|
});
|
|
|
|
|
|
2023-12-18 13:27:44 -08:00
|
|
|
|
addConsoleAction("etbinfo", [](){
|
|
|
|
|
efiPrintf("etbAutoTune=%d", engine->etbAutoTune);
|
|
|
|
|
efiPrintf("TPS=%.2f", Sensor::getOrZero(SensorType::Tps1));
|
|
|
|
|
|
2023-12-18 15:01:13 -08:00
|
|
|
|
efiPrintf("ETB1 duty=%.2f",
|
2024-06-10 18:22:56 -07:00
|
|
|
|
(float)engine->outputChannels.etb1DutyCycle);
|
2023-12-18 13:27:44 -08:00
|
|
|
|
|
|
|
|
|
efiPrintf("ETB freq=%d",
|
|
|
|
|
engineConfiguration->etbFreq);
|
2022-10-26 14:33:10 -07:00
|
|
|
|
|
2023-12-18 13:27:44 -08:00
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
|
|
|
|
efiPrintf("ETB%d", i);
|
|
|
|
|
efiPrintf(" dir1=%s", hwPortname(engineConfiguration->etbIo[i].directionPin1));
|
|
|
|
|
efiPrintf(" dir2=%s", hwPortname(engineConfiguration->etbIo[i].directionPin2));
|
|
|
|
|
efiPrintf(" control=%s", hwPortname(engineConfiguration->etbIo[i].controlPin));
|
|
|
|
|
efiPrintf(" disable=%s", hwPortname(engineConfiguration->etbIo[i].disablePin));
|
|
|
|
|
showDcMotorInfo(i);
|
|
|
|
|
}
|
2022-10-26 14:33:10 -07:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#endif /* EFI_PROD_CODE */
|
|
|
|
|
|
2024-03-04 14:58:24 -08:00
|
|
|
|
pedal2tpsMap.initTable(config->pedalToTpsTable, config->pedalToTpsRpmBins, config->pedalToTpsPedalBins);
|
|
|
|
|
throttle2TrimTable.initTable(config->throttle2TrimTable, config->throttle2TrimRpmBins, config->throttle2TrimTpsBins);
|
|
|
|
|
tcEtbDropTable.initTable(engineConfiguration->tractionControlEtbDrop, engineConfiguration->tractionControlSlipBins, engineConfiguration->tractionControlSpeedBins);
|
2022-10-26 14:33:10 -07:00
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
doInitElectronicThrottle();
|
2020-04-01 21:32:03 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setEtbIdlePosition(percent_t pos) {
|
2020-04-20 13:26:35 -07:00
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
2020-10-18 18:57:04 -07:00
|
|
|
|
if (auto etb = engine->etbControllers[i]) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
assertNotNullVoid(etb);
|
2020-04-20 13:26:35 -07:00
|
|
|
|
etb->setIdlePosition(pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setEtbWastegatePosition(percent_t pos) {
|
2020-10-18 18:57:04 -07:00
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
|
|
|
|
if (auto etb = engine->etbControllers[i]) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
assertNotNullVoid(etb);
|
2020-10-18 18:57:04 -07:00
|
|
|
|
etb->setWastegatePosition(pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 19:46:28 -07:00
|
|
|
|
void setEtbLuaAdjustment(percent_t pos) {
|
|
|
|
|
for (int i = 0; i < ETB_COUNT; i++) {
|
|
|
|
|
if (auto etb = engine->etbControllers[i]) {
|
2024-10-09 19:33:09 -07:00
|
|
|
|
assertNotNullVoid(etb);
|
2022-07-09 19:46:28 -07:00
|
|
|
|
etb->setLuaAdjustment(pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setToyota89281_33010_pedal_position_sensor() {
|
2023-02-11 19:44:42 -08:00
|
|
|
|
setPPSCalibration(0, 4.1, 0.73, 4.9);
|
2020-12-25 21:57:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setHitachiEtbCalibration() {
|
|
|
|
|
setToyota89281_33010_pedal_position_sensor();
|
2020-12-25 21:57:23 -08:00
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
setHitachiEtbBiasBins();
|
2020-12-25 21:57:23 -08:00
|
|
|
|
|
|
|
|
|
engineConfiguration->etb.pFactor = 2.7999;
|
|
|
|
|
engineConfiguration->etb.iFactor = 25.5;
|
|
|
|
|
engineConfiguration->etb.dFactor = 0.053;
|
|
|
|
|
engineConfiguration->etb.offset = 0.0;
|
|
|
|
|
engineConfiguration->etb.periodMs = 5.0;
|
|
|
|
|
engineConfiguration->etb.minValue = -100.0;
|
|
|
|
|
engineConfiguration->etb.maxValue = 100.0;
|
|
|
|
|
|
|
|
|
|
// Nissan 60mm throttle
|
2021-11-17 00:54:21 -08:00
|
|
|
|
engineConfiguration->tpsMin = engineConfiguration->tps2Min = 113;
|
|
|
|
|
engineConfiguration->tpsMax = engineConfiguration->tps2Max = 846;
|
|
|
|
|
engineConfiguration->tps1SecondaryMin = engineConfiguration->tps2SecondaryMin = 897;
|
|
|
|
|
engineConfiguration->tps1SecondaryMax = engineConfiguration->tps2SecondaryMax = 161;
|
2020-12-25 21:57:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
|
void setProteusHitachiEtbDefaults() {
|
2022-05-04 14:05:08 -07:00
|
|
|
|
#if HW_PROTEUS
|
2021-11-16 01:15:29 -08:00
|
|
|
|
setHitachiEtbCalibration();
|
2021-10-10 13:29:45 -07:00
|
|
|
|
|
|
|
|
|
// EFI_ADC_12: "Analog Volt 3"
|
2022-05-04 13:28:20 -07:00
|
|
|
|
engineConfiguration->tps1_2AdcChannel = PROTEUS_IN_TPS1_2;
|
2021-10-10 13:29:45 -07:00
|
|
|
|
// EFI_ADC_13: "Analog Volt 4"
|
2022-05-04 13:28:20 -07:00
|
|
|
|
engineConfiguration->tps2_1AdcChannel = PROTEUS_IN_TPS2_1;
|
2021-10-10 13:29:45 -07:00
|
|
|
|
// EFI_ADC_0: "Analog Volt 5"
|
2022-06-02 20:28:39 -07:00
|
|
|
|
engineConfiguration->tps2_2AdcChannel = PROTEUS_IN_ANALOG_VOLT_5;
|
2022-10-29 20:04:24 -07:00
|
|
|
|
setPPSInputs(PROTEUS_IN_ANALOG_VOLT_6, PROTEUS_IN_PPS2);
|
2022-05-04 14:05:08 -07:00
|
|
|
|
#endif // HW_PROTEUS
|
2021-10-10 13:29:45 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
|
#endif /* EFI_ELECTRONIC_THROTTLE_BODY */
|
2022-11-30 16:29:22 -08:00
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
const electronic_throttle_s* getLiveData(size_t idx) {
|
|
|
|
|
#if EFI_ELECTRONIC_THROTTLE_BODY
|
|
|
|
|
if (idx >= efi::size(etbControllers)) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return etbControllers[idx];
|
|
|
|
|
#else
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2024-11-08 16:42:40 -08:00
|
|
|
|
|