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.
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 |
World |
A sim's world: a robot standing in a scene, and the clock it runs on. |
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.
World
World(
robot: RobotConfig,
scene: str | None = None,
lockstep_hz: int | None = None,
viewer: bool = False,
address: str | 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: |
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
|
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. |
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. |
address
instance-attribute
address: str
Where the server is, "host:port": what an anvil.hw.SimHw and an anvil.camera.SimCamera reach.
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
|
|
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. |