Simplicity is an important design goal. I wrote a different post explaining why. How might this principle beconsidered when design a complex system like a UAS autopilot.
First I want to address the question of why? Why develop an UAS autopilot ecosystem from scratch? In my case there are numerous reasons and I will spare you the long story that starts in the early to mid 2000’s. The highlights would include: wishing to do things the available systems could not do, wishing to figure things out myself, maybe sometimes wishing to do the same thing I try to do every night, Pinky, try to take over the world. Maybe the original curse in the Garden of Eden was giving humans opinions on things, and now here I am with opinions that no one seems interested in hearing.
I suspect some of my opinions might be controversial or seem flat out wrong. Please hear me out!
Simplicity in Language Choice
From what I’ve seen, most modern performance & safety critical embedded systems are written in some variant of C/C++. There are memory footprint and memory allocation considerations, performance considerations, and for most people, this is just how things are done.
I learned C and then C++ in the late 80’s and early 90’s. But for a long time I’ve been enamored with Python.
- When I port my C++ code to Python, I usually end up with less than 50% the original lines of code, plus I drop the clunky .h/.cpp architecture. Often the average length of my lines and symbol names also shrinks dramatically. This makes code much more readable. I can communicate the same thing in a simpler, more compact form. This is a big win, especially when more than one person is working on a project together.
- Python has a rich ecosystem of high quality modules. When we launched the FlightGear open-source flight simulator project in the late 90’s, it was written in C++ and much of our initial development time was spent crafting multiplatform libraries to do basic things. I have noticed that so many of these things are available already in the python ecosystem.
- A quick note on performance: often performance critical python modules are written in C++. Python can often serve as a convenient glue layerer for managing calls to the high performance existing code. Simply writing a project in C++ doesn’t mean your implementation will be as inspired or well-researched or well written as the python module. This is true of most modern scripting systems. If performance is considered at every decision point (along with simplicity) it is possible to write well performing python code that meets all the performance objectives.
- Here is a casual (slightly snarky) observation intended with good humor: Much of the new evolution in the C++ language is to [almost but not quite] provide data type flexibility similar to interpreted langauages. The problem as I see it is that they have built these new features with immensely clunky and unreadable syntax conventions. Lines of code grow to be wider than your editor screen, common things have ‘<’ and ‘[’ and ‘(‘ scattered throughout. There is power there, and probably a lot more than chasing scripted langauge features, but modern C++ is not a human readable language.
More on Python
In the past few years Adafruit has made a huge commitment to running python on all their microcontrollers. They have moved away from the C-based Arduino system. They clearly think the ease of use and lower barrier to entry is important. They clearly think the performance is adequate for most users. They clearly see the future trending in this direction. Adafruit is one of the more visionary and kind hearted DIY hardware/stem related companies, prove me wrong!
Simplicity in Architecture
Complexity creeps into our systems architecture design. I’m going to touch on a few items I think are worth considering. All of these have a ‘cost’ of increasing complexity in your system. I’m never arguing there is a right or wrong way, my point is simply to understand the overall cost in all the dimensions at every decision point (so don’t forget about complexity, and understand the costs you pay when you head down these different twisted paths.)
Threads == Complexity. Threads != Simplicity.
We can accept this fact and move on. Or we can design our system without threads except where absolutely positively unavoidable, and then constrained into the tiniest sandbox possible.
I’ve posted before on the dangers of threads and their associeated complexity. Threads can hide bugs. Threads often don’t work exactly how we imagined. In an embedded single-cpu environment, threads can introduce serious timing issues and indeterminism. Real time systems aren’t as real time as you think, unless you understand how to activate and monitor all the real time features. And threaded architectures can quickly become very complex to understand because there is no easy way to directly observe the control flow.
Abstraction layers can be good tools for simplifying a system and hiding complexity. This is true, but I argue that fewer are better.
Abstraction layers can be over used. Each abstraction layer creates a new API (or language) that a new developer needs to learn in order to understand the system. When abstractions are layered on top of layers it can become extremely difficult to understand a system. So understand the cost of a decision to add an abstraction layer.
Code generators. This can be another tool to reduce complexity. We can create a simpler, higher level langauge that and associated code generation tools. However, like abstraction layers, we creating a new language that needs to be learned and understood in order to begin to understand the larger project. Sometimes these are excellent strategies, but understand the cost, and understand that overuse can be detrimental.
This is a hard one to talk about. In my experience, build systems involve a tremendous amount of complexity. Many existing UAS autopilot systems endeavor to support the widest range of boards and cpu’s and sensors and functionality possible. This leads to complexity in other areas, but a key place this shows up is in the build system.
When you think of coding in python (even when writing some of your performance critical modules in C++) the build system can be made very simple and work on every platform that supports python.
Simplicity through Scripting
This is an area I really want to focus on. Python itself is a scripting language, so if the entire flight controller is written in python, is there still a place for scripting?
Why use scripting languages or why embed a scripting language in your flight controller?
Simplicity by Fewer Comments
This really should go along with langauge choice, but it’s important enough (and controversial enough) to have it’s own section. Can comments do more harm than good? I argue that often, yes. If I am trying to wrap my head around a function or a module, every line of comments in my editor view is one less line of code I can see. When the comment is redundant with the code, please consider dropping it. Please trust my ability to read the syntax and understand what basic primitives and data types do. When you’ve done something truly exotic and incomprehensible, then a few comments to help explain are worth while.
Simplicity by Doing Fewer Things
So I applaud systems that put a deliberate priority on supporting every possible cpu and hardware board, every possible sensor, every possible platform, every possible host computer, every possible vehicle, every possible build system, every possible algorithm, every possible functionality. This is truly impressive, truly difficult, truly complex.
My question is this. What if a system limited the platforms it supported, limited the features included, limited the sensors supported? Clearly that’s not a solution for everyone across the entire planet, but if it reduced the complexity of the system by 10-fold. Would that be worth consdering?
If the barrier to entry and understanding was 1/10th the height, is that worth considering?
If you need to validate a mission critical system and it is 10x simpler, is that worth considering?
2021-04-11 00:00:00 -0500 - Written by curt