DIY marine instrument · build sheet v1

Twin-shaft sync tachometer

A two-channel shaft RPM gauge from common parts. It reads each prop shaft, shows the average, and gives you a center-zero needle for matching the two — so the engines run in step instead of fighting each other.

2
channels
±0.1%
rpm accuracy
~1700
working rpm
12V
boat power

New to electronics? Start here

What we're actually building

If you've ever replaced a crank position sensor or an ignition pickup, you already understand the heart of this. A magnet sweeps past a sensor, the sensor says "tick," and from the rhythm of those ticks you know how fast something is spinning. We do exactly that on each prop shaft — then put both numbers on a screen in the cockpit, with a needle that tells you when the two engines are matched.

Magnet on shaft spins past, makes a tick Sensor feels each tick Tiny computer works out the RPM Cockpit screen shows it to you passes by ticks over one shared pair of wires ONE SET LIKE THIS PER ENGINE ROOM

The four pieces, in plain terms

01

A magnet on each shaft

One or two small magnets fixed to a stainless clamp around the shaft. This is the thing the sensor "sees" go by. (No magnets? There's a sensor that reads the coupling bolts instead — see Options.)

02

A sensor beside it

Mounted a few millimetres away on a solid bracket. Every time a magnet passes, it sends a tick — just like the pickup that already tells your tach how fast the engine's turning.

03

A tiny computer

A cheap (~$10) module that counts the rhythm of the ticks and works out the RPM. "Arduino" is just the friendly, well-documented way to load a program onto it. You flash the code we provide once, and after that it simply runs.

04

A screen in the cockpit

A small 4" display showing both shaft RPMs, the average, and the sync needle. When the needle sits centered, your engines are matched.

Why one wire instead of a fat cable bundle

Your boat already does this. Rather than run a separate wire from every sensor all the way to the dash, modern gear shares one pair of wires and takes turns talking — that's what NMEA 2000 (or J1939 on the engine side) is. We borrow the same trick, called CAN. Each engine room gets its own little computer, and both report up a single shared pair of wires to the screen. Adding a third shaft later is just hanging one more box on that pair.

What the build actually involves

Glue a couple of magnets to a stainless clamp on each shaft (or fit a sensor that reads the coupling bolts), mount a sensor a few millimetres away on a solid bracket, run a two-wire bus to the cockpit, mount the screen, and flash the code we hand you using a free program on your laptop. No prior coding needed for the starter version — you copy our sketch, click upload, and watch the number move.

Good news

You can prove the whole idea on your kitchen table for about $35, before drilling a single hole. That's the Start here tab.

How it works

Time the magnet, don't count it

The whole accuracy story lives in one decision, and it's worth understanding before buying anything.

The naive way — avoid

Glue a magnet to the shaft, count pulses in a fixed time window. At ~1700 rpm a single magnet only ticks ~28 times a second. In a quarter-second window you'd catch ~7 pulses — being off by a single count is a 14% error. Useless for matching two engines.

What we do instead

The tiny computer timestamps each magnet pass with a microsecond clock and measures the period between passes. A ~35 ms gap timed to 1 µs resolves to roughly 0.003%. Same sensor, same magnet — it's purely how the firmware reads it. That headroom is what makes a believable sync needle.

For sync specifically, what matters is the relative timing of the two shafts. Run both channels identically and average each reading over one full revolution, and most of the per-magnet placement error cancels — the needle settles instead of buzzing.

Read first

A bare stainless or bronze shaft is non-magnetic — a Hall sensor pointed at it sees nothing. You either add magnets to the shaft, or switch to an inductive sensor that reads the steel coupling bolts. Both are covered in Options; just know the bare shaft alone won't trigger anything.

Start here

Prove one shaft on the bench

Before anything goes near the boat, get a single channel reading RPM on your desk. One board, one sensor, a tiny screen. An afternoon, ~$35, and you'll understand the whole system.

Use what you've got

For the bench demo, any microcontroller works — the simple Arduino already on his shelf is perfect. Nothing here needs an ESP32 yet; save that decision for the real build. The sketch below compiles on both as-is — it picks the right interrupt pin automatically. The only differences on a classic Uno or Nano are physical: the auto-selected sensor pin is D2 (instead of GPIO 4), and the OLED's I²C goes to A4/A5 instead of 21/22. The timing logic is identical.

  1. Wire the Hall module to the board

    Three pins: 3.3V, GND, and signal to a GPIO. The common A3144-based module already has a pull-up and an LED that blinks on each magnet pass — instant visual confirmation.

  2. Spin a magnet past it by hand

    Tape a neodymium magnet to anything that turns — a drill chuck, a bench grinder, a bit of dowel. Watch the module's LED tick. South pole facing the sensor for an A3144.

  3. Flash the period-timing sketch

    The snippet below reads RPM from the interval between pulses and prints it over USB. No screen needed yet — just the serial monitor.

  4. Add the OLED, then the second channel

    Drop in a small I²C OLED for a standalone readout. Once one channel is solid, duplicating it for the second shaft is the easy part.

Wiring — which pin goes where

Everything shares one 3.3V rail and one ground. The Hall sensor's output goes to GPIO 4 (the HALL_PIN in the sketch); the OLED uses the ESP32's standard I²C pins, GPIO 21 and GPIO 22.

ESP32 DevKitC 3V3 GND D4 3V3 GND D21 D22 Hall sensor A3144 module VCC GND OUT OLED screen SSD1306 128×64 VCC GND SDA SCL
3.3V power Ground Signal → GPIO 4 I²C → GPIO 21 / 22
Hall module → ESP32
VCC3V3
GNDGND
OUTGPIO 4
OLED → ESP32
VCC3V3
GNDGND
SDAGPIO 21
SCLGPIO 22
Voltage note

Power the Hall module from 3.3V so its output is safe for the ESP32. If your particular A3144 module won't trigger reliably below 4.5V, run it from the 5V (VIN) pin instead and drop its OUT line through a simple two-resistor divider to ~3.3V before GPIO 4 — never feed 5V straight into an ESP32 pin.

// Bench starter — one shaft, RPM by period. Runs on ESP32 or Uno/Nano.
#ifndef IRAM_ATTR
#define IRAM_ATTR // no-op on AVR; real attribute on ESP32
#endif

#if defined(ESP32)
 const int HALL_PIN = 4; // any GPIO — matches the wiring diagram
#else
 const int HALL_PIN = 2; // Uno/Nano interrupt pin (D2)
#endif

const int MAGNETS_PER_REV = 2; // match your magnet count
volatile uint32_t lastEdge = 0, period = 0;

void IRAM_ATTR onPulse() {
 uint32_t now = micros();
 uint32_t dt = now - lastEdge;
 if (dt > 500) { period = dt; lastEdge = now; } // glitch filter
}

void setup() {
 Serial.begin(115200);
 pinMode(HALL_PIN, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(HALL_PIN), onPulse, FALLING);
}

void loop() {
 uint32_t p; noInterrupts(); p = period; interrupts();
 float rpm = p ? 60000000.0 / ((float)p * MAGNETS_PER_REV) : 0;
 Serial.print("RPM: "); Serial.println(rpm, 0);
 delay(200);
}

Bench starter kit

≈ $35 USD
PartTypical pickQtyApprox
ESP32 dev boardThe brain. Arduino-IDE programmable.ESP32-WROOM DevKitC1$9
Hall effect moduleDigital out, on-board pull-up + LED.A3144 3-pin module1$3
Neodymium disc magnets6×3 mm, grab a pack.N35 6×3 mm1 pk$8
OLED displayFirst standalone readout.SSD1306 128×64 I²C1$5
Breadboard + jumpers1$8
USB cableprobably in a drawer1$0

The full build

Two smart nodes, one bus

Two engine rooms means two long sensor runs to the cockpit — and raw Hall pulses dragged past alternators turn to noise. So put a small brain at each shaft and send finished numbers up a robust two-wire bus.

Sensor node · ×2

One per engine room: a small computer + sensor + bus chip, in a sealed box bolted near the coupling. It does the microsecond timing locally and broadcasts a clean RPM number. Doing the timing millimetres from the sensor — not after 10 m of cable — removes a whole class of jitter.

Display node · ×1

A board + 4" screen in the cockpit, also on the bus. It hears both shafts, computes the average and the difference, and draws the gauges. Adding a third shaft later is just another box on the bus — that's your "combine the rooms later" path, free.

The bus is CAN: two twisted wires, differential, built for exactly this kind of electrically filthy environment — the same physical layer NMEA 2000 rides on. The board has a CAN controller built in; each node just needs a cheap transceiver chip, with a 120 Ω resistor at each end of the run.

Minimal alt

If both shafts are in one hull with short runs, you can skip the bus: a single board in the cockpit with two sensor cables works fine. Cheaper and simpler — just harder to extend and more exposed to noise. Noted here so the choice is yours.

Full cockpit build

≈ $150–230 USD
PartTypical pickQtyApprox
Sensing — per shaft
Shaft sensorHall (with magnets) or inductive (on bolts) — see Options.A3144 · or LJ12A3-4-Z/BX2$6–18
Magnets + stainless collarEpoxy magnets to a hose clamp, not the shaft directly.N35 + SS clamp2$14
Marine epoxyFor bonding magnets / brackets.G/flex or JB Weld1$12
Compute
Sensor-node boardOne per engine room.ESP32-WROOM DevKitC2$18
Display node4" IPS, onboard CAN + RS485, runs LVGL. One board = whole display.Waveshare ESP32-S3-Touch-LCD-41$40
Bus
CAN transceiverSensor nodes only — display board has CAN built in.SN65HVD230 module2$6
Termination + cable120 Ω each end, twisted tinned pair.120 Ω · marine 2-core$15
Power & protection — per node
Buck regulator12V → 5V.MP1584 / LM25963$8
Transient + reverse protectionEngine-bank supply is noisy.SMBJ16A TVS + Schottky + fuse3$12
Marine hardware
Sealed enclosuresOne per node.IP65/67 box + glands3$30
Wire, heat-shrink, dielectric grease, connectorstinned · Deutsch DT optional$25

Prices are rough USD ballparks for mid-2026 and move with supplier and region — treat them as planning figures, not quotes.

Wiring diagrams

The schematics

Drawn to the recommended parts — ESP32 sensor nodes, Hall sensing, the Waveshare display, distributed CAN. One colour code throughout: power, ground, sensor signal, CAN. Swap the sensor or display and a few pin labels shift.

01 · sensor node

Sensor node

One per engine room: the Hall sensor feeds the ESP32, which times the pulses and broadcasts RPM onto the bus through a transceiver. Power arrives pre-conditioned from diagram 02.

Hall sensor A3144 VCC GND OUT ESP32 sensor node 3V3 GND GPIO4 GPIO5 GPIO18 3V3 GND 5V GND CAN xcvr SN65HVD230 D R VCC GND CANH CANL → to CAN bus from Power & protection (12V → 5V)
power (3V3 / 5V) ground sensor signal CAN
Hall → ESP32
VCC3V3
GNDGND
OUTGPIO 4
CAN xcvr → ESP32
D (TX)GPIO 5
R (RX)GPIO 18
VCC3V3
GNDGND
Inductive alt

Reading the coupling bolts with an inductive sensor instead? It's powered from 12V — not 3V3 — and its output must pass through a level interface (open-collector into a 3.3V pull-up, or an optocoupler) before GPIO 4. The rest of the node is unchanged.

02 · power & protection

Power & protection

One chain per node. Takes raw 12V off the boat and makes clean 5V — fused, protected against reversed leads, clamped against engine-bank spikes.

GND 12V boat bank + Fuse 1 A inline Reverse block P-FET / Schottky TVS clamp SMBJ16A Buck 12V → 5V · MP1584 5V out GND 12V → to node 5V / GND
positive rail (12V → 5V) ground rail
Why each piece

Fuse: a dead short can't start a fire. Reverse block: wire it backwards and nothing dies. TVS: clamps the load-dump spike at engine start. Buck: drops 12V to a steady 5V without cooking. Skip these on an engine bank and you'll eventually lose a node.

03 · can bus

CAN bus topology

All three nodes share one twisted pair — a single line, not a star — with a 120 Ω resistor across the wires at each far end. Middle nodes just tap on.

H L 120 Ω 120 Ω Sensor node 1 engine room · bus end terminate here Display node cockpit · middle tap no termination Sensor node 2 engine room · bus end terminate here
CAN twisted pair (H / L) 120 Ω termination
Two rules

One: 120 Ω goes on the two physical ends only — never a middle node, never more than two. Two: all nodes need a shared ground reference, so run a third conductor (or rely on a solid common bond) alongside the pair. Node order doesn't matter; which two are the ends does.

04 · display node

Display node

Almost no wiring — the recommended board has the screen and CAN transceiver built in. Two pairs land on it: power, and the bus.

Display node Waveshare ESP32-S3-Touch-LCD-4 4" IPS screen LVGL gauges onboard: · CAN transceiver · RS485 · ESP32-S3 + WiFi/BT CANH CANL 5V GND → CAN bus → CAN bus → from Power (5V) → common GND
CAN bus (H / L) 5V power in ground
Display node terminals
CANHbus H
CANLbus L
5Vbuck 5V out
GNDcommon ground
Termination

Middle of the bus: leave it un-terminated. Physical end of the run: it's one of your two 120 Ω points (see diagram 03). The screen and transceiver are already on the board, so no extra parts here.

05 · mounting

Magnet & sensor mounting

The one physical bit. Magnets ride on a stainless clamp around the shaft; the sensor sits on a rigid bracket a few millimetres away. Magnets go in pairs so the shaft stays balanced.

rigid bracket → hull/engine mount Hall 2–4 mm gap prop shaft stainless clamp collar 2 magnets, 180° apart balanced · same pole facing out ticks once per magnet pass →
magnet (pole out) magnet (180° opposite) Hall sensor
Alt: no magnets

Don't want to glue anything to a spinning shaft? Mount an inductive proximity sensor facing the steel bolt heads on the coupling flange — it ticks once per bolt, evenly spaced, no magnets and no added rotating mass. Same small, steady gap. See diagram 01 for how its output wires in.

06 · full system

Full system on one sheet

How the five fit together: two sensor nodes in the engine rooms, one display node in the cockpit, all on a single CAN pair, each with its own protected 12V → 5V supply.

CAN bus — one twisted pair (H / L) 120 Ω 120 Ω Engine room 1 sensor node Hall → ESP32 → CAN 12V → 5V (protected) Cockpit display node ESP32-S3 + 4" screen avg + sync needle Engine room 2 sensor node Hall → ESP32 → CAN 12V → 5V (protected) each node also carries its own 12V→5V power chain (diagram 02)
CAN bus 120 Ω end termination protected power per node
Reads as

Three boxes, one pair of wires between them, terminated at the two ends, a small power chain inside each box. Add a third shaft later and it's simply a fourth box tapping the same pair — the whole "combine the rooms later" promise.

Options to weigh

Five forks in the road

Each has a sensible default (marked) and a reason you might go the other way. Open any one for the tradeoff.

Which microcontroller — do you even need an ESP32?default: esp32

Timing the gap between magnet passes is easy work — almost any microcontroller can do it, so the sensing side never forces the choice. What actually decides it is the bus and the display.

ESP32 recommended

Chosen mainly because CAN is built into the chip — each node needs only a ~$1 transceiver, no separate controller board. It also has the RAM to drive the 4" LVGL screen, and the all-in-one display board is already an ESP32-S3, so there's one in the cockpit no matter what you do. Bonus: WiFi and Bluetooth come along for free (more below).

Classic Arduino (Nano / Uno) familiar ground

Fully capable of the sensing, and the platform he's already learning. Two catches: CAN needs a bolt-on MCP2515 module (~$4) at each node, and a 2 KB-RAM Arduino can't draw a graphical 4" screen — so you pair it with a Nextion smart display, where the Arduino just sends numbers over serial and the screen draws itself. Best fit for the single-box build with no bus.

RP2040 (Raspberry Pi Pico)

Cheap, plenty of RAM, drives displays nicely. No built-in CAN, so you add a transceiver (through the Pico's PIO or an external controller).

Bonus: wireless

Because the ESP32 carries WiFi and Bluetooth on board, the same hardware can grow later with no extra parts: mirror the gauges on a phone or tablet, log RPM and sync data across a trip, calibrate or tweak settings from a web page, or push firmware updates over the air — so nobody's crawling into the engine room with a laptop to reflash a node.

How do you sense the shaft?default: hall + magnets
Hall + magnets easiest start

Cheapest, simplest, and what the bench build uses. You epoxy 2 magnets to a stainless collar on the shaft. Downside: you're adding rotating mass (balance it) and the sensor gap must stay small and steady.

Inductive proximity on the coupling bolts most rugged

An industrial sensor (LJ12A3-4-Z/BX) reads the steel flange bolts directly — no magnets, ~4 mm range, sealed and shrugging off oil and spray. Very mechanic-friendly. It runs on 12V but its output needs a simple level interface to the 3.3V board (open-collector into a 3.3V pull-up, or an optocoupler). Pulse count is set by bolt count, so they must be evenly spaced — usually are.

How many magnets per revolution?default: 2 at 180°
One magnet

Simplest to mount, but its exact placement shows up as a fixed wobble every rev, and it adds an out-of-balance mass.

Two, 180° apart recommended

Balanced (no vibration), and averaging the two readings each rev cancels most placement error — the sync needle you'll be staring at gets noticeably smoother. Best effort-to-payoff ratio.

Four, 90° apart

Highest resolution and fastest update, but more mounting fuss and four magnets to keep balanced and evenly spaced. Overkill unless you want a very twitchy live needle.

Which 4" display?default: all-in-one IPS
Waveshare ESP32-S3-Touch-LCD-4 recommended

4" 480×480 IPS with CAN and the board already on it, runs LVGL gauge graphics. One part is your entire display node. Bright backlit IPS — great in a shaded cockpit pod, fine in most daylight, not built for direct midday sun.

Transflective / reflective panel true sun-readable

Transflective TFTs (VIEWE, Crystalfontz, Newhaven) or a reflective RLCD board get brighter in direct sun and sip power, which is the dream for an open helm. Tradeoffs: 4"-ish sizes are pricier and often monochrome, and you'll wire a separate board + CAN. Worth it if the gauge lives in full sun.

Bare ST7796 / ILI9488 SPI TFT budget

~$15–25 for a 4" panel; pair with a separate board + CAN transceiver and drive it with LVGL or TFT_eSPI. Most control, lowest cost, mediocre in sun.

Nextion 4.3" smart display fastest GUI

You draw the gauge faces in their editor; the board just sends numbers over serial. Quickest route to a polished-looking gauge with the least graphics code. Sun-readability is mediocre.

Distributed nodes or single box?default: distributed CAN
Distributed nodes on CAN recommended

A node per engine room, numbers over a two-wire bus. Noise-immune over long boat runs, and extending it (third shaft, merged rooms) is plug-and-play. The right call for two separate engine rooms.

Single board, two sensor cables

Cheaper and fewer parts. Fine if both shafts are close and in one hull. Harder to extend and more exposed to electrical noise on long runs.

Before it touches saltwater

The marine reality checklist

Balance the magnets

Anything you add to a spinning shaft is rotating mass. Two magnets at 180° (or four at 90°) keeps it balanced. Don't bolt a single lump on and call it done.

Rigid sensor gap

Hall range is only a few millimetres. The bracket must hold the gap steady through vibration and not creep into the spinning collar. Inductive sensors are far more forgiving here.

Seal everything

IP65/67 boxes, cable glands, marine-tinned wire, dielectric grease on connections, and a drip loop so water runs away from the box, not into it.

Fuse and protect at the source

Tap 12V through an inline fuse, with reverse-polarity and a TVS diode at each node. Engine-start surges and load-dump will find unprotected electronics.

One ground reference

Give the CAN bus a common ground reference across nodes and keep it clear of high-current engine ground loops, or you'll chase phantom noise.

Heat and sun

A cockpit pod bakes. Pick an enclosure and display rated for it, and shade the screen if you didn't go transflective.

Firmware shape

What each node actually runs

Sensor node

An interrupt grabs micros() on every magnet pass into a small ring buffer. RPM comes from the averaged interval over a full revolution, with a glitch filter rejecting impossibly short gaps. It publishes a CAN frame (this shaft's RPM) every ~100 ms. That's the whole job — small and boring, which is what you want hanging off an engine.

Display node

Listens for both shafts' frames, computes the average and the signed difference, lightly smooths them, and feeds LVGL: two digital readouts, an average, and the center-zero sync needle. If a shaft stops broadcasting, it greys out instead of freezing on a stale number.

The bench snippet in Start here is the kernel of the sensor node. The rest is hardening — the ring-buffer averaging, the CAN publish, the LVGL faces — and it's a natural next step once one channel reads true on the desk.