Transform tree inspectionΒΆ
tree() returns a one-shot snapshot of topology and
edge poses. subscribe_tree() streams updates as
poses or topology changes.
By default each yield is a full FrameTree; call
changes() on the same subscription for raw
TreeDelta batches (added / updated). The first
delta is always a snapshot, so skip it to see incremental changes. Scoped trees
omit external ancestor edges by default, so root nodes are pose-less unless
include_ancestors=True.
import time
from olo import Client
from olo.spatial import Transform
with Client() as client:
robot = client.robot()
# Namespace-scoped TF tree.
robot_frames = robot.frames
base_frame = robot_frames.base_frame()
if base_frame is None:
raise RuntimeError("No base frame detected for this robot")
# Read the scoped robot tree and the full TF tree.
print(robot_frames.tree())
print(client.spatial.tree())
# Each iteration prints the whole tree. Publish between reads to drive updates.
with robot_frames.subscribe_tree() as stream:
for _, tree in zip(range(3), stream):
print(f"Received tree with {len(tree.flatten())} frames")
robot_frames.publish_static(
Transform(frame_id=base_frame, child_frame_id=f"frame_{time.time_ns()}")
)
# Delta streams expose raw added and updated edges.
with robot_frames.subscribe_tree() as stream:
changes = stream.changes()
# Skip the initial snapshot.
next(changes)
robot_frames.publish_static(
Transform(frame_id=base_frame, child_frame_id=f"frame_{time.time_ns()}")
)
# Parse the next incremental response.
delta = next(changes)
added = [edge.child_frame_id for edge in delta.added]
print(f"Added: {added}")
import { connect } from "olo/web";
import { Transform } from "olo/spatial";
const client = connect();
const robot = await client.robot();
// Namespace-scoped TF tree.
const robotFrames = robot.frames;
const baseFrame = await robotFrames.baseFrame();
if (baseFrame === undefined) {
throw new Error("No base frame detected for this robot");
}
// Read the scoped robot tree and the full TF tree.
console.log(`${await robotFrames.tree()}`);
console.log(`${await client.spatial.tree()}`);
{
// Each iteration prints the whole tree. Publish between reads to drive updates.
const stream = robotFrames.subscribeTree();
let count = 0;
for await (const tree of stream) {
console.log(`Received tree with ${tree.flatten().length} frames`);
await robotFrames.publishStatic(
new Transform({ frameId: baseFrame, childFrameId: `frame_${Date.now()}` }),
);
if (++count === 3) stream.close();
}
}
{
// Delta streams expose raw added and updated edges.
const stream = robotFrames.subscribeTree();
const changes = stream.changes();
// Skip the initial snapshot.
await changes.next();
await robotFrames.publishStatic(
new Transform({ frameId: baseFrame, childFrameId: `frame_${Date.now()}` }),
);
// Parse the next incremental response.
const { value: delta } = await changes.next();
const added = delta === undefined ? [] : delta.added.map((edge) => edge.childFrameId);
console.log(`Added: ${added.join(", ")}`);
stream.close();
}