Having introduced ArduPilot as a whole in our first post, in this second one we look into its components. For ArduPilot, having a sound architecture is important because the software needs to manage various sensors and actuators while operating all kinds of drones like helicopters, planes, rovers, or even submarines. As exemplified by the popular “4+1 View” model 1 of software architecture as well as various academic sources 2 3, there are many ways to view the architecture, each with a different focus. In this post we analyze ArduPilot using some of these views. We focus on the different architectural elements of ArduPilot and the connections between them, and the design principles used by the software that allow it to soar.
In terms of architectural views, we see from our research that the Development View, Deployment View, and Run Time View are relevant to the project, because the developers discuss topics about them at length in the documentation 4. We will look at these views in detail after mentioning some fundamental aspects of the architecture.
A key aspect of ArduPilot is it being designed with a multi-layered structure. It has three layers: vehicle-specific code, shared library code, and the hardware abstraction layer (“HAL”). Similarly, ArduPilot itself is a part of a larger multi-layer system, as later described when describing the module structure. Meanwhile, the codebase is split into five parts, with the three layers having their own parts. The other two parts are tools directories (like testing tools), and external support code (that runs alongside ArduPilot) 4. This functionality-based division into layers and parts demonstrates the principle of the separation of concerns, which allows developers to manage each aspect of the software individually while treating the others as blackboxes 3.
Looking at the architecture of ArduPilot’s code files, many of them imitate the iconic “setup()” and “loop()” structure of Arduino sketches5 from which the software gets its name. However unlike Arduino sketches, ArduPilot’s software is multi-threaded6. Also, because it deals with sensors and controllers, ArduPilot has an event-driven architecture, operating primarily using tasks and a task scheduler 7.
While it is normal for form to reflect function, we see that non-functional properties too shape ArduPilot’s architecture, namely universal applicability and security:
ArduPilot aims to be universally applicable. This means that its developers want it to run on as many kinds of unmanned vehicles as possible. Although the development team hasn’t explicitly stated it, this goal is arguably why ArduPilot has no first-party graphical user interface (GUI). If ArduPilot were to implement custom GUI’s for the dozens of vehicles it supports8 , it would have to shift much of the developers’ efforts away from controlling the vehicles to designing several specific GUI’s. Therefore, ArduPilot has users write their own GUI software or pick from supported external “ground stations” that serve this purpose9, but in return the autopilot core gets much more development time.
It is possible for vehicles to receive control messages from different ground stations than the one they were booted up on. While going through the code, we saw that a simple but effective security measure was put in place to prevent this: The vehicle would check whether the message received came from the ground station they were registered on, and would not execute the order otherwise. Thus we see that ArduPilot was designed to support one ground station at a time. This is good for security, but in return it makes users unable to send their vehicles very far away, where the control could be passed over to other ground stations.
Development View: ArduPilot as A Software Collection
Careful design decisions are needed when creating a development environment that can successfully realize ArduPilot. The development viewpoint relates to the code and modules structure and the building, testing, releasing, and configuration requirements standardized within ArduPilot 10.
Module Structure of ArduPilot
ArduPilot’s three layers can be seen in this structure, while communication (with MAVLink) and user interfacing (with Ground Station or DroneKit) can be seen as two other layers above it.
- Ground Station module: As a supported external software for ArduPilot, Ground Station runs on a ground-based computer, and communicates with an unmanned aerial vehicle (UAV). It displays real-time data on the UAV, and can be used for controlling it.
- DroneKit: As another supported external software, DroneKit helps create powerful apps for UAV’s, running on a UAV’s Companion Computer.
- MAVLink: An external software used by ArduPilot with its own protocols for communication with ground stations / companion computers.
- Vehicles Modules: The unique firmware for each vehicle type.
- Shared libraries modules: The code usable by multiple vehicles including core, sensors, and other libraries for various functions: control, navigation, etc.
- Hardware abstractions module: Renders ArduPilot portable to many different platforms and development boards.
ArduPilot’s Source Code Structure
The overall structure of the ArduPilot directory is represented above 11. It is designed to be simple to comprehend, as each folder is named after the module it represents. This layout also exhibits a separation of concerns, which simplifies development as previously explained.
Given the structure, we have vehicle code files in the folders APMrover2, ArduCopter, ArduPlane, and ArduSub. This code is largely
.cpp files since ArduPilot is largely written in C++, while vehicle directory also contains a make.inc file which lists library dependencies for that vehicle. Meanwhile, the Antenna Tracker folder is home to the firmware responsible for controlling the Antenna Tracker which tracks a vehicle’s location in order to properly align a directional antenna.
The Tools folder contains miscellaneous support tools, namely the AutoTest suite which regularly tests the vehicle code. The libraries and docs folders are respectively home to the shared libraries and the documentation for the four vehicle types and the AntennaTracker.
Build, Integration, and Test Approach of ArduPilot Developers
Building ArduPilot differs based on the platform it is meant to run from (i.e. Linux/Ubuntu, MacOS or Windows). The main steps are:
- Setting up the Build Environment on the required platform
- Building / Compiling, which supports two build systems, “waf” or “make”, based on the board used
- Building Mission Planner (which is an independent ground control station software used for Plane, Copter and Rover) 12
For continuous integration, ArduPilot makes use of “Travis CI”, an integration service used for building and testing software projects hosted on GitHub 13.
Thus, each integration can be directly verified by an automated build and automated tests allowing developers to quickly detect and locate errors. The
.travis.yml file in the root directory specifies the programming language used (C++), the dependencies, building environment, testing, etc. 14
As for testing, an autotest consisting of 28 tests can be run 11. Its results and logs can be visualized and monitored from the project’s root. Testing can be performed either on real hardware or in simulations that allow for safe testing of experimental code and settings. Some of the most commonly used simulators for ArduPilot testing are: SITL, Gazebo, RealFlight, and AirSim 1516.
The diagram below describes the overall build, integration and testing approach followed by ArduPilot developers:
ArduPilot’s Release Process
A clear process for releasing ArduPilot is available on the website 17. We have summarized it here:
- Alpha Testing: AutoTester runs these tests after a commit is done
- Releasing Beta Versions
- Create a new release branch or switch to an existing release branch in the GitHub repository
- Pull from the master
- Update release details such as version, release notes and tags
- Make sure Mission Planner displays correctly the new versions added
- Announce the availability of a new version to the beta testers, who test in simulations or on hardware
- Releasing Stable Versions
- After weeks / months of beta testing, and no more unexplained crashes, prepare to release the stable version
- Discuss the go-no-go decision on a stable release on the preceding weekly development call
- Release the stable version similarly to the beta one and add the “stable” version tag: i.e. add the ArduCopter-stable and ArduCopter-stable-heli tags in the case of a version relating to ArduCopter
- Create an additional tag with the patch release number
- Make an announcement on ArduPilot’s forums and on ArduPilot’s Facebook page. Mission Planner will also show a pop-up informing users that a new version is available.
Currently, ArduPilot does not seem to have an official configuration management process that keeps a record of any parameter changes. However, GitHub can be used instead for easy configuration management: one can check the changes in the code and quickly switch to different versions or settings. Hence there is no need to manually do things like maintaining backups.
Run Time View: Connecting the Modules
ArduPilot has to take care of different scenarios while it runs. The run time view specifies how the modules work together to realize certain key scenarios. Think of starting up a drone and configuring it, then controlling and moving it as you want, and then returning the vehicle back to the ground control. We will describe the first two of these scenarios in further detail, assuming the vehicle is a drone copter. In the first scenario, we talk about the dependencies between the process, the libraries and the HAL to realize the initialization. In the other scenario we will talk about the dependency between certain actions during autonomous flight mode.
For dronecopter running ArduCopter, the function
Copter::init_ardupilot takes care of all necessary initialization before taking off. Surprisingly, this function initially assumes that the copter is in mid-air. Later on, the system determines if the copter is actually in the air or on the ground. Only at a ground start, the copter will perform a calibration to ensure correct values on its devices. During the startup phase, several modules are initialized which include:
- Board: setting the correct time, scheduler delay and SD Card settings
- Battery: clearing out the cell voltages and turning on battery monitoring
- Radio channels: setting values for the flight control parameters of roll, pitch, yaw and throttle, and the default dead zones
- Sensors: initializing the GPS and the compass
- Motors: settings the loop and update rate
The figure below shows how some of these initializations depend on the shared library layer and HAL layer in order to do an operation.
A copter on the ground is cool, but making it fly is a lot more impressive. How about making it fly on its own? Even better! The autopilot control of the copter is done in the
mode_auto.cpp file. The file has its own initialization for the automated controller and contains 10 different implementations such as taking off, waypoint navigation, and landing. The function
ModeAuto::run() ensures that the correct auto controller is selected, and
ModeAuto::run_autopilot() handles the decision making process as well as the non-navigation related commands. Each type of action has its own verifying operation, which returns true if the action has completed. Only when the verify function returns true, a new action is allowed.
Deployment View: Realizing ArduPilot
Since ArduPilot supports four different types of vehicles, an end user can implement the software based on the type of vehicle they want to deploy. The software is commonly used by commercial companies seeking professional performance levels 18, or by hobbyists who strive to augment their toys with custom features in a more affordable way 19. The ArduPilot software can be implemented on various dedicated control boards, such as the Pixhawk and the Mateksys. As well as on the more popular Raspberry Pi boards with a Navio2 HAT. ArduPilot runs on Linux, and is in the process of supporting ChibiOS too 2021. Vehicles that are supported by ArduPilot are listed on their website 8.
In this post we examined the architecture of ArduPilot both in general and from multiple views. Having three different views with different focuses enables the separation of concerns. This allows developers to work on specific aspects of the project without having to consider all aspects at once 3. Meanwhile, the three views come together to paint a wholistic picture of the project.
Jim Coplien Gertrud Bjørnvig. Lean Architecture for Agile Software Development. Wiley, 2010 ↩
Software Systems Architecture, Chapters 20 (development viewpoint) ↩