anvil.sim
anvil.sim
The sim: MuJoCo standing in for the drives, a robot that collides with itself and with the scene it stands in.
A World is the scene and the clock, served by a process of its own on this machine or another; an anvil.hw.SimHw
drives the robot in it as an anvil.hw.DamiaoHw drives real drives, and an anvil.camera.SimCamera watches it.
anvil-robotics sim serves a world on a port, for a loop on another machine to drive. Importing this module loads no
MuJoCo: the physics runs in the server.
The server draws its cameras and its viewer the way Anvil Forge draws a robot, each part shaded by its finish under a
studio's lights, or with MuJoCo's own renderer: a Renderer says which, and how to pick one.
Classes:
| Name | Description |
|---|---|
Contact |
Two geoms of the world touching. |
Contacts |
What a world is touching, and what it has touched since it was set up, from |
FreeCamera |
Where a world's free camera looks from, orbiting a point as MuJoCo's own window does. |
Picked |
What |
Renderer |
What the sim's server draws its cameras and its window with. |
World |
A sim's world: a robot standing in a scene, and the clock it runs on. |
Functions:
| Name | Description |
|---|---|
scenes |
Returns the scenes a server started from this package can stand a robot in, by the name a |
Contact
dataclass
Contact(first: str, second: str, depth_m: float)
Two geoms of the world touching.
Attributes:
| Name | Type | Description |
|---|---|---|
first |
str
|
One of them, by the name its scene or the robot's URDF gives it, e.g. |
second |
str
|
The other. |
depth_m |
float
|
How far apart they are, in meters: negative is how deep they are pushed into each other. |
first
instance-attribute
first: str
One of them, by the name its scene or the robot's URDF gives it, e.g. "table_top".
second
instance-attribute
second: str
The other.
depth_m
instance-attribute
depth_m: float
How far apart they are, in meters: negative is how deep they are pushed into each other.
Contacts
dataclass
Contacts(
now: list[Contact],
touched: set[tuple[str, str]],
worst_depth_m: float,
)
What a world is touching, and what it has touched since it was set up, from World.contacts.
Attributes:
| Name | Type | Description |
|---|---|---|
now |
list[Contact]
|
Every pair touching at the instant the question was asked. |
touched |
set[tuple[str, str]]
|
Every pair of geoms that has touched, whether or not it still is, as |
worst_depth_m |
float
|
The deepest any two have been pushed into each other, in meters: negative, or 0 where nothing touched. |
now
instance-attribute
now: list[Contact]
Every pair touching at the instant the question was asked.
touched
instance-attribute
touched: set[tuple[str, str]]
Every pair of geoms that has touched, whether or not it still is, as (first, second).
worst_depth_m
instance-attribute
worst_depth_m: float
The deepest any two have been pushed into each other, in meters: negative, or 0 where nothing touched.
FreeCamera
dataclass
FreeCamera(
lookat_m: tuple[float, float, float],
distance_m: float,
azimuth_deg: float,
elevation_deg: float,
)
Where a world's free camera looks from, orbiting a point as MuJoCo's own window does.
A world has one, which World.set_free_camera moves and every anvil.camera.SimFreeCamera watching the world
shows. It starts looking at the robot from in front of it and a little above.
Attributes:
| Name | Type | Description |
|---|---|---|
lookat_m |
tuple[float, float, float]
|
The point it orbits and looks at, x, y and z in the world frame, in meters. |
distance_m |
float
|
How far from that point it stands, in meters. |
azimuth_deg |
float
|
Which way it faces about world +z, in degrees from +x: 0 looks along +x. |
elevation_deg |
float
|
How far it looks up, in degrees: negative looks down at the point from above it. |
lookat_m
instance-attribute
lookat_m: tuple[float, float, float]
The point it orbits and looks at, x, y and z in the world frame, in meters.
distance_m
instance-attribute
distance_m: float
How far from that point it stands, in meters.
azimuth_deg
instance-attribute
azimuth_deg: float
Which way it faces about world +z, in degrees from +x: 0 looks along +x.
elevation_deg
instance-attribute
elevation_deg: float
How far it looks up, in degrees: negative looks down at the point from above it.
Picked
dataclass
Picked(point_m: tuple[float, float, float], body: str)
What World.pick found: the nearest surface under a point of the free camera's picture.
Attributes:
| Name | Type | Description |
|---|---|---|
point_m |
tuple[float, float, float]
|
Where on it, x, y and z in the world frame, in meters. |
body |
str
|
The body it belongs to, by name, e.g. |
point_m
instance-attribute
point_m: tuple[float, float, float]
Where on it, x, y and z in the world frame, in meters.
body
instance-attribute
body: str
The body it belongs to, by name, e.g. "table" or a link of the robot.
Renderer
Bases: StrEnum
What the sim's server draws its cameras and its window with.
A World that starts its server takes one, as does anvil-robotics sim --renderer; a server started with none
named reads ANVIL_SIM_RENDERER from its environment, which a World passes on from this process's, and with that
unset draws with ANVIL.
Attributes:
| Name | Type | Description |
|---|---|---|
ANVIL |
Each part shaded by its finish under a studio's lights, as Anvil Forge draws a robot. |
|
MUJOCO |
MuJoCo's own renderer, untouched. |
ANVIL
class-attribute
instance-attribute
ANVIL
Each part shaded by its finish under a studio's lights, as Anvil Forge draws a robot.
The room's reflections on it, and a line on every crease.
Where OpenGL renders on the CPU its key light casts no shadow, which would cost each camera most of its frame rate there.
MUJOCO
class-attribute
instance-attribute
MUJOCO
MuJoCo's own renderer, untouched.
For frames that have to be MuJoCo's, or a machine the shading costs too much on.
World
World(
robot: RobotConfig,
scene: str | None = None,
lockstep_hz: int | None = None,
viewer: bool = False,
address: str | None = None,
renderer: Renderer | None = None,
)
Bases: Handle
A sim's world: a robot standing in a scene, and the clock it runs on.
Without an address it starts a server on this machine, anvil-robotics sim in a process of its own. With one it
sets up the world of a server already running, as often as not on another machine: the sim stands in for metal, so
the box that would drive the metal need not also simulate it, and the window is nicer on the machine you are sitting
at.
The robot stands in the world from the start with its drives disabled, as an arm stands on the bench switched off,
so an anvil.camera.SimCamera watches it before anything drives it; an anvil.hw.SimHw then takes it over and
drives it. This answers what is touching and places loose objects, beside whatever drives it. Another robot is
another world. Closing it, or letting it be collected, ends this connection; a server it started stops once every
anvil.hw.SimHw driving it is gone too. Every method but close raises anvil.OperationError once it is closed.
Sets the world up with robot standing in it, starting a server for it unless address names one.
Whatever world the server held goes, and its cameras are told so.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
robot
|
RobotConfig
|
The robot standing in the world, e.g. |
required |
scene
|
str | None
|
The world the robot is bolted into: one of |
None
|
lockstep_hz
|
int | None
|
The rate to step at, 250 or 500, giving up the sim's own clock for repeatability: the world
then steps once per |
None
|
viewer
|
bool
|
Whether to open a window on the world. Only for a server started here. |
False
|
address
|
str | None
|
A server already listening, |
None
|
renderer
|
Renderer | None
|
What its cameras and window draw with. |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
UnreachableError
|
Nothing answered at |
OperationError
|
The server would not start, or it refused the world: a scene it does not have, a
robot it cannot build, or an |
Methods:
| Name | Description |
|---|---|
close |
Ends this connection; a server it started stops once every |
contacts |
Returns what the world is touching, and what it has touched since it was set up. |
place |
Puts a loose body of the scene, a block on the table, where a run wants it, and stops it dead there. |
hold |
Holds each named joint of the robot at its angle, at rest, whatever drives it, until told again. |
free_camera |
Returns where the world's free camera looks from: what every |
set_free_camera |
Moves the world's free camera, which every |
pick |
Returns the nearest surface the free camera sees at a point of its picture, or |
show_window |
Opens MuJoCo's window on the world, unless one is open already. |
Attributes:
| Name | Type | Description |
|---|---|---|
address |
str
|
Where the server is, |
robot |
RobotConfig
|
The robot standing in the world. |
robot_pose |
Pose
|
Where the robot's own frame sits in the world, on its stand and raised so its base plate rests there. |
free_camera_fovy_deg |
float
|
How wide the free camera sees, vertically, in degrees. |
address
instance-attribute
address: str
Where the server is, "host:port": what an anvil.hw.SimHw and an anvil.camera.SimCamera reach.
robot_pose
property
robot_pose: Pose
Where the robot's own frame sits in the world, on its stand and raised so its base plate rests there.
It is the frame the robot's URDF and every target are stated in. The world frame is the one contacts, place,
pick and the free camera are stated in, so this is what turns a point picked in the world into a target for
the robot.
free_camera_fovy_deg
property
free_camera_fovy_deg: float
How wide the free camera sees, vertically, in degrees.
The world's own, which a picture drawn over an anvil.camera.SimFreeCamera projects with.
close
close() -> None
Ends this connection; a server it started stops once every anvil.hw.SimHw driving it is gone too.
Closing twice does nothing.
contacts
contacts() -> Contacts
Returns what the world is touching, and what it has touched since it was set up.
The world looks every physics step, so a touch between two of these questions is still reported, which is how "nothing collided during the whole sweep" is asked. A round trip to the server, never a tick.
Raises:
| Type | Description |
|---|---|
OperationError
|
The server went away. |
place
place(
body: str,
position_m: Sequence[float],
orientation_xyzw: Sequence[float] | None = None,
) -> None
Puts a loose body of the scene, a block on the table, where a run wants it, and stops it dead there.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
str
|
The body's name in the scene. |
required |
position_m
|
Sequence[float]
|
Where to put it, x, y and z in the world frame, in meters. |
required |
orientation_xyzw
|
Sequence[float] | None
|
How to turn it, a unit quaternion with w last, or |
None
|
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
|
OperationError
|
|
hold
hold(q_rad: Mapping[str, float]) -> None
Holds each named joint of the robot at its angle, at rest, whatever drives it, until told again.
A hand holding the arm still, and moving it as a hand would when called again with the next angles: how a run
moves an arm nothing drives, such as a leader the operator would move by hand, which an
anvil.control.LeaderFollowerController leaves limp. The joints read back exactly these angles, still. Each
call replaces the last, so a joint it does not name goes back to its drive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q_rad
|
Mapping[str, float]
|
Angles in radians, or meters for a prismatic joint, by URDF joint name as
|
required |
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
|
OperationError
|
|
free_camera
free_camera() -> FreeCamera
Returns where the world's free camera looks from: what every anvil.camera.SimFreeCamera shows.
Raises:
| Type | Description |
|---|---|
OperationError
|
The server went away. |
set_free_camera
set_free_camera(free_camera: FreeCamera) -> None
Moves the world's free camera, which every anvil.camera.SimFreeCamera shows from its next frame.
A round trip to the server, never a tick, so a page orbiting the camera as a mouse drags costs the loop nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
free_camera
|
FreeCamera
|
Where it looks from. |
required |
Raises:
| Type | Description |
|---|---|
OperationError
|
A number is not finite or the distance is not positive, which the message says, or the server went away. |
pick
pick(
x_frac: float, y_frac: float, aspect_ratio: float
) -> Picked | None
Returns the nearest surface the free camera sees at a point of its picture, or None where only sky is.
The picture is an anvil.camera.SimFreeCamera's frame, whose shape sets how wide the camera sees: a click on
a stream of it, turned into a place in the world.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_frac
|
float
|
How far across the picture from its left edge, 0 to 1. |
required |
y_frac
|
float
|
How far down it from its top edge, 0 to 1. |
required |
aspect_ratio
|
float
|
The picture's width over its height. |
required |
Raises:
| Type | Description |
|---|---|
OperationError
|
A fraction is outside 0 to 1 or the aspect ratio is not positive, which the message says, or the server went away. |
show_window
show_window() -> None
Opens MuJoCo's window on the world, unless one is open already.
The window opens on the machine the server runs on, which for a world started here is this one: orbit, pan and
zoom with the mouse, and pick a body with a double-click to push it with Ctrl and a drag. Closing it leaves the
world running. Unlike the viewer argument, this works on a world already set up, and on a server something
else started.
Raises:
| Type | Description |
|---|---|
OperationError
|
The server's machine has no display to open a window on, which the message says, or the server went away. |
scenes
scenes() -> list[str]
Returns the scenes a server started from this package can stand a robot in, by the name a World takes.
"empty" is the ground alone, and "lift" and "lift_bracket" the robot's stands, what a World given no scene
sets up for a robot on one. "workbench" and "fruit_bowl" put a workbench before the robot, the first with
Anvil's Devbox 2.0, a leader handle and two camera modules on it, the second a bowl of fruit and a cutting board;
"table" and "two_tables" are blocks on tables, as the gate tests use them. Every one but "empty" and "table"
stands the robot on the lift.