Kod*Lab Mjbots SDK
open-source SDK for developing Mjbots-driven legged robots
The Kod*Lab Mjbots SDK is available on GitHub at https://github.com/KodlabPenn/kodlab_mjbots_sdk. This project is a collaboration with Shane Rozen-Levy and J. Diego Caporale.
Overview
The Kod*Lab MJBots SDK is a Kod*Lab-developed, open-source control framework for interfacing with the MJBots brushless motor driver ecosystem. It extends the MJBots Pi3Hat library developed by MJBots. The SDK provides a modern C++ (C++ 17) framework for writing high-level robot behaviors with support for concurrent computing and running on a real-time operating system (RTOS). In the near future, the SDK will incorporate support for dynamic simulation via the open-source MuJoCo physics engine. Some of the key features are:
- 1-kilohertz update loop on the Raspberry Pi, including communication with the motors, logging, and remote communications
- interface with the 30-kilohertz position control loop on the Moteus motor driver
- cross-compiling support from Ubuntu 20.04 to Raspberry Pi Raspbian
- integration with the NYU/Max Planck Real-Time Tools package for better realtime performance
- integration with Lightweight Communications and Marshalling (LCM) library for remote input and logging.
We use Git for version control, and GitHub for remote repository hosting and collaborative coding tools. We develop code by creating and peer-reviewing pull requests for implementing features and fixing bugs.
My Contributions
Below are a summary of my contributions to the Kod*Lab MJBots SDK.
Architectural Refactoring
As the breadth of robots operating on and behaviors implemented using the SDK grew, demand grew for interfaces to facilitate implementing higher-level code and promote code reuse. To this end, I co-authored a series of pull requests that reorganized the core functionalities into intuitive, modular abstract classes and implementations. The new architecture uses modern C++ memory management techniques (smart pointers) on the backend, but limits user exposure to these constructs. This was an exercise in collaborative, iterative improvement of existing code based on changing demands, and also provided exposure to the benefits and drawbacks of several STL data containers. The new structure is summarized below.
Class (Template) | Description |
---|---|
MjbotsControlLoop | An abstract class template defining the structure and parameters of the control loop and virtual methods for remote input and logging via LCM. |
RobotBase | An abstract class template defining the robot, with virtual methods for reading sensors and sending commands to all robot joints. |
JointBase | An abstract class defining virtual methods for interfacing with generic servo hardware. |
MjbotsHardwareInterface | A hardware interface for communicating with any number of Moteus joints. |
JointMoteus | An implementation of JointBase that adds support for CAN communication and reading Moteus-driver-specific data. |
In the future, we will create an abstract, hardware-agnostic ControlLoop
class for implementing behaviors on other hardware (e.g., in simulation or on another motor driver platform).
Behavior Infrastructure
Typically, when implementing multiple behaviors on a single robot, the control loop infrastructure remains largely the same (e.g., logging the same state parameters). With this in mind, I created an infrastructure for implementing high-level robot behaviors and a scheduler for handling multiple behaviors and transitions between them within a single control loop. Building this internal framework helped build my understanding of compile- and run-time polymorphism, as the internal scheduler object had to work for all user-defined behavior child classes. The behavior framework is outlined below.
Class (Template) | Description |
---|---|
Behavior | An abstract class template with framework for implementing a robot behavior (e.g., initialization, updating). |
IOBehavior | A Behavior -derived abstract class template for implementing behaviors with behavior-level remote inputs and/or outputs. |
BehaviorManager | A class handling the initialization, scheduling, and transitioning between different behaviors (Behavior child classes). |
MjbotsBehaviorLoop | An abstract class template which implements a BehaviorManager within the control loop framework. |
LCM Publisher-Subscriber Interface
The control loop supports concurrent LCM logging and input monitoring on separate processors. I developed several objects to handle multiple publishing and subscribing via a single, internal lcm::LCM
object and across multiple processors. Implementing this interface was an exercise in concurrency as remote input data is read and written from different processors via the LcmMessageHandler
class. This also utilized smart pointers to share the internal lcm::LCM
object across several objects in a memory-safe way.
Class (Template) | Description |
---|---|
LcmMessageHandler | A decorator class template handling concurrent remote updating and local reading of input data. |
LcmSubscriber | A class handling one or multiple LCM subscriptions via a single internal LCM object. |
LcmPublisher | A class template for populating and publishing messages via a single internal LCM object. |
LCM | The object handling remote communications in the LCM API. |
IMU & Rotation Infrastructure
I implemented a container for interfacing with the internal Pi3Hat inertial measurement unit (IMU) and several classes and methods for handling storage and manipulation of IMU data and other rigid body transforms. The IMUData
class made use of caching to prevent duplicate computation of alternate rotation representations during a single control loop update. As a result, the overhead for computing these is minimal, even when accessing them from different locations in the code (e.g., via a shared_ptr
). The rotation infrastructure included various rotation representations, and methods for converting between them.
Terminal Logging Framework
I implemented a single-header logging framework for logging to the console while running a control loop. The logging framework supports several levels of importance, and is written using macros to support logging of location-specific information (i.e. file, function, and line number). The implementation can easily be adapted to support logging to a file as well.
Simulation
I am in the process of adding simulation support to the SDK via the MuJoCo physics engine. This simulation will use the abstract classes provided in the architecture refactoring to implement an equivalent control loop, interface, and joint for use in simulation. Thanks to the object-oriented nature of the code, these should insert seamlessly into the current code base. Users will then provide robot configurations via an XML representation (either URDF or MuJoCo’s MJCF). I am using this project to better understand CMake and multi-contact rigid-body simulation tools.
Mentoring
The SDK serves as a platform for running a growing number of robots and devices in Kod*Lab. In the lab, I act as a mentor to several Master’s students, helping them implement their machinations. When they encounter features that they wish existed in the SDK, I will mentor them in implementing them. For many of them, this acts as both an introduction to working with the SDK and to writing modern C++ code for controls applications. I feel that there is no better way to learn than to teach, and I have used mentoring as an opportunity to hone my core C++, controls, and manipulator kinematics understanding. Some of my active mentee projects are described below.
Project | Description |
---|---|
Abstract Limb Class | Zac Gong is working on implementing an abstract class for describing robot limbs. In the current architecture, this will be an optional way for users to define limbs and their kinematics/dynamics separate from the higher-level, RobotBase -derived, robot class. Eventually these kinematic computations will be automated using user-specified Denavit-Hartenberg parameters. |
Digital Filter Class | Lucien Peach is working to provide an abstract class for implementing filters, as well as several common filter implementations. Eventually, this interface will support filter specification from LCCDE transfer functions. |
Controller Class | Chandravaran Kunjeti is working on a general interface for creating controllers and some common controller implementations. |