Coordinate Frames¶
This example shows how to use Pose3d
and Frame3d
to represent objects that are connected to each other.
Here, we have a moving blue box and a rotating pink box with a camera attached to it.
The button allows switching the pink box between the blue box's frame and the world frame at runtime.
Note that the relationship between the pink box and the camera is unaffected by the frame switch.
#!/usr/bin/env python3
import math
from nicegui import ui
import rosys
from rosys.geometry import Pose3d, Rotation
from rosys.vision import CameraSceneObject, SimulatedCalibratableCamera
blue = Pose3d(z=0.5).as_frame('blue')
pink = Pose3d(z=0.75).as_frame('pink').in_frame(blue)
camera = SimulatedCalibratableCamera.create_calibrated(id='Camera', z=0.5, roll=math.pi / 2, frame=pink)
with ui.scene() as scene:
blue_box = scene.box(width=1, height=1, depth=1).material(color='SteelBlue')
pink_box = scene.box(width=0.5, height=0.5, depth=0.5).material(color='HotPink')
camera_object = CameraSceneObject(camera)
def update():
blue.x = math.cos(0.5 * rosys.time())
blue.y = math.sin(0.5 * rosys.time())
pink.rotation *= Rotation.from_euler(0, 0, 0.005)
blue_box.rotate_R(blue.resolve().rotation.R)
blue_box.move(*blue.resolve().translation)
pink_box.rotate_R(pink.resolve().rotation.R)
pink_box.move(*pink.resolve().translation)
camera_object.rotate_R(camera.calibration.extrinsics.resolve().rotation.R)
camera_object.move(*camera.calibration.extrinsics.resolve().translation)
rosys.on_repeat(update, interval=0.01)
ui.button('Toggle frame', on_click=lambda: pink.in_frame(None if pink.frame_id == 'blue' else blue))
ui.run(title='RoSys')
Persistence¶
Frames are defined and accessed through an id
. The id
must be unique and is used lazily whenever a transformation is needed.
This id
makes it possible to fully persist Pose3d
, Frame3d
and their relationships.
This can be useful for situation where exact relationships are calibrated at runtime (e.g. multi-camera calibration) or when a robot's axes are expected to be persistent across reboots.
For the second case, make sure that you know when the persistence overwrite happens (in the rosys startup handler) so that everything is loaded correctly. See examples/camera_arm for an example on that.