upkie 6.1.0
Open-source wheeled biped robots
Loading...
Searching...
No Matches
Developer notes

From newbie to sourcie

While newcomers will likely run start_simulation.sh and import the upkie package in Python, as you get acquainted with the robot and develop your own agents (by forking upkie/new_agent), you may want to contribute some features back to the upstream repository. Here is a short guide on compiling from source to do that.

Build environment setup

First, setup a build environment following the instructions for your system:

To upload software to the robot, you will also need to define the UPKIE_NAME environment variable. Assuming the hostname of your Upkie is "michel-strogoff", for example, you can add the following to your shell configuration file:

export UPKIE_NAME="michel-strogoff"

An IP address will also work.

To make sure your build environment works, try to run a bullet spine from source:

make run_bullet_spine

Once the simulation builds and runs successfully, move onto building the pi3hat spine from source, upload it and run it on your robot.

Using the local Python module

If you make changes to the upkie Python module, you will want to make Python import your local version rather than the one installed from conda-forge or PyPI. There are two ways to do so. One of them is to re-install the package locally, using pip from the root of (your local copy of) the repository:

cd upkie
pip install -U .

Another one is to simply link the module from the directory you are working in. For instance, in the examples directory:

cd upkie/examples
ln -s ../upkie ./

Inter-process communication

Upkie implements an action-observation loop to control robot actuators from a standalone "agent" process. The inter-process communication (IPC) protocol between the agent and the "spine" process that talks to actuators looks like this:

Action-observation loop

The agent can be a simple Python script with few dependencies. This separation between agent and spine provides a robot/simulation switch to train or test agents in a simulation spine before running them on a real robot.

This protocol is suitable for real-time but not high-frequency (> 1000 Hz) performance, which is fine for balancing and locomotion on Upkies. (If you are wondering whether Python is suitable for real-time applications, we were too, until we tried it out.) All design decisions have their pros and cons. Some pros for this design are:

  • Run the same Python code on simulated and real robots
  • Interfaces with to the mjbots pi3hat and mjbots actuators
  • Interfaces with to the Bullet simulator
  • Observer pipeline to extend observations
  • Soft real-time: spine-agent loop interactions are predictable and repeatable
  • Unit tested, and not only with end-to-end tests

Meanwhile, cons against this design include:

  • Low frequency: designed for tasks that run in the 1–400 Hz range (like balancing)
  • Soft rather than hard real-time guarantee: the code is empirically reliable by a large margin, that's it
  • Weakly-typed IPC: typing is used within agents and spines, but the interface between them is only checked at runtime

Spine state machine

Spines run a state machine depicted in the following diagram:

States have the following purposes:

  • Stop: do nothing, send stop commands to servos.
  • Reset: apply runtime configuration to the spine's actuation interface and observers.
    • The reset state is not time-critical, i.e., configuration can take time.
    • When exiting the reset state, the spine writes observations back to the agent.
  • Idle: do nothing.
  • Act: send action to the actuation interface and write observation back to the agent.
  • Shutdown: terminal state, exit the control loop.

There are three possible events:

  • BEGIN: beginning of a control cycle.
  • END: end of a control cycle.
  • SIGINT: the process received an interrupt signal.

Guards (in blue), i.e. conditions required to trigger a transition, may involve two variables:

  • req: the current Request from the agent.
  • stop_cycles: the number of stop commands cycled in the current state (only available in "stop" and "shutdown" states).

Read/write operations from/to the shared memory are indicated in red.