diff --git a/board/boards/dos.h b/board/boards/dos.h index b6451bd6a..2af19d7cb 100644 --- a/board/boards/dos.h +++ b/board/boards/dos.h @@ -217,7 +217,7 @@ const board board_dos = { .fan_max_rpm = 6500U, .adc_scale = 8862U, .fan_stall_recovery = true, - .fan_enable_cooldown_time = 0U, + .fan_enable_cooldown_time = 3U, .init = dos_init, .enable_can_transceiver = dos_enable_can_transceiver, .enable_can_transceivers = dos_enable_can_transceivers, diff --git a/board/drivers/fan.h b/board/drivers/fan.h index cf4faa09b..bd3b59d11 100644 --- a/board/drivers/fan.h +++ b/board/drivers/fan.h @@ -48,7 +48,7 @@ void fan_tick(void){ current_board->set_fan_enabled(false); // clip integral, can't fully reset otherwise we may always be stuck in stall detection - fan_state.error_integral = MIN(50.0f, MAX(0.0f, fan_state.error_integral)); + fan_state.error_integral = MIN(0.0f, fan_state.error_integral); } } else { fan_state.stall_counter = 0U; @@ -57,13 +57,10 @@ void fan_tick(void){ } // Update controller - float feedforward = (fan_state.target_rpm * 100.0f) / current_board->fan_max_rpm; - float error = fan_state.target_rpm - fan_rpm_fast; + fan_state.error_integral += FAN_I * (fan_state.target_rpm - fan_rpm_fast); + fan_state.error_integral = MIN(100.0f, MAX(0.0f, fan_state.error_integral)); - fan_state.error_integral += FAN_I * error; - fan_state.error_integral = MIN(70.0f, MAX(-70.0f, fan_state.error_integral)); - - fan_state.power = MIN(100U, MAX(0U, feedforward + fan_state.error_integral)); + fan_state.power = MIN(100U, MAX(0U, fan_state.error_integral)); pwm_set(TIM3, 3, fan_state.power); // Cooldown counter diff --git a/python/__init__.py b/python/__init__.py index dd135c4ef..eca478dbb 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -194,6 +194,12 @@ class Panda: INTERNAL_DEVICES = (HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_TRES) HAS_OBD = (HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_RED_PANDA, HW_TYPE_RED_PANDA_V2, HW_TYPE_TRES) + MAX_FAN_RPMs = { + HW_TYPE_UNO: 5100, + HW_TYPE_DOS: 6500, + HW_TYPE_TRES: 6600, + } + # first byte is for EPS scaling factor FLAG_TOYOTA_ALT_BRAKE = (1 << 8) FLAG_TOYOTA_STOCK_LONGITUDINAL = (2 << 8) diff --git a/tests/fan_overshoot_test.py b/tests/fan_overshoot_test.py new file mode 100755 index 000000000..56fd7650c --- /dev/null +++ b/tests/fan_overshoot_test.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import time +from panda import Panda + +def get_overshoot_rpm(p, power): + # make sure the fan is stopped completely + p.set_fan_power(0) + while p.get_fan_rpm() > 100: + time.sleep(0.1) + time.sleep(1) + + # set it to 30% power to mimic going onroad + p.set_fan_power(power) + max_rpm = 0 + for _ in range(70): + max_rpm = max(max_rpm, p.get_fan_rpm()) + time.sleep(0.1) + + # tolerate 10% overshoot + expected_rpm = Panda.MAX_FAN_RPMs[bytes(p.get_type())] * power / 100 + overshoot = (max_rpm / expected_rpm) - 1 + + return overshoot, max_rpm + +if __name__ == "__main__": + p = Panda() + + for power in range(10, 101, 10): + overshoot, max_rpm = get_overshoot_rpm(p, power) + print(f"Fan power {power}% overshoot: {overshoot:.2f} Max RPM: {max_rpm}")