wideband/firmware/heater_control.cpp

109 lines
2.5 KiB
C++
Raw Normal View History

2020-10-30 01:53:54 -07:00
#include "heater_control.h"
2020-10-31 14:58:34 -07:00
#include "wideband_config.h"
2020-10-30 01:53:54 -07:00
2020-10-30 02:40:18 -07:00
#include "ch.h"
2020-10-30 01:53:54 -07:00
#include "hal.h"
#include "pwm.h"
#include "sampling.h"
2020-10-31 14:58:34 -07:00
#include "pid.h"
2020-10-30 01:53:54 -07:00
// 400khz / 1024 = 390hz PWM
Pwm heaterPwm(PWMD1, 0, 400'000, 1024);
2020-10-30 02:40:18 -07:00
enum class HeaterState
{
Preheat,
WarmupRamp,
ClosedLoop,
};
int preheatCounter = 5000 / 50;
float rampDuty = 0.5f;
static HeaterState GetNextState(HeaterState state, float sensorEsr)
{
switch (state)
{
case HeaterState::Preheat:
preheatCounter--;
if (preheatCounter <= 0)
{
// If enough time has elapsed, start the ramp
// Start the ramp at 50% duty - ~6-7 volts
rampDuty = 0.5f;
return HeaterState::WarmupRamp;
}
2020-10-31 14:54:50 -07:00
// Stay in preheat - wait for time to elapse
break;
2020-10-30 02:40:18 -07:00
case HeaterState::WarmupRamp:
if (sensorEsr < 2000)
{
return HeaterState::ClosedLoop;
}
2020-10-31 14:54:50 -07:00
break;
case HeaterState::ClosedLoop: break;
2020-10-30 02:40:18 -07:00
}
2020-10-31 14:54:50 -07:00
return state;
2020-10-30 02:40:18 -07:00
}
2020-10-31 18:44:09 -07:00
static Pid heaterPid(0.01f, 0.05f, HEATER_CONTROL_PERIOD);
2020-10-31 14:58:34 -07:00
2020-10-30 02:40:18 -07:00
static float GetDutyForState(HeaterState state, float heaterEsr)
{
switch (state)
{
case HeaterState::Preheat: return 0.125f;
case HeaterState::WarmupRamp:
if (rampDuty < 0.9f)
{
// 0.4 volt per second, divided by battery voltage and update rate
rampDuty += (0.4f / (14 * 20));
}
return rampDuty;
case HeaterState::ClosedLoop:
2020-10-31 17:34:36 -07:00
// Negated because lower resistance -> hotter
return heaterPid.GetOutput(-HEATER_TARGET_ESR, -heaterEsr);
2020-11-28 03:04:04 -08:00
default: return 0;
2020-10-30 02:40:18 -07:00
}
}
2020-10-31 14:54:50 -07:00
static HeaterState state = HeaterState::Preheat;
2020-10-30 02:40:18 -07:00
static THD_WORKING_AREA(waHeaterThread, 256);
static void HeaterThread(void*)
{
while (true)
{
// Read sensor state
float heaterEsr = GetSensorInternalResistance();
// Run the state machine
state = GetNextState(state, heaterEsr);
float duty = GetDutyForState(state, heaterEsr);
// Pipe the output to the heater driver
heaterPwm.SetDuty(duty);
// Loop at ~20hz
2020-10-31 14:58:34 -07:00
chThdSleepMilliseconds(HEATER_CONTROL_PERIOD);
2020-10-30 02:40:18 -07:00
}
}
2020-10-30 01:53:54 -07:00
void StartHeaterControl()
{
heaterPwm.Start();
heaterPwm.SetDuty(0);
2020-10-30 02:40:18 -07:00
chThdCreateStatic(waHeaterThread, sizeof(waHeaterThread), NORMALPRIO + 1, HeaterThread, nullptr);
2020-10-30 01:53:54 -07:00
}
2020-10-31 14:54:50 -07:00
bool IsRunningClosedLoop()
{
return state == HeaterState::ClosedLoop;
}