Files
StarPilot/system/hardware/fan_controller.py
T
whoisdomi 04ba07e706 C3/C3X Aggressive Fan Curve + Toggle
C3 and C3X Cooling Curve. 10 - 16 C cooler than stock curve.
2026-09-14 09:48:15 -05:00

54 lines
2.1 KiB
Python
Executable File

#!/usr/bin/env python3
import numpy as np
from abc import ABC, abstractmethod
from openpilot.common.realtime import DT_HW
from openpilot.common.swaglog import cloudlog
from openpilot.common.pid import PIDController
from openpilot.system.hardware import HARDWARE
# comma 4 (mici) always uses the stock curve; comma 3/3X (tici/tizi) can opt into a more
# aggressive, cooler-targeting curve via the "C3/C3X Aggressive Cooling" toggle
IS_MICI = HARDWARE.get_device_type() == "mici"
# original comma/sunnypilot curve: quieter on tici/tizi (higher setpoint) than on mici
STOCK_CURVE = dict(offset=0, k_p=0, ff_low=60.0, ff_high=100.0) if IS_MICI else \
dict(offset=5, k_p=0, ff_low=65.0, ff_high=105.0)
AGGRESSIVE_CURVE = dict(offset=-5, k_p=1.0, ff_low=55.0, ff_high=80.0)
class BaseFanController(ABC):
@abstractmethod
def update(self, cur_temp: float, ignition: bool, aggressive_cooling: bool = False) -> int:
pass
class TiciFanController(BaseFanController):
def __init__(self) -> None:
super().__init__()
cloudlog.info("Setting up TICI fan handler")
self.last_ignition = False
self.last_aggressive_cooling = False
self.controller = PIDController(k_p=STOCK_CURVE["k_p"], k_i=4e-3, rate=(1 / DT_HW))
def update(self, cur_temp: float, ignition: bool, aggressive_cooling: bool = False) -> int:
use_aggressive = aggressive_cooling and not IS_MICI
curve = AGGRESSIVE_CURVE if use_aggressive else STOCK_CURVE
self.controller.pos_limit = 100 if ignition else 30
self.controller.neg_limit = 30 if ignition else 0
self.controller._k_p = [[0], [curve["k_p"]]]
if ignition != self.last_ignition or use_aggressive != self.last_aggressive_cooling:
self.controller.reset()
error = cur_temp - (75 + curve["offset"])
fan_pwr_out = int(self.controller.update(
error=error,
feedforward=np.interp(cur_temp, [curve["ff_low"], curve["ff_high"]], [0, 100])
))
self.last_ignition = ignition
self.last_aggressive_cooling = use_aggressive
return fan_pwr_out