← all builds

From-Scratch Build · Mobile Robotics

Networked Mobile-Robot Service

A wheeled robot that drives itself around a building — turned into a network service you can start, map with, and steer from somewhere else entirely. Rebuilt from scratch to understand how robot autonomy, ROS and containers fit together.

ROSNavigationLiDAR + AMCL Docker ComposeSimulation

What it is

A robot you call like an API

The robot is a small two-wheeled mobile base with a spinning laser scanner on top. Left to itself it can build a map of a room, work out where it is on that map, and drive to a goal while avoiding obstacles. The idea I wanted to learn here is to stop treating that robot as one monolithic program and instead expose it as a service: a set of independent pieces that any machine on the network can start, stop and talk to.

Every capability — the hardware drivers, the map server, the localisation, the path planner, the control loop — lives in its own container. Bring them up together and you have a self-driving robot. Move some of them onto another host and the same robot is now operated over the network, which is the whole point of the exercise.

The core idea I wanted to learn: a robot's "intelligence" is just a handful of programs swapping messages. If you package each one as a container and let them find each other over the network, "the robot" stops being a single device and becomes a service that can run on the robot, on a nearby server, or in simulation — with no change to the code.

The stack

Tools under the hood

The point of this rebuild was the toolchain. Each of these was new to me; here is what each one actually does in the system.

middleware

ROS

The Robot Operating System — a messaging bus, not an OS. Nodes publish and subscribe to topics, so the driver, planner and controller cooperate without ever knowing about each other directly.

localisation

AMCL

Adaptive Monte-Carlo Localisation. It scatters thousands of guesses ("particles") about where the robot is, then uses laser readings to converge on the true pose against a known map.

perception

RPLiDAR

A spinning laser range-finder. It sweeps the room and returns distances all around the robot — the raw data that both mapping and obstacle avoidance depend on.

planning

move_base + costmaps

The navigation core. A global planner finds a route across the map; a local planner steers around things that weren't there before, using layered costmaps of free and blocked space.

control

Kobuki base + Lua scripts

The mobile base driver turns velocity commands into wheel motion. Small Lua scripts drive a mirrored model and offer keyboard tele-operation of the base.

packaging

Docker + Compose

Each module ships as its own image with a launch file. Compose wires them together, which is exactly what makes the same stack runnable on one host or split across many.

Architecture

One robot, many services

The service is assembled from a set of containers, each responsible for one slice of the robot's behaviour. Brought up together they form a complete self-driving stack; pulled apart, they become a robot operated over the network.

  1. Core + Map Server live

    Hosts the ROS master (naming and discovery for every other node) and serves the saved floor map that localisation and planning are measured against.

  2. Robot Drivers live

    The hardware layer — the wheeled base and the laser scanner. A simulation variant stands in for the physical robot so the whole service can run without real hardware.

  3. Localisation Service live

    Runs AMCL so the robot always knows where it is on the map, and exposes that as a clean service other modules can request.

  4. Navigation live

    Global and local planning with costmaps and a logger node — turns "go to this point" into a safe, obstacle-aware trajectory.

  5. Control + Tele-op live

    The base controller plus Lua scripts for keyboard driving and a mirrored model, so an operator can take manual command.

  6. Single-Compose Bring-up future

    One Compose file to launch the entire service in a single command, with the namespace passed in as an environment variable. Left as future work in this build.

How it runs

From simulation to the network

Deployment is the whole game. The build ships launch scenarios describing which modules come up and where they live:

In my rebuild I focused on the simulated path: start the core and map server, attach the simulated drivers, bring up localisation and navigation, then send a goal and watch the planner drive the robot there — all coordinated through ROS launch files and per-module containers.

Reflection

What rebuilding it taught me