Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Camera Streaming: Raspberry Pi 5 → Laptop

License: MIT

A lightweight TCP-based camera streaming framework for transmitting video from a Raspberry Pi 5 (Pi Camera or USB Webcam) to a laptop for real-time computer vision applications.

The Raspberry Pi is responsible only for image acquisition and transmission. All image processing, object detection, tracking, visual servoing, and control algorithms are executed on the laptop.


Repository Structure

Camera_streaming_rpi/
├── camera.py
├── capture_rpi.py
├── README.md
└── stream.py

Files

camera.py

Camera abstraction layer.

Supported camera sources:

  • Raspberry Pi Camera Module (Picamera2)
  • USB Webcam

The class automatically selects the available camera source and provides a unified OpenCV-compatible interface.

stream.py

Streaming server running on the Raspberry Pi.

Responsibilities:

  • Acquire frames from the camera
  • JPEG compress frames
  • Stream frames through a TCP socket

capture_rpi.py

Streaming client running on the laptop.

Responsibilities:

  • Wait for Raspberry Pi connectivity
  • Launch stream.py remotely through SSH
  • Connect to the streaming server
  • Receive and decode image frames
  • Display the live video stream

System Architecture

Raspberry Pi Camera / USB Webcam
                │
                ▼
          camera.py
                │
                ▼
          stream.py
                │
           TCP Socket
                │
        Ethernet Link
                │
                ▼
        capture_rpi.py
                │
                ▼
      OpenCV / Tracking /
      Detection Pipeline

The Raspberry Pi performs only image acquisition and transmission.

All image processing is performed on the laptop.


Requirements

Raspberry Pi

  • Raspberry Pi 5
  • Raspberry Pi OS or Ubuntu 24.04
  • Raspberry Pi Camera Module or USB Webcam

Laptop

  • Linux system
  • Python 3
  • OpenCV
  • NumPy

Installation

Clone the repository on both systems:

git clone <repository-url>

Install Python dependencies:

pip install opencv-python numpy

For Raspberry Pi Camera support:

pip install picamera2

Network Configuration

This project have two network configuration

  1. Over the ethernet streaming
  2. Wireless using Rpi as Access point

This project assumes a direct Ethernet connection between the Raspberry Pi and the laptop.

Over the ethernet method

Laptop <------ Ethernet ------> Raspberry Pi 5

Static IPv4 Configuration

The following IP addresses are used throughout the project:

Laptop IP      : 192.168.10.1
Raspberry Pi IP: 192.168.10.2
Subnet Mask    : 255.255.255.0
Port           : 9999

Raspberry Pi Configuration

This project uses a static IPv4 address on the Raspberry Pi Ethernet interface.

Before configuring a static address, verify that there are no conflicting network configurations generated by cloud-init or NetworkManager.

Check Existing Network Configuration

List all Netplan configuration files:

ls -l /etc/netplan/

Display all Netplan configuration contents:

sudo grep -R . /etc/netplan/

Ubuntu Desktop installations may contain multiple Netplan files generated by:

  • NetworkManager
  • cloud-init
  • Desktop networking tools

Conflicting configurations can cause:

  • SSH sessions to freeze
  • Ethernet disconnects
  • NetworkManager reconnect loops
  • Loss of communication between laptop and Raspberry Pi

Disable Conflicting cloud-init Configuration

If a file such as:

/etc/netplan/50-cloud-init.yaml

contains an Ethernet configuration for eth0, disable it:

sudo mv /etc/netplan/50-cloud-init.yaml \
/etc/netplan/50-cloud-init.yaml.bak

Prevent cloud-init from recreating network configurations:

sudo mkdir -p /etc/cloud/cloud.cfg.d

echo "network: {config: disabled}" | \
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg

Configure Static Ethernet Address

Create a dedicated Netplan configuration:

sudo nano /etc/netplan/10-eth0-static.yaml

Contents:

network:
  version: 2
  renderer: NetworkManager

  ethernets:
    eth0:
      dhcp4: false
      dhcp6: false
      addresses:
        - 192.168.10.2/24

Apply the configuration:

sudo netplan generate
sudo netplan apply

Verify:

ip addr show eth0

Expected:

inet 192.168.10.2/24

Verify Final Netplan Configuration

Display the merged Netplan configuration:

sudo netplan get

Ensure that eth0 appears only once and contains:

eth0:
  dhcp4: false
  dhcp6: false
  addresses:
    - 192.168.10.2/24

Do not mix:

dhcp4: true

and

dhcp4: false

for the same Ethernet interface.


Laptop Configuration

Identify the Ethernet interface:

ip link

Typical Ethernet interface names:

eno1
enp3s0
enp88s0
eth0

Assign a static IPv4 address:

sudo ip addr add 192.168.10.1/24 dev <ethernet_interface>

Example:

sudo ip addr add 192.168.10.1/24 dev enp88s0

Verify:

ip addr show <ethernet_interface>

Expected:

inet 192.168.10.1/24

Connectivity Test

From the laptop:

ping 192.168.10.2

From the Raspberry Pi:

ping 192.168.10.1

Successful communication confirms that the Ethernet link is correctly configured.


Troubleshooting

SSH Session Freezes

If SSH becomes unresponsive, verify that the Raspberry Pi is still reachable:

ping 192.168.10.2

If the ping fails, inspect NetworkManager logs:

journalctl -u NetworkManager -b

Look for messages similar to:

dhcp4 (eth0): canceled DHCP transaction
policy: auto-activating connection

These messages usually indicate conflicting Ethernet configurations.


Check Active Ethernet Configuration

Display the active address:

ip addr show eth0

Display the merged Netplan configuration:

sudo netplan get

Search for conflicting DHCP settings:

sudo grep -R dhcp4 /etc/netplan/

For a static Ethernet configuration, only:

dhcp4: false

should be present for eth0.


Ethernet Randomly Disconnects

Verify that only a single Netplan configuration manages eth0.

Check:

sudo grep -R . /etc/netplan/

If both of the following exist for eth0:

dhcp4: true

and

dhcp4: false

remove the conflicting configuration and reapply Netplan:

sudo netplan generate
sudo netplan apply

A conflicting DHCP/static configuration can cause periodic Ethernet disconnects and SSH timeouts.

SSH Configuration

Verify SSH access from the laptop:

ssh <username>@192.168.10.2

Example:

ssh aryan@192.168.10.2

Enable passwordless SSH:

ssh-copy-id aryan@192.168.10.2

This allows capture_rpi.py to automatically launch the streaming server.


Raspberry Pi 5 Access Point + Internet Sharing Setup

Overview

This document describes how to configure a Raspberry Pi 5 running Ubuntu 24.04 LTS as:

  • A permanent WiFi Access Point (DroneNet)
  • A camera streaming server
  • A robotics companion computer

while simultaneously receiving internet access from a laptop through Ethernet.

Final architecture:

                    Internet
                        │
                  CU-Wireless
                        │
                     Laptop
                        │
                  Ethernet
                 192.168.10.1
                        │
                        ▼
                 Raspberry Pi 5
                 192.168.10.3
                 ┌───────────┐
                 │   eth0    │
                 └─────┬─────┘
                       │
                 Internet Access

                 ┌───────────┐
                 │   wlan0   │
                 └─────┬─────┘
                       │
                  DroneNet AP
                  192.168.4.1
                       │
      Camera Streaming / SSH / ROS2 / PX4

1. Verify AP Mode Support

On the Raspberry Pi:

iw list | grep -A 15 "Supported interface modes"

Verify that:

* AP

appears in the output.


2. Create Access Point

Create a new NetworkManager connection:

sudo nmcli connection add \
    type wifi \
    ifname wlan0 \
    con-name DroneAP \
    autoconnect yes \
    ssid DroneNet

3. Configure AP Mode

Configure the connection as an Access Point:

sudo nmcli connection modify DroneAP \
    802-11-wireless.mode ap \
    802-11-wireless.band a

The a band enables 5 GHz operation.


4. Configure WPA2 Security

Choose a password with at least 8 characters.

Example:

sudo nmcli connection modify DroneAP \
    wifi-sec.key-mgmt wpa-psk \
    wifi-sec.psk "YourPasswordHere"

5. Configure Static AP Address

Assign a fixed address to the AP:

sudo nmcli connection modify DroneAP \
    ipv4.method shared \
    ipv4.addresses 192.168.4.1/24

6. Disable Other WiFi Profiles

Prevent the Pi from automatically joining other WiFi networks.

Example:

sudo nmcli connection modify CU-Wireless connection.autoconnect no

sudo nmcli connection modify "CU-Wireless 1" connection.autoconnect no

7. Start the Access Point

sudo nmcli connection up DroneAP

Verify:

ip addr show wlan0

Expected:

inet 192.168.4.1/24

8. Verify Auto Start

Reboot:

sudo reboot

Verify that:

DroneNet

appears automatically without running any commands.


9. Configure Static Ethernet

Edit:

sudo nano /etc/netplan/01-network-manager-all.yaml

Configuration:

network:
  version: 2
  renderer: NetworkManager

  ethernets:
    eth0:
      dhcp4: false

      addresses:
        - 192.168.10.3/24

      routes:
        - to: default
          via: 192.168.10.1

      nameservers:
        addresses:
          - 8.8.8.8
          - 1.1.1.1

Apply:

sudo netplan apply

Verify:

ip addr show eth0

Expected:

inet 192.168.10.3/24

10. Configure Laptop Ethernet

Configure the laptop Ethernet adapter manually.

Example:

Interface : enp88s0

Address   : 192.168.10.1
Netmask   : 255.255.255.0
Gateway   : (leave blank)

Verify:

ip addr show enp88s0

Expected:

inet 192.168.10.1/24

11. Enable IP Forwarding on Laptop

Verify:

sudo sysctl net.ipv4.ip_forward

Expected:

net.ipv4.ip_forward = 1

If disabled:

sudo sysctl -w net.ipv4.ip_forward=1

Make permanent:

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

12. Configure NAT on Laptop

Allow Ethernet clients to use the laptop's WiFi connection.

Replace:

wlp0s20f3

with your WiFi interface name if different.

Add NAT:

sudo iptables -t nat -A POSTROUTING \
    -o wlp0s20f3 \
    -j MASQUERADE

Allow forwarding:

sudo iptables -A FORWARD \
    -i enp88s0 \
    -o wlp0s20f3 \
    -j ACCEPT

Allow return traffic:

sudo iptables -A FORWARD \
    -i wlp0s20f3 \
    -o enp88s0 \
    -m state --state RELATED,ESTABLISHED \
    -j ACCEPT

13. Make iptables Persistent

Install:

sudo apt update
sudo apt install iptables-persistent -y

Save current rules:

sudo netfilter-persistent save

Verify after reboot:

sudo iptables -t nat -L -n -v

14. Verify Internet Access on Pi

Verify routing:

ip route

Expected:

default via 192.168.10.1 dev eth0

Test internet:

ping 8.8.8.8

Test DNS:

ping google.com

Update packages:

sudo apt update

15. Connect Laptop to DroneNet

Search for:

DroneNet

Connect using the configured password.

Verify:

ping 192.168.4.1

SSH:

ssh aryan@192.168.4.1

Final Network Configuration

Raspberry Pi

wlan0
IP: 192.168.4.1
Mode: Access Point
SSID: DroneNet

eth0
IP: 192.168.10.3
Gateway: 192.168.10.1
DNS:
  8.8.8.8
  1.1.1.1

Laptop

WiFi
Internet Connection

Ethernet
IP: 192.168.10.1
NAT Enabled
IP Forwarding Enabled

Typical Usage

Power on Raspberry Pi:

DroneNet starts automatically

Connect laptop to:

DroneNet

Use:

ssh aryan@192.168.4.1

Camera streaming:

PI_IP = "192.168.4.1"

Install packages on Pi:

sudo apt update
sudo apt install ...

through the Ethernet connection without modifying the DroneNet network.

Camera Abstraction Layer

The Camera class automatically selects the available camera source.

Priority:

  1. Raspberry Pi Camera Module
  2. USB Webcam

Example:

from camera import Camera

camera = Camera(
    width=640,
    height=480
)

Reading frames:

ret, frame = camera.read()

Returned images are OpenCV-compatible BGR images.

This allows the remainder of the code to remain independent of camera hardware.


Starting the Streaming Server

On the Raspberry Pi:

python3 stream.py

Expected output:

Streaming server started on 0.0.0.0:9999
Waiting for client...

Once connected:

Client connected: ('192.168.10.1', XXXXX)

The server continuously:

  1. Captures images from the camera
  2. Compresses images using JPEG
  3. Sends frames through a TCP socket

Starting the Streaming Client

On the laptop:

python3 capture_rpi.py

The client automatically:

  1. Waits for the Raspberry Pi to become reachable
  2. Starts stream.py remotely through SSH
  3. Connects to the streaming server
  4. Receives compressed image frames
  5. Decodes images using OpenCV
  6. Displays the live video stream

Press:

ESC

to terminate the application.


Integration with Computer Vision Pipelines

The received frame can be directly used with:

  • OpenCV
  • Object Detection
  • Object Tracking
  • Visual Servoing
  • SLAM
  • Custom Computer Vision Pipelines

Example:

ret, frame = stream.read()

outputs = tracker.track(frame)

No modifications to the streaming layer are required.


Performance Notes

Current configuration:

Resolution    : 640 × 480
JPEG Quality  : 80
Transport     : TCP
Port          : 9999

This configuration is suitable for:

  • Object Tracking
  • Object Detection
  • Visual Servoing
  • SLAM Visualization
  • Remote Camera Monitoring

Image resolution and JPEG quality can be modified in:

camera.py
stream.py

depending on the desired image quality and available network bandwidth.


Troubleshooting

Cannot SSH Into Raspberry Pi

Verify SSH is running:

sudo systemctl status ssh

Enable SSH:

sudo systemctl enable ssh

sudo systemctl start ssh

Cannot Connect To Stream

Verify connectivity:

ping 192.168.10.2

Verify the streaming server is running:

netstat -tlnp | grep 9999

Expected:

0.0.0.0:9999

Camera Not Detected

List Raspberry Pi cameras:

rpicam-still --list-cameras

List USB cameras:

v4l2-ctl --list-devices

Connection Reset Errors

If the client is closed unexpectedly, the server may display:

BrokenPipeError
ConnectionResetError

This is normal behavior and simply indicates that the client disconnected.

The server automatically returns to:

Waiting for client...

and is ready for the next connection.


Typical Workflow

  1. Connect Raspberry Pi and laptop via Ethernet.
  2. Verify connectivity:
ping 192.168.10.2
  1. Verify SSH access:
ssh aryan@192.168.10.2
  1. Run:
python3 capture_rpi.py
  1. The client automatically:

    • Waits for Raspberry Pi connectivity
    • Launches the streaming server
    • Connects to the video stream
  2. Begin image processing on the laptop.


Future Work

  • H.264/H.265 hardware encoding
  • ROS 2 integration
  • Multi-camera streaming support

License

This project is released under the MIT License.

You are free to use, modify, and distribute this software for both academic and commercial purposes, provided that the original copyright notice and license are included.

See the LICENSE file for the full license text.

About

Camera streaming setup b/w rpi and laptop

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages