Files
overland-controller/docs/SENSOR_NODE_PROTOCOL.md
T

3.6 KiB

XIAO ESP32-C6 Sensor Node Protocol

The XIAO sensor node reads the BNO086 and MAX-M10S and publishes vehicle telemetry over half-duplex RS485 at 115200 8-N-1, one JSON object per line at 4 Hz. It owns no control state. Cargo remains the controller, HTTP server, and /api/v1 source of truth; JBD/NimBLE behavior is unchanged.

The expansion-board pins are D2 driver enable, D4 TX, and D5 RX. This matches Seeed's working example call begin(115200, SERIAL_8N1, 7, 6): on XIAO, GPIO7 is D5/RX and GPIO6 is D4/TX. Only physical bus ends should be terminated. Confirm A/B polarity because vendor labels vary.

Schema version 1

sensor_status includes node_id, firmware_version, boot_id, monotonically increasing frame_sequence, uptime_ms, and:

  • imu: rotation data plus linear acceleration, angular velocity, gravity, stability classification, and per-report accuracy/age.
  • gps: existing navigation data plus HDOP and location/time ages.

online only means UART bytes arrived recently. In gps.nmea, a rising sentences_passed count proves valid NMEA at the configured baud rate. A rising character count with no passed sentences indicates wrong-baud noise or malformed data. A consistently rising failed count indicates corrupt UART data or a baud mismatch.

Consumers must check valid or fix before displaying measurements and ignore unknown fields. The native breakout coordinate frame is reported initially; installation-specific axis remapping should follow physical calibration.

The receiver should parse only newline-complete JSON objects. A changed boot_id indicates a node restart. A gap in frame_sequence indicates one or more dropped/corrupt frames. The node refuses to transmit an overflowed frame or one larger than 1900 bytes. At 115200 baud and 4 Hz, the maximum configured frame size consumes about 66% of the bus, leaving receive windows for commands and responses.

RS485 bench check

  1. Connect XIAO A to receiver A, B to B, and share ground. If no valid frames appear, swap A/B once because vendor labels vary.
  2. Use 115200 baud, 8-N-1, and read through newline.
  3. Confirm every received line parses as JSON with type: sensor_status.
  4. Confirm boot_id stays constant, frame_sequence increments by one, and sensor ages remain low.
  5. Disconnect/reconnect one bus conductor and verify the receiver detects sequence gaps rather than accepting partial JSON.
  6. Terminate only the two physical ends of a long installed bus; a short bench cable normally does not need termination.

The Waveshare dashboard receiver uses GPIO43 RX and GPIO44 TX through its onboard automatic-direction RS485 transceiver. Its diagnostics overlay displays the initial parsed sensor model and transport counters; this link is separate from Cargo WiFi/HTTP control.

This link does not replace dashboard-to-Cargo WiFi/HTTP. A future dashboard receiver may display this telemetry without moving relay, BMS, alarm, or configuration authority away from Cargo.

Level calibration commands

The receiver may send {"type":"calibrate_level"} followed by a newline. The node immediately responds with calibration_response result started, then samples the IMU for five seconds. If pitch or roll moves by more than two degrees, it responds with vehicle_moved and retains the previous calibration. On success it saves averaged pitch and roll offsets in NVS and responds with complete.

Send {"type":"clear_level_calibration"} to erase the saved offsets. Telemetry retains native imu.pitch_degrees and imu.roll_degrees and adds imu.level_calibration containing status, offsets, and calibrated pitch/roll. Level calibration intentionally does not alter yaw.