Skip to content

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')

Coordinate Frames

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.