Autopilot: Flight Simulator for Embedded Systems Development

Oguzhan Oztaskin
5 min readJun 26, 2024

--

Hi everyone again! In this article, I will talk about the simulator I created for my students as part of an assignment. It runs and tests the students’ homeworks which simulate a flight of a plane. You can browse the repository by clicking here.

Altitude Mode of the Simulator

I used PyGame to implement its UI, and used pyserial to communicate with the board.

I will shortly talk about its features and then focus on the development process I had.

Features

  • Semi-periodic serial communication with the board. Expects periodic messages from the board and sends commands / replies to the board.
  • Shows altitude zones in its PyGame UI as in the screenshot, and expects the user to align the plane to the expected altitude via ADC.
  • Lits leds and expects the corresponding buttons to be pressed.
  • Expects errors and logs them. Logs are used for grading.
  • Consists of many modular components called agents, which will be the focus of this article.

For a demo of the ADC controls, you can watch this YouTube video:

Hustles of Development

In the following sections, I will share my opinions and comments on PyGame and the design I followed.

PyGame

PyGame library allows you to create a window, draw shapes, set FPS etc. on a very basic level. PyGame lacks many fundamental higher level things I would expect from a graphics library (like a container system or alike as in PIXI) that has “game” (you work with composed entities) in its name. However, this is just my expectation and I understand that if it does not have to or maybe it is better this way.

Thus, I had to create those higher level things from scratch. I created a container system because that was how I worked with PIXI JS. The best things I produced are I believe:

  • Sliding background image with perfect tile loop.
  • Container system for ease of control of UI elements.
  • Simple text anchors.

Containers allowed me to make UI components modular. I could put images, texts, containers in a parent containers and move the parent container around with everything in it also moving the same way. I was developing in agile fashion, and I knew I had to try different things with the UI, so I had to make sure it was flexible enough and it really paid off. Same with the text anchors.

Also, you do not even have transparency right out of the box. In order to draw a semi-transparent rectangle, you need to draw it onto a surface (call it canvas) with SRCALPHA attribute and then blit that canvas onto the target surface. That’s how I created the semi-transparent altitude zones.

Making a sliding background image was similar. I had to draw the repeating tiled image on a temporary surface I called canvas, then blit a region of that canvas onto the target surface in order to crop it. This is because you cannot select what region of the source surface will be blitted (aka. cropping) but you can select within which region of the target surface you will blit it to. Thus, everything that falls out of that destination region is lost. That’s how you achieve cropping. Counter-intuitive to me but I guess that is just as much as valid as cropping is. Maybe this way it is easier to implement and port? Maybe the underlying library is this way?

Overall, despite lacking the tools I am used to and being counter-intuitive to me, PyGame is good and docs and troubleshooting were good too.

Agents

Designing the agents was the most fun part of the design process. I designed the agents from the most abstract classes to more solid and useful classes. The simulator consisted of various interacting systems that override each other. In order to leave space for changes and avoiding tight coupling, this was necessary. With back and forth interactions, really hard to debug/fix bugs could have occurred but I did not run into them with this design.

Below, I list the important agents from the most abstract to the solid:

  • Agent: Defines and implements Agent interface and basic functionalities.
  • ThreadedAgent extends Agent: Base class for agents that require a thread. Provides functions for starting and stopping its worker thread.
  • CommandDispatcherAgent extends ThreadedAgent: Commands received are fed into a queue (CommandQueue) elsewhere. This agent blocks on this queue and dispatches the commands to its sub-agents as soon as it gets the commands. Since it is blocking, it needs its own thread.
  • AlarmAgent extends ThreadedAgent: Simulator uses timed events for changing its states. Many agents need to act on certain times: Leds needs to be turned off after timing out by LedAgent, AltitudeControllerAgent needs to enter and exit to altitude mode, fake commands will be sent etc. AlarmAgent uses a single thread to wait for the soonest event / alarm in its queue (a priority queue) and provides methods to add new events anytime. Existent alternative solutions I found created a new thread for each alarm requested.
  • PeriodicAgent extends Agent: An abstract agent that consumes or rejects the command received during the current period. Details on PeriodicityAgent.
  • PeriodicityAgent extends Agent: Subscriber of the CommandDispatcherAgent. Checks if the retrieved message belongs to the current period, and if so, attempts to feed the command into its PeriodicAgents by the order of importance.
    PeriodicAgents need to know if they missed a message or if they are overriden by a higher priority PeriodicAgent during that period. If they missed a message, that’s a failure and if they were overriden, they did not fail.
    PeriodicAgents only consume or ignore a message, the state and delivery of the message is handled by the PeriodicityAgent. This simplifies the interactions between the agents.
  • DistanceAgent, LedAgent, AltitudeAgent etc. extend PeriodicAgent: They are all agents of periodic messages handled by PeriodicityAgent.

That’s all for the agents.

To conclude, in this project I learned or practiced PyGame, blitting images, timing events, simplifying complex interactions between different modules (agents). I wanted this simulator to be the base implementation of evaluators for embedded course’s assignments but it still has way to go. For example, more interactions among the agents can be simplified or more focus for the non-periodic messages can be given.

Thank you for reading my article. I hope you enjoyed.

Once again, to browse the repository you can click here.

--

--