Lifecycle of a Driver Part 1: PX4 running on NuttX

The PX4 autopilot running on the NuttX RTOS is an interesting case study. NuttX itself provides a variety of POSIX-compliant facilities for supporting driver-like activities, such as streams, file descriptors, paths, and so forth. However, that is not enough to support high-speed handling of sensors and actuators on an embedded platform.

Because of the nature of the technical domain (robotic guidance, navigation, and control), PX4 must pull data from a wide variety of sensors and send commands to a wide variety of actuators. The sensors vary widely in their bandwidth and latency requirements, everything from gyroscopes to barometers, GPS to LIDAR.

PX4 has converged on a common architecture for most of the commonly used drivers. This consists of a few main components:

  • a command line wrapper
  • the core driver
  • an interface to the publish-subscribe messaging bus of PX4, uORB

Keep in mind that NuttX does provide a kind of shell: nsh, the NuttX Shell. At startup drivers are typically started from nsh using their command line wrappers. During runtime, the drivers can also be stopped and restarted.

Command Line Wrapper

Most PX4 drivers have a command line wrapper that may be called from nsh, the NuttX shell. These wrappers generally provide commands such as:

  • start: Start the core driver running
  • stop: Stop the driver running
  • status: Print the status of the driver

It’s important to note that the wrapper itself is not creating a NuttX process: its start method simply instantiates a core driver and stores it. Any subequent commands issued to the wrapper simply poke at the existing driver instance.

Example

Take for example the ms5611 barometer wrapper: ms5611_main is the main() function for this wrapper. This might be invoked under nsh using the command line ms5611 start with various bus-selecting options (SPI, I2C). This start method in turn creates the core driver.

Core Drivers: ScheduledWorkItem

Take for instance the MS5611 class: class MS5611 : public px4::ScheduledWorkItem {..} This is the class that performs the core activities we normally associate with a driver: configuring an attached device, reading data from it, communicating with it.

Most core drivers are a kind of PX4 ScheduledWorkItem.
WorkItems can be added to one of PX4’s WorkQueues. This is how they are able to schedule asynchronous processing.

The core driver provides essentially a Run method that can reschedule itself for running at some future time. The run method typically does some tiny amount of work (for example, starting the process of taking a sensor measurement in measure or subsequently collecting the results of that measurement in collect) then calls ScheduleDelayed to schedule itself to run again in the future.

Core Driver Methods:

  • init: Called synchronously by the wrapper
  • start: Schedules the driver to begin asap (using ScheduleNow)
  • stop: Stops the driver from running (using ScheduleClear to deschedule it)
  • Run: Performs work asychronously, called by the WorkQueue.

Pub-Sub Interface

Most PX4 modules (essentially applications or processes) running on PX4 do not access sensor drivers directly. Instead they subscribe to a topic on the platform’s common pub-sub messaging bus (called “uORB”) and wait for sensors to publish data on those topics. This pub-sub messaging bus model is similar to that used by another popular robotics framework, ROS the “Robot Operating System”.

Most sensor drivers use a common set of interfaces to uORB. For example, all barometers use PX4Barometer to publish barometer data to a well-known topic. In practice this allows developers to add drivers for new sensors easily, without needing to change the code receiving the sensor data.

Not all drivers follow this model, but drivers for the most critical and redundant sensors do: for example, an autpilot is likely to have multiple redundant accelerometers and gyroscopes, and although the core drivers for each might be different, they use the same PX4Accelerometer and PX4Gyroscope glue to publish to the uORB bus.

Summary

  • Drivers are started and stopped from the command line using wrappers. Portions of the setup/init and start procedures run synchronously with the command line wrapper, but mostly drivers run asynchronously by scheduling themselves in a common WorkQueue.
  • One can use the nsh command line to start a driver, stop a driver, and check the status of a driver.
  • The work queue can be driven in many different ways depending on the underlying OS/RTOS.
  • Most sensor drivers publish data to well-known topics on the shared uORB message bus. Some eg actuator drivers subscribe to other well-known topics to receive commands for driving their associated actuators.
  • Applications running in the PX4 environment receive data from sensor drivers by subscribing to well-known topics on the uORB pub-sub message bus.