Skip to content

Science Board

Reads the atmospheric sensors on the science payload and publishes their readings on the CAN bus. Firmware lives in src/science.

Five sensors. Four sit on one I2C bus; the UV sensor is read through the ADC.

SensorPartBusAddressPublishes
Temperature, humidity, pressureBME280I2C0x77temperature, humidity, pressure
Carbon dioxideSCD4xI2C0x29co2
OxygenI2C0x70oxygen
OzoneI2C0x73ozone
UVanalogADCuv_index
TimerRatePurpose
htim2400 msCO2 sensor transmit
htim3100 msCO2 sensor receive
htim6500 mspublish SCISensorData
htim7500 msI2C watchdog
htim15100 mspublish SCISensorState
htim161000 msretry faulted sensors

Every sensor derives from ScienceSensor (src/science/Inc/ScienceSensor.hpp), which gives them all the same four-part interface:

MethodPurpose
init()configure the device; returns false if it does not respond
poll()start an acquisition
update()consume the result and store it
restart()re-run init() on a faulted sensor and clear the fault if it succeeds

Acquisition is asynchronous: poll() starts a transfer and the completion interrupt drives update(), so the main loop never blocks on a slow sensor. The CO2 sensor gets its own transmit and receive timers because its exchange is slower than the others.

Each sensor carries a state flag. One that fails to respond is flagged and the board keeps running with the rest, publishing the flags so the rover knows which readings to trust. A 1 Hz timer retries flagged sensors through restart(), so a sensor that browns out or is reseated recovers on its own without a board reset.

The board publishes to host 0x10 from node 0x40, both fixed in src/science/Inc/config.hpp.

MessageBase IDDLCSignals
SCIResetCommand0x805100001reset, clear_faults
MessageBase IDDLCSignals
SCISensorData0x8060000032uv_index, temperature, humidity, pressure, oxygen, ozone, co2 (seven 32-bit signed values)
SCISensorState0x806100001uv_state, thp_state, oxygen_state, ozone_state, co2_state (one bit each)

clear_faults clears the sensor state flags without restarting the board; reset restarts the MCU.

None over CAN. There is no config/science.yaml; the CAN IDs are compile-time constants in src/science/Inc/config.hpp, so changing them means rebuilding and reflashing.

The BME280 needs its factory calibration coefficients read out of NVM at startup before any reading can be converted to physical units, which is why init() does several blocking reads before the sensor becomes usable. The CO2 sensor has CRC checking disabled during initialization.

See Communication Protocols for background on I2C itself.

Terminal window
./scripts/build.sh --src src/science --preset Debug
./scripts/build.sh --src src/science --preset Debug --flash