IMUDCLIENT(3) Arduino Library Manual IMUDCLIENT(3)

Name

ImudClient — Arduino/ESP32 client library for the imud IMU daemon

Heading, pitch, roll, quaternion, heave and sea state on a microcontroller, straight off the network.

Synopsis

#include <WiFi.h>
#include <ImudClient.h>

ImudClient imud;
WiFiClient net;

void setup() {
    Serial.begin(115200);
    WiFi.begin("ssid", "password");
    while (WiFi.status() != WL_CONNECTED) delay(100);

    imud.beginTCP(net, "192.168.1.50", 10112);
}

void loop() {
    if (imud.poll()) {                    // a NEW valid packet arrived
        const imud_packet_t &p = imud.packet();
        Serial.printf("heading %.1f  pitch %.1f  roll %.1f\n",
                      p.heading_deg,
                      imud_rad_to_deg(p.pitch),
                      imud_rad_to_deg(p.roll));
    }
}

Description

ImudClient is a header-only Arduino library that receives, validates, and decodes the binary attitude packets published by imud — an IMU daemon for marine and robotics navigation that fuses gyro, accelerometer, and magnetometer data with a Kalman filter and publishes the result over the network.

The daemon does the sensor work on a Linux host. The microcontroller just reads the answer. That makes it a practical way to build cockpit displays, NMEA gauges, autopilot remotes, and telemetry heads that need live attitude without carrying an IMU or a filter of their own.

Both transports, one packet.
TCP on port 10112 — lossless, framed, up to 8 concurrent clients — or UDP on port 10111, unicast, broadcast, or multicast, at up to 500 Hz.
No heap, no String, no exceptions.
Fixed buffers only, roughly 600 bytes of RAM.
Header-only.
Drop in src/ImudClient.h and #include <ImudClient.h>. Nothing to build or link.
Portable core.
The parser depends only on the C++ standard library and is unit-tested on a host PC — no Arduino, no mocks. The Arduino wrapper touches only the abstract Client and UDP base classes, so it works with WiFiClient/WiFiUDP, EthernetClient/EthernetUDP, or anything else implementing those interfaces.
Hostile-input hardened.
Wire data is untrusted. Packets are validated on magic, version, size, and CRC; the range checks fail closed on NaN and infinities, and the streaming path resynchronizes by rescanning for the next magic sequence rather than discarding its buffer.

Requirements

Match the versions. ImudClient 1.2.0 speaks imud wire v18 and requires imud 1.10 or newer. The 1.1.x line is the correct one for imud 1.7–1.9, and 1.0.x for imud 1.4–1.6. They are not interchangeable, and a mismatch fails silently: the parser rejects every packet whose version word it does not recognise, so you get no data and no error — just a millisSinceLastPacket() that climbs forever. If a sketch connects but never receives, check this first.

There is deliberately no dual-version support. The CRC offset moved again between v17 and v18, so a parser would have to guess a frame's length before it could validate it — on a stream where the framing is the validation.

Boards. ESP32 is the primary target, under both the Arduino IDE and PlatformIO. The library also compiles for ESP8266, RP2040 (Pico W), and Ethernet-shield boards.

Installation

Arduino IDE. Tools → Manage Libraries…, search for ImudClient, and click Install. The examples then appear under File → Examples → ImudClient; start with HelloAttitude.

PlatformIO. Add the repository to platformio.ini:

lib_deps =
    https://github.com/richcreations/imud-arduino.git

To install an unreleased version or a fork, download the repository as a ZIP and use Sketch → Include Library → Add .ZIP Library…, or clone straight into your Arduino libraries/ folder.

Transports

TCP — beginTCP(net, host, 10112)
Lossless, framed, ordered, up to 8 concurrent clients. The right choice for a display that needs every update. The initial connect is allowed to fail — auto-reconnect takes over, throttled to one attempt every 2 seconds.
UDP — beginUDP(udp, 10111)
Higher rate, up to 500 Hz, unicast or broadcast. Binding is all that is needed; beginUDP() calls udp.begin() for you.
UDP multicast
imud's default high-rate destination is 239.255.0.1. The abstract Arduino UDP class has no portable multicast join, so join with the concrete transport's own API first, then hand over the already-bound socket:
WiFiUDP udp;
udp.beginMulticast(IPAddress(239, 255, 0, 1), 10111);   // ESP32 API
imud.beginUDP(udp, 10111, /*alreadyBound=*/true);

What's in a packet

Every packet carries the same full set of fields, read straight off the struct — imud.packet().heading_deg. There are no per-field accessors.

Watch the units. heading_deg is in degrees, but pitch, roll, and yaw are in radians. Convert with imud_rad_to_deg(). Rate of turn is in degrees per minute.
FieldMeaningUnits
heading_degmagnetic headingdegrees, 0–360
trueHeading()true heading; -1.0f if unknowndegrees, 0–360
pitch / roll / yawbow up +, starboard up +radians
quat_w/x/y/zsame orientation, body→NEDunit quaternion
rate_of_turnturn rate, + = rightdegrees/minute
declination_degmagnetic variation, + = eastdegrees
heave_m / heave_ratevertical displacement / velocity, + upm, m/s
wave_height_msignificant wave height (Hs)metres
wave_period_smean zero-crossing wave periodseconds
roll_period_s / pitch_period_svessel periods; 0.0 = not rollingseconds
accel_* / gyro_* / mag_*calibrated sensors, NED; *_raw_* before calibrationm/s², rad/s, µT

Some fields are gated by a validity flag and read 0.0 until it is set — heave by HEAVE_VALID, sea state by WAVE_VALID, true heading and declination by DECLINATION_VALID. The full 288-byte struct and the IMUD_FLAG_* bitmask are defined in src/ImudClient.h.

Interface

MethodDescription
beginTCP(c, host, port)Stores host/port for reconnects. A failed initial connect is fine.
beginUDP(u, port, alreadyBound)Binds unless alreadyBound; pass true for multicast.
poll()Non-blocking drain. true if ≥1 new valid packet arrived.
packet()The newest valid packet; zero-initialized before the first.
trueHeading()True heading, or -1.0f until declination is valid.
connected()TCP link state; always true on UDP after beginUDP().
reconnect()TCP only. Blocks, as Client::connect() does.
setAutoReconnect(on)Default on, ≥2 s between attempts. Turn off in latency-critical loops.
millisSinceLastPacket()For watchdogs and staleness indicators; UINT32_MAX before the first.
daemonShutdown()true on the daemon's final packet — a clean exit, not a dropped link.
packetsReceived() / crcErrors() / resyncs()Cumulative counters.
end()Stops the transport, resets the parser and counters.

Power users can use ImudParser directly — pure C++, zero Arduino includes, zero I/O. It is what ImudClient wraps, and what the host-side unit tests exercise. Use it to decode packets from a transport the wrapper does not cover, or from a file of captured frames.

Examples

HelloAttitude
The smallest sketch that prints live heading, pitch, and roll.
TcpBasic
A complete TCP sketch with staleness detection, reconnect handling, and daemon-shutdown reporting.
UdpListen
UDP reception that also reports the achieved packet rate.

You do not need an IMU, or any wiring, to try these. The repository ships a test server in tools/ that feeds a sketch synthetic packets from a PC — the getting-started guide walks from an empty sketch to live attitude on the Serial Monitor using it.

See also

Author

Written by Richard Simpson. Released under the MIT license.

ImudClient 1.2.0 2026-07-26 IMUDCLIENT(3)