Robosim: lightweight multi-player robotics simulator

logo

Simulator that implements a client-server architecture. The server holds a 3D scene (obstacles, walls, floor and a set of controllable robots) as entities in an ECS World, and renders it. On the physics side, it supports collision detection (cubes and spheres) and two physics levels: level 1 (direct velocity control) and level 2 (acceleration-based 6DoF with linear drag), chosen per robot. Each robot can be controlled through the network using a generic protocol with commands like move. On the client side, we implement a few use-cases, such as automatically generating a planned trajectory (i.e. A -> via points -> B).

Documentation at: link.

Installation

In a fresh virtual environment (e.g. venv or conda):

$ python -m venv .venv/                                                 # Make a virtual environment in this dir
$ source .venv/bin/activate                                             # Windows: .venv\Scripts\Activate.ps1
$ pip install -e .[client]                                              # server + engine + client. For server+engine only do just "pip install -e ."
$ ./server/server.py [--map_path PATH_TO_JSON] [--headless] [-p PORT]   # all args optional
$ ./client/client.py localhost -p PORT                                  # client runs standalone if server is elsewhere

Notes:

  • Install editable (with -e).
  • Server and client have different deps and can run in separate envs on different machines.
  • We "vendor" a bunch of packages (existing ones but also some self built for this project) in pkg/. setup.py handles this too.
    • If you use VSCode and static analyzers don't understand this, update this in .vscode/settings.josn:
    • "python.analysis.extraPaths": ["pkg/colorama", "pkg/loggez", "pkg/microecs", "pkg/microspec", "pkg/overrides"]

Repository layout

cli/        # Executables: server.py (symlink), client.py (symlink), robosim-ncat.py (protocol tool)
server/     # simulator process: builds the ECS World, owns systems + main loop, plus plugins/ and maps/
robosim/    # the simulator engine. A standalone Python library: math/physics, collisions, networking, ECS components
client/     # standalone client: keyboard control + trajectory generation (uses robochan, not robosim)
pkg/        # vendored packages (microspec, microecs, overrides, loggez, colorama (for loggez coloring) etc.)
resources/  # textures, meshes, logo
test/       # e2e (test/e2e → server.py), manual diagnostics (test/manual/), lint (test/lint/)

robosim/ is an ECS: all state lives in a single microecs.World (Struct-of-Arrays component pools). There are no entity OOP classes. All objects have a spawn function (make_robot(...)) that spawns an entit with a set of components. Behavior is done via systems (internal to the simulator) and plugins (external systems from conributors to add behavior, like UAV racing or trajectory error environment for learning trajectories).

You can control the standard UAVs in FPV mode via: W, A, S, D, arrows, Q, E, PGDOWN, PGUP to control the 6-DoF UAV.

Getting started: running the tests

The project currently has only end to end tests (written in bash at test/e2e/*/run.sh) as we are constantly iterating on the interfaces and even submodules. The only thing that doesn't change is use-cases, i.e. you move the UAV forward for 1 second with some acceleration, it does that regardless of how it is implemented. We have a protocol which is described in the docs. These tests run at protocol level.

# if CI=true is set, it will also run the latency e2e test, which spawns 100 robots and can be a bit heavy on the system
[CI=true] bash test/e2e/run_all.sh
bash test/lint/run_all.sh

CLI interface: interactive control

We built our robosim-ncat.py tool for an interactive CLI experience (a netcat-like wrapper over the binary msgpack protocol. See Protocol & Wire Format for the why and the byte-level details). Below is how to use the tool:

./cli/server.py -p 5555
# in other terminal
./cli/robosim-ncat.py localhost -p 5555
> {'status': 'connected', 'id': 0, 'timestamp': '1900-01-01T00:00:00.123456'}
move 0 0 1 2 0 0.5 # X Y Z pitch yaw roll. ncat parses this into {"cmd": "move", "control_input": [0, 0, 1, 2, 0, 0.5]}
> {'status': 'Applied control_input=(0, 0, 1, 2, 0, 0.5). Current pose: (...)', 'timestamp': '1900-01-01T00:00:00.123456'}
...

tcp.jpg

Documentation

Reference material lives in standalone pages (rendered, alongside the autogenerated API, into the hosted docs):

The docs site is built by docs/build_docs.sh (pdoc; no sphinx/config). Build it locally with bash docs/build_docs.sh and open the printed file:// link.