Design decisions
Decisions
Why things are built the way they are: what was chosen, what else was on the table, and what tipped it.
- Accepted
- Proposed
- Superseded
- acceptedBuild this site with Astro, hosted on Cloudflare Workers
· A static site generated from Markdown, deployed automatically from GitHub.
- acceptedWhen the signal generator runs dry, it sends legal DCC bits instead of DC
· If PicoDCC's PIO program runs out of packet data, it keeps emitting valid DCC '1' bits rather than parking the output pin. Running short of packets costs throughput instead of putting DC on the rails.
- acceptedThe layout starts with track power off
· Connecting to the command station checks the power state instead of switching it on. Only an operator turns the track on.
- acceptedBuild our own active-high block detector
· Off-the-shelf detectors pull low for occupied, so a broken wire under the layout reads as a clear block. A home-designed board with an active-high output makes that fault read as occupied instead.
- acceptedThe block detectors' Input A is left unpowered, against the datasheet
· Powering an LM-iD.1's Input A, as every datasheet says to, makes its output idle at 5V into 3.3V expander inputs. It's deliberately left unpowered on Westgate Hollow.
- acceptedMQTT for hardware, WebSocket for operators
· Sensors and point feedback talk to the orchestrator over MQTT under a binding contract. Operator devices, including the handheld throttle, use the orchestrator's WebSocket control plane.
- acceptedPoints are commanded by one device and read back by another
· Cobalt iP point motors take DCC commands but can't report their position, so position comes from their S2 contacts on a feedback node. That catches hand-thrown points, but creates two mappings nothing cross-checks.
- acceptedThe throttle's transport is chosen at runtime, not compiled in
· The ESP32 throttle speaks both WiThrottle (to JMRI) and the orchestrator's WebSocket, as equal peers selectable from its settings screen. With no over-the-air updates, a compile-time switch would mean a cable at the layout.
- acceptedSensor nodes publish only the sensors that are actually wired
· An unwired expander input reads as "clear", so publishing the whole pin table would tell the orchestrator a block is empty using a wire that doesn't exist. Nodes publish an allow-list instead.
- acceptedSensors must keep talking, and silence is treated differently from lying
· Every sensor re-sends its reading at least every 30 seconds. A silent sensor degrades only its own blocks, while a garbled message Safe-Stops the layout.
- acceptedThe track diagram is compiled into the route graph, under operator review
· Instead of describing the railway twice by hand, as a drawing and as a graph, the drawing is compiled into the graph. The operator reviews the diff and applies it.
- acceptedNever guess a stopping distance
· Automated braking uses only measured track lengths and refuses on unmeasured track. Automation's one invariant is that a train never passes the end of its authority, and where a beam is fitted, the beam breaking is what stops it.
- acceptedControl messages are never retained
· A retained MQTT control message replays to every client that reconnects, which would make a loco move with nobody asking. Control topics are always published unretained.
- acceptedWhen the system is unsure, it stops
· If sensor, block, MQTT or DCC state becomes unknown, automated movement halts and an operator has to recover it. The system never guesses where a train is.
- acceptedFlash writes only in Layout Maintenance Mode
· Saving settings to flash stops DCC output for about 410ms, which makes decoders run away at full speed. So writes are only allowed with the main track off, in a mode entered from the command station's own screen.
- acceptedBuild a small test layout before a full-room layout
· Westgate Hollow Yard is a deliberately small OO gauge goods yard for proving the control system and practising, ahead of a larger full-room layout.