Skip to content

The world ​

The .world file declares where the robot starts, what surrounds it, and the places the task refers to.

robotdsl
World demo {
    physics(gravity = (0, 0, -9.81))
    spawn(robot = @core/diff_bot, pose = (0, 0, 0.05, 0, 0, 0, 1))
    Scenario room(ref = "empty", ground_plane = true) {
        Obstacle box(type = "box", pos = (1.2, 0, 0.25, 0, 0, 0, 1), size = (0.3, 0.3, 0.5))
        Marker flag(type = "cylinder", pos = (2.5, 0, 0.01, 0, 0, 0, 1), size = (0.3, 0.3, 0.02))
    }
    Goal goal(pose = (2.5, 0, 0, 0, 0, 0, 1))
}

Poses ​

A pose is seven numbers, a position and a quaternion: (x, y, z, qx, qy, qz, qw). No rotation is (x, y, z, 0, 0, 0, 1). Lengths are metres.

Physics and spawn ​

physics(gravity = (x, y, z)) sets gravity in m/s². Without it, the targets use standard gravity, (0, 0, -9.81).

spawn places the robot the .core file declares:

robotdsl
spawn(robot = @core/diff_bot, pose = (0, 0, 0.05, 0, 0, 0, 1))

Scenarios and entities ​

A scenario groups the things in one environment. Its ref is the base environment: "empty" for none, where the room is whatever the scenario's entities make it, or the id of an environment a library holds, below. ground_plane = true adds a floor, and without one the robot falls.

Each entity has a type, a name, a shape and a pose:

Entity typeIs
ObstacleSomething the robot must not touch. Touching one fails the run's physical verdict.
SupportSurfaceA floor, ramp or pad the robot drives on; contact is expected.
MarkerA visual mark, such as a goal disc. It has no collision unless collision = true.

The shape is a type of "box", "sphere" or "cylinder" with a size of (x, y, z) in metres; a sphere's diameter and a cylinder's are the x size, a cylinder's height the z size. Or the entity is an object of a library, named by ref, as the next section says.

Entities stay where they are placed. Leave is_static out, or write is_static = true; an entity declared movable is refused, because an entity states no mass to move it with.

Obstacles are drawn into the navigation map, seen by the robot's sensors, and measured against when a run is judged.

A Marker that does not collide is only seen. Both simulators' cameras see it. Gazebo's lasers and range finders see it too, since they see what is shown; MuJoCo's return only from what collides, which compile.json says for each such mark.

A program states no light and no colours. Both simulators light a world alike: a sun, a pale sky, a light grey floor, and a mid grey for a shape a program states. A colour camera reads one world in the two within a few parts in 255. A camera draws nothing beyond the far end of its range and shows the sky there: 5 m from it for one that measures depth, 10 m ahead of it for a plain one.

An entity's name is its own, apart from the robot's components. The Gazebo target holds the robot and the floor as models of the same world, so there an entity cannot share the robot's name, or ground_plane when the scenario has a floor.

Objects from a library ​

A table, a shelf or a ramp is not written as boxes. It is an object of a component library, and an entity takes it by its id, as a component takes its part:

robotdsl
Scenario room(ref = "empty", ground_plane = true) {
    Obstacle table(ref = "work_table", pos = (2.0, 0.6, 0, 0, 0, 0, 1))
    SupportSurface ramp(ref = "ramp_10deg", pos = (1.0, -1.5, 0, 0, 0, 0, 1))
    Marker spot(ref = "floor_disc", pos = (3.0, 0, 0, 0, 0, 0, 1))
}

The example library holds a pallet rack, a work table, a pallet jack, a cardboard box, a traffic cone and a pallet, each a model that a collection publishes for simulators, and a ramp and a mark painted on the floor.

The object's library entry states the mesh it is shown by and the shapes it collides by. The program states where it stands, by pos, and what it is to the robot, by the entity type: the same crate is an Obstacle in one world and a Marker in another. A program names no file and no address; where an object's mesh comes from is its library's business.

An entity takes type with size, or ref: never both, and never size beside ref, since an object is as large as its entry says. An object that declares no collision is only shown, so it can be a Marker and cannot be an Obstacle or a SupportSurface.

The map and the run's verdict take an object by its shapes, each where it stands: a gate by its two posts and not by the passage between them. They take each shape seen from above, as they take a primitive, so a table's top covers the floor under it and a robot is planned around the table, not under it.

Both simulators show an object's mesh to their cameras, in its materials' colours and with the pictures laid on them. Gazebo decodes the mesh, and its lasers see it too. MuJoCo decodes no glTF, so the output's own node reads the mesh, while its lasers see the shapes the object collides by; compile.json says so for each object. A laser sees a ramp as it sees a wall, so a robot that navigates by a laser does not plan a way up one.

Environments from a library ​

A room or a hall is written once, in a component library, and a scenario takes it whole by its id:

robotdsl
Scenario room(ref = "room_6x4") {
    Obstacle box(type = "box", pos = (1.2, 0, 0.25, 0, 0, 0, 1), size = (0.3, 0.3, 0.5))
}
Goal goal(target = @world/dock)

The environment brings its floor and its entities: here a storeroom of four walls, with a loaded pallet rack, a work table, a pallet with two cartons, a pallet jack, a traffic cone and a mark on the floor called dock. They are the scenario's own beside the ones the program adds: drawn into the map, seen by the sensors, judged against, and named like any entity, so a goal can target the room's dock and a task drive to it. An entity the program adds cannot take a name the environment already holds.

An environment that brings its floor needs no ground_plane. A world has one floor: ground_plane = true is refused as a second where an environment of any of the world's scenarios brings its floor, or where another scenario already lays it. The floors of two environments are that one floor. An environment's entities stand where its library entry places them, in the world's frame; a scenario does not move or turn the environment it takes.

Goals ​

A goal is a named place the task can drive to, given by a pose or by an entity as target:

robotdsl
Goal goal(pose = (2.5, 0, 0, 0, 0, 0, 1))
Goal at_flag(target = @world/flag)

The task refers to it as @world/goal.

Next ​

The task says what the robot does in this world.