Webcam: Publish Live Video with BabyROS
SUMMARY
Stream live video using BabyROS as the communication layer. Two scripts share responsibility: a camera server that owns the hardware connection, and a client that controls streaming remotely via BabyROS topics.
Example
The camera server (camera_loop.py) runs in Terminal 1 — it connects to the hardware and keeps BabyROS nodes alive. The client (publish_video_example.py) runs in Terminal 2 — it publishes a start signal, subscribes to the video topic to receive and log frames to Rerun, then publishes a stop signal after 10 seconds.
Code
Terminal 1 — Camera Server:
"""
Camera loop for the Webcam.
"""
import time
from loguru import logger
from babyros import node
from medulla.cameras import webcam
def main():
camera = None
try:
camera = webcam.Webcam(
name="my_webcam",
camera_id=0
)
camera.connect()
logger.info("Camera Server is running... Press Ctrl+C to stop.")
while True:
time.sleep(1)
except KeyboardInterrupt:
logger.info("Shutting down server...")
finally:
if camera is not None:
camera.disconnect()
node.SessionManager.delete()
logger.info("Completed cleanup.")
if __name__ == "__main__":
main()Terminal 2 — BabyROS Client:
"""
A simple example demonstrating how to use the webcam camera with BabyROS to
stream live video.
Please run this example from a terminal to avoid issues with rerun's spawn mode.
"""
import time
from loguru import logger
import rerun as rr
import numpy as np
from babyros import node
def log_video(image: np.ndarray) -> None:
rr.log(
"Continuous_Image_Capture",
rr.Image(image)
)
def main():
rr.init("Webcam_Example", spawn=True)
name = "my_webcam"
base_topic = f"medulla/v1/camera/webcam/{name}"
start_video_stream_publisher = node.Publisher(
topic=f"{base_topic}/start_video_stream"
)
stop_video_stream_publisher = node.Publisher(
topic=f"{base_topic}/stop_video_stream"
)
video_subscriber = node.Subscriber(
topic=f"{base_topic}/video",
callback=log_video,
)
try:
start_video_stream_publisher.publish(data={})
time.sleep(10)
stop_video_stream_publisher.publish(data={})
except KeyboardInterrupt:
logger.info("Shutting down.")
finally:
start_video_stream_publisher.delete()
stop_video_stream_publisher.delete()
video_subscriber.delete()
node.SessionManager.delete()
logger.info("Completed cleanup.")
if __name__ == "__main__":
main()Explanation
Now, let's break down the code piece by piece.
Camera Server (camera_loop.py)
The server creates a Webcam instance and connects to the hardware. After connecting, it enters an infinite sleep loop — this does nothing except keep the process, and the BabyROS nodes registered inside the Webcam instance, alive and reachable by remote clients.
camera = webcam.Webcam(
name="my_webcam",
camera_id=0
)
camera.connect()
while True:
time.sleep(1)On Ctrl+C, the finally block disconnects the camera and calls node.SessionManager.delete() to cleanly tear down the BabyROS session.
finally:
if camera is not None:
camera.disconnect()
node.SessionManager.delete()BabyROS Client (publish_video_example.py)
The client never accesses the camera hardware directly. Instead it constructs three BabyROS nodes whose topic paths mirror those registered by the Webcam instance in the server process. The name variable must exactly match the name passed to Webcam in the server, because both sides derive their topic paths from it.
name = "my_webcam"
base_topic = f"medulla/v1/camera/webcam/{name}"
start_video_stream_publisher = node.Publisher(topic=f"{base_topic}/start_video_stream")
stop_video_stream_publisher = node.Publisher(topic=f"{base_topic}/stop_video_stream")
video_subscriber = node.Subscriber(topic=f"{base_topic}/video", callback=log_video)Publishing an empty payload to start_video_stream signals the server to begin continuous acquisition. The server pushes each incoming frame as a raw NumPy array onto the video topic. Each frame arrives in the log_video callback and is forwarded directly to Rerun using rr.Image. After 10 seconds, publishing to stop_video_stream halts acquisition on the server side.
start_video_stream_publisher.publish(data={})
time.sleep(10)
stop_video_stream_publisher.publish(data={})The finally block deletes all three nodes and closes the BabyROS session regardless of how the script exits.
finally:
start_video_stream_publisher.delete()
stop_video_stream_publisher.delete()
video_subscriber.delete()
node.SessionManager.delete()Run
Start the server first, then the client. Both must run from a terminal.
Terminal 1:
python camera_loop.pyWait for Camera Server is running... Press Ctrl+C to stop., then:
Terminal 2:
python publish_video_example.pyFrames stream under Continuous_Image_Capture for 10 seconds. Press Ctrl+C in Terminal 1 to shut down the server.

