This document provides a detailed technical overview of the Arm Feed Subsystem for the rover - Orbitron built by Team Qbotix Rover, developed for the International Rover Challenge 2026.
The Arm Feed subsystem is a real-time video streaming solution designed to transmit live video from two cameras mounted on the rover's robotic arm to the base station. This provides operators with crucial visual feedback for manipulation tasks, sample collection, and navigating complex terrain.
The system is architected for low-latency, high-framerate streaming over a standard IP network, using WebRTC as its core communication protocol. It consists of two main components: a Python-based server running on the rover's onboard computer (Raspberry Pi) and a web-based client viewer on the base station.
The architecture is a simple client-server model:
- Edge Device (Server): A Raspberry Pi connected to two USB cameras. It runs a Python script that captures the video feeds and hosts a WebRTC signaling server.
- Base Station (Client): Any computer with a modern web browser. It hosts a simple HTML page that acts as the video receiver and player.
+---------------------------------+ +---------------------------------+
| Rover (Raspberry Pi) | | Base Station (Computer) |
| | | |
| +-----------+ +-----------+ | | |
| | USB Cam 1 | | USB Cam 2 | | | |
| +-----+-----+ +-----+-----+ | | |
| | | | | |
| v v | | |
| +-------------------------+ | | +----------------------+ |
| | sender_armfeed.py | | | | armfeed.html | |
| |(OpenCV, aiohttp, aiortc)| ----TCP/IP----> |(Browser, WebRTC JS) | |
| +-------------------------+ | | +----------------------+ |
| | | |
+---------------------------------+ +---------------------------------+
- Camera frames captured via OpenCV.
- Frames converted to a WebRTC-compatible format using PyAV.
- SDP offer/answer metadata is exchanged between client and server via HTTP.
- A direct peer-to-peer connection is established.
- Video tracks are streamed directly to the browser and rendered.
- Initialization: The
sender_armfeed.pyscript starts on the Raspberry Pi. It initializes two separate camera capture loops using OpenCV and starts anaiohttpweb server. - Signaling: The operator on the base station opens
armfeed.html. Clicking "Stream" triggers a JavaScript function that creates a WebRTC "offer". This offer, containing session description protocol (SDP) information, is sent via an HTTP POST request to the/offerendpoint on the Python server. - Negotiation: The Python server receives the offer, generates a corresponding WebRTC "answer", and sends it back to the client. This handshake establishes a direct peer-to-peer connection between the browser and the Python script.
- Streaming: Once the connection is established, the Python script continuously grabs frames from the cameras, converts them, and streams them directly to the browser via the established WebRTC
PeerConnection. - Display: The browser receives the two separate video tracks and renders them in their respective
<video>elements on the HTML page.
- Dual Camera Support: Streams two camera feeds simultaneously.
- Low Latency: Utilizes WebRTC for near real-time video transmission.
- Robust Reconnection: If a camera feed is lost, the script initiates a retry loop, attempting to reconnect every 30 seconds without halting the other active stream.
- Bandwidth Management: Includes server-side logic to limit the stream bitrate, preventing network congestion.
- Web-Based Client: Requires no special software on the base station besides a standard web browser.
- High Compatibility: Based on standard web technologies (Python, asyncio, JS).
-
Server-Side (Edge Device):
- Language: Python 3
- Libraries:
opencv-python: For capturing video from USB cameras.aiohttp: Asynchronous web server for signaling.aiortc: Python implementation of WebRTC.numpy: For numerical operations on video frames.av: For video frame format conversion (PyAV).
-
Client-Side (Base Station):
- HTML5
- CSS3
- JavaScript (with the native
RTCPeerConnectionAPI)
- WebRTC over RTSP/HTTP Streaming: Chosen for its low-latency, peer-to-peer communication and native browser support, which eliminates the need for special client software.
- aiortc (Python) over native C++: Enables rapid development and seamless integration with Python-based computer vision pipelines.
- aiohttp for Signaling: A lightweight asynchronous server is sufficient for the SDP exchange and avoids introducing heavier frameworks.
- Dual Independent Camera Loops: This design prevents the entire capture process from blocking and ensures that the failure of one camera does not halt the stream from the other.
sender_armfeed.py: Handles camera capture, WebRTC negotiation, and the streaming pipeline.- Camera Capture Loops: Independent
asynciotasks for main and side cameras using OpenCV. - WebRTC Signaling Endpoint (
/offer): Anaiohttproute that handles the SDP exchange between client and server. armfeed.html: The browser-based viewer that handles the client-side WebRTC connection and renders the incoming video streams.
The server operates on a non-blocking, asynchronous model powered by asyncio.
- Concurrent Capture: Each camera runs in an independent
asynccapture loop (arm_cam_grab_loop). This prevents a slow or disconnected camera from blocking the main thread or the other camera's feed. - Frame Buffering & Handling: The most recent frame from each camera is stored in a global variable, acting as a simple in-memory buffer. When the WebRTC track handler (
.recv()) is ready for a new frame, it pulls the latest one from this buffer. - Frame Conversion: The
aiortclibrary does not natively consume OpenCV's NumPy frame format. Therefore, each frame is first converted to a PyAVVideoFrameobject (av.VideoFrame.from_ndarray) before being passed to the WebRTC stack. - Integrated Event Loop: The
aiohttpweb server andaiortcpeer connections all run on the sameasyncioevent loop. This allows the application to efficiently manage both HTTP signaling and WebRTC streaming concurrently within a single thread.
- Prerequisites: Ensure Python 3 and
pipare installed. - Install Dependencies:
pip install opencv-python aiohttp aiortc numpy av
- Configuration:
- Open
sender_armfeed.pyin a text editor. - Adjust
ARM_MAIN_CAM_INDEXandARM_SIDE_CAM_INDEXto match your system's camera setup (e.g., found vials /dev/video*on Linux). - (Optional) Modify the
HOSTandPORT. The default0.0.0.0allows connections from any IP on the network.
- Open
- Run the Server:
python sender_armfeed.py
- Prerequisites: A modern web browser (Chrome, Firefox, Edge).
- Configuration:
- Open
armfeed.htmlin a text editor. - Modify the
ARM_SERVER_URLconstant to match the IP address and port of your Raspberry Pi.
const ARM_SERVER_URL = "http://<YOUR_RASPBERRY_PI_IP>:8080";
- Open
- Launch the Viewer:
- Open the modified
armfeed.htmlfile in your browser. - Click "Stream" to start the video feeds.
- Open the modified
- Latency: Typically sub-second under stable local network conditions.
- Bandwidth: ~2–4 Mbps for dual 480p streams, depending on bitrate settings.
- Scalability: Designed for a single client. Multiple simultaneous clients will increase CPU and bandwidth usage significantly.
- Single-Client Focus: The system is not optimized for multiple concurrent viewers.
- Network Dependent: Performance is highly sensitive to network stability and bandwidth.
- Basic Security: The implementation does not include authentication or authorization layers beyond the default security provided by WebRTC (DTLS-SRTP).
- Hardware Constraints: Stream resolution and framerate are limited by the Raspberry Pi's processing power.
- No video appears:
- Verify the
ARM_SERVER_URLinarmfeed.htmlis correct and that the Raspberry Pi is reachable (ping <YOUR_RASPBERRY_PI_IP>). - Check the browser's developer console (F12) for JavaScript or WebRTC connection errors.
- Check the console output of
sender_armfeed.pyfor camera initialization errors.
- Verify the
- "Failed to open camera" error:
- Ensure the camera indices in the Python script are correct.
- Verify the cameras are properly connected and not in use by another application.
- Video is choppy or lagging:
- Ensure a strong, stable network connection (Ethernet is preferred over Wi-Fi).
- Consider lowering the
ARM_CAM_TARGET_FPSor resolution constants in the Python script to reduce bandwidth requirements.