Obelisk API

The Obelisk API defines a consistent set of interfaces to modularize the development of robotics stacks. At the core of Obelisk is ROS2, which provides a publish-subscribe interface for heterogenous nodes to interact with each other. Obelisk provides unified interfaces to simulators, hardware, state estimators, controllers, and other utilities like visualization and logging as well as libraries written natively in both C++ and Python that allow you to easily interface with the Obelisk ecosystem. It is possible to interface with non-Obelisk ROS2 systems from the Obelisk ecosystem, but this will be significantly more effort than staying in the Obelisk ecosystem. Obelisk is open source, so if you want a feature added, feel free to submit a pull request on Github.

Below we will cover all the concepts needed to work with Obelisk, including all relevant parts of the ROS2 ecosystem.

Overview

In Obelisk we assume that there are three main blocks in every control system stack:

  • Controller

  • State estimator

  • System (robot)

Beyond these main blocks, there are a number of optional blocks:

  • Sensors

  • Visualization (TBD)

The block diagram is as follows:

block-diagram

The blocks in pink are required, so every system using Obelisk must at least include one Controller, one State Estimator, and one System, but additional blocks may be added. Further, each of these blocks expects to be connected to each other in this configuration. For example, the state estimator always receives information from the System, and outputs an estimate to the Controller. When writing a robotics stack in Obelisk, these connections are always present, but are only a minimal requirement, and more can always be added. For example, the Controller may output more than just the control action.

For the Controller, State Estimator, and Offboard Sensors, Obelisk provides a set of abstract class interfaces. You must implement certain abstract functions in these classes, but much of the boilerplate code is handled for you.

On the other hand, the System block is different from every other block: the System block is what is being controlled, and thus is not normally implemented by the user. The System block may either be the hardware interface or the simulation interface, both of which are provided by Obelisk. For each simulator, there is a single simulation interface that supports all robots, and currently there is only one supported simulator: Mujoco. On the other hand, for each robot there is a specific hardware interface. Each robot that is in Obelisk ecosystem will need a custom hardware interface written for it, but once it is written, anyone using Obelisk can easily interface with it.

Obelisk Nodes

Each block in the above figure is composed of one or more Obelisk nodes. Obelisk nodes are specialized ROS2 nodes, so we will begin by describing ROS2 nodes.

Nodes are processes that can interact with each other via a publish-subscribe system. This means that each node has the ability to both publish any number and type of messages and subscribe to any number and type of messages. Every message is published to a “topic” which is effectively a message stream, where the topic name is given by a string. Then any node that wants to listen to that data just needs to subscribe to that topic.

Each node must be “launched” when booting up your stack, and this is normally handled via a launch file. All Obelisk nodes are ROS2 Lifecycle nodes, which means that each node keeps track of its internal state. Lifecycle nodes can undergo the following state transitions:

  • Configuration

  • Activation

  • Deactivation

  • Cleanup

  • Shutdown

During each of these, internal functions are automatically called to facilitate the transition. More information on generic ROS2 nodes can be found here.

An Obelisk node is a specific ROS2 node that has special features designed to make bringing up a robotics stack easy and hassle-free. All of these are made up of the following parts:

node

Some of the main features are:

  • Automatic handling (activation, deactivation, cleanup) of all Components

  • Easy stack configuration via a yaml file

  • Nominally only publish and subscribe to Obelisk messages

  • Automatically launched - no need to write a custom launch file!

  • Lifecycle states (as briefly mentioned above)

Obelisk nodes make it so you don’t have to worry about all the details of the ROS interface, so that you can focus on writing the callbacks, which is the meat of most control stacks.

Obelisk Messages and Topics

Obelisk comes with a set of custom message types that are designed to be used with Obelisk nodes. Having a standardized set of messages allows us to easily interface with other’s code as it defines a basic input-output API, but also it allows us to encode useful meta-data in each message. Here we list all supported Obelisk message types (details on each message type is given in the code).

  • Controller messages:

    • PositionSetpoint

  • Estimator messages:

    • EstimatedState

  • Sensor messages:

    • JointEncoders

    • TrueSimState

The topic names are configurable in the node configuration (yaml) file.