The problem
Riding off with the side-stand down, or the motor responding when nobody is seated, causes accidents. Indian two-wheeler regulations and most electric scooters include such interlocks, and they must be robust to switch bounce and faulty inputs.
Objectives
- Read debounced side-stand, seat and brake inputs
- Implement a ready-mode state machine with a throttle-closed start check
- Drive the motor only in the Ready state and cut it immediately on an unsafe input
- Test every combination of inputs in a truth table
What you need
From the EV Embedded Development Kit
- STM32F103C8T6 microcontroller unit (Arm Cortex-M3)
- 4×3 matrix keypad
- Analog potentiometer input
- Motor driver for PWM motor-control experiments
- 16×2 LCD
- RGB LEDs and a buzzer
Software
- STM32CubeIDE with HAL GPIO, TIM and ADC
- Embedded C
Extra parts
- A small brushed DC motor within the motor driver's rating — The kit has a motor driver but no motor; it shows when traction is allowed.
Key concepts
- Interlock
- A condition that must be true before an action is allowed, such as stand up and seat occupied before the motor can be powered.
- Debouncing
- Mechanical switches bounce for a few milliseconds; requiring a stable reading for about 20 ms prevents false transitions.
- Ready mode
- Like a car's ignition, the scooter needs a deliberate action (brake plus start key) to enter a state where throttle is accepted.
Step-by-step guide
- 1
Requirements and truth table
Define the inputs: keypad 1 toggles the side-stand switch, 2 toggles the seat switch, 3 held is the brake and * is the start button. Motor power is allowed only when the stand is up, the seat is occupied, ready mode was entered with the brake held, and the throttle was below 5% at that moment. Write the full truth table of input combinations and expected outputs, and review it as a team before coding.
Checkpoint: A truth table covering every input combination, reviewed by the team.
- 2
Board setup
Use the DIP switches to enable the keypad, potentiometer, motor driver, LCD and RGB LEDs. In CubeMX configure the 72 MHz clock, the keypad row outputs and column inputs with pull-ups, ADC on the pot, a 20 kHz PWM channel and direction pins for the motor driver, and a timer for a 100 Hz main loop. Build a test program that shows keypad presses and the pot value on the LCD before adding the interlock logic.
Checkpoint: A test build shows keypad presses and pot values on the LCD.
- 3
Debounced inputs
Scan the keypad every 10 ms and accept a change only after two consecutive identical reads. Keep the side-stand and seat as toggled states and the brake as a held state, since that is how the real switches behave. Show all inputs on the LCD so testers can see what the controller believes. Press keys rapidly to check that no toggle is ever counted twice, because a false toggle here would defeat the interlock.
Checkpoint: Rapid presses never produce double toggles.
- 4
State machine
Implement four states: Off, Standby, Ready and Fault. Standby moves to Ready only when the stand is up, the seat is occupied, the brake is held, the throttle is closed and start is pressed. Any unsafe input while in Ready returns the system to Standby and sets the duty to zero immediately. Fault is entered on inconsistent inputs and needs a full reset sequence to clear. Draw the diagram and keep it in sync with the code.
Checkpoint: Every transition in the diagram can be triggered and illegal ones are refused.
- 5
Throttle and motor
In Ready, map the potentiometer to PWM duty with a short ramp so starts are smooth. Outside Ready, force the duty to zero on every loop rather than only on the transition, so no missed event or code path can leave the motor powered. Measure how long it takes from putting the stand down while driving to zero duty, by toggling a GPIO and watching it on an oscilloscope.
Checkpoint: Putting the stand down while driving stops the motor within one loop period.
- 6
Indications
Show the reason power is blocked on the LCD, such as 'Stand down', 'No rider' or 'Close throttle', so the rider knows what to fix. Set the RGB LED green in Ready, amber in Standby and red in Fault, and beep when a start attempt is refused. Check that every refusal in the truth table shows the correct reason, since a wrong message would send the rider looking for the wrong problem.
Checkpoint: Each refusal shows the correct reason.
- 7
Test against the truth table
Work through every row of the truth table, set the inputs, and record the actual state, duty and message against the expected ones. Add sequence tests that the table cannot show: inputs changing while in Ready, the throttle held open at start, start pressed without the brake, and rapid toggling. Fix any failure and rerun the full set, because changes to a state machine can break other rows.
Checkpoint: All rows pass.
- 8
Document
Write up the requirements, the truth table, the state machine and the test results. Add a short safety argument explaining why the motor cannot be powered in an unsafe state, pointing to the forced-zero duty and the start conditions. Include a demonstration video and a note on how a production scooter would use real switches, wiring checks for broken wires, and a dashboard indicator.
Checkpoint: Report and demonstration video.
Testing & validation
- Truth-table test of every input combination
- Response time from unsafe input to zero duty
- Throttle-open-at-start refusal
Expected results
A tested safety interlock that only lets the motor run with the stand up, rider seated and a deliberate ready sequence, and that cuts power at once on any unsafe change.
Take it further
- Replace keypad emulation with real microswitches on GPIO inputs
- Add input plausibility checks and a fault for stuck switches
- Report interlock state over CAN to a dashboard node
Viva and review questions
Why force duty to zero every loop outside Ready?
So no missed transition or bug can leave a non-zero duty set while the vehicle is unsafe.
Why check the throttle at start?
If the throttle is already open, entering Ready would make the scooter lurch forward.
What is switch bounce?
A mechanical contact makes and breaks several times in a few milliseconds when pressed; debouncing filters it.