6 pillars. 14 Arduinos. 20+ sensor modalities. Every schematic, wiring diagram, firmware spec, and channel map — fully open source under the MIT license.
Six physical pillars are arranged around a central measurement zone. Each pillar carries two Arduino microcontrollers and a set of sensors. All modules communicate over USB serial at 115,200 baud (camera boards at 500 kbaud or 2 Mbaud) using a CRC8-validated binary packet protocol to a central C# / Godot 4 host application running on Windows.
HOST PC — Windows 11
┌─────────────────────────────────────────────────────────────────┐
│ Godot 4.x + C# (.NET 6) │
│ │
│ ModuleManager ──► SignalAnalysisEngine ──► PhaseEngine │
│ │ FFT @ 200 ms 4-ch PLL │
│ │ 8 invariants Lock detect │
│ ▼ │
│ 30+ UI Pages: Dashboard · Magnetic · Thermal · Gas · LiDAR │
│ RF · Phase · Magnitude · Fusion · MetatronUnits │
│ │
│ Logger ──► session.bin │ ApiServer ──► REST :8080 │
│ │ WebSocketServer ──► WS :8081 │
└─────────────────────────────────────────────────────────────────┘
│ USB/Serial ×14 (COM ports)
│
┌──────┴──────────────────────────────────────────────────────────┐
│ PHYSICAL SENSOR RING │
│ │
│ PILLAR 1–3 │ PILLAR 4–6 │
│ Nano (Hall+Ultra) │ Uno (Thermal+Gas) │
│ Uno (AV Camera) │ Uno (LiDAR+Microwave) │
│ 320×240 RGB565 │ Uno (Hi-Res Camera 640×480) │
│ │ │
│ VOLTAGE_01 (Uno) VOLTAGE_02 (Nano) │
│ IMPEDANCE_01 (Uno) IMPEDANCE_02 (Nano) │
└─────────────────────────────────────────────────────────────────┘Pillars 1, 2 & 3
2 boards each
Nano (Hall+Ultra) + Uno (AV Camera)
Pillars 4, 5 & 6
3 boards each
Uno (Thermal+Gas) + Uno (LiDAR+MW) + Uno (Hi-Res Camera)
Voltage Modules
2 boards total
VOLTAGE_01 (Uno) + VOLTAGE_02 (Nano)
Impedance Modules
2 boards total
IMPEDANCE_01 (Uno) + IMPEDANCE_02 (Nano)
Hall Effect + Ultrasonic + Low-Res AV Camera
Arduino Nano (ATmega328P)
Sensors
Analog magnetic field sensing. 4-bit pattern encodes which magnets are present. 10 ms debounce, auto-calibrated baseline at boot.
40 kHz ToF ranging. Distance = pulse_µs × 0.0343 / 2. 3-sample circular buffer, outlier rejection >50 cm from median.
Live display of Hall pattern, active count, and distances. Refreshes every 250 ms.
Arduino Uno (ATmega328P)
Sensors
RGB565 pixel format. 320×240 = 153,600 bytes/frame. UART_MODE 5 at 500 kbaud. 8 MHz XCLK from Timer2. 3.3V only — use AMS1117-3.3 regulator.
Comparator-based sound sensor. Digital presence flag sent every frame cycle. Threshold set by onboard potentiometer.
Thermal+Gas / LiDAR+Microwave + Hi-Res Camera (Dual Arduino, Back-to-Back)
Arduino Uno (ATmega328P)
Sensors
Non-contact object + ambient temperature. Shared I²C bus with AMG8833.
64-pixel thermal image at 10 fps, 0.25°C resolution, 60° FoV. Full 64-pixel frame sent in 4 chunks of 16 pixels every 40 ms.
Rs = (Vcc−Vout)/Vout × RL. PPM = a×(Rs/R0)^b. Supports MQ-2 through MQ-138. 11 sensor variants, 4 gas curves each. 5-sample R0 calibration at boot.
Bit-bang protocol. Pulses <40 µs = 0, ≥40 µs = 1. 5-byte frame with checksum.
Used with photodiodes for optical interruption detection.
Voltage divider: 10 kΩ to GND. Optical presence sensing.
Digital proximity detection.
Arduino Uno (ATmega328P)
Sensors
940 nm Class 1 VCSEL. 16×16 SPAD array. Long Distance mode, 33 ms timing budget. ±25 mm accuracy up to 4 m. d = (c × t) / 2. Servo sweeps 0–90° in 1° steps, 25 ms settle.
3-axis gyro + 3-axis accel. Accel: raw/4096 × 9.80665 m/s². Gyro: raw/65.5 × π/180 rad/s. Temp: raw/340 + 36.53°C. Read every 50 ms.
8-channel I²C multiplexer. Firmware auto-scans all 8 channels at boot to locate LiDAR (0x29) and OLED (0x3C). Physical wiring order is flexible.
Motion presence and intensity. Up to 128 bytes buffered per packet. Host interprets as motion detection.
Pan/tilt for LiDAR scanning. 0–90° range, 1° step. Auto-sleep after 30 s of no host command. CMD_SET_SCAN wakes it.
Live scan angle and distance display.
Arduino Uno (ATmega328P)
Sensors
RGB565 pixel format. 640×480 = 614,400 bytes/frame. UART_MODE 16 at 2 Mbaud. Same wiring as Pillars 1–3 low-res board — only baud rate and resolution config differ. 3.3V only.
VOLTAGE_01 (Uno) + VOLTAGE_02 (Nano)
IMPEDANCE_01 (Uno) + IMPEDANCE_02 (Nano)
All 14 Arduino boards use the same CRC8-validated binary packet format. The host's ModuleManager scans all COM ports, parses IDENT packets, and routes DATA packets to subscribers.
Byte: [0] [1] [2] [3 … N+2] [N+3] [N+4]
START LEN TYPE PAYLOAD CRC8 END
0xAA N+1 0x01–0A N bytes poly07 0x55
START = 0xAA — fixed frame marker
LEN = payload length + 1 (includes TYPE byte)
TYPE = message type (see table)
CRC8 = polynomial 0x07 over bytes [1 … N+2]
END = 0x55 — fixed frame terminator| Type | Code | Direction | Description |
|---|---|---|---|
| IDENT | 0x01 | Module→Host | JSON identification: id, type, fw, channels, health |
| DATA | 0x02 | Module→Host | Sensor data. Payload: 4B timestamp, 1B channel, 1B module type, 2B data length, then data |
| STATUS | 0x03 | Module→Host | Health report: temp, voltage, uptime, error count, SNR, status byte |
| CALIBRATE | 0x04 | Host→Module | Trigger calibration sequence |
| CONFIG | 0x05 | Host→Module | Update configuration parameters |
| ERROR | 0x06 | Module→Host | Error report with error code and message string |
| HEARTBEAT | 0x07 | Module→Host | 5-byte keep-alive: 4B uptime (big-endian) + 1B health status |
| ACK | 0x08 | Module→Host | 2-byte acknowledgment: command byte + result byte (0=OK) |
| COMMAND | 0x09 | Host→Module | Command packet. First payload byte = command ID |
| REQUEST_IDENT | 0x0A | Host→Module | Request module to re-send IDENT |
MQ Gas Sensor — Rs from ADC
Rs = (Vcc − Vout) / Vout × RL
Vout = ADC_raw / 1023 × 5.0 V
RL = 10,000 Ω (load resistor)
PPM = a × (Rs/R0)^b (non-linear)
PPM = 10^(a × log₁₀(Rs/R0) + b) (log-linear)
VL53L1X LiDAR — Time of Flight
d = (c × t) / 2
c = 3×10⁸ m/s (speed of light)
t = round-trip photon time
Resolution: 1 mm
Accuracy: ±25 mm up to 4 m (Long Distance mode)
MPU6050 IMU — Unit Conversion
a_xyz [m/s²] = raw / 4096.0 × 9.80665 (±8G range)
ω_xyz [rad/s] = raw / 65.5 × (π / 180) (±500°/s)
T [°C] = raw / 340.0 + 36.53
All 14 registers (0x3B–0x48) read every 50 ms
HC-SR04 Ultrasonic — Distance
Trigger: HIGH pulse for 10 µs
Distance [cm] = pulse_µs × 0.0343 / 2
Speed of sound = 0.0343 cm/µs
Valid range: 2–400 cm
Quality = 100 − 5×σ (3-sample circular buffer)
Voltage Module — Divider
V_out = (ADC_raw / 1023.0) × 5.0 × 5.0
Divider: R1 = 30 kΩ (top), R2 = 7.5 kΩ (bottom)
Effective range: 0–25 V
EEPROM CalibrationTable: up to 5 points, linear interp
Impedance Module — |Z| from ADC
|Z| = (Vref − Vmeasured) / Vmeasured × 400 Ω
Default scale: 400 Ω (reference load)
Phase [°] from phase-shifted secondary ADC channel
Signal source → R_ref (10 kΩ) → Z_x → GND
| Sensor | Gas A | Gas B | Gas C | Gas D |
|---|---|---|---|---|
| MQ-2 (default) | LPG | CO | H₂ | Alcohol |
| MQ-3 | Alcohol | Benzene | CO | LPG |
| MQ-4 | CH₄ | LPG | CO | Alcohol |
| MQ-5 | LPG | CH₄ | CO | H₂ |
| MQ-7 | CO | H₂ | LPG | CH₄ |
| MQ-135 | NH₃ | CO | Alcohol | Benzene |
11 MQ sensor variants supported total (MQ-2 through MQ-138). Each with a lookup table of 4 gas curves. Dominant gas = highest PPM above 10 ppm threshold.