Work in progress: this documentation is still being written and reviewed. Check details against the source code.

Robot and trajectory viewer

Display the robot, task previews, and configured obstacles in an embedded 3D viewer.

mtc_gui.visualization_panel · Source

Operator GUI · Guide · Symbol index

How it is used

MTCMainWindow creates VisualizationPanel and connects joint, gripper, and trajectory signals. The panel starts a loopback HTTP server for viewer assets and robot meshes, then waits for the embedded WebEngine page before loading the model. Its controls and previews affect the display only.

Use preview_pose() and end_preview() around a task editor’s goal preview; play_trajectory() animates an orchestrator preview. Pose lists use degrees, while trajectory waypoint positions use radians. Python uses the configured arm-joint order, but the JavaScript viewer still expects six fixed UR joint names. closeEvent() stops the panel’s timer and mesh server.

Start here

Callable

Purpose

VisualizationPanel.__init__

Locate robot assets, create the viewer controls, and start local asset serving.

VisualizationPanel.preview_pose

Display a six-angle goal preview and temporarily suppress live pose updates.

VisualizationPanel.end_preview

Release a goal-pose preview and restore the most recently cached live pose.

VisualizationPanel.play_trajectory

Convert trajectory waypoints into arm poses and animate them in the viewer.

VisualizationPanel.stop_preview

Stop trajectory playback and clear its active interpolation track.

VisualizationPanel

Own the WebEngine view, robot model selection, preview state, and visual scene. Updates arrive on the GUI thread; the panel does not command the robot.

Inherits from: QWidget.

VisualizationPanel.__init__()

Locate robot assets, create the viewer controls, and start local asset serving.

Lifecycle · Source

__init__(self, ros2_bridge=None, parent=None)

Parameter

Meaning

ros2_bridge

Optional bridge reference retained as ros2; this constructor does not connect its signals.

parent

Optional parent widget.

Errors: Description-package lookup falls back to cms_robot_description; other package/UI/server failures propagate.

Side effects: Creates an inactive 33 ms preview timer, resolves paths/packages, creates WebEngine or fallback UI, and starts mesh server/page loading when WebEngine is available. Initial gripper name is epick.

VisualizationPanel.preview_pose()

Display a six-angle goal preview and temporarily suppress live pose updates.

Method · Source

preview_pose(self, pose_deg)

Parameter

Meaning

pose_deg

List or tuple of exactly six values in degrees; contents are not checked for numeric validity.

Returns: None.

Errors: Returns for unreadied page or wrong container/length; Qt errors propagate.

Side effects: Sets _preview_hold=True and calls window.updateJoints with a list. This is display-only.

VisualizationPanel.end_preview()

Release a goal-pose preview and restore the most recently cached live pose.

Method · Source

end_preview(self)

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Clears _preview_hold and, when ready with a truthy cached pose, sends it to window.updateJoints.

VisualizationPanel.play_trajectory()

Convert trajectory waypoints into arm poses and animate them in the viewer.

Callback · Source

play_trajectory(self, _unused_names, waypoints)

Parameter

Meaning

_unused_names

Ignored compatibility signal argument; names come from each waypoint.

waypoints

Sequence of (joint_names, positions_in_radians, cumulative_seconds). Named positions may include arm or gripper joints; complete arm samples are converted to degrees rounded to three decimals.

Returns: None.

Errors: Returns before readiness or for no points; malformed names/positions/times raise. Does not validate chronological order or that all points have six arm joints.

Side effects: Seeds from the first complete arm sample or six zeros, holds the last arm state across partial/gripper-only points, stores the full track, duration from its last point, and monotonic start; shows preview controls and starts the timer. It does not set _preview_hold, so live updates can interleave with playback.

VisualizationPanel.stop_preview()

Stop trajectory playback and clear its active interpolation track.

Callback · Source

stop_preview(self)

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Stops timer, clears label, hides Stop Preview, and clears _preview_arm_track. It does not restore live pose, clear saved waypoints, or change goal-preview hold.

Referenced in source (1)

VisualizationPanel.closeEvent()

Stop preview timing and the mesh server before delegating widget closure.

Lifecycle · Source

closeEvent(self, event)

Parameter

Meaning

event

QCloseEvent passed unchanged to the base widget handler.

Returns: None.

Errors: Server shutdown/Qt errors propagate; readiness polling is not explicitly stopped here.

Side effects: Stops preview timer, shuts down loopback server when present, then invokes QWidget.closeEvent.

Internal callbacks and helpers

VisualizationPanel._setup_ui()

Create the 3D viewport and display-only controls, or a fallback message if WebEngine is unavailable.

Internal helper · Source

_setup_ui(self)

Returns: None.

Errors: Without WebEngine creates an installation hint and returns; other Qt failures propagate.

Side effects: Creates toolbar/status widgets and web_view when available; no ROS goal is sent by these controls.

Referenced in source (1)

VisualizationPanel._referenced_packages()

Collect package references from each distinct URDF named by configured grippers.

Internal helper · Source

_referenced_packages(self) -> set[str]

Returns: Union of package references, or the full known-package set when configuration loading fails, no URDF names are declared, or _urdf_dir is None.

Errors: Malformed gripper mappings and non-OSError file failures may propagate. Individual unreadable files produce empty sets through _packages_referenced_by_urdf, not the broad fallback claimed by the docstring.

Side effects: Loads beamline configuration and reads declared URDF files.

Referenced in source (1)

VisualizationPanel._start_server()

Serve the viewer locally and begin loading viewer.html into WebEngine.

Internal helper · Source

_start_server(self)

Returns: None.

Errors: No-op without WebEngine. Socket/server/Qt errors propagate.

Side effects: Creates/starts _MeshServer, updates status with the port, connects loadFinished, and loads the loopback static URL.

Referenced in source (1)

VisualizationPanel._on_page_loaded()

Start readiness polling after a successful browser page load.

Callback · Source

_on_page_loaded(self, ok)

Parameter

Meaning

ok

QWebEngine loadFinished Boolean; False shows failure and returns.

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Shows Waiting for JS, creates _ready_poll, connects readiness checks, and starts it every 100 ms after success.

Referenced in source (1)

VisualizationPanel._check_ready()

Ask JavaScript whether the viewer has set window._vizReady to true.

Callback · Source

_check_ready(self)

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Runs a WebEngine script and routes its asynchronous result to _on_ready_result.

Referenced in source (1)

VisualizationPanel._on_ready_result()

Finish readiness polling and load the current robot model and scene when JavaScript is ready.

Callback · Source

_on_ready_result(self, ready)

Parameter

Meaning

ready

Result of the window._vizReady equality check; false values leave polling active.

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Stops readiness timer, sets _page_ready=True, updates status, calls _load_urdf and _reload_scene.

Referenced in source (1)

VisualizationPanel._load_urdf()

Load the configured gripper’s robot URDF through the local mesh server.

Internal helper · Source

_load_urdf(self, gripper)

Parameter

Meaning

gripper

Gripper name passed to gripper_urdf_file, with ur_standalone.urdf as the fallback filename.

Returns: None.

Errors: No-op before page readiness. Configuration import/lookup, missing server, or Qt failures propagate.

Side effects: Builds a loopback URDF URL and runs window.loadRobot(url, port); does not await or report JavaScript load success.

Referenced in source (2)

VisualizationPanel.set_gripper()

Normalize the selected gripper to lowercase and request its visual robot model.

Callback · Source

set_gripper(self, gripper_name)

Parameter

Meaning

gripper_name

String gripper selection.

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Sets _current_gripper and calls _load_urdf, which waits for page readiness by returning early when necessary.

VisualizationPanel._on_joint_state()

Cache live joint angles and update the viewer unless a goal preview is held.

Callback · Source

_on_joint_state(self, pose_deg)

Parameter

Meaning

pose_deg

Joint-angle list in configured arm order, conventionally six numeric degrees values; this handler does not validate shape or types. The JavaScript consumer maps array positions to its hardcoded UR joint-name order.

Returns: None.

Errors: No-op before readiness; malformed/Qt errors otherwise propagate.

Side effects: Caches the latest pose only after readiness, suppresses updates during _preview_hold, throttles by monotonic 0.033 s, and runs window.updateJoints.

VisualizationPanel._reset_view()

Reset the JavaScript camera view when the page is ready.

Callback · Source

_reset_view(self)

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Runs window.resetView(); no-op before readiness.

Referenced in source (1)

VisualizationPanel._home_pose()

Show the viewer’s home pose when the page is ready.

Callback · Source

_home_pose(self)

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Runs window.setHomePose(); changes only visualization, not robot joint state.

Referenced in source (1)

VisualizationPanel._toggle_demo()

Enable or disable the viewer’s demonstration animation.

Callback · Source

_toggle_demo(self, checked)

Parameter

Meaning

checked

Boolean toggle state serialized as JavaScript true/false.

Returns: None.

Errors: Qt/widget errors propagate; no local exception handler.

Side effects: Runs window.demoMode when ready; controls only the local viewer.

Referenced in source (1)

VisualizationPanel._tick_preview()

Advance visual trajectory playback by interpolating between timed arm poses.

Callback · Source

_tick_preview(self)

Returns: None.

Errors: Empty track stops timer. Invalid track data/Qt errors propagate; times before the first point or outside a matching segment cause no update.

Side effects: Uses monotonic elapsed time and a linear scan, sends three-decimal interpolated joints, or snaps to final pose and stops at completion. Shows PREVIEW done and schedules label clearing after two seconds; completed track remains stored.

Referenced in source (1)

VisualizationPanel._reload_scene()

Load supported obstacle shapes from the configured scene into the viewer.

Callback · Source

_reload_scene(self)

Returns: None.

Errors: Missing path and YAML read/parse exceptions update status and return. Per-obstacle KeyError/TypeError/ValueError entries are skipped; unsupported types are skipped. A nonmapping YAML root, malformed obstacle object raising AttributeError, short box size raising IndexError, or JavaScript-call error can still propagate despite the docstring’s broader promise.

Side effects: Reads YAML and emits window.setSceneObstacles([{name,type,pos:[x,y,z],rot:[roll,pitch,yaw],dims:{size|height,radius}}]); positions and dimensions are interpreted as metres and rotations as radians by viewer.html, with no per-obstacle frame transform in this Python path. JavaScript replaces the existing displayed obstacle list. Updates obstacle/skipped count status; makes no planning-scene service call.

Referenced in source (2)

Functions

Internal callbacks and helpers

_load_arm_joints()

Read configured arm-joint order, falling back to the six standard UR joint names.

Internal helper · Source

_load_arm_joints() -> list[str]

Returns: List of joint-name strings; the module stores the result once in _ARM_JOINTS. The bundled JavaScript still has its own hardcoded six-name UR order; this helper does not configure it.

Errors: Catches all Exception failures from the config-loader import/call.

Side effects: Loads beamline joint configuration when available.

_base_packages()

Resolve required arm and beamline description package names.

Internal helper · Source

_base_packages() -> list[str]

Returns: [“ur_description”, configured_description_package], or [“ur_description”, “cms_robot_description”] on failure.

Errors: Catches all Exception failures.

Side effects: Consults config_loader; module caches the result in _BASE_PACKAGES.

_packages_referenced_by_urdf()

Extract unique package names from package:// references in URDF text.

Internal helper · Source

_packages_referenced_by_urdf(urdf_path: Path) -> set[str]

Parameter

Meaning

urdf_path

Path object supporting read_text; content is scanned with a regular expression rather than parsed as XML.

Returns: Set of referenced package names, or an empty set after an OSError.

Errors: Catches only OSError; decoding/type errors propagate.

Side effects: Reads the URDF file.

Referenced in source (1)

_find_workspace_roots()

Locate a source/install workspace from this module’s ancestry, optionally including an ancestor main workspace.

Internal helper · Source

_find_workspace_roots()

Returns: List of Path roots. Fallback is Path(file).resolve().parents[3] when no matching ancestor is found.

Errors: Filesystem/path errors are not caught.

Side effects: Checks ancestor src/install directories; does not change the workspace.

Referenced in source (2)

_resolve_packages()

Map required description packages to installed or workspace source directories.

Internal helper · Source

_resolve_packages(required: set[str] | None=None)

Parameter

Meaning

required

Optional package-name set; None starts with all known descriptions. Base packages are always included, even for an empty set.

Returns: Dict of package name to directory string; packages that cannot be located are omitted.

Errors: Missing ament import and per-package ament lookup failures are tolerated; other filesystem/type errors propagate.

Side effects: Checks ament and fixed /opt/ros/jazzy/workspace install/source candidates; reads no meshes and writes no files.

Referenced in source (1)

_resolve_scene_yaml()

Resolve the active beamline’s scene_file to an existing file.

Internal helper · Source

_resolve_scene_yaml()

Returns: Path to the scene YAML, or None for missing configuration, absent scene_file, nonexistent file, or any caught failure.

Errors: Catches all Exception failures from config/path resolution.

Side effects: Loads beamline configuration and checks the candidate file.

Referenced in source (1)

_MeshRequestHandler

Map viewer URLs to static, URDF, and package files. Filesystem containment checks keep requests within the configured roots.

Inherits from: SimpleHTTPRequestHandler.

_MeshRequestHandler.__init__()

Attach viewer route roots before the standard HTTP request handler processes a request.

Lifecycle · Source

__init__(self, *args, package_map, resources_dir, urdf_dir, **kwargs)

Parameter

Meaning

args

Positional SimpleHTTPRequestHandler arguments, normally request socket, client address, and server.

package_map

Mapping of ROS package names to share/source directories.

resources_dir

Root for viewer HTML/JavaScript/static files.

urdf_dir

Root for configured robot URDF files.

kwargs

Keyword arguments forwarded to SimpleHTTPRequestHandler.

Errors: Standard HTTP-handler and filesystem errors follow base-class behavior.

Side effects: Stores routing roots and delegates request handling to SimpleHTTPRequestHandler.

Internal callbacks and helpers

_MeshRequestHandler.translate_path()

Decode the URL path and route static, URDF, or package requests through containment-checked filesystem resolution.

Callback · Source

translate_path(self, path)

Parameter

Meaning

path

HTTP request URL/path; query and fragment are removed via urlsplit and percent escapes decoded once.

Returns: Filesystem path string. /static/ uses resources_dir, /urdf/ uses urdf_dir, known /package/… uses package_map; all other paths fall back under resources_dir.

Errors: URL/path errors propagate; traversal is redirected by _resolve_under rather than explicitly raising an HTTP error.

Side effects: Resolves filesystem paths; does not itself open the response file.

_MeshRequestHandler._resolve_under()

Resolve a relative path and prevent it from escaping its resolved root, including through symlinks.

Internal helper · Source

@staticmethod
_resolve_under(root, relative)

Parameter

Meaning

root

Allowed filesystem directory.

relative

Path component interpreted beneath root; may contain traversal components that are checked after resolution.

Returns: Resolved candidate path string when contained, otherwise root/.beambot-path-denied.

Errors: Path-resolution errors propagate; denial uses a sentinel filename and does not itself guarantee that filename is absent.

Side effects: Performs path resolution only.

Referenced in source (1)

_MeshRequestHandler.end_headers()

Attach a one-hour public cache directive to every HTTP response before finishing headers.

Callback · Source

end_headers(self)

Returns: None.

Errors: HTTP header/output failures from send_header or the base end_headers propagate; no local exception handler.

Side effects: Sends Cache-Control: public, max-age=3600 and delegates to the base end_headers.

_MeshRequestHandler.log_message()

Suppress the standard HTTP request-log output.

Callback · Source

log_message(self, format, *args)

Parameter

Meaning

format

Ignored logging format string supplied by the HTTP handler.

args

Ignored formatting arguments.

Returns: None.

Errors: No validation or error handling.

Side effects: None; deliberately emits no request logs.

_MeshServer

Serve local viewer files and robot meshes on an ephemeral loopback port. VisualizationPanel starts and stops its daemon thread.

_MeshServer.__init__()

Bind the viewer’s HTTP server to an ephemeral loopback port.

Lifecycle · Source

__init__(self, package_map, resources_dir, urdf_dir)

Parameter

Meaning

package_map

Package route mapping passed to each request handler.

resources_dir

Viewer static-resource root.

urdf_dir

Robot URDF root.

Errors: Bind/server construction failures propagate.

Side effects: Opens an HTTP listening socket at 127.0.0.1:0, records the assigned port, and creates but does not start the serving thread.

Referenced in source (1)

_MeshServer.start()

Start the prepared daemon HTTP-serving thread.

Lifecycle · Source

start(self)

Returns: None.

Errors: Thread errors propagate; repeated starts are not guarded.

Side effects: Begins serving viewer/URDF/mesh resources over loopback.

_MeshServer.stop()

Shut down serving, close the listening socket, and join the worker for up to one second.

Lifecycle · Source

stop(self)

Returns: None.

Errors: Server/thread errors propagate; this assumes serve_forever was started.

Side effects: Stops HTTP service and closes its socket.