Height sensors

From 'Engineers of Innovation Wiki'
Jump to navigation Jump to search

The height sensors measure the distance between the hull and the water surface, which is what tells the crew and the Autopilot — how high the boat is flying on its foils. Two ultrasonic sensors look down at a slight angle outward from the nose of the hull. They are not read directly by anything: a dedicated RS485-to-CAN interface board polls them and rebroadcasts each reading on the bus, where the display, autopilot, and the datalogger pick it up.

The RS485-to-CAN interface board that polls the height sensors

At a glance

Height sensing summary
Property Value
Sensors 2 × DYP A02 ultrasonic, RS-485 / Modbus RTU
Reading Distance to the water surface, in millimetres
Sensor positions As far forward as possible, port and starboard of the hull nose
Update rate 8 Hz per sensor (16 Hz combined, staggered)
Interface board RS485-to-CAN interface, STM32L471RGT6 — 4 channels, 2 in use
Board location Under the deck, just forward of the throttle, near the pilot cabin
Bus CAN 2.0A, 1 Mbit/s, 11-bit standard identifiers
CAN identifiers 0x011 front left, 0x012 front right
Application type 0x02 — its address in the bootloader protocol
Firmware Rust, embassy, binary height-sensor-controller
Firmware source firmware/ in the eoi-can monorepo
Hardware source Altium project AKD-CAN_Interface (Altium 365)
Field update Over CAN, no debug probe needed

The sensors

We use DYP A02 RS-485 ultrasonic sensors. The sensor does all the timing itself: it is a Modbus RTU slave that answers a register read with a distance in millimetres, so the interface board never sees a raw echo.

Both sensors are mounted as far forward as they fit, one to port and one to starboard of the nose, pointing down at the water. Each one passes through the hull on a miniature 5-pin Binder connector which is watertight even when unmated, so a sensor can be unplugged without opening the hull up. Wire colours for that harness are listed on the Foils page.

What the number means. It is the raw distance from the sensor face to whatever the ultrasonic pulse hit — nothing more. It is not corrected for pitch, roll or sensor offset, and a wave crest passing under the nose reads as the boat dropping. Treat it as a ride-height indication, not a calibrated altitude.

Interface board

The board is the Altium project AKD-CAN_Interface. It is the same PCB as the e-paper dashboard in the cockpit — that board fits a display on SPI2 where this one fits the RS-485 channels. The height-sensor unit itself lives under the deck, a little forward of the throttle near the pilot cabin.

RS-485 channels

The schematic repeats one RS-485 channel sheet four times, so there are four identical sensor channels, numbered 2 to 5 after the USART each one lands on. The firmware only uses two of them.

RS-485 channel allocation
Channel USART TX RX DIR (DE) Detect Used for CAN ID
2 USART2 PA2 PA3 PA1 PA0 Height sensor front left 0x011
3 USART3 PC4 PC5 PB1 PB2 Height sensor front right 0x012
4 UART4 PC10 PC11 PA15 PA12 unused 0x013 (reserved)
5 UART5 PC12 PD2 PB4 PB5 unused 0x014 (reserved)

Each channel is one half-duplex transceiver (TI SN65HVD3088E, 20 Mbit/s, 1/8 unit load) running from the board's 5 V rail, with DE and RE tied together so the part either drives or listens. The microcontroller runs at 3.3 V, so the transceiver's receiver output and the detect line both present 5 V logic to it — every pin in the table above is a 5 V-tolerant FT pin.


Sensor connector

One 5-contact M8 female panel-mount connector per channel.

Pin Signal Notes
1 Sensor supply 5 V. Selected by a 0603 link: one jumper to 5 V, an alternative to 24 V. Fit one — populating both shorts 5 V to 24 V.
2 RS-485 A / Y
3 RS-485 B / Z
4 Presence detect 100 kΩ pull-up to 5 V. Pull to ground to signal "sensor connected"
5 GND

This is the board's own pin order. It is not necessarily the order of the Binder connector in the hull, and it is not the A02's own cable colour code — check the harness rather than assuming the numbering carries across.

Power and bus

24 V arrives on the CAN-bus connector through a resettable PTC fuse (30 V, 100 mA hold) and feeds two Würth fixed step-down modules, one producing 5 V for the RS-485 side and one producing 3.3 V for the microcontroller. The CAN transceiver is an MCP2542FD. The safety line passes straight through between the two CAN connectors and is not connected to the microcontroller, so this board neither reads nor breaks the safety circuit.

Board temperature

A Würth WSEN-TIDS sensor on I²C2 (PB10/PB11, address 0x3F) reports the PCB temperature once per second on 0x210, in hundredths of a degree. This is a board health measurement — it is how you tell whether the sealed compartment under the deck is cooking.

How the firmware reads them

Each sensor is a Modbus RTU slave at address 0x01, spoken to at 9600 baud, 8 data bits, no parity, 2 stop bits. One read is a single holding register at 0x0101, and the response is the distance in millimetres.

Sending the request is what starts the ultrasonic ping, so the request and the measurement are the same event. A read normally completes in about 100 ms, which is also used as the response timeout.

The two sensors are never pinged at the same time. A sequencer alternates front-left, front-right, front-left, … and only starts the next sensor once the previous read has finished, because two overlapping ultrasonic pings at the front of the hull can hear each other and produce a plausible but wrong distance. When reads complete promptly the sequencer paces itself to a 62.5 ms slot, giving 8 Hz per sensor and 16 Hz combined; if reads run to the full timeout the combined rate falls back toward 10 Hz on its own.

Before each request the receive buffer is drained, so a late response from a previous timed-out read cannot be mistaken for the current one.

The presence-detect pin is sampled first. If it reads high the channel is reported as NotPluggedIn and no Modbus traffic is generated at all. Any failure to build, send, receive or parse the Modbus frame reports ModbusError. In both cases the height field is sent as 0 — 0 mm is not a measurement, always read the state byte first.

CAN messages

The board joins the bus at 1 Mbit/s with 11-bit identifiers. All multi-byte fields are little-endian.

Frames the height-sensor board sends
ID Message DLC Rate
0x011 HeightSensorFrontLeft 3 every 125 ms
0x012 HeightSensorFrontRight 3 every 125 ms
0x035 Bootloader response 2–8 on request only
0x210 TemperatureHeightSensorsController 2 every 1 s

0x013 and 0x014 are reserved for the two unused channels and are not transmitted.

0x011 and 0x012 — height sensor reading

Byte Field Type Values
0 State u8 enum 0 = NotPluggedIn, 1 = ModbusError, 2 = Operational, 0xFF = Unknown
1–2 Height u16 LE Distance to the water surface in mm. 0 whenever the state is not Operational.

0x210 — TemperatureHeightSensorsController

Byte Field Type Values
0–1 Board temperature i16 LE Hundredths of a degree Celsius. 2500 = 25.00 °C.

Received

The application uses an accept-all hardware filter and ignores everything that does not concern it. The only frames it acts on are the bootloader ones: the discovery broadcast 0x030, its own command identifier 0x031 + (0x02 − 1) × 3 = 0x034, and firmware write data on 0x036.

Firmware update over CAN

The first 80 KB of flash holds a CAN bootloader, so the board can be updated without pulling it out from under the deck. It owns application type 0x02, which gives it the identifier block 0x034 (command) / 0x035 (response) / 0x036 (write data); the bootloader's hardware filter rejects every other block, so a command aimed at another board cannot touch this one.

eoi-flash-tool scan                                        # what is on the bus?
eoi-flash-tool flash height-sensor-controller              # target comes from the ELF
eoi-flash-tool --board height-sensor-controller version    # which build is on it?

The protocol, the flash layout and the addressing scheme are shared with the other boards and are documented in full on the Rudder controller page.

Diagnostics

Reading the board without a debugger
Symptom Meaning
Green LED toggling once per second Application running normally
Red LED double-flashing Sitting in the bootloader, waiting or flashing
No LED activity No power, or a boot hang
State byte 1 (ModbusError) No valid reply within 100 ms. Sensor unpowered, A/B swapped, broken cable, or a flooded sensor.
State byte 0 (NotPluggedIn) Detect pin reads high, so the connector is seen as empty
Height plausible but frozen The sensor is answering with a stale value; power-cycle the channel
On the bus but dropping frames Suspect the 16 MHz crystal. The firmware falls back to the internal oscillator, whose ±1 % accuracy is not good enough for 1 Mbit/s.

A 4-second independent hardware watchdog is petted once per second by the heartbeat task, so wedged firmware resets itself instead of sitting silent on the bus. Detailed logging is available over SWD through defmt.

A sensor can be exercised on the bench without any hardware: firmware/tools/height_sensor_sim.py pretends to be the Modbus slave on a USB RS-485 adapter, with a fixed or swept distance.

Known gaps

  • Half the channels are unused. Channels 4 and 5 are fitted and wired, and 0x013/0x014 are allocated to them, but no position on the boat has been decided yet, so no firmware reads them.
  • The detect pin's pull direction is contradictory. The board pulls the line up to 5 V through 100 kΩ, so an empty connector should read high — but the firmware also enables the microcontroller's internal pull-down on that pin. That pull-down is 40 kΩ typical (25–55 kΩ), which drags the line to somewhere around 1.4 V, below the input threshold, so an absent sensor is likely to be reported as ModbusError rather than NotPluggedIn. The pin wants no internal pull at all — the microcontroller datasheet requires the internal pulls to be disabled on any pin held above VDD anyway. Worth confirming on the bench.
  • No filtering. Each frame is one ping. There is no averaging, no rate limiting and no outlier rejection, so single bad echoes go straight onto the bus. Any smoothing has to happen in the consumer.
  • The bus-wide reference is out of date. CAN_MESSAGES.md still describes the height field as "raw, unit undecided". The firmware sends millimetres. This page follows the firmware.
  • The rotary switch is not read. A sealed 4-bit hex switch is fitted and wired, but no firmware uses it. It was presumably intended for a node address or a variant selection.
  • No temperature compensation. The speed of sound varies with air temperature by roughly 0.17 % per °C, which is about 2 mm per °C at a 1 m range. The A02 is left to its own internal compensation, whatever that is.

See also

  • Foils — what the ride height is measured for, and the sensor harness wire colours
  • Autopilot — the intended consumer of these readings
  • CAN-bus — bus wiring, cable pinout and the bus-wide identifier map
  • Rudder controller — sister board, and the full bootloader protocol
  • Instrumentation Panel — where the readings are displayed
  • Datalogger — where they are recorded
  • Altium PCB — house PCB design conventions