Skip to content

Latest commit

Β 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

X19-Core: Purdue ROV ZeroMQ & Protobuf System

This repository hosts the core communication, sensing, and control architecture for the Purdue ROV X-19 underwater vehicle. The system uses ZeroMQ (ZMQ) for low-latency inter-process communication and Protocol Buffers (Protobuf) for type-safe, cross-language serialization (C++ and Python).


πŸ“‚ Codebase Directory Layout

X19-Core/
β”œβ”€β”€ config/                  # Configuration files (ports, address bindings)
β”œβ”€β”€ launch.sh                # Bare-bones node launcher script (no tmux)
β”œβ”€β”€ launch.yaml              # Declarative node configuration
β”œβ”€β”€ src/                    # Communication wrappers & middleware
β”‚   β”œβ”€β”€ cpp/                 # C++ wrapper library
β”‚   └── python/              # Python wrapper library (python.messaging package)
β”‚       └── messaging/
β”‚           β”œβ”€β”€ publisher.py
β”‚           └── subscriber.py
β”œβ”€β”€ nodes/                   # Independent executable nodes
β”‚   β”œβ”€β”€ cpp/                 # C++ nodes (thrusters, pid controls, etc.)
β”‚   └── python/              # Python nodes (video, pilot control, etc.)
β”œβ”€β”€ proto/                   # Protobuf message schemas
β”œβ”€β”€ scripts/                 # Utility scripts (setup, compilation, launch runner)
β”‚   β”œβ”€β”€ compile_protos.sh    # Protobuf schema compiler
β”‚   β”œβ”€β”€ launch.py            # Lightweight YAML process runner
β”‚   └── setup.sh             # System dependency provisioner
β”œβ”€β”€ testing/                 # Validation and testing scripts
β”œβ”€β”€ run.sh                   # Test runner shortcut script
└── MVPs.md                  # Development checklist & milestones

βš™οΈ Setup & Installation

1. System & Python Dependencies

Prerequisites include the Protobuf Compiler (protoc), ZeroMQ development headers, and Python 3.

Run the automated setup script to provision your system:

./scripts/setup.sh

(This installs protobuf-compiler and libzmq3-dev via apt-get, and builds the Python dependencies defined in requirements.txt into your virtual environment).

2. Compile Protobuf Schemas

Compile your .proto files in the proto/ directory to generate C++ and Python bindings:

./scripts/compile_protos.sh

This outputs compiled bindings directly to src/protocols/cpp and src/protocols/python.


πŸš€ Running the Code

1. Multi-Node Launcher (launch.sh & launch.yaml)

To launch all vehicle nodes on the Raspberry Pi without tmux:

# 1. Launch with default surface address (192.168.1.7:5556)
./launch.sh

# 2. Launch with a specific Surface laptop IP address
./launch.sh -i 192.168.1.100

# 3. View options
./launch.sh --help

How the Launch Workflow Operates:

  1. Dependency Verification: launch.sh verifies that python3 and pyyaml are installed. If missing, it alerts you with instructions to install them via pip install -r requirements.txt.
  2. Environment & IP Setup: Formats the Surface IP into tcp://<IP>:5556 and exports SURFACE_ZMQ_ADDRESS.
  3. Execution: Hands off launch.yaml to scripts/launch.py, which starts each defined node in the background and tags console logs with node labels (e.g. [videos]).
  4. Graceful Cleanup: Pressing Ctrl+C cleanly shuts down all nodes and terminates any spawned child processes (e.g., ffmpeg camera streams).

Adding Future Nodes:

To add new nodes (e.g. thrusters, telemetry), simply add their entry to launch.yaml:

nodes:
  - name: "videos"
    cmd: "python3 src/python/videos/get_ip.py"

  # Future nodes:
  - name: "thrusters"
    cmd: "python3 src/python/thrusters/thruster_node.py"

2. Standalone Test Scripts (run.sh)

Use the root run.sh script to execute standalone test scripts:

# Run the hello_pub test node
./run.sh

# Recompile protobuf schemas AND run the hello_pub test node
./run.sh -p

πŸ› οΈ Messaging Wrapper API

To make writing nodes simple and robust, lightweight wrappers wrap ZMQ sockets into easy-to-use classes.

Python API

1. Publisher (python.messaging.Publisher)

Creates a ZMQ PUB socket that serializes and publishes Protobuf messages on a specific topic.

from src.python.messaging import Publisher
from src.protocols.python import telemetry_pb2

# Initialize publisher (binds to address by default)
publisher = Publisher(address="tcp://127.0.0.1:5555", topic="telemetry")

# Create and publish a Protobuf message
msg = telemetry_pb2.SensorData(depth=1.24)
publisher.publish(msg)

# Clean up
publisher.close()
  • __init__(address: str, topic: str, bind: bool = True)
    • address: ZMQ address endpoint (e.g., tcp://*:5555).
    • topic: Topic name string.
    • bind: Binds socket to the port if True; connects if False.
  • publish(proto_message)
    • Serializes the Protobuf class instance and publishes it.
  • close()
    • Closes the underlying ZMQ socket.

2. Subscriber (core.messaging.Subscriber)

Creates a ZMQ SUB socket that connects to a publisher, subscribes to a topic, and parses incoming Protobuf payloads.

from src.python.messaging import Subscriber
from src.protocols.python import telemetry_pb2

def telemetry_callback(data):
    print(f"Received depth: {data.depth}")

# Initialize subscriber (connects to address by default)
subscriber = Subscriber(
    address="tcp://127.0.0.1:5555",
    topic="telemetry",
    message_type=telemetry_pb2.SensorData,
    callback=telemetry_callback
)

# Process a single incoming message (timeout in milliseconds)
subscriber.spin_once(timeout_ms=100)

# Clean up
subscriber.close()
  • __init__(address: str, topic: str, message_type, callback, bind: bool = False)
    • address: Target publisher endpoint (e.g., tcp://127.0.0.1:5555).
    • topic: Subscribed topic string.
    • message_type: Protobuf class type used to deserialize payloads.
    • callback: Callback function signature def callback(message).
    • bind: Binds socket if True; connects if False.
  • spin_once(timeout_ms: int)
    • Polls the socket. If data is available, it deserializes the payload and invokes the callback. Returns True if processed, otherwise False.
  • close()
    • Closes the underlying ZMQ socket.

3. Running The Code

  • set python path to dir root
export PYTHONPATH=<project_root>
  • run publisher using virtual env first
./.venv/bin/python ./testing/hello_pub.py 
  • run subscriber using virtual env next
./.venv/bin/python ./testing/hello_sub.py 

πŸ“Ή Video Streaming & ZMQ IP Discovery

X19-Core contains the camera acquisition and low-latency H.264 RTSP streaming pipeline for the ROV cameras.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   X19-Core Video Subsystem                       β”‚
β”‚                                                                  β”‚
β”‚  1. get_ip.py (ZMQ Subscriber on port 5556)                      β”‚
β”‚     - Connects to tcp://<SURFACE_IP>:5556 on topic 'surface_ip'  β”‚
β”‚     - Deserializes Protobuf payload: telemetry_pb2.test(msg=ip)  β”‚
β”‚                                                                  β”‚
β”‚  2. V4L2 Device Auto-Discovery                                   β”‚
β”‚     - Runs 'v4l2-ctl --list-devices'                             β”‚
β”‚     - Detects attached exploreHD / Arducam / Intel cameras       β”‚
β”‚                                                                  β”‚
β”‚  3. FFmpeg RTSP Streamers (videos_launch.py)                     β”‚
β”‚     - Spawns background FFmpeg process for each camera           β”‚
β”‚     - Encodes H.264 / MJPEG video with zerolatency preset        β”‚
β”‚     - Pushes RTSP stream to rtsp://<SURFACE_IP>:8554/camera<N>   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Video Nodes in src/python/videos/:

  • get_ip.py: ZMQ subscriber node listening for Surface IP broadcast. Once IP is received, triggers camera discovery and starts streaming processes.
  • videos_launch.py: Low-latency FFmpeg RTSP camera streamer node (--ip, --device, --camera-number).
  • cv_camera_connect.py: DepthAI camera RTSP streamer node for OAK/DepthAI hardware.

🌐 Network Ports & Field Deployment Guide

When running on the Raspberry Pi connected to the Surface Topside Laptop via Ethernet/tether network:

Port Protocol Target Node Purpose
5555 ZMQ (TCP) Surface Telemetry Receives telemetry packets on topic telemetry
5556 ZMQ (TCP) Surface IP Publisher Receives Surface IP broadcast on topic surface_ip
8554 RTSP (TCP) Go2RTC Server Pushes RTSP camera streams to Surface media server

Running on Raspberry Pi (Hardware Network Setup):

  1. On Surface Topside Laptop: Start go2rtc_node.py (or run ./launch --field in X19-Surface). Note the Surface laptop IP address (e.g. 192.168.1.100).
  2. On Raspberry Pi (X19-Core): Launch all vehicle nodes pointing to the Surface laptop's IP address:
    ./launch.sh -i 192.168.1.100
    (This automatically forwards the Surface address to get_ip.py, discovers local cameras, and streams RTSP video back to the Surface computer).

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages