TeleMetrum Software Design

Mission Priorities

  1. Avoiding risk to people and property. Recovery charges must only be fired when the rocket is at altitude.
  2. Deploy recovery systems. Getting the rocket safely back to the ground.
  3. Transmit beacon signal. Locating the rocket after landing using RDF.
  4. Capture flight data. Recording altitude and acceleration data (and GPS).
  5. Transmit flight data. Sending data over the RF link.

The software and hardware must be designed with these priorities in mind

Hardware Environment

  • CPU: TI cc1111
  • 8051 core
  • 6 12-bit A/D converters
  • SPI
  • USB
  • 70cm digital transceiver
  • Misc GPIOs
  • Pressure Sensor: MP3H6115A
  • Accelerometer: MMA2202EG
  • Thermometer: MCP9700
  • Serial port for NMEA-encoded GPS
  • SPI Flash: 25LC1024 (128KB)
  • Recovery deployment: FD335 FETs

Of particular interest is the A/D architecture here. The CC1111 can trigger a sequence of A/D operations off of a timer, and then use a DMA engine to copy those results to memory. Once all of the A/D operations are written to memory, the CPU will receive a single interrupt. This means that we can capture the analog data with very little CPU intervention, and that it will continue capturing data without prompting from software.

We should also be able to use the DMA engine to write to the SPI flash part, queueing a SPI transaction to write memory and then sending it off.

The serial port may not have a GPS device attached; the design has a bare port which is signal-compatible with the SparkFun GPS-08936 module.

The USB port is used to charge the on-board LiPo battery as well as communicate with a host computer to extract data and program the device.

Software Environment

  • SDCC toolchain (compiler/assembler/linker)
  • FreeRTOS real time operating system
  • lpcusb USB stack

Highlevel System Architecture

  • Data capture system captures data from A/D sensors to ring buffer
  • Flight analysis system tracks sensor data, computes rocket status
  • Flight event system tracks rocket status and runs recovery components
  • Beacon system lights up radio transmitter for location
  • Data logging system reads ring buffer and writes to flash
  • Data transmit system reads ring buffer and sends to beacon system
  • GPS system reads serial port and sends to beacon system
  • Console system communicates over fake USB serial port

We could implement each of these systems as separate threads within the FreeRTOS system, but I don't believe that is necessary. Instead, I suggest partitioning as follows:

  1. Data capture uses timer 1 and DMA to automatically capture data at a fixed rate. This will generate reliably spaced data points. The DMA complete interrupt will copy data from the DMA capture ring to a FreeRTOS queue object.
  2. GPS system uses a separate thread to read from the serial port.
  3. Console system uses a separate thread to read/write commands from USB
  4. Beacon uses a separate thread to write data over the radio
  5. Everything else lives in a big loop, reading data from the ring and acting on it. It will wake up each time data is added to the data capture queue.

Main Loop

struct {
    /*
     * Raw sensor data
     */
    uint16_t    acceleration;
    uint16_t    pressure;
    uint16_t    temperature;
    uint16_t    battery_voltage;
    uint16_t    drogue_sense;
    uint16_t    main_sense;

    /*
     * GPS data
     */
    uint8_t     gps_hour;
    uint8_t     gps_minute;
    uint8_t     gps_second;
    int32_t     gps_lat;
    int32_t     gps_lon;
    int32_t     gps_alt;

    /*
     * Filtered data, used to compute flight state
     */
    uint16_t    filtered_acceleration;
    uint16_t    filtered_pressure;

    /* 
     * Flight state
     */
    enum {
        READY_FOR_LAUNCH,
        GOING_UP,
        ON_DROGUE,
        ON_MAIN,
        LANDED,
    } state;
} blackboard;

blackboard.state = READY_FOR_LAUNCH;

for (;;) {
    read_data(&blackboard);
    flash_sample(&blackboard);
    update_flight_state(&blackboard);
}

Beacon

for (;;) {
    send_data(&sample_buffer);
    if (flight_state == GOING_UP)
        sleep(10ms);
    else
        sleep(1000ms);
}

GPS

for (;;) {
    read_nmea(&nmea_buffer);
    if (is_gga(&nmea_buffer))
        parse_nmea(&nmea_buffer, &blackboard);
}

Console

for (;;) {
    print_prompt();
    read_command(&command_buffer);
    execute_command(&command_buffer);
}