2020-02-02 00:56:21 -08:00
|
|
|
/*
|
|
|
|
* boost_control.cpp
|
|
|
|
*
|
|
|
|
* Created on: 13. des. 2019
|
|
|
|
* Author: Ola Ruud
|
|
|
|
*/
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "pch.h"
|
2020-02-02 00:56:21 -08:00
|
|
|
|
|
|
|
#if EFI_BOOST_CONTROL
|
|
|
|
|
|
|
|
#include "boost_control.h"
|
|
|
|
#include "pid_auto_tune.h"
|
2020-10-18 18:57:04 -07:00
|
|
|
#include "electronic_throttle.h"
|
|
|
|
|
2020-02-02 00:56:21 -08:00
|
|
|
#define NO_PIN_PERIOD 500
|
|
|
|
|
|
|
|
#if defined(HAS_OS_ACCESS)
|
|
|
|
#error "Unexpected OS ACCESS HERE"
|
|
|
|
#endif
|
|
|
|
|
2021-06-03 11:30:25 -07:00
|
|
|
static boostOpenLoop_Map3D_t boostMapOpen;
|
|
|
|
static boostOpenLoop_Map3D_t boostMapClosed;
|
2020-02-02 00:56:21 -08:00
|
|
|
static SimplePwm boostPwmControl("boost");
|
|
|
|
|
2021-07-01 06:21:18 -07:00
|
|
|
void BoostController::init(IPwm* pwm, const ValueProvider3D* openLoopMap, const ValueProvider3D* closedLoopTargetMap, pid_s* pidParams) {
|
2020-05-06 05:40:42 -07:00
|
|
|
m_pwm = pwm;
|
|
|
|
m_openLoopMap = openLoopMap;
|
|
|
|
m_closedLoopTargetMap = closedLoopTargetMap;
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
m_pid.initPidClass(pidParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoostController::onConfigurationChange(pid_s* previousConfiguration) {
|
|
|
|
if (!m_pid.isSame(previousConfiguration)) {
|
|
|
|
m_shouldResetPid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expected<float> BoostController::observePlant() const {
|
2020-12-30 05:43:49 -08:00
|
|
|
return Sensor::get(SensorType::Map);
|
2020-05-06 05:40:42 -07:00
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
expected<float> BoostController::getSetpoint() const {
|
2020-11-25 04:27:24 -08:00
|
|
|
// If we're in open loop only mode, disregard any target computation.
|
|
|
|
// Open loop needs to work even in case of invalid closed loop config
|
|
|
|
if (engineConfiguration->boostType != CLOSED_LOOP) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
float rpm = GET_RPM();
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
2020-02-04 17:17:31 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
if (!tps) {
|
|
|
|
return unexpected;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_closedLoopTargetMap) {
|
|
|
|
return unexpected;
|
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-09-10 15:44:10 -07:00
|
|
|
return m_closedLoopTargetMap->getValue(rpm / RPM_1_BYTE_PACKING_MULT, tps.Value / TPS_1_BYTE_PACKING_MULT);
|
2020-05-06 05:40:42 -07:00
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
expected<percent_t> BoostController::getOpenLoop(float target) const {
|
2021-09-07 11:07:47 -07:00
|
|
|
// Boost control open loop doesn't care about target - only TPS/RPM
|
2020-05-06 05:40:42 -07:00
|
|
|
UNUSED(target);
|
2020-04-05 16:33:33 -07:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
float rpm = GET_RPM();
|
|
|
|
auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
|
|
|
|
|
|
|
if (!tps) {
|
|
|
|
return unexpected;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_openLoopMap) {
|
|
|
|
return unexpected;
|
|
|
|
}
|
2020-02-04 17:17:31 -08:00
|
|
|
|
2020-09-10 15:44:10 -07:00
|
|
|
percent_t openLoop = m_openLoopMap->getValue(rpm / RPM_1_BYTE_PACKING_MULT, tps.Value / TPS_1_BYTE_PACKING_MULT);
|
2020-02-04 17:17:31 -08:00
|
|
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
2020-05-06 05:40:42 -07:00
|
|
|
if (engineConfiguration->debugMode == DBG_BOOST) {
|
|
|
|
tsOutputChannels.debugFloatField1 = openLoop;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return openLoop;
|
|
|
|
}
|
2020-02-04 17:17:31 -08:00
|
|
|
|
2021-09-07 11:07:47 -07:00
|
|
|
percent_t BoostController::getClosedLoopImpl(float target, float manifoldPressure) {
|
2020-05-06 05:40:42 -07:00
|
|
|
// If we're in open loop only mode, make no closed loop correction.
|
|
|
|
if (engineConfiguration->boostType != CLOSED_LOOP) {
|
|
|
|
return 0;
|
2020-03-26 16:22:14 -07:00
|
|
|
}
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
// Reset PID if requested
|
|
|
|
if (m_shouldResetPid) {
|
|
|
|
m_pid.reset();
|
|
|
|
m_shouldResetPid = false;
|
2020-02-04 17:17:31 -08:00
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
// If the engine isn't running, don't correct.
|
|
|
|
if (GET_RPM() == 0) {
|
|
|
|
m_pid.reset();
|
|
|
|
return 0;
|
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
2021-08-27 14:54:08 -07:00
|
|
|
if (manifoldPressure < CONFIG(minimumBoostClosedLoopMap)) {
|
|
|
|
// We're below the CL threshold, inhibit CL for now
|
|
|
|
m_pid.reset();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-07 11:07:47 -07:00
|
|
|
return m_pid.getOutput(target, manifoldPressure, SLOW_CALLBACK_PERIOD_MS / 1000.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
expected<percent_t> BoostController::getClosedLoop(float target, float manifoldPressure) {
|
|
|
|
auto closedLoop = getClosedLoopImpl(target, manifoldPressure);
|
2020-05-06 05:40:42 -07:00
|
|
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
if (engineConfiguration->debugMode == DBG_BOOST) {
|
|
|
|
tsOutputChannels.debugFloatField2 = closedLoop;
|
2021-09-07 11:07:47 -07:00
|
|
|
tsOutputChannels.debugFloatField3 = target;
|
2020-05-06 05:40:42 -07:00
|
|
|
}
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
|
|
|
|
|
|
|
return closedLoop;
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
void BoostController::setOutput(expected<float> output) {
|
2021-05-30 04:04:04 -07:00
|
|
|
percent_t percent = output.value_or(CONFIG(boostControlSafeDutyCycle));
|
2021-09-07 11:07:47 -07:00
|
|
|
|
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
if (engineConfiguration->debugMode == DBG_BOOST) {
|
|
|
|
tsOutputChannels.debugFloatField3 = percent;
|
|
|
|
}
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
|
|
|
|
2020-11-25 18:14:06 -08:00
|
|
|
float duty = PERCENT_TO_DUTY(percent);
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
if (m_pwm) {
|
|
|
|
m_pwm->setSimplePwmDutyCycle(duty);
|
|
|
|
}
|
2020-10-18 18:57:04 -07:00
|
|
|
|
2020-11-25 18:14:06 -08:00
|
|
|
setEtbWastegatePosition(percent PASS_ENGINE_PARAMETER_SUFFIX);
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
2021-01-18 04:04:14 -08:00
|
|
|
void BoostController::update() {
|
2020-05-06 05:40:42 -07:00
|
|
|
m_pid.iTermMin = -50;
|
|
|
|
m_pid.iTermMax = 50;
|
|
|
|
|
2021-01-18 04:04:14 -08:00
|
|
|
ClosedLoopController::update();
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
2020-05-06 05:40:42 -07:00
|
|
|
|
2021-01-18 04:04:14 -08:00
|
|
|
static BoostController boostController;
|
|
|
|
static bool hasInitBoost = false;
|
|
|
|
|
|
|
|
void updateBoostControl() {
|
|
|
|
if (hasInitBoost) {
|
|
|
|
boostController.update();
|
|
|
|
}
|
|
|
|
}
|
2020-02-02 00:56:21 -08:00
|
|
|
|
|
|
|
void setDefaultBoostParameters(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
2021-01-18 04:04:14 -08:00
|
|
|
engineConfiguration->boostPwmFrequency = 33;
|
2020-02-02 00:56:21 -08:00
|
|
|
engineConfiguration->boostPid.offset = 0;
|
|
|
|
engineConfiguration->boostPid.pFactor = 0.5;
|
|
|
|
engineConfiguration->boostPid.iFactor = 0.3;
|
2021-01-18 04:04:14 -08:00
|
|
|
engineConfiguration->boostPid.maxValue = 20;
|
|
|
|
engineConfiguration->boostPid.minValue = -20;
|
2020-02-02 00:56:21 -08:00
|
|
|
engineConfiguration->boostControlPin = GPIO_UNASSIGNED;
|
|
|
|
engineConfiguration->boostControlPinMode = OM_DEFAULT;
|
|
|
|
|
|
|
|
setLinearCurve(config->boostRpmBins, 0, 8000 / RPM_1_BYTE_PACKING_MULT, 1);
|
|
|
|
setLinearCurve(config->boostTpsBins, 0, 100 / TPS_1_BYTE_PACKING_MULT, 1);
|
2020-05-06 05:40:42 -07:00
|
|
|
|
|
|
|
for (int loadIndex = 0; loadIndex < BOOST_LOAD_COUNT; loadIndex++) {
|
|
|
|
for (int rpmIndex = 0; rpmIndex < BOOST_RPM_COUNT; rpmIndex++) {
|
|
|
|
config->boostTableOpenLoop[loadIndex][rpmIndex] = config->boostTpsBins[loadIndex];
|
2020-02-04 17:17:31 -08:00
|
|
|
config->boostTableClosedLoop[loadIndex][rpmIndex] = config->boostTpsBins[loadIndex];
|
|
|
|
}
|
|
|
|
}
|
2020-11-22 15:30:19 -08:00
|
|
|
|
|
|
|
// Defaults for ETB-style wastegate actuator
|
|
|
|
CONFIG(etbWastegatePid).pFactor = 1;
|
|
|
|
CONFIG(etbWastegatePid).minValue = -60;
|
|
|
|
CONFIG(etbWastegatePid).maxValue = 60;
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
void startBoostPin() {
|
2020-03-23 20:06:52 -07:00
|
|
|
#if !EFI_UNIT_TEST
|
2020-11-22 15:30:19 -08:00
|
|
|
// Only init if a pin is set, no need to start PWM without a pin
|
2021-01-08 17:01:26 -08:00
|
|
|
if (!isBrainPinValid(CONFIG(boostControlPin))) {
|
2020-02-02 00:56:21 -08:00
|
|
|
return;
|
|
|
|
}
|
2020-02-04 17:17:31 -08:00
|
|
|
|
2020-11-02 21:09:42 -08:00
|
|
|
startSimplePwm(
|
2020-02-04 17:17:31 -08:00
|
|
|
&boostPwmControl,
|
|
|
|
"Boost",
|
|
|
|
&engine->executor,
|
|
|
|
&enginePins.boostPin,
|
|
|
|
engineConfiguration->boostPwmFrequency,
|
2020-03-25 15:14:09 -07:00
|
|
|
0.5f
|
2020-02-04 17:17:31 -08:00
|
|
|
);
|
2020-03-23 20:06:52 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void onConfigurationChangeBoostCallback(engine_configuration_s *previousConfiguration) {
|
2020-05-06 05:40:42 -07:00
|
|
|
boostController.onConfigurationChange(&previousConfiguration->boostPid);
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
2021-04-21 11:28:48 -07:00
|
|
|
void initBoostCtrl(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2020-12-06 15:39:50 -08:00
|
|
|
// todo: why do we have 'isBoostControlEnabled' setting exactly?
|
|
|
|
// 'initAuxPid' is an example of a subsystem without explicit enable
|
2020-11-22 15:30:19 -08:00
|
|
|
if (!CONFIG(isBoostControlEnabled)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasAnyEtbWastegate = false;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < efi::size(CONFIG(etbFunctions)); i++) {
|
|
|
|
hasAnyEtbWastegate |= CONFIG(etbFunctions)[i] == ETB_Wastegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have neither a boost PWM pin nor ETB wastegate, nothing more to do
|
2021-01-08 17:01:26 -08:00
|
|
|
if (!isBrainPinValid(CONFIG(boostControlPin)) && !hasAnyEtbWastegate) {
|
2020-02-04 17:17:31 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-06 05:40:42 -07:00
|
|
|
// Set up open & closed loop tables
|
|
|
|
boostMapOpen.init(config->boostTableOpenLoop, config->boostTpsBins, config->boostRpmBins);
|
2020-02-02 00:56:21 -08:00
|
|
|
boostMapClosed.init(config->boostTableClosedLoop, config->boostTpsBins, config->boostRpmBins);
|
2020-05-06 05:40:42 -07:00
|
|
|
|
|
|
|
// Set up boost controller instance
|
|
|
|
boostController.init(&boostPwmControl, &boostMapOpen, &boostMapClosed, &engineConfiguration->boostPid);
|
|
|
|
|
2020-03-23 20:51:51 -07:00
|
|
|
#if !EFI_UNIT_TEST
|
2020-02-02 00:56:21 -08:00
|
|
|
startBoostPin();
|
2021-01-18 04:04:14 -08:00
|
|
|
hasInitBoost = true;
|
2020-03-23 20:06:52 -07:00
|
|
|
#endif
|
2020-02-02 00:56:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|