PID calibration

This commit is contained in:
Alessandro Mauri 2026-05-11 18:03:22 +02:00
parent 3a6e6bdcea
commit 9799947842
2 changed files with 50 additions and 45 deletions

View File

@ -29,15 +29,9 @@
#define ENCODER_DEBOUNCE 6000
// TODO: these need to be calibrated
// Tip mV to deg C conversion factor numerator
#define TC_CONV_NOM 151
// Tip mV to deg C conversion factor denumerator
#define TC_CONV_DEN 1000
#define MAX_BOARD_TEMP 50
#define MAX_TIP_TEMP 500
#define TURN_OFF_DELAY 2
#define TURN_OFF_DELAY 3
#define CYCLES_PER_MEASURE 2
#define BOARD_MAX_VOLTAGE 28000

View File

@ -364,6 +364,40 @@ static inline uint16_t isqrt(uint32_t x)
}
// Input: temperature difference
// Output: duty-cycle 0-max_duty
uint16_t pid(int16_t delta, int16_t max_duty)
{
static s32 err_p, err_i, err_d, dt, prev_err;
static u32 t, prev_t;
t = funSysTick32();
dt = FR_DIV(I2FR((t-prev_t)/DELAY_MS_TIME, R), R, I2FR(1000, R), R);
s32 err = I2FR(delta, R); // temperature delta as fixed point number
err_p = err;
if (delta > 40 && delta < -40) err_i = FR_CLAMP(FR_FixAddSat(err_i, FR_FixMulSat(err, dt)), I2FR(-1000, R), I2FR(1000, R));
else err_i = 0;
err_d = FR_DIV(FR_FixAddSat(prev_err, -err), R, dt, R);
prev_err = err;
prev_t = t;
// PID coefficients
const s32 kp = FR_numstr("1.1700", R);
const s32 ki = FR_numstr("0.05000", R);
const s32 kd = FR_numstr("0.07000", R);
s32 e = 0;
e = FR_FixAddSat(e, FR_FixMulSat(err_p, kp));
e = FR_FixAddSat(e, FR_FixMulSat(err_i, ki));
e = FR_FixAddSat(e, FR_FixMulSat(err_d, kd));
e = FR_CLAMP(e, I2FR(0, R), I2FR(100, R));
return FR2I(FR_FixMulSat(FR_DIV(e, R, I2FR(100, R), R), I2FR(max_duty, R)), R);
}
__attribute__((noreturn)) int main(void)
{
SystemInit();
@ -492,7 +526,7 @@ __attribute__((noreturn)) int main(void)
static uint16_t vbus_mv, current_ma;
static volatile int16_t temp_c, tip_temp_c;
static uint16_t power;
static s32 e;
static uint16_t duty;
vbus_mv = U16_FP_EMA_K4(vbus_mv, ((u32)adc_buffer[0]*VCC_MV*11)/4096);
current_ma = U16_FP_EMA_K4(current_ma, get_current_ma(adc_buffer[1]));
temp_c = I16_FP_EMA_K4(temp_c, get_temp_c(adc_buffer[2]));
@ -503,9 +537,17 @@ __attribute__((noreturn)) int main(void)
Delay_Ms(TURN_OFF_DELAY);
adc_injection_conversion();
u32 tip_mv = ((u32)injection_results[0]*VCC_MV)/4096;
tip_temp_c = I16_FP_EMA_K2(tip_temp_c, (tip_mv*TC_CONV_NOM)/TC_CONV_DEN) + temp_c;
// Tip calibration factors
const s32 tip_k = FR_numstr("0.144728", R);
const s32 tip_off = FR_numstr("0", R);
int16_t tt_now = FR2I(FR_FixAddSat(FR_FixMulSat(I2FR(tip_mv, R), tip_k), tip_off), R);
tip_temp_c = I16_FP_EMA_K4(tip_temp_c, tt_now + temp_c);
if (enabled) {
duty = pid((int16_t)pd_profile.set_temp - tip_temp_c, pd_profile.max_duty);
} else {
duty = 0;
}
}
int16_t delta = (int16_t)pd_profile.set_temp - tip_temp_c;
switch (state) {
case STATE_MENU:
@ -529,15 +571,14 @@ __attribute__((noreturn)) int main(void)
case STATE_HEATING:
// Display tip temperature
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TIP:");
u8g2_DrawStr(u8g2, x_off+20, y_off+7, u16toa(tip_temp_c));
u8g2_DrawStr(u8g2, x_off+20, y_off+7, i16toa(tip_temp_c));
// Display bus voltage
u8g2_DrawStr(u8g2, x_off+45, y_off+7, "V:");
u8g2_DrawStr(u8g2, x_off+55, y_off+7, u16toa(vbus_mv/1000));
// Display power
//u8g2_DrawStr(u8g2, x_off+0, y_off+15, "W:");
//u8g2_DrawStr(u8g2, x_off+10, y_off+15, u8g2_u16toa(power, 3));
FR_printNumF(buf_putc, e, R, 0, 3);
u8g2_DrawStr(u8g2, x_off+0, y_off+15, buf_get());
u8g2_DrawStr(u8g2, x_off+0, y_off+15, u16toa(duty));
// Display current
// u8g2_DrawStr(u8g2, x_off+45, y_off+15, "A:");
// u8g2_DrawStr(u8g2, x_off+55, y_off+15, u16toa(current_ma));
@ -571,37 +612,8 @@ __attribute__((noreturn)) int main(void)
if (pwm) {
const uint16_t tim_max = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1;
static s32 err_p, err_i, err_d, dt, fpt, prev_fpt;
static u32 t, prev_t;
uint16_t duty;
// absolute temperature error
s32 err = I2FR(delta, R);
fpt = I2FR(tip_temp_c, R);
t = funSysTick32();
dt = FR_DIV(I2FR((t-prev_t)/DELAY_MS_TIME, R), R, I2FR(1000, R), R);
err_p = err;
// Conditional integration
if (delta > 40 && delta < -40) err_i = FR_CLAMP(FR_FixAddSat(err_i, FR_FixMulSat(err, dt)), I2FR(-1000, R), I2FR(1000, R));
err_d = FR_DIV(FR_FixAddSat(prev_fpt, -fpt), R, dt, R);
prev_t = t;
prev_fpt = fpt;
const s32 kp = FR_numstr("1.2000", R);
const s32 ki = FR_numstr("0.05000", R);
const s32 kd = FR_numstr("0.00000", R);
e = 0;
e = FR_FixAddSat(e, FR_FixMulSat(err_p, kp));
e = FR_FixAddSat(e, FR_FixMulSat(err_i, ki));
e = FR_FixAddSat(e, FR_FixMulSat(err_d, kd));
e = FR_CLAMP(e, I2FR(0, R), I2FR(100, R));
duty = FR2I(FR_FixMulSat(FR_DIV(e, R, I2FR(100, R), R), I2FR(pd_profile.max_duty, R)), R);
if (duty <= 100) {
pwm_set(((u32)duty*tim_max)/100);
u8g2_DrawBox(u8g2, x_off+92, y_off+12, 4, 4);
}
pwm_set(((u32)duty*tim_max)/100);
u8g2_DrawBox(u8g2, x_off+92, y_off+12, 4, 4);
} else {
pwm_set(0);
}
@ -622,7 +634,6 @@ __attribute__((noreturn)) int main(void)
if (enabled) {
pwm_on();
} else {
e = 0;
pwm_off();
}
}