After reviewing existing autopilot modules, our sensor choices for the I/O boards were fairly straightforward:
The MPU-6050 and MS5611 are on-board; the HMC5883 is on a separate board connected via I2C, the GPS units are connected via TTL serial, and the other sensors are connected via analogue inputs.
Sensor interfacing is handled by an Atmel AVR32UC3C1512 MCU, which is a 32-bit 66MHz part with 64KB RAM and 512KB on-chip flash. We’re running it at 48MHz to simplify USB timing (slightly). The MCU provides three I2C buses, so each I2C device is on its own bus; we also use the four on-board PWM channels for servo control, and the ADC channels for the pitot and rangefinder.
A key requirement was avoidance of single points of failure in the servo PWM path; thus, each board has a set of capacitive isolators (2kV breakdown) powered directly from the servo batteries, with a daisy-chain capability controlled by an enable pin on the MCU. In the event of an unexpected restart or failure on the logic power supply, the MCU enable pin goes low and the servo isolators switch to pass-through mode.
In addition, each sensor has its own overload-protected power switch, with enable lines controlled by the MCU; if a sensor fails to respond with valid data in time, the MCU executes a reset procedure which powers the sensor off, waits, and re-initializes from scratch. This provides a high degree of tolerance to sensor hardware faults, as well as short-circuits and reverse polarity conditions (speaking from experience).
The MCU software is bare-bones, essentially running a loop which initializes a set of DMA transfers for each sensor, then processes the results when they arrive. Interrupts are only used for debugging systems, which makes reasoning about timing and concurrency much simpler; the structure of the code ensures every execution path is used at least once per run (startup code once plus every time a sensor fails; sensor read code generally every millisecond).
The effect of this is that CPU usage is very predictable, and cannot under any circumstances exceed 50% of available cycles; a watchdog timer is in place to reset the device if the deadline is not met, since it indicates a severe failure. The predictability of CPU usage also means that sensor data packets are sent to the DSP every millisecond with almost no jitter and a maximum latency of one millisecond, simplifying the UKF timing code significantly.
After Daniel designed the boards, we had a small run of PCBs manufactured in China; they’re able to be hand-assembled (although not by me) so he made three up once the PCBs arrived.
The boards worked perfectly, aside from an issue with the DSP-controlled board reset line interfering with JTAG programming. We simply cut the DSP reset traces to fix that, but will need to repair them prior to flight under full DSP control (fortunately the firmware is almost feature-complete so we won’t need to re-program them frequently).
Aside from the main LVDS serial interface to the DSP, the boards have JTAG and micro-USB connectors for debugging purposes. All output packets are mirrored between the DSP serial link and the USB connection; as the DSP board is not yet ready, we’ve been logging 2×1000Hz sensor data feeds to an ODROID-X2 single-board computer via USB.
The I/O monitor source code is available at sfwa/iomon. Obviously it’s really only useful for AVR32-based boards.