Flight Software Design
Introduction
As of Fall 2023, flight software will be utilizing Zephyr RTOS as its primary platform instead of launch-core. Several benefits of this include greater hardware and platform independence, as well as better software support and reliability by leveraging an open-source community.
Although using a RTOS may be considered overkill for our purposes, we can better utilize our chips' resources (similar to launch-core's scheduler but with less headaches) and provide valuable learning experiences for members to talk about with prospective employers in the embedded industry.
This page serves as a way of communicating general philosophies when designing flight software for various hardware components including but not limited to backplane modules, extension boards and payload flight computers.
This page also serves as place to standardize how data should be communicated within a board and across different boards.
These pages may change as time goes on and the team learns of better practices when designing software around a RTOS.
General Software Guidelines
All flight software will go under the FSW repo for now
This allows us to unify all flight software instead of having scattered repos
The trade-off is that all software needs to be using the same Zephyr version. This could have long term impacts if Zephyr decides to change features that certain board firmware may use, leading to increased maintenance in the future.
Since all flight software is unified on one repository, shared functionality is expected to go under the lib folder to enforce DRY principles. This includes but is not limited to
Networking
File System
Telemetry
Data logging should be a buffered operation! Constantly logging telemetry means constant I/O operations which can negatively impact performance.
Multiple tasks should not write to global variables!
In general global variables should be frowned upon. Especially in a multi threaded environment.
Multiple threads writing to global data means there is a good chance of race conditions occurring.
Why not use a mutex? This leads to tasks competing for access to data which could also incur performance costs and there are better tools for the job
Utilize thread safe queues which a good RTOS should provide. (see below software design)
There's probably more I can't list off the top of my head at the moment and this will eventually be expanded.
General Software Design
Software should follow an event driven architecture. This leads to better decoupling of software components and greater responsiveness to certain events
This means following a producer-consumer pattern where some tasks will produce data and other tasks will consume that data
i.e Sensor telemetry tasks produce data for a logging task to consume and store data
Data should be put on a thread-safe queue by producers for other consumers to use
Certain tasks should be triggered based on certain events.
For example, if a module detects that the rocket has launched, it should start logging data and notify other modules to do the same
Closely related application functionality shall be grouped under one RTOS task instead of split across multiple tasks.
For example, if there are a few sensors reading data at 100 Hz, they should be grouped under one task instead of a sensor per task
When developing embedded software, you need to be aware of your limited hardware resources. Each task needs its own stack space which means you're eating up RAM.
Although you should limit the number of tasks you have, tasks shall not be overloaded as well
Goldilocks principle.
Large tasks = Overly complex tasks and violation of single responsibility. Run the risk of timing critical events not being serviced in time.
Many tasks = Unnecessary wastage of memory
Some software requirements may include servicing asynchronous reads from communication interfaces like Ethernet and LoRa
Those may need to be serviced quickly in time for the next read and that data could impact how a certain module should behave
Individual Board Software Design
Ethernet Communication Standards
The first 3 numbers in an IP address represent the network ID and therefore must be the same across modules.
All communication between modules over Ethernet will be done over UDP.
To maintain simplicity, at this point in time all packets will be broadcasted to the network.
It is up to each individual module to handle packets on specific ports.
Each module can reserve a range of ports for various purposes.
Port purposes will be specified in individual board software design pages
Port assignments should be defined in a header file under the lib folder to reduce code defects and reduce work if standards change
Port assignments should be specified under an enum with naming following the pattern (MODULE NAME)_(PURPOSE NAME)_PORT
i.e SENSOR_HUNDRED_HZ_TELEMETRY_PORT or RADIO_LIFTOFF_PORT
Port 9999 will be reserved for notifying other modules of flight events including liftoff, apogee and landing
Module | Port Range |
---|---|
Autopilot | 10,000 - 10,999 |
Power | 11,000 - 11,999 |
Radio | 12,000 - 12,999 |
Sensor | 13,000 - 13,999 |
RS-485 Communication Standards
Currently, the team has no experience with communicating with boards using the RS-232 interface and this section will be adjusted as we learn more
UART is the expected communication protocol over RS-485. To frame data for proper interpretation and ease of debugging, the SLIP protocol will be used
Non-backplane boards should constantly transmit an identifier until it receives acknowledgment from a parent device before transmitting its data
Unknown if this is necessary at this point
The idea is to not hard-code extension board functionality into module software
Functionality for responding to data from extension boards may be required to be put under lib to increase software flexibility