ouch finger
This commit is contained in:
@@ -42,19 +42,20 @@ static const float PID_KI = HEAT_PI_KI;
|
||||
static const float PID_KD = 0.0f;
|
||||
static const float GOOD_SPREAD_C = 5.0f;
|
||||
|
||||
// Tiered heater cap during heat-up
|
||||
static const float HEATER_MAX_DUTY_COLD = 85.0f;
|
||||
static const float HEATER_MAX_DUTY_MID = 65.0f;
|
||||
// Tiered heater cap during heat-up (100% until near target)
|
||||
static const float HEATER_MAX_DUTY_COLD = 100.0f;
|
||||
static const float HEATER_MAX_DUTY_MID = 75.0f;
|
||||
static const float HEATER_MAX_DUTY_NEAR = 45.0f;
|
||||
static const float HEATER_COLD_BELOW_C = 10.0f;
|
||||
static const float HEATER_WARM_BELOW_C = 3.0f;
|
||||
static const float CORNER_LIMIT_BAND_C = 10.0f;
|
||||
// Corner taper only within this band below target (was 10°C — blocked heat-up in uneven chambers)
|
||||
static const float CORNER_LIMIT_BAND_C = 2.0f;
|
||||
static const float HEATER_SLEW_UP_PER_S = 18.0f;
|
||||
static const float MAX_TEMP_HEADROOM_C = 15.0f;
|
||||
|
||||
static const uint16_t HEATER_CYCLE_MS = 3000;
|
||||
|
||||
// Fan PWM — FAN_IDLE_PWM ≈ 30%; off only while chamber avg is below 40°C
|
||||
// Fan PWM — stir speed when target > 0; off below 40°C only when idle (target 0)
|
||||
static const uint8_t FAN_IDLE_PWM = 77;
|
||||
static const float IDLE_AUTO_FAN_OFF_TEMP_C = 40.0f;
|
||||
static const uint8_t FAN_MAX_PWM = 255;
|
||||
|
||||
75
include/fan_characterize.h
Normal file
75
include/fan_characterize.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
class FanCharacterize {
|
||||
public:
|
||||
enum class Phase : uint8_t { Idle, Precool, Heat, Hold, Cooldown, Done, Failed };
|
||||
|
||||
FanCharacterize();
|
||||
|
||||
Phase phase() const { return phase_; }
|
||||
|
||||
bool isActive() const;
|
||||
|
||||
uint32_t elapsedMs(uint32_t nowMs) const;
|
||||
|
||||
uint8_t profileIndex() const { return profileIndex_; }
|
||||
|
||||
uint8_t profileCount() const { return FANCHARS_COARSE_COUNT + 1; }
|
||||
|
||||
uint8_t currentFanPwm() const;
|
||||
|
||||
float heaterPct() const { return heaterPct_; }
|
||||
|
||||
uint8_t winnerFanPwm() const { return winnerFanPwm_; }
|
||||
|
||||
bool isRefineRun() const { return refineRun_ && profileIndex_ >= FANCHARS_COARSE_COUNT; }
|
||||
|
||||
const char *phaseName() const;
|
||||
|
||||
bool start(float maxCornerC, float avgTempC);
|
||||
|
||||
void abort();
|
||||
|
||||
void reset();
|
||||
|
||||
bool update(float avgTempC, float maxTempC, float spreadC, uint32_t nowMs, float &heaterDutyOut,
|
||||
uint8_t &fanPwmOut);
|
||||
|
||||
void logIfDue(const float *sensorTemps, const bool *sensorValid, uint8_t sensorCount,
|
||||
float avgTempC, float minTempC, float maxTempC, float spreadC, uint32_t nowMs);
|
||||
|
||||
private:
|
||||
struct ProfileResult {
|
||||
uint8_t fanPwm;
|
||||
float meanSpreadC;
|
||||
};
|
||||
|
||||
void resetProfileStats();
|
||||
void beginProfileHeat(uint32_t nowMs);
|
||||
void enterHold(uint32_t nowMs);
|
||||
void finishProfile(uint32_t nowMs);
|
||||
void skipProfile(uint32_t nowMs, float maxTempC);
|
||||
void planRefine(uint32_t nowMs);
|
||||
void finishAll(uint32_t nowMs);
|
||||
void fail(const __FlashStringHelper *reason);
|
||||
|
||||
Phase phase_;
|
||||
float maxCornerC_;
|
||||
float coolAvgC_;
|
||||
float heaterPct_;
|
||||
uint8_t profileIndex_;
|
||||
uint8_t refineFanPwm_;
|
||||
bool refineRun_;
|
||||
uint32_t sessionStartMs_;
|
||||
uint32_t phaseStartMs_;
|
||||
uint32_t lastLogMs_;
|
||||
float spreadSum_;
|
||||
uint16_t spreadSamples_;
|
||||
uint8_t resultCount_;
|
||||
uint8_t winnerFanPwm_;
|
||||
ProfileResult results_[FANCHARS_MAX_RESULTS];
|
||||
};
|
||||
@@ -456,7 +456,7 @@ private:
|
||||
|
||||
void updateAutotune(float avgTempC, float maxTempC, uint32_t nowMs) {
|
||||
float duty = 0.0f;
|
||||
uint8_t fan = AUTOTUNE_PREHEAT_FAN_PWM;
|
||||
uint8_t fan = stirFanPwm_;
|
||||
autotuner_.update(avgTempC, maxTempC, cornerSpreadC_, nowMs, duty, fan);
|
||||
|
||||
heaterDutyPercent_ = duty;
|
||||
@@ -464,7 +464,7 @@ private:
|
||||
heaterOn_ = duty >= 50.0f;
|
||||
digitalWrite(HEATER_PIN, heaterOn_ ? HIGH : LOW);
|
||||
heaterBlock_ = duty > 0.0f ? HeaterBlock::None : HeaterBlock::Autotune;
|
||||
writeFan(fan);
|
||||
writeFan(fanManualActive_ ? fanManualPwm_ : stirFanPwm_);
|
||||
lastHeaterUpdateMs_ = nowMs;
|
||||
commitAutotuneIfDone();
|
||||
}
|
||||
@@ -513,15 +513,7 @@ private:
|
||||
}
|
||||
heaterDutyPercent_ = applyHeaterRamp(duty, avgTempC, nowMs);
|
||||
|
||||
const uint8_t fanPwm = fanManualActive_ ? fanManualPwm_ : stirFanPwm_;
|
||||
regulatingFanPwm_ = fanWithMinStir(avgTempC, fanPwm);
|
||||
}
|
||||
|
||||
uint8_t fanWithMinStir(float avgTempC, uint8_t pwm) const {
|
||||
if (avgTempC < IDLE_AUTO_FAN_OFF_TEMP_C) {
|
||||
return 0;
|
||||
}
|
||||
return pwm;
|
||||
regulatingFanPwm_ = fanManualActive_ ? fanManualPwm_ : stirFanPwm_;
|
||||
}
|
||||
|
||||
static float clampPercent(float value) {
|
||||
@@ -547,6 +539,11 @@ private:
|
||||
|
||||
float allowanceFromMaxCorner(float maxTempC, float avgTempC) const {
|
||||
if (!shouldLimitMaxCorner(avgTempC)) {
|
||||
// Heat-up: only taper when a hot corner nears the emergency ceiling
|
||||
if (maxTempC >= EMERGENCY_MAX_TEMP_C - 3.0f) {
|
||||
const float headroom = EMERGENCY_MAX_TEMP_C - maxTempC;
|
||||
return clampPercent((headroom / 3.0f) * 100.0f);
|
||||
}
|
||||
return 100.0f;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user