ROS and F'(F Prime) - Robotics Middlewares

what is a middleware?

In this context, I use the word middleware to mean some software framework that provides API calls to send data over some transport, and provides a mechanism for some callback on the receive side. The middleware may also provide a wire format, a representation of data that allows it to be sent in a stream of bytes.

(Note, the transport can be separated from the wire format, as in the case of ZeroMQ, which mainly uses TCP and UDP sockets, but does not specify a wire format, such as raw C structs, Protobuf, etc.).

what can middleware do for you?

When building a large, multiprocess / multithreaded software application, using some sort of middleware greatly simplifies the design. When only using a single thread of execution, data can be accessed across multiple logical scopes (software components) without worrying about concurrency. This won't work for multithreaded / multiprocess: threading brings risks of race conditions, and multiple processes add the additional requirement that data needs to be transferred between them (often on separate processors).

Middlewares keep the logic for supporting data flow separate from the logic inside components.

middlewares for robotics

For robotics applications, I've found two middlewares especially useful: ROS and F' (F Prime). For those unfamiliar with ROS, there are many excellent tutorials and explanations of the design process. In middleware terms, ROS1 operates as a “broker as a directory service”. The ROS master, the broker, records which nodes advertise or wish to subscribe to a particular message, then arbitrates the direct connections between those nodes. In ROS2, the ROS master is gone, and the magic of distributed discovery is handled by an implementation of the DDS specification. Again, ROS2 tutorials and design rationales abound.

F' is a NASA JPL framework (open-source) for building space flight software “deployments”, which include the binaries that run on the spacecraft, as well as the command, event, and telemetry dictionaries for communicating with the spacecraft. An F' deployment, akin to describing all the connections in an entire ROS system, is made up of many software components connected using the F' middleware. Usually, the binary either executes on bare metal, or runs as a single process when running on top of an OS. The F' middleware helps handle concurrency issues that arise when multithreading, and provides predefined types and premade components for command and data handling (C&DH). F' also encourages modularity and reuse of components across projects.

F' GitHub: https://github.com/nasa/fprime

which middleware for what

My background is in highly dynamic mobile robotics, both aerial vehicles and legged ground platforms. Through my work on the Flight Software team for NASA's Mars Helicopter, I came up the learning curve on F', and it is my go-to tool in these situations:

1) Embedded programming. On SWaP-constrained platforms, adding another Atmel micro or STM32 for each new function you need doesn't scale like it does on heavy ground platforms. So instead of that, I'll pick an embedded board that handles all of the low-level functionality I need, and create an F' deployment for it. Often, bare-metal execution makes it much easier to run control loops with guaranteed low latency, without the complexity of an RTOS. Then, I connect this board to a board running an OS, usually some Linux flavor with good ROS support.

2) High-rate and/or latency critical data flow. For example, if the IMU on your aerial platform is experiencing 2g of vibration, even after vibration isolation, and you drop IMU samples (as ROS will do above about 100 Hz on typical embedded platforms), this will significantly shift your mean acceleration and impact the quality of state estimation.

3) Moving large amounts of data (streaming images or point clouds). ROS1 has nodelets for this use case, and ROS2 is targeting a single API for both nodes and nodelets. In F', all data is by default accessible from the same address space (because most F' deployments are a single process).

4) Need for high-reliability coding with unit tests of the interfaces, and design-time analysis of the deployments. The F' unit testing framework, built around gtest, allows assertions and expectations on component behavior, using the same interfaces that a component would use to interact with others. The equivalent for ROS would be having hooks into the publish calls to check what is published, and hooks into the subscribe calls to inject specific inputs. By unit testing at the interface rather than at an internal level, the entire component behavior can be verified against requirements. As I mentioned above, an F' deployment captures all of the connections between components in a centralized way, suitable for automated design rule checks and for human verification.

why not use both?

I ended up combining the best of both ROS and F' in the aerial vehicle flight stack I wrote:

QUEST (Quadrotor Unified Embedded Stack)

QUEST Github Organization: https://github.com/quest-fw/

More on that design to follow.