Skip to content

Main State Machine (FSM)

The main part is build from a state machine, defining the use case environment for the BMS.

Firmware FSM In-/Outputs (Context)

Inputs to the firmware FSM come from:

  • Hardware Classes (e.g. state of the Latches, SCP, button, etc.)
  • Analog Thread (e.g. ADC, GPIO, other sensors, periodically samples)
  • Cyphal Receive Classes (e.g. Heartbeat and data messages from other battery packs)

Outputs / The firmware FSM state is used in:

  • Board shutdown (State Shutdown moves the BMS to a standby state)
  • Latch Control (e.g. voltage on pack side enabled by BMS internal latches). Class Latch, updated periodically in main-loop with the current fsm state.
  • LEDs (e.g. 5 RGB LEDs on top of the BMS). Class HotSwap, updated periodically in main-loop with the current fsm state.
  • Cyphal Messages (e.g. state is published in data messages)
  • Flash storage partition data (e.g. statistic data)

FSM Diagram

Hold "Alt" / "Option" to enable pan & zoom
stateDiagram-v2
    state state_machine {
        [*] --> Init: wake-up
        Init --> Idle: timeout | latch_off
        Init --> SoCFeedback: unconnected + button press
        Init --> Copter: in copter && latch_on
        Init --> ChargerCHG_DSG: in charger && latch_on

        Idle --> Shutdown: timeout
        Idle --> SoCFeedback: button
        Idle --> HotSwapCharge: engage && in copter
        Idle --> Error: on error detect
        Idle --> ChargerIdle: in charger

        SoCFeedback --> Idle: timeout || long button
        SoCFeedback --> Error: on error detect

        HotSwapCharge --> Idle: in open
        HotSwapCharge --> CopterWarmup: hs_voltage_ok && in copter && pin closed
        HotSwapCharge --> ChargerHS: hs_voltage_ok && in charger && pin closed
        HotSwapCharge --> Error: on error detect

        CopterWarmup --> Copter: timeout
        CopterWarmup --> Idle: in open && pin open
        CopterWarmup --> Error: on error detect

        Copter --> Shutdown: in open && pin open
        Copter --> Shutdown: multiple packs have shutdown requested

        ChargerIdle --> ChargerWaiting: vbus ok
        ChargerIdle --> Shutdown: vbus off
        ChargerIdle --> ChargerHS: engage
        ChargerIdle --> Idle: in open
        ChargerIdle --> Error: on error detect

        ChargerWaiting --> Shutdown: vbus off
        ChargerWaiting --> ChargerHS: engage || this set begin
        ChargerWaiting --> Idle: in open
        ChargerWaiting --> Error: on error detect

        ChargerHS --> Shutdown: timeout
        ChargerHS --> Error: on error detect
        ChargerHS --> Idle: in open
        ChargerHS --> ChargerWaiting: other set should begin || incomplete
        ChargerHS --> ChargerCHG_DSG: voltage ok

        ChargerCHG_DSG --> Error: on error detect
        ChargerCHG_DSG --> Idle: in open
        ChargerCHG_DSG --> ChargerWaiting: other set should begin && no charging || incomplete

        Error --> Shutdown: error resolve && in open

        Shutdown --> [*]

        [*] --> Maintenance: on register activation
        Maintenance --> [*]: register target && deactivation
    }
State Description
Init Initial state after wake-up. Identifies the latch states to enable exceptional restart of the state machine.
Idle System is waiting for events or user input. Turns off after 1s.
Shutdown Shuts down the BMS safely, disabling outputs and power-off.
SoCFeedback Displays the State of Charge (SoC) for a short period (e.g., 1 second).
HotSwapCharge Hot Swap (Precharge) is active, allowing limited current to output for safe connection/disconnection.
CopterWarmup Latches for output current are active (pre flight mode). Error detection possible for initial timeout. LED of set in syncing process
Copter Latches for output current are active (flight mode). All protection features are disabled for operation.
ChargerIdle Charger is connected, waiting for further action. Automatic wakeup lands here. Switch to Wait when vbus is ok.
ChargerWaiting Charger is connected, waiting for further action. After engage or when vbus is ok.
ChargerHS Charger with Hot Swap to safely enable current. Stays if external charge is out of operational range.
ChargerCHG_DSG Charger with full operations. Latches are enabled.
Error An error was encountered (e.g., short circuit, overvoltage, overtemperature).
Maintenance Internal use only. The Cyphal Registry can trigger the transitions (from/to anywhere), timeout, ...

State Encoding

According to bms_app/include/helper/bms.hpp, the following enumeration is used for integer encoding of the FSM States:

enum class FSM_STATE : uint8_t {
 UNKNOWN = 0,
 INIT,
 IDLE,
 HOTSWAP_CHARGE,
 COPTER,
 CHARGER_IDLE,
 ERROR,
 SHUTDOWN,
 SOC_FEEDBACK,
 CHARGER_HS,
 CHARGER_CHG_DSG,
 CHARGER_WAITING,
 MAINTENANCE,
 COPTER_WARMUP,
 END, // for array indices, always at end!
};

Maintenance

The Maintenance state is special as it is designed for internal use only!

To enter the state, the Cyphal Register bms.maintenance.active can be set via cyphal. During this state, the latch and the hotswap are set by the Cyphal Registers bms.maintenance.latch and bms.maintenance.hotswap. The exit transition occurs when the Cyphal Register bms.maintenance.active is unset or a timeout occurs. The timeout is set via Kconfig (CONFIG_BMS_FSM_MAINTENANCE_MAX_DURATION_SEC) to 15min and reset every time one of the bms.maintenance.-Registers is written. The exit transition target state is set by the Cyphal Register bms.maintenance.exit_state (default: IDLE).

During Maintenance, the LEDs show a blinking state led (LED[4]; 🟠 orange - ⚫ off). The LED[1] represents the HotSwap, while LED[2] shows the Latch. In disabled state they are 🟠 orange, if activated, ⚪ white. The Hotswap switches (could be immediately) to 🟢 green if the voltage is in range to activate the latch.

Latch activation

The latch activation performs no automated check whether the voltage level is in range / ok!

Maintenance notes

  • Set the outputs (latch/hotswap) before entering the state to ensure continuous operation
  • Periodically set at least one bms.maintenance.-Register to avoid exit by timeout
  • Define the bms.maintenance.exit_state before exiting