Replaces manual H264/TCP stereo streaming with NVIDIA CloudXR for
higher-quality stereoscopic rendering and lower latency.
Changes:
- teleop_xr_agent.py: add --cloudxr flag (enables Isaac Sim XR mode,
disables manual StreamingManager)
- deps/cloudxr/: NVIDIA CloudXR.js SDK (Early Access) with Isaac Lab
teleop React web client
- deps/cloudxr/Dockerfile.wss.proxy: HAProxy WSS proxy for PICO 4 Ultra
HTTPS mode (routes wss://48322 → ws://49100)
- deps/cloudxr/isaac/webpack.dev.js: disable file watching to avoid
EMFILE errors with large node_modules
- deps/cloudxr/INSTALL.md: full setup guide
Usage:
# Start CloudXR Runtime + Isaac Lab
cd ~/IsaacLab && ./docker/container.py start \
--files docker-compose.cloudxr-runtime.patch.yaml \
--env-file .env.cloudxr-runtime
# Run teleop with CloudXR
~/IsaacLab/isaaclab.sh -p teleop_xr_agent.py \
--task Isaac-MindRobot-2i-DualArm-IK-Abs-v0 --cloudxr
# Serve web client
cd deps/cloudxr/isaac && npm run dev-server:https
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
export function getOrCreateCanvas(
|
|
id: string,
|
|
resolution?: { width: number; height: number }
|
|
): HTMLCanvasElement {
|
|
let canvas = document.getElementById(id) as HTMLCanvasElement | null;
|
|
if (!canvas) {
|
|
canvas = document.createElement('canvas') as HTMLCanvasElement;
|
|
canvas.id = id;
|
|
// canvas.style.display = "none";
|
|
document.body.appendChild(canvas);
|
|
}
|
|
if (!canvas) {
|
|
throw new Error('Failed to create canvas');
|
|
}
|
|
if (resolution) {
|
|
canvas.width = resolution.width;
|
|
canvas.height = resolution.height;
|
|
}
|
|
return canvas;
|
|
}
|
|
|
|
export function logOrThrow(tagString: string, gl: WebGL2RenderingContext) {
|
|
const err = gl.getError();
|
|
if (err !== gl.NO_ERROR) {
|
|
let errorString;
|
|
switch (err) {
|
|
case gl.INVALID_ENUM:
|
|
errorString = 'INVALID_ENUM';
|
|
break;
|
|
case gl.INVALID_VALUE:
|
|
errorString = 'INVALID_VALUE';
|
|
break;
|
|
case gl.INVALID_OPERATION:
|
|
errorString = 'INVALID_OPERATION';
|
|
break;
|
|
case gl.INVALID_FRAMEBUFFER_OPERATION:
|
|
errorString = 'INVALID_FRAMEBUFFER_OPERATION';
|
|
break;
|
|
case gl.OUT_OF_MEMORY:
|
|
errorString = 'OUT_OF_MEMORY';
|
|
break;
|
|
case gl.CONTEXT_LOST_WEBGL:
|
|
errorString = 'CONTEXT_LOST_WEBGL';
|
|
break;
|
|
default:
|
|
errorString = 'UNKNOWN_ERROR';
|
|
break;
|
|
}
|
|
|
|
throw new Error('WebGL error: ' + tagString + ': ' + errorString + ' (' + err + ')');
|
|
} else {
|
|
console.debug('WebGL no-error: ' + tagString);
|
|
}
|
|
}
|