$npx -y skills add arpitg1304/robotics-agent-skills --skill ros2-web-integrationPatterns and best practices for integrating ROS2 systems with web technologies including REST APIs, WebSocket bridges, and browser-based robot interfaces. Use this skill when building web dashboards for robots, streaming camera feeds to browsers, exposing ROS2 services as REST en
| 1 | # ROS2 Web Integration Skill |
| 2 | |
| 3 | ## When to Use This Skill |
| 4 | - Building a web dashboard to monitor or control a robot running ROS2 |
| 5 | - Streaming camera feeds (MJPEG, WebRTC, compressed WebSocket) from a robot to a browser |
| 6 | - Exposing ROS2 services and actions as REST API endpoints |
| 7 | - Implementing bidirectional WebSocket communication between a web UI and ROS2 nodes |
| 8 | - Setting up rosbridge_suite for quick prototyping or foxglove integration |
| 9 | - Writing a custom FastAPI or Flask bridge to ROS2 for production deployments |
| 10 | - Adding authentication, rate limiting, or CORS to robot web interfaces |
| 11 | - Running an async web server (uvicorn) alongside the rclpy executor without deadlocks |
| 12 | - Publishing teleop commands from a browser joystick to cmd_vel |
| 13 | - Serving ROS2 parameter configuration pages or diagnostic dashboards over HTTP |
| 14 | |
| 15 | ## Architecture Overview |
| 16 | |
| 17 | ### Comparison Table |
| 18 | |
| 19 | | Feature | rosbridge_suite | Custom FastAPI Bridge | Custom Flask Bridge | |
| 20 | |---|---|---|---| |
| 21 | | Latency | ~5-15ms (WebSocket) | ~2-5ms (WebSocket), ~10-30ms (REST) | ~10-50ms (REST only without extensions) | |
| 22 | | Throughput | Medium (JSON serialization overhead) | High (binary WebSocket, async) | Low-Medium (sync, GIL-bound) | |
| 23 | | Auth | Basic (rosauth, limited) | Full (JWT, OAuth2, API keys) | Full (Flask-Login, JWT) | |
| 24 | | Complexity | Low (launch and connect) | Medium (must manage two event loops) | Medium (must manage threading) | |
| 25 | | Video Streaming | Requires separate web_video_server | Native (MJPEG, WebSocket binary) | MJPEG via generator responses | |
| 26 | | Production Ready | No (exposes full topic graph) | Yes | Yes (with gunicorn) | |
| 27 | | When to Use | Prototyping, foxglove, quick demos | Production APIs, high-perf streaming | Simple internal tools, legacy systems | |
| 28 | |
| 29 | ### When to Use rosbridge vs Custom Bridge |
| 30 | |
| 31 | Use **rosbridge_suite** when: |
| 32 | - You need a working bridge in under 10 minutes |
| 33 | - The client is foxglove, webviz, or another rosbridge-aware tool |
| 34 | - Security is not a concern (local network, demo environment) |
| 35 | - You do not need custom business logic between web and ROS2 |
| 36 | |
| 37 | Use a **custom bridge** (FastAPI/Flask) when: |
| 38 | - You need authentication, authorization, or rate limiting |
| 39 | - You want to expose only specific topics/services (not the entire ROS2 graph) |
| 40 | - You need to transform or aggregate data before sending to the client |
| 41 | - You need REST endpoints for integration with non-WebSocket clients |
| 42 | - You are streaming video and need control over encoding and quality |
| 43 | - The system is deployed in production or on a public network |
| 44 | |
| 45 | ## Pattern 1: rosbridge_suite |
| 46 | |
| 47 | ### Installation and Launch |
| 48 | |
| 49 | ```bash |
| 50 | # Install rosbridge_suite |
| 51 | sudo apt install ros-${ROS_DISTRO}-rosbridge-suite |
| 52 | |
| 53 | # Launch with default settings (port 9090) |
| 54 | ros2 launch rosbridge_server rosbridge_websocket_launch.xml |
| 55 | |
| 56 | # Launch with custom port and SSL |
| 57 | ros2 launch rosbridge_server rosbridge_websocket_launch.xml \ |
| 58 | port:=9091 \ |
| 59 | ssl:=true \ |
| 60 | certfile:=/etc/ssl/certs/robot.pem \ |
| 61 | keyfile:=/etc/ssl/private/robot.key |
| 62 | |
| 63 | # Launch with authentication (rosauth) |
| 64 | ros2 launch rosbridge_server rosbridge_websocket_launch.xml \ |
| 65 | authenticate:=true |
| 66 | ``` |
| 67 | |
| 68 | ### JavaScript Client (roslibjs) |
| 69 | |
| 70 | ```javascript |
| 71 | // Connect to rosbridge WebSocket |
| 72 | const ros = new ROSLIB.Ros({ url: 'ws://robot-host:9090' }); |
| 73 | |
| 74 | ros.on('connection', () => console.log('Connected to rosbridge')); |
| 75 | ros.on('error', (err) => console.error('Connection error:', err)); |
| 76 | ros.on('close', () => console.log('Connection closed')); |
| 77 | |
| 78 | // Subscribe to compressed camera images |
| 79 | const imageTopic = new ROSLIB.Topic({ |
| 80 | ros: ros, |
| 81 | name: '/camera/image/compressed', |
| 82 | messageType: 'sensor_msgs/msg/CompressedImage', |
| 83 | // Throttle to 10 Hz to avoid flooding the browser |
| 84 | throttle_rate: 100, |
| 85 | // Queue size of 1 — drop stale frames |
| 86 | queue_size: 1 |
| 87 | }); |
| 88 | |
| 89 | imageTopic.subscribe((msg) => { |
| 90 | // msg.data is base64-encoded JPEG |
| 91 | const imgElement = document.getElementById('camera-feed'); |
| 92 | imgElement.src = 'data:image/jpeg;base64,' + msg.data; |
| 93 | }); |
| 94 | |
| 95 | // C |