Organized by what you’re seeing, since that’s what you know when you get stuck. New to the library? Work through GETTING-STARTED.md first — most problems below are a step from that guide that got skipped.
Most likely: the Serial Monitor was opened before the board finished booting, or the board hasn’t been reset since upload.
delay(200) after Serial.begin() for this reason.Output like ����@�x�� means exactly one thing: the baud rate doesn’t
match. Set the Serial Monitor to 115200, the same number as
Serial.begin(115200) in the sketch. Nothing else causes this specific
symptom, so don’t go looking further.
The sketch prints one dot per attempt, so an endless row of dots
(Connecting to WiFi "home"........) means the join is failing.
You see the board’s own IP printed, then waiting for the first packet...
repeating. The network stack is fine; the board can’t reach the daemon.
Work down this list in order:
IMUD_HOST the right address? It must be the IP of the machine
running imud or fake_daemon.py — not the board’s own IP (which the
sketch prints, and which is a different number), and never 127.0.0.1
or localhost.fake_daemon.py terminal should
still be showing TCP listener on 0.0.0.0:10112. It also prints
client (…) connected when your board reaches it — if that line never
appears, nothing is getting through.ufw/firewalld for port 10112.[stream] tcp_port in the daemon config, match it here.[stream] tcp_enabled = true in
/etc/imud/imud.conf, and that the daemon is running.A quick way to isolate the board from the equation: from another computer on
the same network, run telnet <host> 10112 or nc <host> 10112. If that
also hangs, the problem is the server or the network, not your sketch.
heading, pitch and roll all sit at exactly 0.0 and never move.
If no packet has ever arrived, this is a display artifact: packet() is
zero-filled until the first valid packet lands. HelloAttitude and
UdpListen guard against this, but a sketch of your own might not. Check
imud.packetsReceived() > 0 before trusting any field, then work through
no packets ever arrive.
If packets are arriving (pkts= is climbing), then the daemon really
is reporting zeros — look at the daemon end, not the client.
Working as designed. True heading needs the local magnetic declination,
and the library refuses to guess: imud_true_heading() returns -1.0f
whenever IMUD_FLAG_DECLINATION_VALID is clear, rather than silently
handing you a wrong bearing. See GLOSSARY.md.
Set the declination in the daemon’s configuration. Note that
fake_daemon.py does set it (to 11.25°), so with the test server you
should see a real number — true_hdg exactly 11.25 higher than hdg.
The attitude filter hasn’t settled yet. Give it 10–30 seconds after the
daemon starts. Don’t trust attitude while this reads no.
If it never converges on real hardware, the daemon end needs attention — typically magnetometer calibration or a sensor mounted near something magnetic.
Each count is a packet that failed validation and was discarded.
crc_err even though the CRC
itself was fine; the counter covers all validation failures, not just CRC.The parser lost frame alignment and had to hunt for the next packet
boundary. This essentially always rises alongside crc_err and for the
same reasons — treat it as a symptom, not a separate fault. On a healthy TCP
link both stay at 0.
resyncs rising while crc_err stays flat would be unusual and worth
reporting as a bug.
Almost always multicast being dropped by your network. Many consumer access points silently discard or heavily rate-limit multicast traffic, and some drop it entirely when a client is in power-save mode.
To confirm it’s the network and not your sketch, bypass multicast entirely and send UDP straight to the board’s own IP (the one it prints at startup):
python3 tools/fake_daemon.py --udp 192.168.1.87:10111 --rate 100
If unicast works and multicast doesn’t, it’s the access point. Options: use
the TCP path instead (TcpBasic), use unicast UDP, or enable IGMP
snooping/multicast forwarding on the router if it offers it.
Also worth checking: [highrate] enabled = true in the daemon config, and
that the group and port match on both ends.
Link down -- auto-reconnect is retrying in TcpBasic is often the
daemon reaching its 8-client limit. The 9th client is accepted and
then immediately closed, which looks identical to a network drop from the
client side. Close any other connected clients.>>> imud daemon reported a clean shutdown. —
that’s the daemon stopping on purpose, not a fault.WiFi.setSleep(false)
in setup() trades power for a steadier link.#error "This example needs a WiFi-capable core (ESP32, ESP8266, or RP2040 W)"
The examples need a board with networking. An Arduino Uno, Nano, or Mega won’t work. Select an ESP32, ESP8266, or Pico W board under Tools → Board.
If you’re using an Ethernet shield rather than WiFi, the library supports
that fine — it works with any Client/UDP implementation — but the
examples are written for WiFi. Swap WiFiClient for EthernetClient and
drop the WiFi-join code.
You’re compiling an example from this version against an older copy of
ImudClient.h. The Arduino IDE keeps libraries in your sketchbook
libraries/ folder — an old ImudClient there will shadow the one you think
you installed. Delete the old copy and re-install.
The related runtime trap: this library version speaks wire v18 and requires imud ≥ 1.10. Against an older daemon it receives nothing at all — no error, no packets, just silence — because every packet fails the version check. If you’re on an older daemon, install the ImudClient line that matches it instead:
| Daemon | Wire | ImudClient |
|---|---|---|
| imud 1.4–1.6 | v14 | 1.0.x |
| imud 1.7–1.9 | v17 | 1.1.x |
| imud ≥ 1.10 | v18 | 1.2.x |
Open an issue — see Reporting bugs for what to include. A copy of your Serial Monitor output, your board type, and your imud version make this much faster to diagnose.