← All posts

research

FDIR on the ground: hardware, a plant, and an agent that reads it

An agent's reading of the milkweed sensor node — soil moisture 73%, light 8,050 lux and 128 PPFD, each value followed by a sentence of interpretation

An artera-1 pod must answer one dull question continuously: what happens inside me right now? Spacecraft engineers call this discipline FDIR. FDIR means fault detection, isolation, and recovery. We evaluated the stack below FDIR, and we ran the whole test on the ground.

Three things had to meet for the test to say anything. Cheap hardware. A living plant that nobody protects. And an agent that reads the hardware and states what the numbers mean. The first two are the substrate. The third is the part that does not yet exist for a pod.

We kept the test cheap. If you specify flight avionics first, you find the integration problems late. Instead we built the measure-and-report loop that a pod owes the control plane (HW-001-R7). We built it from parts that we can change at a bench in one afternoon.

We compared three platforms

Mycodo runs on a Raspberry Pi. It controls pumps and dosing with PID loops. We did not need that actuation yet. The Pi also has no analog input, so a soil moisture sensor needs an external ADC.

Prometheus with custom firmware is the professional answer, and we expected to choose it. An ESP32 can serve a metrics endpoint directly. The cost is hand-written Arduino C++ for each sensor. Prometheus also needs a scrape server, but that cost is not a difference: we must store the data whichever firmware we choose. The decision therefore turned on the firmware only.

ESPHome compiles declarative YAML into ESP32 firmware. It supplies a component for each sensor on our list. It also supplies Wi-Fi, time sync, and over-the-air updates.

We chose ESPHome, and not for its cost. With ESPHome, the instrumentation behavior becomes a reviewable config artifact instead of opaque C++. This subsystem must be trustworthy about failure. A reader can read the device behavior from one YAML file. That is worth more than the flexibility we gave up.

Criterion Mycodo Prometheus + custom ESPHome
Hardware $15+ (Pi) $4.71 (ESP32) $4.71 (ESP32)
Custom code Minimal Arduino/C++ None (YAML)
Analog inputs Needs external ADC Built-in Built-in
Setup complexity Medium High Low

What the bench node measures

Each node costs about $18.49. It contains an ESP32-C3, a BMP280 for temperature and pressure, a BH1750 for light, and one capacitive soil moisture probe. The node uses three GPIO pins. Two I2C devices share GPIO4 and GPIO5. The soil probe uses GPIO1 for the ADC. All parts run at 3.3 V, so the node needs no level shifter and no custom PCB.

An ESP32-C3 board on a breadboard. The BMP280 and the BH1750 share one I2C
pair. The capacitive soil probe connects to an ADC1
pin.

The BH1750 measures lux. The firmware converts lux to PPFD. PPFD is the unit that governs photosynthesis, and our crop models use it. This conversion lets a bench measure the flux that a candidate grow light delivers. You can measure the light before you specify it as flight hardware.

The first firmware flash. The node reports live sensor readings over
Wi-Fi.

ESPHome supplies a web server, so you can inspect the node when it boots. You do not need to build a dashboard first to see if the hardware works.

The ESPHome web dashboard. It shows live temperature, pressure, light, and
soil moisture
readings.

We then tested the node outdoors, on a plant that nobody protects. The plant gets full sun, irregular water, and a wide day-to-night temperature range.

The sensor node on an outdoor milkweed plant. A portable USB battery supplies
the
power.

Outdoors the node measured 73% soil moisture. We validated the full range first: 0% in dry air, and 100% in water. The node measured 22.4 °C. It measured 8,050 lux, against 30 lux on an indoor shelf. From that light it derived 128 µmol m⁻² s⁻¹ PPFD. The Wi-Fi signal held at −69 dBm through one exterior wall.

An agent read the endpoint back

An agent wrote the device YAML with us, flashed it over the air, and then read the metrics endpoint on the node it had just helped build.

An agent’s report of the milkweed node: soil moisture 73% at 1.52 V, light
8,050 lux and 128 PPFD, temperature 22.4 °C, pressure 1,025.0 hPa, Wi-Fi
−69 dBm. Each value carries one sentence that says what it
means.

A metrics endpoint gives you numbers. The agent gave a statement for each number, and each statement compares the value with something: 8,050 lux is about 270 times the 30 lux we measured on an indoor shelf, and the 128 µmol m⁻² s⁻¹ derived from it is well below the 1,500 to 2,000 of full sun. −69 dBm outdoors is weaker than the −55 dBm indoors, and is still a working link. The move from 0% in dry air to 73% in soil shows that the calibration holds at both ends.

None of those comparisons is difficult. Every one of them needs a reader. A dashboard shows you 73% and waits for you to know whether 73% is good.

The limit is where the result stops. A person asked for this reading, and a plant that we can look at gave the ground truth. That is the correct order to do it in, and it is not yet the thing a pod needs: an agent that reads the stream when nobody asks it to.

We carry three hardware lessons into the pod design:

  1. Use an ADC1 pin for the analog sensor. ADC2 conflicts with Wi-Fi.
  2. Do not put the soil probe on GPIO0. GPIO0 is boot-related and gave erratic ADC readings. We moved the probe to GPIO1.
  3. Use a capacitive soil sensor, and calibrate each one. A resistive probe corrodes in days.

Where this sits on FDIR

This is not an FDIR system. It is the substrate that you build one on.

Detection: the substrate exists

The node sends grow readings, Wi-Fi signal, and uptime. It sends them on a Prometheus metrics endpoint that ESPHome supplies, and we wrote none of that code. Nothing yet watches the continuity of the stream. A sensor can report a value that looks correct but is wrong. A channel can also go quiet. Today nobody gets an alert for either fault.

Isolation: partial, and free

One failed sensor does not stop the other readings. The firmware gives us this property deliberately. But it isolates at the sensor level only. Nothing isolates one failed node from a group of good nodes. We also have one node only.

Recovery: not started

This is the honest gap, and it matters most for a pod. The firmware keeps no offline backlog. A network outage therefore leaves a hole in the record. The plant continues to grow, and we lose the evidence of what it did. At a bench 15 meters from an access point, this is an annoyance. A pod has a comms blackout on each orbit. For a pod, this is the difference between a mission record and an anecdote. The pod must hold its own data until it can transmit the data.

What this does not prove

Terrestrial COTS parts show the pattern. They are not flight avionics. This test says nothing about radiation tolerance, thermal-vacuum survival, or biological containment. We also did not test long-term uptime. A node must serve metrics for 30 days or more without help. A test of that kind looks correct for one week and then fails.

The gaps name the next work:

  1. Send the readings from the device to a time-series store.
  2. Measure the continuity of that stream, and raise an alert when a channel goes quiet.
  3. Keep an offline backlog in the firmware, and prove the replay path.

You cannot recover from a fault that you never recorded.


We measured every value here on our own bench hardware. The full-sun figure is a standard reference, not our measurement.