Examples¶
Thirty-three worked scenarios, ordered from the shortest script that does something to full scenarios you can hand to a colleague.
How to read this page¶
The first scenarios are complete files, login included. Start there.
The single-feature scenarios that follow drop the boilerplate and show one operation at a time. Each snippet assumes it sits inside this frame:
from mimic_sdk.scene_edition import MimicSceneEditor
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="my_sequence")
with scene.generate_variant("my_variant") as variant:
... # <- the snippet goes here
print(client.document_path())
The last scenarios are full files again, this time combining several operations into a scenario worth rendering.
Three rules apply throughout:
Variants are forks. Every
withblock starts from the same baseline. A second block does not continue where the first one stopped.Nothing runs locally. Each call records an op. The scene is edited when MIMIC replays the variant.
Values are bounded. The recorder refuses an out-of-range argument on the spot. The bounds differ for the ego, for actors already in the scene, and for actors your script inserts — see Limits.
Scenario: The Shortest Useful Script¶
Take one actor out of the scene. A single line of editing, and it exercises the whole path: login, open, record, save.
from mimic_sdk.scene_edition import MimicSceneEditor
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="my_sequence")
with scene.generate_variant("without_actor_0") as variant:
variant.remove_actor(actor_id=0)
Scenario: Nudge The Ego And Submit¶
Move the ego a metre to the left, turn it slightly, and ask the Backend to render it.
from mimic_sdk.scene_edition import MimicSceneEditor
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="my_sequence")
with scene.generate_variant("ego_left_1m") as variant:
variant.ego.shift(left=1.0)
variant.ego.rotate(yaw=5.0)
variant.recompute_all_sensor_world_poses()
recompute_all_sensor_world_poses() refreshes every sensor pose after the rig
has moved. Add it whenever you move the ego and care about sensor output.
Scenario: Several Variants From One Baseline¶
Three blocks, three independent forks of the same scene. ego_right_1m does
not start from the result of ego_left_1m.
from mimic_sdk.scene_edition import MimicSceneEditor
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="my_sequence")
with scene.generate_variant("ego_left_1m") as variant:
variant.ego.shift(left=1.0)
with scene.generate_variant("ego_right_1m") as variant:
variant.ego.shift(right=1.0)
with scene.generate_variant("ego_turned") as variant:
variant.ego.rotate(yaw=2.0)
Scenario: Ego Shift¶
Six named directions, all optional, all in metres. referential="local" (the
default) means the ego’s own axes; "world" means the scene’s.
variant.ego.shift(left=1.5) # one lane to the left
variant.ego.shift(forward=8.0, up=0.2) # ahead and a bit higher
variant.ego.shift(right=2.0, referential="world")
Limits for the ego: ±5 m lateral, ±2 m vertical, ±20 m longitudinal.
Scenario: Editing Part Of The Trajectory¶
start_idx / end_idx restrict a transform to a frame window. Omit them and
the whole trajectory moves.
variant.ego.shift(left=3.0, start_idx=40, end_idx=90) # drift, then hold
variant.ego.rotate(yaw=-4.0, start_idx=60, end_idx=75)
Scenario: Ego Translate¶
ego.translate takes the same six directions, the same frame window and the
same referential as ego.shift. On an actor it is the narrower of the two:
actor.translate has no frame window and no referential, so it always moves
the whole trajectory in the actor’s own axes.
variant.ego.translate(forward=5.0, left=0.5)
variant.ego.translate(forward=5.0, start_idx=0, end_idx=30)
variant.actor(4).translate(forward=5.0) # whole trajectory, local axes
Scenario: Ego Rotate¶
Degrees, not radians. Pitch is deliberately asymmetric on the ego: −3° to +25°.
variant.ego.rotate(yaw=15.0) # heading
variant.ego.rotate(pitch=2.5, roll=-1.0) # nose up, lean left
variant.ego.rotate(yaw=10.0, referential="world")
Scenario: Ego Transform¶
Translation and rotation in a single op. Watch the default: transform is
referential="world" on the ego, unlike shift and rotate.
variant.ego.transform(forward=4.0, left=1.0, yaw=8.0)
variant.ego.transform(up=0.3, pitch=1.5, referential="local")
Scenario: Ego Resample And Offset¶
resample rebuilds the trajectory on a new rate; offset slides it in whole
frames against everything else in the scene.
variant.ego.resample(hz=20.0) # 0.1 – 200 Hz
variant.ego.offset(offset_frame=5) # -20 – +20 frames
Scenario: Ego Apply T Sequence¶
Feed a stack of 4×4 matrices straight in. The recorder serialises the array, so the SDK never imports numpy — but your script can.
import numpy as np
WOBBLE = np.tile(np.eye(4), (4, 1, 1))
WOBBLE[1, 0, 3], WOBBLE[1, 1, 3] = 0.05, 0.02
WOBBLE[2, 0, 3] = 0.10
WOBBLE[3, 0, 3], WOBBLE[3, 1, 3] = 0.05, -0.02
variant.ego.apply_T_sequence(T=WOBBLE, start_idx=0, end_idx=4)
variant.ego.apply_T_sequence(
T=WOBBLE,
start_idx=10,
end_idx=14,
referential="local",
mode="local",
coverage="all",
)
At most 4096 scalars and three levels of nesting — a (256, 4, 4) stack is the
widest legal input.
Scenario: Reaching An Actor¶
Three spellings, one actor. The integer and the "actor_<id>" string are
equivalent for actors already in the scene; a handle is what an insert gives back.
variant.actor(4) # by scene id
variant.actor("actor_4") # same actor, same recording
handle = variant.insert_actor(actor_id="actor_10001")
variant.actor(handle) # the actor this script inserted
Scenario: Actor Shift, Translate And Rotate¶
Same vocabulary as the ego, tighter bounds: ±5 m lateral, ±15 m longitudinal, ±0.15 m vertical, ±10° yaw for actors that were in the scene at load time.
variant.actor(4).shift(left=3.5) # one lane over
variant.actor(4).shift(forward=6.0, start_idx=0, end_idx=50)
variant.actor(4).translate(backward=4.0)
variant.actor(4).rotate(yaw=-8.0)
Scenario: Actor Speed And Move Forward¶
speed rescales the existing motion. move_forward overwrites it with a
constant-speed run from a given frame, in m/s.
variant.actor(84).speed(1.25) # 25 % faster
variant.actor(84).speed(0.7) # 30 % slower
variant.actor(84).move_forward(start_idx=0, speed=6.0)
Scenario: Actor Stop And Make Static¶
Two ways to bring an actor to rest. stop decelerates into frame at_idx —
give it either a duration in frames or a decel rate. make_static_at
simply freezes the actor from that frame on.
variant.actor(84).stop(40, duration=30, profile="min_jerk")
variant.actor(84).stop(40, decel=12, profile="linear")
variant.actor(84).make_static_at(at_idx=30)
Scenario: Trajectory Slice, Resample And Offset¶
Cut the trajectory down to a window, change its rate, or slide it in time.
slice takes its two frame indices positionally.
variant.actor(84).slice(10, 60) # keep frames 10..60
variant.actor(84).resample(12.5) # Hz
variant.actor(84).offset_frames(5) # shift the actor's own frames
To slide an actor against the scene clock instead, use the scene-level op, which is bounded to ±20 frames:
variant.offset_actor(actor_id=84, offset_frame=-6)
Scenario: Actor Transform And Apply T Sequence¶
The combined op and the matrix op, both defaulting to referential="local" on
an actor.
import numpy as np
variant.actor(1).transform(forward=2.0, left=0.5, yaw=6.0)
JITTER = np.tile(np.eye(4), (4, 1, 1))
JITTER[1, 0, 3] = 0.05
JITTER[2, 0, 3] = 0.10
variant.actor(1).apply_T_sequence(T=JITTER, start_idx=0, end_idx=4)
Scenario: Fluent Chains¶
Every op that edits in place returns its receiver, so calls chain. Ops that
produce a new actor (the inserts, crossing) return a handle instead and end
the chain.
variant.actor(84).move_forward(start_idx=0, speed=6.0).speed(1.1).stop(
at_idx=45, decel=12
)
variant.ego.shift(forward=5.0).rotate(yaw=3.0)
Scenario: Insert Actor¶
The plainest insert. Name the asset by its durable id — copy it from the MIMIC library browser; the Backend resolves it at submit time.
car = variant.insert_actor(actor_id="actor_10001")
variant.actor(car).translate(forward=12.0, left=3.5)
Inserted actors get the wider limit table: ±50 m lateral and longitudinal, ±180° yaw.
Scenario: Insert Static Actor¶
Position is relative to the ego at frame at_idx. ground=True drops the
asset onto the road surface.
truck = variant.insert_static_actor(
actor_id="actor_10021",
at_idx=60,
forward=18.0,
right=3.0,
yaw=45.0,
ground=True,
)
Scenario: Insert Actor On Ego Trajectory¶
The new actor inherits the ego’s own path, offset by the distances you give. Good for lead vehicles and followers.
lead = variant.insert_actor_on_ego_trajectory(
actor_id="actor_10033", forward=25.0
)
follower = variant.insert_actor_on_ego_trajectory(
actor_id="actor_10034", backward=15.0, left=3.5
)
variant.actor(lead).move_forward(start_idx=0, speed=9.0)
Scenario: Crossing¶
A crossing actor walks from lateral across the ego’s path, entering at frame
start and clearing by frame end.
walker = variant.crossing(
actor="actor_10040",
start=20,
end=45,
forward=25.0,
lateral=-10.0,
direction="right_to_left",
speed=1.4,
ground=True,
graceful_stop=False,
)
variant.actor(walker).speed(0.9)
graceful_stop=True has the actor decelerate at the far kerb instead of walking
straight out of frame.
Scenario: Removing Actors¶
Clear one actor, or clear the board before rebuilding it.
variant.remove_actor(actor_id=0)
variant.remove_actor(actor_id="actor_11")
variant.remove_all_actors()
A handle stays a live Python name after its actor is removed. Editing it records the op and warns — the actor is still gone.
Scenario: Object Appearance¶
Scene-wide, then per actor. These two ops control the appearance of vehicle backlights and flashing lights per frames, at False by default.
variant.object_appearance(enabled=False) # whole scene off
variant.actor(34).object_appearance(enabled=True) # this one back on
Scenario: Moving A Sensor¶
Cameras, LiDARs and radars share one vocabulary; only the accessor differs.
recompute=False defers the world-pose refresh when you are about to move
several sensors.
variant.camera("FRONT").shift(up=0.12)
variant.camera("FRONT").rotate(pitch=-1.5)
variant.lidar("TOP").shift(forward=0.10, up=0.05, recompute=False)
variant.radar("FRONT_RADAR").rotate(yaw=1.0)
variant.recompute_all_sensor_world_poses()
Scenario: Sensor Conventions And Resolution¶
transform on a sensor takes a frame ("vehicle" or "sensor") and an
axis convention ("vehicle" is X-forward, "opencv" is Z-forward).
scale_camera_resolution rescales the image and the intrinsics with it.
variant.camera("FRONT").transform(
up=0.10, pitch=-1.0, referential="sensor", convention="opencv"
)
variant.camera("FRONT_LEFT").convert_convention(
from_convention="opencv", to_convention="vehicle"
)
variant.camera("SIDE_RIGHT").scale_camera_resolution(0.5)
Scenario: Pedestrian Crossing In Front Of The Ego¶
One walker steps out 25 m ahead, right to left, at a brisk pace. The ego eases right to give itself room.
from mimic_sdk.scene_edition import MimicSceneEditor
WALKER = "actor_10040"
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="urban_crossing")
with scene.generate_variant("pedestrian_steps_out") as variant:
walker = variant.crossing(
actor=WALKER,
start=30,
end=70,
forward=25.0,
lateral=-9.0,
direction="right_to_left",
speed=1.5,
ground=True,
)
variant.actor(walker).rotate(yaw=4.0)
variant.ego.shift(right=0.8, start_idx=25, end_idx=80)
variant.recompute_all_sensor_world_poses()
Scenario: Lead Vehicle Brake Check¶
A car is dropped 30 m ahead on our own path, accelerates away, then brakes hard into frame 55.
from mimic_sdk.scene_edition import MimicSceneEditor
LEAD = "actor_10033"
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="highway_run")
with scene.generate_variant("lead_brakes_hard") as variant:
lead = variant.insert_actor_on_ego_trajectory(actor_id=LEAD, forward=30.0)
variant.actor(lead).move_forward(start_idx=0, speed=11.0).stop(
55, duration=20, profile="min_jerk"
)
Scenario: Roadworks Cone Corridor¶
Eight cones taper the lane down, and the ego threads through them. The loop is ordinary Python — the recorder sees only the eight resulting ops.
from mimic_sdk.scene_edition import MimicSceneEditor
CONES = ["actor_10019", "actor_10020"]
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="roadworks")
with scene.generate_variant("cone_corridor") as variant:
for i in range(8):
variant.insert_static_actor(
actor_id=CONES[i % 2],
at_idx=20,
forward=12.0 + i * 3.5,
right=3.0 - i * 0.25,
ground=True,
)
variant.ego.shift(left=1.2, start_idx=20, end_idx=70)
variant.recompute_all_sensor_world_poses()
Scenario: Convoy On The Ego Path¶
Three vehicles trail behind us, each further back and slightly quicker than the last, each braking a few frames later.
from mimic_sdk.scene_edition import MimicSceneEditor
CONVOY = ["actor_10033", "actor_10034", "actor_10035"]
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="convoy")
with scene.generate_variant("three_car_convoy") as variant:
for i, asset in enumerate(CONVOY):
car = variant.insert_actor_on_ego_trajectory(
actor_id=asset, backward=8.0 + i * 12.0
)
variant.actor(car).move_forward(
start_idx=0, speed=6.0 + i * 0.5
).speed(1.1).stop(at_idx=40 + i * 5, decel=12)
Scenario: Occlusion Study¶
A parked truck is angled into the kerb so it hides an actor that matters, and a distracting actor is taken out of the scene entirely.
from mimic_sdk.scene_edition import MimicSceneEditor
TRUCK = "actor_10021"
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="lane_occlusion")
with scene.generate_variant("truck_hides_cyclist") as variant:
truck = variant.insert_static_actor(
actor_id=TRUCK, at_idx=60, forward=14.0, right=2.5, yaw=45.0
)
variant.actor(truck).translate(forward=3.0)
variant.actor(4).shift(left=1.0) # the cyclist, nudged behind it
variant.remove_actor(actor_id=0) # remove the distraction
Scenario: Sensor Rig Rebuild¶
Raise and pitch the front camera, move the LiDAR forward, fix a camera that was calibrated in OpenCV axes, halve one side camera’s resolution, then refresh every world pose once at the end.
from mimic_sdk.scene_edition import MimicSceneEditor
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="rig_study")
with scene.generate_variant("rig_rebuild") as variant:
variant.camera("FRONT").shift(up=0.12, recompute=False)
variant.camera("FRONT").rotate(pitch=-1.5, recompute=False)
variant.lidar("TOP").shift(forward=0.10, up=0.05, recompute=False)
variant.camera("FRONT_LEFT").convert_convention(
from_convention="opencv", to_convention="vehicle", recompute=False
)
variant.camera("SIDE_RIGHT").scale_camera_resolution(0.5)
variant.recompute_all_sensor_world_poses()
Scenario: Parameter Sweep¶
Twelve variants out of one baseline: four lateral offsets crossed with three
parked-car counts. One with block per variant, each a clean fork.
from mimic_sdk.scene_edition import MimicSceneEditor
CAR = "actor_10001"
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="sweep")
def park(variant, count):
"""Clear the scene and line up ``count`` parked cars."""
variant.remove_all_actors()
for k in range(count):
car = variant.insert_actor(actor_id=CAR)
variant.actor(car).translate(forward=k * 6.0, right=3.0)
for offset in (0.0, 0.5, 1.0, 1.5):
for count in (1, 2, 3):
with scene.generate_variant(f"offset{offset}_cars{count}") as variant:
park(variant, count)
variant.ego.shift(left=offset)
Scenario: DataFrame Driven Schedule¶
The recorder takes plain numbers, so anything that produces them works — including pandas. Here a drift schedule becomes four matrix stacks.
import numpy as np
import pandas as pd
from mimic_sdk.scene_edition import MimicSceneEditor
DRIFT = pd.DataFrame(
{
"start_idx": [0, 4, 8, 12],
"end_idx": [4, 8, 12, 16],
"dx": [0.05, 0.10, 0.15, 0.20],
"dy": [0.00, 0.02, 0.04, 0.06],
}
)
def ramp(frames: int, dx: float, dy: float) -> np.ndarray:
"""A linear ramp to (dx, dy) over ``frames`` poses."""
T = np.tile(np.eye(4), (frames, 1, 1))
weight = np.linspace(0.0, 1.0, frames)
T[:, 0, 3] = weight * dx
T[:, 1, 3] = weight * dy
return T
client = MimicSceneEditor.login()
scene = client.open_scene(sequence_id="drift_study")
with scene.generate_variant("scheduled_drift") as variant:
for row in DRIFT.itertuples(index=False):
start, end = int(row.start_idx), int(row.end_idx)
variant.ego.apply_T_sequence(
T=ramp(end - start, float(row.dx), float(row.dy)),
start_idx=start,
end_idx=end,
)
variant.ego.shift(forward=round(float(DRIFT["dx"].sum()), 3))
Where to go next¶
Getting Started — installing the SDK and running your first script.
Limits — the full bound table for the ego, scene actors and inserted actors.
API Reference — the reference for every editor and every operation.