Programming Cold Flow Update - MCL Overview

Written on11/7/2020

The flight software is the code loaded on the Raspberry Pi on our test stand. On our test stand, we have three microcontrollers: two Arduinos and one Raspberry Pi.

Main Control Loop (MCL) is the name of the logic of our flight software and the class Supervisor runs MCL. MCL consists of three parts: read, control, and actuate (RCA). The code is running these three steps over and over again, hence the word "loop." We will be using pressure as an example to illustrate this concept further.


The "read" section of MCL reads the data from the sensors, including thermocouples, pressure sensors, and load cells. For example, the code will read pressure data from the pressure sensors.


The "control" section of the code makes decisions on the rocket. To reiterate, it only makes the decisions and does not actually do anything. If the pressure is out of a certain range (too high), the code will know that the solenoid will have to open in order to relieve the pressure.


Finally, the "actuate" stage actually performs all the actions. The code will now know (reason explained later down the page) to open the solenoid valve to decrease the pressure.

Tasks and Drivers

Tasks contain the RCA portion of the code. The three types of tasks are ReadTasks, ControlTasks, and ActuateTasks (these are just types, not the names of the actual classes/files).

The two files that store the data for sequencing are the Registry and Flag classes. The Registry class contains all the variables that store the different states of the rocket (i.e. stage_status and mcl_start_time). If we check the registry, we can see what is happening on the rocket. The Flag class stores all the decisions made in the ControlTask (i.e. stores the queue of the telemetry commands and stores the dictionary of actuation priorities).

Drivers include the commands to interface with the sensors and valves. Our two drivers are ArduinoDriver and TelemetryDriver. TelemetryDriver contains the code to set up the sockets (allows us to have two way interactive communication), connect to ground station, and send/receive messages. ArduinoDriver contains the code to send/receive data from the Arduinos.

As mentioned before, we have three types of tasks: ReadTasks, ControlTasks, and ActuateTasks. Instead of splitting the files up into these three groups, we have two different "groups" of tasks: Tasks and ControlTasks. The Tasks contain two methods: read() and actuate(). The ControlTasks contain the methods necessary to make decisions about the state of the rocket, and whether we need to vent, pulse, or abort.

For the Tasks group, we have three different classes: SensorTask, TelemetryTask, and ValveTask.


  • read(): gets data from the sensors using ArduinoDriver
  • actuate(): N/A (you can't actuate sensors!)


  • read(): receives all incoming messages and updates the Registry class with a list of methods that need to be ingested (takes methods in for immediate use)
  • actuate(): sends messages in the Flag class to ground station


  • read(): reads the state of the valves from the ValveArduino and updates the Registry class from these readings; then, gets the current actuation of each solenoid and updates the registry with those readings
  • actuate(): looks at the flags in the Flag class and actuates valves based on the readings
  • Note: each actuation has its' own priority; each actuation is put in a priority queue in the Flags class and the actuations are executed based on the priority (1 is the highest priority, while 2 is the lowest priority)

For the ControlTasks, were have four different classes: SensorControl, TelemetryControl, ValveControl, and PressureControl.


  • Reads sensors values in the Registry
  • Applies Kalman Filter to data (Kalman Filter: normalizes data and filters out outliers)
  • Compares normalized sensor values with the critical values in config.json and updates the sensor status of each sensor in the Registry
    • If any of the statuses for the sensors are critical, then the soft_abort flag is set to True; if the statuses are safe, set to False
  • Sends a flag to send sensor data down to ground station at an interval of time


  • Processes all the messages, called packets, that are coming from ground station
    • After, it sets the flags to either send a message back with requested information or to actuate a valve


  • Enqueues messages with valve data to send down to ground station at a given interval
  • Sets a flag to OPEN_VENT all valves if either the abort flags are true


  • Opens the solenoid valve when the pressure is too high
  • Closes the solenoid valve when the pressure gets within the "safe" range


  1. Soft abort is recoverable, meaning that it will stop aborting if we tell the code to do so
  2. Hard abort is not recoverable, meaning that it is permanent and will happen no matter what other commands we try to send to the flight software

Project Caelus | Copyright © 2018-2021. All rights reserved.