static
Safety features: what we built in, and why
GearSense's TIM, the Throttle Injection Module, lets GearSense drive an e-bike's throttle line. Anything that can command a motor can do so incorrectly. When that motor is propelling s vehicle, an out of control motor is unacceptable. A great deal of TIM's design effort has gone into one question: what happens when something fails? This page lists every safety feature in the design, why each one is there, and how far along it is. It is written from the design documents in the gearsense-hardware repo (TIM_FMEA_PRELIMINARY, TIM_FAILSAFE_ARCHITECTURE_REVIEW, TGM_CARD_SPEC, TGM_FIRMWARE_BRIEF, TIM_RELAY_SELECTION, TIM_THROTTLE_SENSE_DESIGN, TIM_ASSIST_CEILING_DESIGN, TIM_MAIN_BOARD_SPEC), as of 2 November 2026.
Status key. Bench-proven: built and tested. In Rev A: in the TIM main board Rev A design, which has gone to manufacture and has not been built or tested yet. Designed: specified in full, firmware not yet written.
The hazard we are designing against
On the test bike (Cargo, Lishui controller) the throttle is inverted: about 3.4 V at rest and about 0.83 V at full throttle. Low voltage means more power. So any wire, chip, or output that fails towards 0 V could potentially command full power. Every failure path in TIM therefore has to end at "the rider's own throttle", never at "some voltage TIM was holding". Other bikes use the normal sense (low = idle), and TIM has to be safe on those too, without the client setting anything.
The principles
- The rider always wins. Any deliberate throttle movement takes control back at once.
- A failed TIM must be an absent TIM. Power loss, a software crash or a fault must remove TIM from the circuit. It must not leave the circuit holding a value. This is done with a special kind of relay.
- Physics first, firmware second. The fail-safe is the relay's resting position and a few resistors. Firmware checks are layered on top and are never the only protection.
- No guard, no injection - enforced in copper. The injection path physically runs through the guard circuit. This check was introduced when the design was modular to ensure no throttle signal could reach the bike if the TGM was absent. With the integrated version that becomes moot.
- Prove it every ride. The checks that matter run at every power-up and on every hand-back, not once at the factory.
- Plug and play. No switches, trimpots or setup steps for the client. Learned settings err towards less power.
- Right first time. Safety features go in complete from Rev A, not as footprints to fill later (Bjorn's advice, adopted 2026-10-22).
1. The relay rests on the rider's throttle
K1 is a changeover relay. It's job is to switch between the bike's control ant TIM's control. With its coil off, the rider's throttle goes through the normally-closed contact straight to the controller (ESC). All your normal bike controls work. TIM's DAC is only connected through the normally-open contact, so it can only reach the ESC while the coil is deliberately energized. Unpowered, unplugged, crashed or reset, TIM is electrically invisible, as if it had never been installed.
Why? Because it doesn't depend on TIM behaving correctly, when TIM fails it simply drops out of the circuit. This was chosen deliberately over analogue "combiner" designs (min-select, max-select, diode-OR), where a failure leaves a blended voltage on the line.
Status: bench-proven 2026-08-08 (TIM_Relay_Test: click, LED and continuity all confirm COM/NC/NO mapping and active-high enable).
2. A safety relay that can prove it let go
A relay contact can weld shut. If K1's normally-open contact welds, the ESC stays on the DAC even after the coil is switched off, and every other protection that works by dropping the relay is defeated. K1 is a forcibly guided relay (Finder 50.12.9.005.5000, EN 61810-3 Type B, gold-clad contacts for signal-level switching). Its second pole is mechanically tied to the first, so a welded normally-open contact physically holds the second pole's normally-closed "mirror" contact open. That mirror contact is wired back to the ESP32 as RELAY_STATE, so firmware reads the real position of the contacts, not just what it commanded.
- Checked at every power-up, and on every exit from assist: the contacts must be back at rest within 15 ms of the coil dropping.
- If they aren't: FAULT_WELD. The DAC is held at idle, the fault is latched in non-volatile storage, the rider is told ("relay fault — throttle disconnected, motor at idle"), and assist is never offered again until a bench reset. The brake cutout still works.
- The same readback catches a dead coil, a failed driver or a stuck mechanism (FMEA-01, FMEA-02).
Why: a weld is unlikely on a signal-level line, but it would silently disable everything else (FMEA-11). The earlier design used two separate relays, and those could not detect a weld in each other. Paul pulled this from Rev B into Rev A, and kept it after the cost check (about $23 each, more than the display module): "It is an important feature."
Status: in Rev A. K1 is fitted by hand.
3. The Throttle Guard (TGM)
The guard sits only on the injection path, between the DAC and the relay's normally-open contact. It never touches the rider's own path. It has four jobs:
- Fail-safe bias. If the DAC stops driving (dies, floats, or enters a power-down mode), the guarded path drifts to idle rather than to whatever the ESC's input happens to pull towards. This covers FMEA-04, where the Lishui ESC's response to a floating throttle input was unknown and could have read as full power.
- Hardware assist clamp. A buffered floor and ceiling clamp means the guarded path can never go beyond a set limit, whatever the firmware commands. On an inverted bike the assist cap is a voltage floor. Getting that sign wrong in code is exactly the bug the clamp exists to survive (FMEA-07b). Both clamp sides are always fitted, and the unused one is parked out of range, so one board fits either throttle polarity.
- Sensing. ESC_SENSE shows what the ESC actually sees, and CLAMP_SENSE shows what the guarded path is doing, so firmware can compare both against what it commanded.
- Interlock. RELAY_EN and the DAC path both run through the guard, so there is no injection without it. On the consolidated board it is always fitted, and its presence is still checked (the guard's memory chip must answer on I²C).
A 1 kΩ series resistor between the DAC and the guarded node also limits what a fault on either side can push into the other.
Status: in Rev A.
4. Limits that are learned, stored, and locked
The bias, floor and ceiling used to be a switch and two trimpots, which every client would have had to set correctly. They are now learned by firmware and held in a non-volatile quad digital pot (MCP4461):
- Learning: idle comes from the throttle at rest at power-up. Polarity and span come from the rider's first deliberate twist. Learning only ever watches the rider's path and never moves the motor. A partial first twist gives a smaller span and a tighter clamp, so learning errs safe. The span may only grow later, by the same rule.
- Relearning: if the stored signature doesn't match, or the idle at power-up falls outside the learned envelope (the board has moved to another bike).
- Writes: only with the relay off and its contacts at rest for at least 40 ms. Every write is read back, with a signature and CRC kept in both the pot's EEPROM and the ESP32's NVS.
- Two independent hardware locks: whenever RELAY_EN is high or the contacts are away from rest, (A) the pot is cut off from the I²C bus, which works with any I²C part, and (B) it is held in reset, which forces its outputs back to the stored values. The "or contacts away from rest" leg means a welded relay keeps the clamp locked too.
Why: a clamp that firmware can rewrite while injecting is not a clamp. The locks make "no writes while injecting" a fact in copper, twice over, and neither depends on one part's special feature.
Status: in Rev A (the pot is U102 on the main board). Learning firmware designed.
5. Self-test at every power-up
The guarded path can be tested with the relay off, because the normally-open contact is then disconnected from the ESC. That means zero motor risk. Each power-up:
- The contacts are at rest, and ESC_SENSE matches the rider's throttle (a welded contact shows up here).
- The pot is present and its signature is valid.
- The bias is proven: the DAC is put into a high-impedance mode, and the path must drift to idle.
- The clamp is proven: the DAC is driven to its "most power" extreme, and the path must stop at the stored limit.
- The DAC is returned to idle.
- Lock proof, the only step that energizes K1, with the DAC at idle and only after the clamp is proven. Each lock and each leg of the lock gate is shown to work separately: the lock engages before the contacts move, holds until they are back at rest, and stays engaged for an unlock delay. Lock B is proven by the pot reloading its stored value.
Any failure leaves assist unavailable, with a specific fault code (FAULT_NOCARD, FAULT_POT, FAULT_BIAS, FAULT_CLAMP, FAULT_PATH, FAULT_LOCKSENSE, FAULT_LOCKA/B, FAULT_ORDER, FAULT_MIRRORLEG, FAULT_DELAY, FAULT_RELAY, FAULT_WELD).
Status: designed (TGM_FIRMWARE_BRIEF). The hardware it tests is in Rev A.
6. Watching every tick while assisting
While TIM is driving, every control tick checks that:
- the contacts are still where they should be (RELAY_STATE);
- both locks are still holding (LOCK_SENSE);
- the ESC sees what was commanded (ESC_SENSE, within 80 mV after filtering);
- the clamp has not been passed (CLAMP_SENSE).
Any deviation drops the relay and locks out assist. Every exit, for whatever reason, runs in the same order: DAC to idle, lock the pot, drop the relay, then confirm the contacts were released (weld check). A watchdog also drops RELAY_EN if the main loop stalls, as a software net over the hardware one.
Status: designed.
7. The rider can always take it back
A healthy TIM that is busy driving still has to give way to the rider (FMEA-10). THROTTLE_SENSE reads the rider's throttle continuously, even while it is disconnected from the ESC. Any deliberate movement outside the learned idle envelope (6% of span) for two filtered samples, about 2–8 ms, drops the relay immediately and unconditionally and latches OVERRIDE.
Resuming is deliberately slow. The throttle must sit continuously inside the idle envelope for a hold time (about 0.5–1 s). Then the DAC is set to idle before the relay re-energizes, and assist ramps in again from idle. It never snaps back to its old output.
Why the asymmetry: a false override costs a moment without assist. A missed override is the real hazard. So leaving assist is fast and generous, and resuming it is slow and conservative.
Status: sense network bench-tested (TIM_Throttle_Sense_Test). State machine designed.
8. The DAC is at idle before the relay ever closes
If the relay energized before the DAC had been given a safe value, the ESC would briefly see whatever the DAC powered up with (FMEA-03). Three things close this:
- The DAC's stored power-on value is set to idle when it is commissioned.
- Every entry into assist, including resuming after an override, writes idle first.
- The fail-safe bias catches a DAC that isn't driving at all.
Status: in Rev A, with firmware designed.
9. An assist controller that fails towards less
The assist law itself (baseline-cadence hold plus a bounded effort term, the "virtual torque sensor") is designed to fail safe:
- The effort term is a bounded nudge, capped by the mode ceiling, and never open-ended.
- If its baseline is uninitialised or corrupt, the effort term is switched off, and only the baseline hold remains.
- Before the first road test, a bench gate: raise the inferred effort and confirm with a meter that the DAC moves in the "more assist" direction for that bike's polarity. Reading the code is not enough.
- The hardware clamp (section 3) bounds the worst case even if all of this is wrong.
Status: designed. The controller is not built yet. Choosing the clamp percentage needs ride data, and that decision is Paul's.
10. Power: no assist without bike power
- A power mux (TPS2116) feeds the head unit from the bike's main battery, taking anything from 11 to 90V and feeding GearSense a 5V rail, or from USB when the bike is off. It blocks reverse current, so USB can never power the relay coil, the guard or the DAC.
- The mux reports which source is live (PWR_SRC). On USB alone, firmware refuses assist and the relay.
- The display module's own USB-C port must be covered by the enclosure, because it bypasses the mux. That is an enclosure requirement.
- The 5 V rail is monitored (V_DROK_SENSE). Losing TIM's power drops the relay, which returns the rider's throttle.
Status: in Rev A.
11. Built to survive a bike it hasn't met
- The throttle sense input is a divider sized so that a standard 0.8–4.2 V Hall throttle (or a 5 V rail) can't exceed the ESP32's ADC limit, with a clamp diode as well. TIM has to be safe on bikes it has never seen.
- One board, no card connectors. Connectors are what fail on a vibrating bike, so the rider's throttle path never crosses one. Power, throttle and ESC arrive on soldered pigtails with strain relief.
- The relay enable has a defined OFF state: a pull-down keeps it low if anything upstream goes away.
Status: in Rev A.
12. The brake still wins, independently
On the test bike, the brake lever is wired straight to the ESC and cuts motor power unconditionally, whatever TIM does. TIM no longer has a brake input of its own (removed 2026-10-28), because it doesn't need one to be safe. It is the last line of defence and depends on nothing in this design. The FMEA notes that any design decision relying on it must be re-examined before TIM goes on a bike without that independent cutout.
13. How we work
- A written FMEA (eleven failure modes so far), with honest status for each: mitigated and confirmed, mitigated by design, or open.
- Measure, don't assume. Throttle wire colours were wrong once. Every new bike's wiring is checked with a meter against a known ground (FMEA-09).
- Bench before road. No energizing the relay against a real ESC under an untested control law. Until then the DAC is driven with known, hand-picked voltages only.
- Safety tests that don't move the motor wherever possible (section 5).
Still to do
- Build and bench-test the Rev A board, including checking K1's footprint against a real relay.
- Write the firmware for the self-test, learning, lock proofs, runtime monitoring, the override state machine and the assist controller. All of these are designed; none are written yet.
- Set the clamp percentage from real ride data.
- Characterize the 5 V rail's worst-case excursion against the mux's 5.5 V limit.