Skip to content

State Machines

Why Do We Need This?

Try it in Lab 07

Build a navigation state machine that combines line following, junction detection, and obstacle avoidance. β†’ State Machines tutorial

Your line-following robot needs to: - Follow the line normally - Stop when it sees an obstacle - Back up and go around - Resume line following

You start coding with if-else chains:

if obstacle and not backing_up and not turning:
    stop()
    backing_up = True
elif backing_up and timer > 500:
    backing_up = False
    turning = True
    ...

Soon you have 5 boolean flags, nested conditions 4 levels deep, and bugs where the robot gets "stuck" in impossible states. Every change breaks something else.

The problem: Your robot has modes (following, avoiding, stopped), but your code doesn't represent them explicitly. State machines fix this by making modes first-class citizens in your design.


Organizing Logic with Finite State Machines (FSMs)

As embedded systems become more complexβ€”especially those with multiple operational modes, user interaction, or real-time controlβ€”organizing control logic in a clear, scalable way becomes essential. One of the most effective techniques for managing this complexity is using a Finite State Machine (FSM).

A state machine models how a system behaves over time in response to external inputs. It acts like a behavioral blueprint for your system, much like a flowchart, where:

  • States represent the current mode or condition of the system.
  • Events are external triggers (e.g., button presses, sensor readings, timer expirations).
  • Transitions define how the system moves from one state to another based on events.
  • Actions are operations performed when entering, exiting, or during a state.

πŸ“Œ What Is an Event?

In a general sense, an event is a discrete occurrence that signals the system to respond or change its behavior.

Formally, an event is an external or internal trigger that, when received by a system in a particular state, may cause it to transition to another state and possibly perform actions.

For example, in an embedded system:

  • A button press generates an ev_ButtonPressed event.
  • A sensor threshold crossed might generate ev_TemperatureHigh.
  • A timeout might trigger ev_TimerExpired.

Using named events (often defined using Enums in Python) makes your state machine robust, readable, and safe from invalid input.


βœ… Why Use FSMs in Embedded Systems?

FSMs provide a structured way to describe how the system should behave in response to external events over time. This is especially useful for:

  • User interface flow (menus, input modes)
  • Device operation modes (e.g., OFF, RUNNING, ERROR)
  • Communication protocols (e.g., waiting for request, sending data)

FSMs promote:

  • Modularity β€” states are clearly separated
  • Clarity β€” transitions are explicit and predictable
  • Maintainability β€” it’s easy to add or modify behavior

Example: LED Control with IR remote

Let’s revisit a classic beginner scenario: controlling an LED using a button. Rather than using flags or nested conditionals, we can model the behavior as a state machine.

We might define:

Start β†’ Idle  
Idle -- right key press  β†’ On   
On -- left key press  β†’ Off

Each arrow represents a transition, triggered by a key press event. Each mode of the LED (OFF, ON) is a clearly defined state.

In the Idle state, turn on the red LED. In the On state, turn on the green LED and turn off the red one. So, only one LED is on at a time as show bellow.

state-machine step0

UML State Machines for Embedded Design

To formalize and visualize FSMs in a standardized way, we use UML (Unified Modeling Language) State Machines. Unlike purely theoretical models like Mealy and Moore machinesβ€”which are abstract and hardware-centricβ€”UML state machines are tailored for software design.

UML diagrams make it easier to design, understand, and communicate system behaviorβ€”especially as complexity grows. A UML State Machine Diagram is a way to visualize the behavior of a system that:

  • Has different modes of operation (states),
  • Changes mode based on events (like button presses),
  • Performs actions during or between states.

The example above in UML State Machine diagram:

state-machine step1

States

A state represents a mode of operation the system can be in. Each state can have associated actions:

  • entry / action β€” runs when the state is entered
  • do / action β€” runs while the system remains in the state
  • exit / action β€” runs just before leaving the stat

Transitions

A transition is a link between two states, triggered by an event.

Format:

ev_button_press [mode == AUTO] / toggle_led()

  • Event β€” the trigger (e.g., a button press, a timeout, or a sensor input)
  • Guard (optional) β€” a condition ([guard])that must be true for the transition to occur
  • Action (optional) β€” code to run during the transition (not in either state)
State Machine Describe Behavior β€” Not Structure or Interaction

It’s important to understand what FSMs are not: - FSMs do not describe the system’s structure (i.e., hardware components, modules, or classes)
- FSMs do not describe interaction diagrams (e.g., message sequences or signal flow)

Instead, FSMs are focused solely on system behaviorβ€”they answer: - What is the system doing now?
- What event should cause it to do something else?
- What happens during that transition? This makes FSMs a great fit for handling mode control, event-driven logic, and system states over time.


A simple State Machine Implementation in MicroPython

The state machine diagram describe only the behavior of the system. The structural design not part of it. The best practice is to split in tow half: - event generation - event handling

This architecture simplify the system. In one part we should card about how the events generated and the other one how the events handled and the state of the state machines working.


State Machine Implementation in MicroPython

Let's implement it! But how? So, we know what behavior we want from our system but we need a structure for it. As we implement it in MicroPython, to make it simple, we'll implement it in modules applying Python classes.

project/
β”‚
β”œβ”€β”€ main.py
β”œβ”€β”€ sm.py
β”œβ”€β”€ event.py
└── led.py
  • main.py contains the
  • sm.py contains the structure of the state machine
  • event.py contains the handling and generating the events
  • led.py contains the LED

How it will interact with each other? Let’s break it down using the diagram below:

state-machine interact

Why This Structure?

We’ve built the system this way for several important reasons:

  • Separation of concerns β€” each part does one job well.
  • Modularity β€” you can easily swap or extend parts (like using buttons or Bluetooth instead of IR).
  • Readability β€” the main loop is simple and easy to understand.
  • Reusability β€” components like the LED controller or state machine can be reused in other projects.

Don’t worry if it doesn’t all click right away β€” that’s normal! As you explore more embedded Python projects and look at different code bases, these design choices will start to make more sense.

πŸŽ“ There’s never just one β€œcorrect” structure β€” this is just one clean and practical example. With experience, you’ll find what works best for different problems.

Let's see the contents.

main.py

The main.py script runs the core control loop of the system.

main.py
from sm import StateMachine
from event import EventGenerator

# Initialize state machine and event system
sm = StateMachine()
event_gen = EventGenerator()

while True:
    # Generate events
    event = event_gen.get_event()

    # Process the events
    sm.process(event)

Inside the Infinite Loop

  • It polls for a new event (e.g., button press, remote signal).

    • This abstracts input handling β€” the main loop doesn't need to know how the event was generated, only that it happened.
  • It passes the event to the state machine, which decides how the system should respond (e.g., turn on an LED, start blinking, etc.).

This clean separation ensures that the core behavior logic (the state machine) stays decoupled from the hardware-specific input mechanisms. As a result, the system becomes more modular and easier to maintain or extend.

Caution

Avoid Blocking Calls in States
The state machine is processed within the main infinite loop.
This means every state handler must be non-blocking β€” if a state includes delays (e.g., sleep()) or long computations, it will prevent the system from polling new events in time.
Instead, use non-blocking techniques, such as:

  • Tracking elapsed time using timestamps (e.g., time.ticks_ms())

  • Updating outputs only when necessary

  • Breaking long tasks into smaller steps over multiple cycles

This approach ensures responsive, real-time behavior and keeps the system reactive to new inputs.

sm.py

The sm.py module defines the behavior of the system using a state machine. This is where the system decides how to respond to different events, like button presses, and what actions to perform (like turning LEDs on or off).

sm.py
from led import LED

# State constants
class State:
    INIT = 0
    IDLE = 1
    ON = 2
    # add more states here

# Event constants
class Event:
    RIGHT = "ev_RightButtonPressed"
    LEFT  = "ev_LeftButtonPressed"
    # add more events here

class StateMachine:
    """
    This state machine handles transitions and LED control.
    It owns the LED controller as a part of its internal state.
    """
    def __init__(self):
        self.state = State.INIT
        self.led = LED()

    def process(self, event):
        """
        Handle state transitions and actions.
        The event can come from IR, sensor, etc.
        """
        if self.state == State.INIT:
            self.state = State.IDLE
            print(">>> INIT β†’ IDLE")
            # init state entry
            self.led.on('red')

        elif self.state == State.IDLE:
            if event == Event.RIGHT:
                self.state = State.ON
                print(">>> IDLE β†’ ON")
                # actual state exit
                self.led.off()
                # next state entry
                self.led.on('green')

        elif self.state == State.ON:
            if event == Event.LEFT:
                self.state = State.IDLE
                print(">>> ON β†’ IDLE")                
                # actual state exit
                self.led.off() 
                # next state entry
                self.led.on('red')

        # add further state here

        # This branch should normally never be reached.
        # It serves as a fallback for error handling in case
        # an invalid or unexpected state occurs.
        else:
            self.state = State.IDLE

Let's break down a bit.

Constants

State Constants

INIT = 0
IDLE = 1
ON = 2

  • Represents all possible modes (states) the system can be in.
    Event Constants

    RIGHT = "ev_RightButtonPressed"
    LEFT  = "ev_LeftButtonPressed"
    

  • Represents external events that trigger transitions.

  • These come from user inputs (e.g., IR remote, buttons).

Why do we assign strings or numbers?

The actual value (0, "ev_...", etc.) doesn’t matter much. The key is using well-named constants to improve code clarity and avoid bugs from mistyped strings or reused numbers.

process(event) – Core Behavior Logic

The process() method is the heart of the state machine. It checks the current state, looks at the incoming event, and performs:

  • Transitions to the next state
  • Exit actions for the current state
  • Entry actions for the next state

Let’s walk through it:

  1. On the very first call, the machine is in INIT. It transitions to IDLE and performs the entry action of that state (red LED on, green off).

  2. Once in IDLE, if it receives Event.RIGHT, it transitions to ON:

    • Exits the IDLE state (turns red LED off)
    • Enters the ON state (turns green LED on)
  3. In ON, if it receives Event.LEFT, it goes back to IDLE, reversing the LED colors.

Each transition typically includes:

  • Exit actions from the current state
  • State change
  • Entry actions for the new state

This separation helps structure complex logic into manageable pieces.

Transitions happen at the same time as entering and exiting states β€” this is where your behavior should be defined.

How to Use Classes (in this context)

This StateMachine is a class, which means:

  • It stores state (self.state) and data (self.led)
  • It encapsulates behavior in methods like process()
  • It’s reusable and extendable β€” you can use it in different projects or tests

event.py

The event module is responsible for generating and handling system events. In this initial stage, our focus is solely on integrating the IR remote module.

Since the IR remote operates through polling, we periodically check its state to detect key press events. When a key press is detected, the module returns the corresponding event as defined in the sm (state machine) module.

For easier debugging and testing, each detected event is printed to the debug console.

from pico_car import ir
from sm import Event

class EventGenerator:
    """
    Handles all event generation from input devices (currently IR remote).
    More sources can be added later (GPIO, Bluetooth, etc.)
    """
    def __init__(self):
        self.ir = ir()  # IR receiver object
        self.last_ir_code = None

        # Mapping IR codes to events
        self.ir_event_map = {
            6: Event.RIGHT,
            4: Event.LEFT
        }

    def get_event(self):
        # First check IR
        event = self._check_ir()
        if event:
            print(f"Event: {event}")
            return event

        # Then check other sources for example:
        # event = self._check_gpio()
        # if event:
        #     return event

        return None

    def _check_ir(self):
        ir_code = self.ir.Getir()

        if ir_code is None:
            self.last_ir_code = None
            return None

        if ir_code == self.last_ir_code:
            return None  # Button held down β†’ skip

        self.last_ir_code = ir_code
        return self.ir_event_map.get(ir_code)

led.py

The LED module provides a class for controlling addressable LED strip. It encapsulates all functionality needed to manage and update the LED states. Please feel free to modify it.

from machine import Pin
import neopixel
import time

# Define basic color names
NAMED_COLORS = {
    'red': (255, 0, 0),
    'green': (0, 255, 0),
    'blue': (0, 0, 255),
    'yellow': (255, 255, 0),
    'white': (255, 255, 255),
    'off': (0, 0, 0)
}

class LED:
    """
    NeoPixel LED controller with support for:
    - setting color only (color())
    - turning on with last or new color (on())
    - blinking current color (blink())
    """
    def __init__(self, pin_num=6, count=8):
        self.strip = neopixel.NeoPixel(Pin(pin_num), count)
        self.count = count
        self._color = NAMED_COLORS['red']
        self._state = False
        self._last_time = time.ticks_ms()

    def color(self, name):
        """Set the internal color, does not light up the LED yet"""
        if name in NAMED_COLORS:
            self._color = NAMED_COLORS[name]
        else:
            raise ValueError(f"Unknown color name: {name}")

    def on(self, name=None):
        """
        Turn on the LED.
        If a color name is given, set and use it.
        Otherwise, use the previously stored color.
        """
        if name:
            self.color(name)
        for i in range(self.count):
            self.strip[i] = self._color
        self.strip.write()

    def off(self):
        """Turn all LEDs off"""
        for i in range(self.count):
            self.strip[i] = (0, 0, 0)
        self.strip.write()

    def blink(self, interval_ms):
        """Non-blocking blink of the current color"""
        now = time.ticks_ms()
        if time.ticks_diff(now, self._last_time) > interval_ms:
            self._last_time = now
            self._state = not self._state
            if self._state:
                self.on()
            else:
                self.off()

It also implements a non-blocking blink method. This is useful because it allows the method to be called at any timeβ€”the LED state will only change when the specified interval has passed. This approach supports non-blocking function calls, enabling smoother multitasking within the application.

Extending the Example: Add a Blinking State

Let’s extend our LED example by adding a blinking state. This introduces a new behavior: the LED should toggle on and off at a timed interval while in the LED_BLINK state.

We’ll now walk through how to design and implement this extended FSM step by step, starting with:

  • Updating the state diagram
  • Adding a timer or using utime.ticks_ms() to handle blinking

state-machine step2


Professional Context: Industrial & Automotive State Machines

Your simple if-else state machine works for LED control. Professional systems use sophisticated state machine architectures for complex behavior, safety certification, and formal verification. Here's how they compare:

State Machine Comparison

Feature Simple FSM (yours) UML Statecharts AUTOSAR BSW Safety-Critical
States Flat list Hierarchical (nested) Mode management Formally specified
Transitions Simple if-else Guards, actions, events Standardized API Verified exhaustive
History None Deep/shallow history State persistence Deterministic recovery
Concurrency None Orthogonal regions Task-based Proven non-interference
Verification Manual testing Model simulation Configuration tools Model checking (SPIN, UPPAAL)
Code generation Manual UML tools AUTOSAR generators Certified code gen
Documentation Comments UML diagrams ARXML Formal specs + traceability
Certification None Optional ISO 26262 DO-178C, IEC 61508

Hierarchical State Machines (Statecharts)

Your flat FSM doesn't scale. With 10 states and 5 events, you might have 50 transitions to manage. Statecharts solve this:

Your FSM (flat):
    IDLE ──► RUNNING ──► ERROR ──► IDLE
    IDLE ──► PAUSED ──► RUNNING
    RUNNING ──► PAUSED
    ... many more transitions

UML Statecharts (hierarchical):
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ OPERATIONAL ───────────────────┐
    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
    β”‚  β”‚  IDLE   │─────►│ RUNNING │─────►│ PAUSED  β”‚   β”‚
    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
    β”‚                β–²                         β”‚        β”‚
    β”‚                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚ error event
                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    ERROR    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    Key features:
    - OPERATIONAL is a superstate containing IDLE, RUNNING, PAUSED
    - Error event from ANY substate β†’ ERROR (one transition, not three)
    - History: return to RUNNING or PAUSED after error recovery
    - Orthogonal regions: motor control || sensor reading (concurrent)

AUTOSAR State Management

Automotive software uses standardized state management:

Your robot:
    state = IDLE
    if event == START:
        state = RUNNING

AUTOSAR Basic Software (BSW):
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚                  ECU State Manager                   β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  BswM (Basic Software Mode Manager)                 β”‚
    β”‚  └── Controls mode transitions across all modules   β”‚
    β”‚                                                     β”‚
    β”‚  ComM (Communication Manager)                       β”‚
    β”‚  └── COMM_NO_COM β†’ COMM_SILENT β†’ COMM_FULL_COM    β”‚
    β”‚                                                     β”‚
    β”‚  EcuM (ECU Manager)                                 β”‚
    β”‚  └── STARTUP β†’ RUN β†’ SLEEP β†’ SHUTDOWN              β”‚
    β”‚                                                     β”‚
    β”‚  All transitions:                                   β”‚
    β”‚  - Defined in ARXML configuration                   β”‚
    β”‚  - Generated code (no manual implementation)        β”‚
    β”‚  - Standardized across all automotive suppliers     β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Formal Verification

For safety-critical systems, "it seems to work" isn't enough:

Your robot:
    Test cases: "Press button, LED turns on" βœ“
    Coverage: Maybe 60-80% of code paths
    Proof: None

Formally verified FSM:
    Model checker input:
        States: {IDLE, ARMED, FIRING}
        Events: {arm, fire, safe}
        Properties to verify:
            - No FIRING without ARMED first (safety)
            - Always possible to reach IDLE (liveness)
            - No deadlock (progress)

    SPIN/UPPAAL output:
        βœ“ Property 1: VERIFIED (all 847 states checked)
        βœ“ Property 2: VERIFIED
        βœ“ Property 3: VERIFIED
        β†’ PROVEN CORRECT for all possible executions

    Result: Mathematical proof, not just testing

Industrial PLC: Grafcet/SFC

Factory automation uses IEC 61131-3 Sequential Function Chart:

Your Python FSM:
    if state == FILL:
        if level > 80:
            state = HEAT

IEC 61131-3 SFC (Grafcet):
    β”Œβ”€β”€β”€β”€β”€β”
    β”‚  1  β”‚ INIT
    β””β”€β”€β”¬β”€β”€β”˜
       β”‚ start_button
    β”Œβ”€β”€β–Όβ”€β”€β”
    β”‚  2  β”‚ FILL ─── action: open_valve
    β””β”€β”€β”¬β”€β”€β”˜
       β”‚ level > 80%
    β”Œβ”€β”€β–Όβ”€β”€β”
    β”‚  3  β”‚ HEAT ─── action: heater_on
    β””β”€β”€β”¬β”€β”€β”˜
       β”‚ temp > 70Β°C
    β”Œβ”€β”€β–Όβ”€β”€β”
    β”‚  4  β”‚ MIX ──── action: mixer_on, timer(60s)
    β””β”€β”€β”¬β”€β”€β”˜
       β”‚ timer_done
    β”Œβ”€β”€β–Όβ”€β”€β”
    β”‚  5  β”‚ DRAIN ── action: drain_valve
    β””β”€β”€β”¬β”€β”€β”˜
       β”‚ level < 5%
       └───► back to step 1

    Features:
    - Graphical programming (visual, not code)
    - Parallel branches (simultaneous operations)
    - Standardized across all PLC vendors
    - Directly maps to ladder logic / function blocks

State Machine Code Generation

Professional tools generate code from models:

Manual coding (your approach):
    1. Draw state diagram
    2. Write Python code
    3. Test manually
    4. Hope diagram matches code

Model-based development:
    1. Draw state diagram in tool (Enterprise Architect, Rhapsody, etc.)
    2. Tool generates code automatically
    3. Code is GUARANTEED to match model
    4. Changes to model β†’ regenerate code

    Example tools:
    - IBM Rhapsody β†’ C/C++ code
    - Mathworks Stateflow β†’ C code
    - Yakindu β†’ C, C++, Java
    - QM (Quantum Modeling) β†’ C/C++ for embedded

Safety-Critical State Machines

For systems where bugs = injuries:

Your robot:
    Bug in state machine β†’ robot behaves weird
    Consequence: Annoyance

Aircraft flight control:
    Bug in state machine β†’ control surface wrong position
    Consequence: Crash, fatalities

    Requirements (DO-178C Level A):
    - Every state transition documented
    - Every transition tested
    - 100% code coverage (MC/DC)
    - Independent verification
    - Formal methods often required
    - Traceability: requirement β†’ design β†’ code β†’ test

    Automotive (ISO 26262 ASIL-D):
    - Similar rigor for steering, braking
    - WCET analysis for state handlers
    - Redundant state machines cross-checking
    - Safe state defined and reachable from any state

What the Industry Uses

Manufacturer Product Application
IBM Rhapsody UML statecharts, code generation
MathWorks Stateflow Simulink-integrated state machines
Quantum Leaps QP Framework Lightweight embedded state machines
Vector DaVinci AUTOSAR state machine configuration
ANSYS SCADE Safety-critical certified code gen
Siemens TIA Portal PLC SFC/Grafcet programming
itemis YAKINDU Open-source statechart tools

Hardware Limits Principle

What Software Can and Cannot Fix

Software CAN improve: - Code organization β†’ state machine pattern vs if-else spaghetti - Readability β†’ named states, events, clear transitions - Maintainability β†’ modular design, separation of concerns - Testing β†’ well-defined states easier to test - Debugging β†’ state logging, transition tracing

Software CANNOT fix: - No formal verification β†’ model checkers need mathematical models - No certification evidence β†’ safety standards need tool qualification - Real-time guarantees β†’ your Python GC can pause state processing - Concurrent state correctness β†’ need proper synchronization primitives - Exhaustive testing β†’ only formal methods prove all paths - Hardware failures β†’ state machine can't recover from dead MCU

The lesson: A well-structured state machine makes your code maintainable and debuggable. But for safety-critical systems requiring formal proof of correctness, you need specialized tools (model checkers), certified code generators, and often different languages (SPARK Ada, formal C subsets). The architecture is similarβ€”states, events, transitionsβ€”but the tooling and rigor are worlds apart.

Real Example: Complexity Growth

States Events Your FSM Statecharts Certified
3 2 Easy Overkill Overkill
10 5 Manageable Recommended Formal model
50 20 Unmaintainable Required Model checking
200+ 50+ Impossible Essential Full formal verification

Your 3-state LED controller is fine with if-else. A car's drive mode selector with 50+ states (Park, Reverse, Neutral, Drive, Sport, Eco, Snow, Tow, Launch, Limp, Error variants...) needs proper statechart tools. A flight control system needs mathematically proven state machines.


Further Reading