chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:05:14 +08:00
commit 2a547be7fe
7904 changed files with 1000926 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
<!--[metadata]
title = "URDF"
tags = ["3D", "Mesh", "URDF", "Animation"]
channel = "main"
include_in_manifest = true
thumbnail = "https://static.rerun.io/animated-urdf-thumbnail/02cd73ad1155db0a202392b1fd8f8036070ad888/480w.png"
thumbnail_dimensions = [480, 480]
-->
<picture>
<img src="https://static.rerun.io/animated_urdf/ebdefa158ab6f26f9dc1cb1924fce4b846fe8db2/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/animated_urdf/ebdefa158ab6f26f9dc1cb1924fce4b846fe8db2/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/animated_urdf/ebdefa158ab6f26f9dc1cb1924fce4b846fe8db2/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/animated_urdf/ebdefa158ab6f26f9dc1cb1924fce4b846fe8db2/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/animated_urdf/ebdefa158ab6f26f9dc1cb1924fce4b846fe8db2/1200w.png">
</picture>
An example of how to load and animate a URDF given some changing joint angles.
## Logging and visualizing with Rerun
This example demonstrates how to:
1. Load and log a URDF file as a static resource
2. Parse the URDF structure using `UrdfTree`
3. Animate joints by logging dynamic transforms
The key steps are:
```python
import rerun as rr
import rerun.urdf import UrdfTree
# Log the URDF file once, as a static resource
rec.log_file_from_path(urdf_path, static=True)
# Load the URDF tree structure into memory
urdf_tree = UrdfTree.from_file_path(urdf_path)
# Animate joints by logging transforms
for joint in urdf_tree.joints():
if joint.joint_type == "revolute":
# compute_transform gives you a complete transform that is ready to log,
# calculated from joint origin and the current angle and with the frame names set.
transform = joint.compute_transform(angle)
rec.log("transforms", transform)
```
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""
An example of how to load and animate a URDF given some changing joint angles.
Usage:
python -m animated_urdf
"""
from __future__ import annotations
import argparse
import math
from pathlib import Path
import rerun as rr
import rerun.blueprint as rrb
TIMELINE = "example_time"
def main() -> None:
parser = argparse.ArgumentParser(
description="An example of how to load and animate a URDF given some changing joint angles.",
)
rr.script_add_args(parser)
parser.add_argument(
"--dual",
action="store_true",
help="Load the same URDF twice with different frame prefixes (dual-arm demo).",
)
args = parser.parse_args()
urdf_path = Path(__file__).parent.parent.parent / "rust" / "animated_urdf" / "data" / "so100.urdf"
if args.dual:
run_dual(args, urdf_path)
else:
run_single(args, urdf_path)
def run_single(args: argparse.Namespace, urdf_path: Path) -> None:
duration = 0.0
rec = rr.script_setup(args, "rerun_example_animated_urdf")
rec.set_time(TIMELINE, duration=duration)
# Log the URDF file once
rec.log_file_from_path(urdf_path)
# Load the URDF tree structure into memory
urdf_tree = rr.urdf.UrdfTree.from_file_path(urdf_path)
# Hide the collision geometries by default in the viewer.
blueprint = rrb.Grid(
rrb.Spatial3DView(
name="Animated URDF", overrides={"so_arm100/collision_geometries": rrb.EntityBehavior(visible=False)}
)
)
rec.send_blueprint(blueprint)
for step in range(10000):
for joint_index, joint in enumerate(urdf_tree.joints()):
if joint.joint_type == "revolute":
# Usually this angle would come from a measurement, here we just fake something
dynamic_angle = _fake_angle(joint, step, joint_index, phase=0.0)
# Rerun loads the URDF transforms with child/parent frame relations.
# To move a joint, we just need to log a new transform between those frames.
# Here, we use the `compute_transform` method that automatically takes care
# of setting the frame names and calculating the full transform from the joint angle.
transform = joint.compute_transform(dynamic_angle, clamp=True)
rec.log("transforms", transform)
# We can also work with links from the URDF tree.
# Here, we change the color of the visual mesh entities of the "jaw" link based on the joint angle.
link = urdf_tree.get_joint_child(joint)
if link.name == "jaw":
for visual_path in urdf_tree.get_visual_geometry_paths(link):
normalized_angle = (dynamic_angle - joint.limit_lower) / (joint.limit_upper - joint.limit_lower)
rgba = [1.0 - normalized_angle, normalized_angle, 0, 0.5]
rec.log(visual_path, rr.Asset3D.from_fields(albedo_factor=rgba))
duration += 0.03
rec.set_time(TIMELINE, duration=duration)
rr.script_teardown(args)
def run_dual(args: argparse.Namespace, urdf_path: Path) -> None:
"""Load the same URDF twice with different frame prefixes (dual-arm demo)."""
rec = rr.script_setup(args, "rerun_example_animated_urdf")
# Load the same URDF twice with different prefixes.
# - entity_path_prefix separates geometry in the entity tree
# - frame_prefix makes frame IDs unique ("left/base", "right/base", …)
left = rr.urdf.UrdfTree.from_file_path(urdf_path, entity_path_prefix="left", frame_prefix="left/")
right = rr.urdf.UrdfTree.from_file_path(urdf_path, entity_path_prefix="right", frame_prefix="right/")
# Log both robots (geometry + static transforms with prefixed frame IDs).
left.log_urdf_to_recording()
right.log_urdf_to_recording()
# Offset the arms so they don't overlap.
rec.log("left", rr.Transform3D(translation=[-0.2, 0, 0]), static=True)
rec.log("right", rr.Transform3D(translation=[0.2, 0, 0]), static=True)
blueprint = rrb.Grid(
rrb.Spatial3DView(
name="Dual Arm",
overrides={
"left/so_arm100/collision_geometries": rrb.EntityBehavior(visible=False),
"right/so_arm100/collision_geometries": rrb.EntityBehavior(visible=False),
},
)
)
rec.send_blueprint(blueprint)
for step in range(10000):
rec.set_time("step", sequence=step)
for joint_index, joint in enumerate(left.joints()):
if joint.joint_type == "revolute":
angle = _fake_angle(joint, step, joint_index, phase=0.0)
rec.log("left/joint_transforms", joint.compute_transform(angle, clamp=True))
for joint_index, joint in enumerate(right.joints()):
if joint.joint_type == "revolute":
angle = _fake_angle(joint, step, joint_index, phase=2.0)
rec.log("right/joint_transforms", joint.compute_transform(angle, clamp=True))
rr.script_teardown(args)
def _fake_angle(joint: rr.urdf.UrdfJoint, step: int, joint_index: int, phase: float) -> float:
"""Generate a smooth oscillating angle within the joint's limits."""
sin_value = math.sin(step * (0.02 + joint_index / 100.0) + phase)
return joint.limit_lower + (sin_value + 1.0) / 3.0 * (joint.limit_upper - joint.limit_lower)
if __name__ == "__main__":
main()
@@ -0,0 +1,12 @@
[project]
name = "animated_urdf"
version = "0.1.0"
readme = "README.md"
dependencies = ["rerun-sdk"]
[project.scripts]
animated_urdf = "animated_urdf:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"