Skip to content

feat(worlds): add configurable simulation worlds - #63

Merged
AksonovSergei merged 20 commits into
mainfrom
52-configurable-worlds
Nov 10, 2026
Merged

AksonovSergei merged 20 commits into
mainfrom
52-configurable-worlds

Conversation

@Fastroof

Copy link
Copy Markdown
Contributor

Closes #52

What and why

A new package kpi_rover_worlds with the simulation worlds, so the simulation is not limited to a few fixed world files:

  • worlds: empty, room, warehouse (world files) and test_square, maze, overpass, garden
    (configurable, built in Python from their arguments);
  • each world is a directory worlds/<name>/ with a manifest <name>.yaml: title, arguments with defaults,
    presets, start points, previews;
  • python3 -m kpi_rover_worlds.world_info lists the worlds and their arguments, --build <world> name:=value
    builds one, --check checks the manifests against the worlds;
  • tools: ros2 run kpi_rover_worlds render_previews.py (previews and the map of a built world),
    spawn_object.py (puts objects into a running world).

Changes outside the package:

  • kpi_rover_bringup: sim.launch.py is now world.launch.py (Gazebo with the world) and
    sim_robot.launch.py (the simulated robot) together; world:= takes a world name or a path,
    start:= puts the robot at a start point of the world. The old world files moved into kpi_rover_worlds.
  • kpi_rover_description: visibility_mask in camera.xacro and lidar.xacro, so the sensors don't see
    the helper visuals shown only in the Gazebo window (start point arrows) and the lidar doesn't see grass.
    The URDF of the real robot changes only by this tag.
  • docker/Dockerfile: the robot image skips kpi_rover_worlds and its dependencies.
  • README (Worlds), CONTRIBUTING (scope worlds).

How it was tested

  • Clean colcon build of the workspace, world_info --check passes.
  • sim.launch.py with every world and every start point (12 runs): the controllers come up, the robot drives
    from /cmd_vel, real time factor 1.0.
  • The README commands, spawn_object.py --list, render_previews.py (map of a built world).

Notes

  • global_costmap logs "Received map message is malformed" in open worlds (empty, test_square), the same
    on main with empty.world: not from this PR.
  • A namespace of the simulated robot for a simulation shared by several robots comes in a separate PR
    (it builds on sim_robot.launch.py from this one).

Checklist

  • The title follows Conventional Commits
  • The description links the issue
  • Builds and runs in simulation

Fastroof and others added 19 commits November 10, 2026 18:23
The Gazebo worlds get a package of their own, one directory per world:
empty, room and warehouse move there from kpi_rover_bringup unchanged, as
worlds/<name>/<name>.world. sim.launch.py takes room.world from there.

The package is for the simulation only: the robot image does not build it.
A Python module kpi_rover_worlds (common/python/) with world_info, for the
launch files and for tools such as the GUI. It finds the worlds,
worlds/<name>/<name>.world (SDF) or <name>.world.xacro (a configurable
world, its arguments are xacro args), reads their manifests <name>.yaml
(title, description, arguments, start points, preview cameras), builds a
configurable world with its arguments into a world file, gives the start
points of a world and checks the manifests against the worlds and their
previews:
    python3 -m kpi_rover_worlds.world_info [--json | --check | --build <world> name:=value ...]

Manifests of empty, room and warehouse.
Media for the shared parts of the configurable worlds:
- photo textures of floors and walls, models of objects (boxes, crates,
  cans, a tyre ...) from Poly Haven, CC0; credits in CREDITS.md
- stripe textures of markings, a traffic cone texture, meshes of traffic
  cones, a flat board and mitered marking ends
Parts used by several worlds; they never refer to a world:
- common/xacro: base.xacro (world setup, materials, visibility flags),
  floor.xacro, marking.xacro (lines, arcs, lanes), walls.xacro (walls and
  the solid boxes they are made of), objects.xacro (the object library),
  start_point.xacro (a robot start point, seen only in the Gazebo GUI)
- common/config: floors, markings, walls and objects, the catalogs the
  choices of world arguments come from
- common/python: scatter.py (objects scattered over the free area of a
  world), textured_box.py (box meshes with textures in real size)
- test_square: a 1x1 m square marked on the floor to check motion and
  odometry; arguments floor and marking, start point a
- maze: a warehouse with a maze of walls, doorways and arches, some of
  them a tight fit or impassable; fixed levels (config/levels) or a
  random one, objects scattered around it, start points at the entrance
  and the exit. generator.py turns the arguments into the layout of the
  walls and arches before the world is built.
The body of the overpass with smooth ramps, in the two sizes of the
overpass world: wide (0.7 m) and narrow (0.4 m).
A warehouse with a figure eight marking and an overpass at the crossing,
so two robots can drive the figure eight at the same time without meeting.
Arguments: the overpass (wide with rails, or narrow), the road surface and
the lane marking, floor, walls and objects. overpass.xacro is the overpass
with its ramps, rails and marking; generator.py makes the road band and the
wall meshes and scatters the objects.
- photo textures of grounds (meadow, loose soil, mud, gravel, sand,
  rubble), a road and tree bark, grass models from Poly Haven, CC0;
  credits in CREDITS.md
- apple tree models made with Blender's Sapling Tree Gen
- worlds/garden/config/relief: heights of a real place for the relief
An apple orchard on uneven terrain: rows of trees on grass with patches
of loose soil and mud, pits and puddles, a field road around, objects
scattered over it. The garden is modeled in real sizes and scaled down to
the robot. generator.py builds the terrain for the arguments (relief,
grounds, grass, trees) with terrain.py, trees.py and textures.py into a
cache, reused on the next launches. common/python gets gltf.py.
Pictures for tools such as the GUI, rendered by render_previews.py: each
world, the robot camera view from its start points, its presets and
examples of its argument values.
world.launch.py starts Gazebo with the world. sim_robot.launch.py is the
simulated robot, the counterpart of robot.launch.py: the robot spawned into
a running Gazebo at a pose (new yaw_pose), the bridge of its sensors, its
controllers, localization, SLAM and navigation. sim.launch.py includes
both, with RViz and joystick teleop as before; tools such as the GUI can
start the world and the robot one by one. The parts of sim.launch.py move
over unchanged.
world.launch.py: world:= takes a world of kpi_rover_worlds by name (room by
default; a configurable one with its default arguments) or a world file,
e.g. one built with other arguments by world_info --build.
sim.launch.py: start:= puts the robot at a start point of the world
instead of x_pose/y_pose.
Visibility masks: the camera and the lidar do not see the visuals the
worlds show only in the Gazebo GUI (start points, the maze route), and the
lidar does not see grass.
ros2 run kpi_rover_worlds render_previews.py renders the previews of a
world (or, with --sdf, the map of a world file, for the GUI);
spawn_object.py puts an object of the library into a running world.
README: the kpi_rover_worlds package, selecting and building a world.
CONTRIBUTING: scope worlds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Each configurable world is worlds/<name>/<name>.py with build(args), which
  returns the SDF made with xml.etree (common/python/sdf.py); the argument
  defaults are in the world manifests. xacro and its templates are gone.
- World geometry configs are constants in the world code; unused ground
  textures and the grass tuft code are removed.
- Faster generation: overpass 9.6 s -> 0.6 s, garden from cache 7.9 s -> 1 s,
  a new garden terrain 16 s -> 8 s (scipy in scatter, Perlin gradient lookup).
- Simpler garden terrain and render_previews.py code.
- world_info --build prints only the world file to stdout.
- The robot image skips kpi_rover_worlds and its dependencies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Fastroof Fastroof linked an issue Nov 10, 2026 that may be closed by this pull request
@AksonovSergei
AksonovSergei merged commit 9148fb1 into main Nov 10, 2026
3 checks passed
@AksonovSergei
AksonovSergei deleted the 52-configurable-worlds branch November 10, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configurable simulation worlds

2 participants