Visualization
SRMP provides two visualization backends that wrap PlannerInterface with
automatic scene tracking and 3D rendering:
VisualPlannerInterface— lightweight MeshCat-based visualizerViserPlannerInterface— interactive Viser-based visualizer with full browser-to-Python bidirectional communication
Both classes inherit from PlannerInterface, so every planning method
(add_articulation, add_box, plan, read_sim, …) is available and the
scene is automatically kept in sync with the 3D view.
Installation
MeshCat visualizer:
$ pip install meshcat
Viser visualizer:
$ pip install viser trimesh
Note
The visualization dependencies are optional. When they are not installed, importing
VisualPlannerInterface or ViserPlannerInterface is silently skipped and
srmp.PlannerInterface remains fully functional.
VisualPlannerInterface (MeshCat)
VisualPlannerInterface connects to a MeshCat
WebGL viewer running in the browser. It is a good choice for quick scene inspection and
trajectory animation when interactive widget editing is not required.
Limitations
MeshCat does not support reading slider values from the browser back into Python. Use the
set_gui_*helper methods to drive GUI state programmatically.
Basic Usage
from srmp import VisualPlannerInterface
import numpy as np
# Create planner with MeshCat visualization
planner = VisualPlannerInterface()
# Add robot and obstacles (tracked automatically)
planner.add_articulation(
name="panda",
end_effector="panda_hand",
urdf_path="/path/to/panda.urdf",
srdf_path="/path/to/panda.srdf", # optional
)
box_pose = planner.Pose() if hasattr(planner, 'Pose') else __import__('srmp').Pose()
import srmp
box_pose = srmp.Pose()
box_pose.p = np.array([0.5, 0.2, 0.4])
planner.add_box("obstacle", np.array([0.1, 0.1, 0.4]), box_pose)
# Open the 3D viewer (prints the browser URL)
planner.visualize()
# Animate a planned trajectory
planner.make_planner(["panda"], {"planner_id": "wAstar", "weight": "10."})
start = np.radians([0, -45, 0, -135, 0, 90, 45])
goal_pose = srmp.Pose()
goal_pose.p = np.array([0.6, 0.0, 0.5])
goal_pose.q = np.array([1.0, 0.0, 0.0, 0.0])
goal = srmp.GoalConstraint(srmp.GoalType.POSE, [goal_pose])
trajectory = planner.plan(start, goal)
planner.animate_trajectory(trajectory, dt=0.05)
GUI Controls (MeshCat)
Because MeshCat cannot relay browser input back to Python, obstacle editing is driven
entirely from Python using the set_gui_* helpers:
# Must call visualize() first
planner.visualize()
planner.add_gui_controls()
# Set obstacle properties in Python, then add to the scene
planner.set_gui_object_type("box")
planner.set_gui_position(0.5, 0.0, 0.5)
planner.set_gui_size(0.1, 0.1, 0.1)
planner.set_gui_object_name("my_box")
planner.add_obstacle_from_gui()
# Load an existing object into the GUI state for editing
planner.load_object_to_gui("my_box")
planner.set_gui_position(0.6, 0.0, 0.5)
planner.update_object_from_gui("my_box")
# Access the browser URL
print(planner.url)
ViserPlannerInterface (Viser)
ViserPlannerInterface uses Viser, a modern 3D web
visualizer that provides true bidirectional communication. Browser sliders, dropdowns,
and buttons trigger Python callbacks in real time, making this backend ideal for
interactive scene authoring and IK-driven teleoperation.
Basic Usage
from srmp import ViserPlannerInterface
import srmp
import numpy as np
# Start Viser server (default port 8080)
planner = ViserPlannerInterface(port=8080)
planner.add_articulation(
name="panda",
end_effector="panda_hand",
urdf_path="/path/to/panda.urdf",
)
box_pose = srmp.Pose()
box_pose.p = np.array([0.5, 0.2, 0.4])
planner.add_box("obstacle", np.array([0.1, 0.1, 0.4]), box_pose)
# Open the 3D viewer
planner.visualize()
print(planner.url) # → http://localhost:8080
# Animate a trajectory
planner.make_planner(["panda"], {"planner_id": "wAstar", "weight": "10."})
start = np.radians([0, -45, 0, -135, 0, 90, 45])
goal = srmp.GoalConstraint(srmp.GoalType.JOINTS,
[np.radians([45, -30, 0, -120, 0, 90, 0])])
trajectory = planner.plan(start, goal)
planner.animate_trajectory(trajectory, dt=0.05)
# Stop the server when done
planner.stop()
Interactive Joint Controls
add_robot_controls() creates per-joint sliders in the browser sidebar.
Moving a slider immediately updates both the Viser geometry and the planner backend:
planner.visualize()
planner.add_robot_controls("panda")
# The browser now shows joint sliders with a Reset button and
# visibility toggles for visual / collision meshes.
End-Effector Drag Control (IK)
add_ee_drag_control() places a 6-DOF transform handle at the robot’s
end-effector. Dragging the gizmo in the browser triggers real-time IK:
planner.visualize()
planner.add_robot_controls("panda") # optional — syncs joint sliders
planner.add_ee_drag_control("panda")
# The browser shows a 3-axis gizmo at the end-effector.
# Drag it to move the robot via IK. On failure the gizmo
# snaps back to the actual EE pose.
import time
time.sleep(60) # Keep server alive while interacting
GUI Object Controls (Viser)
add_gui_controls() adds a browser panel with dropdowns, sliders, text
inputs, and Add / Update / Remove buttons that directly invoke Python:
planner.visualize()
planner.add_gui_controls()
# In the browser:
# 1. Select Object Type → "box"
# 2. Adjust Position, Width/Radius, Height, Depth sliders
# 3. Type a name in the "Object Name" field
# 4. Click "Add Object" → calls planner.add_obstacle_from_gui()
# Click "Update Object" → calls planner.update_object_from_gui(name)
# Click "Remove Object" → calls planner.remove_object(name)
# You can also load an existing object into the GUI for editing:
planner.load_object_to_gui("obstacle")
# For mesh objects, click "Browse Mesh File..." to open a file dialog
# (requires tkinter) or type the path directly.
import time
time.sleep(120) # Keep server alive
MeshCat vs Viser Comparison
Feature |
VisualPlannerInterface |
ViserPlannerInterface |
|---|---|---|
Dependency |
meshcat |
viser, trimesh |
Browser → Python communication |
One-way (Python drives GUI) |
Bidirectional |
Interactive joint sliders |
Display only |
Fully interactive (callbacks) |
End-effector drag / IK |
Not available |
Available |
Object editing buttons |
Python-driven only |
Buttons trigger Python callbacks |
Shareable URLs |
Not available |
Available ( |
Mesh loading |
STL, OBJ, DAE |
Any format supported by trimesh |