URDF visualizer#

Requires yourdfpy and URDF. Any URDF supported by yourdfpy should work.

Examples:

 1from __future__ import annotations
 2
 3import time
 4from pathlib import Path
 5from typing import List
 6
 7import numpy as onp
 8import tyro
 9import viser
10from viser.extras import ViserUrdf
11
12
13def main(urdf_path: Path) -> None:
14    server = viser.ViserServer()
15
16    # Create a helper for adding URDFs to Viser. This just adds meshes to the scene,
17    # helps us set the joint angles, etc.
18    urdf = ViserUrdf(server, urdf_path)
19
20    # Create joint angle sliders.
21    gui_joints: List[viser.GuiInputHandle[float]] = []
22    initial_angles: List[float] = []
23    for joint_name, (lower, upper) in urdf.get_actuated_joint_limits().items():
24        lower = lower if lower is not None else -onp.pi
25        upper = upper if upper is not None else onp.pi
26
27        initial_angle = 0.0 if lower < 0 and upper > 0 else (lower + upper) / 2.0
28        slider = server.add_gui_slider(
29            label=joint_name,
30            min=lower,
31            max=upper,
32            step=1e-3,
33            initial_value=initial_angle,
34        )
35        slider.on_update(  # When sliders move, we update the URDF configuration.
36            lambda _: urdf.update_cfg(onp.array([gui.value for gui in gui_joints]))
37        )
38
39        gui_joints.append(slider)
40        initial_angles.append(initial_angle)
41
42    # Create joint reset button.
43    reset_button = server.add_gui_button("Reset")
44
45    @reset_button.on_click
46    def _(_):
47        for g, initial_angle in zip(gui_joints, initial_angles):
48            g.value = initial_angle
49
50    # Apply initial joint angles.
51    urdf.update_cfg(onp.array([gui.value for gui in gui_joints]))
52
53    while True:
54        time.sleep(10.0)
55
56
57if __name__ == "__main__":
58    tyro.cli(main)