Development

This page concerns details about developing the core of Obelisk, not how to use Obelisk in a downstream project.

Overview

We use the following tools for development:

  • Bash shell (some of the scripts will modify your .bashrc)

  • Docker and Docker Compose for isolating system states and for development containers

  • pixi for package-level dependency management across platforms

  • ruff and pyright for linting, code-style enforcement, and type checking of Python code

  • clang-tidy and clang-format for C++ code

  • pre-commit for registering code checks as commit hooks

  • pytest for python code tests

We ensure that all code checks pass in a CI workflow before allowing PRs to merge into main.

Getting Started

To work in Obelisk, both as a dev and as a user, we suggest working in a docker container. Previously we had also supported pixi, but due to some dependency conflicts/installation issues, we have for now reverted to a docker only build.

First, we need to setup obelisk. The following commands will (1) make sure docker is installed (2) set flags to make sure that the docker build script grabs the correct dependencies (these will NOT be installed on your local machine, only in the docker) (3) tell Obelisk what other options you want and (4) setup obelisk aliases. Please note that the aliases file will be modified on your local machine then mounted into docker.

source setup.sh --docker-install --install-sys-deps-docker --basic --obk-aliases --unitree

Sometimes we have found that .bash_aliases is a folder. For this to work, you will need to delete that and make sure that a single file is created.

If you have just installed docker for the first time, you may need to run

newgrp docker

Now, there are a few options. We suggest working with obelisk from within a dev container through an IDE. VSCode has good support for this and the Jetbrains IDEs have this feature in beta. If you take this (suggested) route, then you will want to open the the dev container in the IDE using the provided .devcontainer.

To build the development Docker container, run from the repo root:

docker compose -f docker/docker-compose.yml run --build obelisk

To enter the container without rebuilding or to join from a different terminal window, run

docker compose -f docker/docker-compose.yml run obelisk

If you are running on a machine with no Nvidia GPUs, you can instead run

docker compose -f docker/docker-compose-no-gpu.yml run --build obelisk

Either way, your repository root will be mounted into the container at the exact same file location, your username, user ID, and group ID will be shared with the container, and you can freely run sudo without supplying a password for any command.

Building and Running the ROS Stack

All of the following commands should be run from within the devcontainer.

We now need to activate obelisk. Assuming you installed the aliases, you can now run

obk

The first time this is run it also builds obelisk. This activation command sources all the relevant scripts (like ROS) so that the stack can be used without hassle.

You can also build everything with the terminal command:

obk-build

this will also be sure to build everything in the correct order.

To launch a ROS stack we can use the following commands.

In a seperate terminal, we can run a ROS stack with:

obk-launch config_file_path=<config file> device_name=<device>

Specifically, for the dummy examples this looks like:

obk-launch config_file_path=dummy_cpp.yaml device_name=onboard

All the documentation for the Obelisk terminal aliases can be found here.

Building and Running C++ Code

We can easily run C++ code using pixi. From within the dev enviroment, the available commands are:

  • cpp-ctest will run all tests registered with CTest. This is the command used in the CI to verify unit tests, so every test should be registered with CTest - see below.

  • cpp-test-node will run all the tests for the main Obelisk library and will do so using the Catch2 framework.

  • cmake which will re-build the cmake.

  • cpp-build which will compile the code.

Note that all the commands will automatically run the commands they depend on. For this reason, to re-build the cmake, compile the code, and run the tests, all we need to do is run cpp-ctest.

We can enter the dev enviroment with pixi shell -e dev or we can run those commands from the normal shell by pre-pending with pixi run -e dev. For example, to run the ctests, pixi run -e dev cpp-ctest.

In the future we will add more commands to run other parts of the code.

C++ Code Structure

The C++ libraries in obelisk/cpp are built with CMake.

All obelisk C++ libraries are placed in obelisk/. Each library should have its own folder. Within that folder there should be an include folder, a CMakeLists.txt, and the source files (i.e., not the header files - those go in include).

Testing

Unit tests are managed with Catch2. Ultimately we plan to run the tests with CTest, and therefore all unit tests need to be registered with CTest, see here. The tests are all placed within tests/tests_cpp.