Skip to main content

RPi Camera Colony: Central control for video acquisition with (many) Raspberry Pi cameras

Project description

DOI Website PyPI Wheel Code style: black

RPi Camera Colony (RCC)

Central control for video acquisition with (many) Raspberry Pi cameras

Record videos in parallel with one or more remote-controlled Raspberry Pi (RPi) cameras. :movie_camera:

A single configuration file and a few lines of code allow specific and reproducible acquisition settings for groups of cameras.

Example use with Python:

import time
from rpi_camera_colony.control.conductor import Conductor

conductor = Conductor(settings_file="configuration_file")  # Manages remote RPi
conductor.start_acquisition()  # Starts recording on all remotes

time.sleep(20)  # do nothing or something else in between

conductor.stop_acquisition()  # Stops recording on all remotes

or on the commandline:

rcc_conductor  --config-data-file CONFIG_DATA_FILE  --acquisition-name ACQUISITION_NAME

Features

A centralised control object

One central object handles all communication with the remote cameras and transmits the configuration settings to each.

A single configuration file to define reproducible multi-camera acquisition

Configuration parameters are centrally defined in an easy-to-read file format and then handed down to the cameras.

Flexible entrypoints

Multiple entrypoints for use in python scripts as well as in a single line on the commandline Additionally, all levels are directly accessible: central Conductor, remote control handlers, and on the RPi the acquisition control (see below for details).

Installation

Python dependencies

  • python >= 3.6

  • pyzmq

  • configobj

  • tqdm

  • numpy

  • pandas

    Note: Use conda to install numpy/pandas to get pre-compiled packages (See below for instructions)

On RPi only:

  • picamera
  • RPi.GPIO

Other useful packages

For video conversion:

  • gpac # contains MP4Box tool for video conversion

Example hardware architecture

  [outside world / internet]
              |
              |
      [central machine]
              |
              |
      [network switch]
      /   |     |    \
     |    |     |     | <- network connection
[rpi #1]  |     |     |     e.g. ethernet cables
          |     |     |
     [rpi #2]   |     |
                |     |
              [...]   |
                      |
                 [rpi #n]

Minimal hardware requirements

  • Central machine, can be RPi itself (as it only holds the control object, but does no computation)
  • Raspberry Pi
    1. Main RPi board + fast SD card (+ card reader if not available on another machine)
    2. RPi Camera (+lens?) (depends on your specific acquisition requirements)
    3. RPi power supply (RPi4 requires USB-C connector)
    4. Display cable (RPi4 requires mico-HDMI connector)
  • Ethernet cables
  • Network switch (if more than one RPi), e.g. any 1GB or faster

Mapping between this package & hardware

One Conductor to instruct all RPi cameras via network communication between the RemoteAcquisitionControl and PiAcquisitionControl.

    Hardware            <-->        Software


    [central machine]   <-->        Conductor
            |                           |
            |                       RemoteAcquisitionControl
            |                           |
           ...                         ...
            |                           |
       [rpi #n]         <-->        PiAcquisitionControl
                                        |
                                    Camera

Raspberry Pi setup

  1. Set up RPi hardware

    1. Install Raspbian -> NOTE: Use Raspbian Buster for now. There is no PiCamera equivalent readily available for the Raspbian Bullseye libcamera apps.
    2. Enable camera, GPIO interfaces, and ssh in sudo raspi-config options
    3. Connect hardware:
      1. Camera

      2. Network cable

      3. GPIO pin connection for TTL in/out (See pinout.xyz for board mode pins to use)

          Note: adjust pin numbers used in configuration file. Default are pin #8 for frame TTL outputs and #16 for inputs. Choose any free ground pins!
        
  2. Install this package

    1. Set up python, e.g. with miniconda
    2. Clone this repository or use distribute_code.sh script (Replace hostnames for your RPi)
    3. Install with
      pip install -e rpi_camera_colony[rpi]  # <- [rpi] argument install specific requirements!
      

Central control machine setup

  1. DHCP server on central computer. (Description only for Ubuntu)

    1. Set up static IP address on network interface that serves RPi colony via network switch, with e.g. /etc/network/interfaces or netplan

    2. Set up DHCP server with isc-dhcp-server

    3. Set up SSH keys to allow interaction with RPi without password (otherwise cannot drop remote process!)

       ssh-keygen  # into standard file if not exists, no passphrase
       ssh-copy-id -i ~/.ssh/id_rsa HOST  # where HOST = RPi host name
      
  2. Set up python environment, e.g. with miniconda

  3. Install this package

    1. Clone this repository
    2. Install with
      pip install rpi_camera_colony
      

Entrypoints & levels

Easy access to central Conductor

rcc_conductor --help

Use acquisition directly on RPi

from rpi_camera_colony.acquisition.acquisition_control import PiAcquisitionControl

or

python rpi_camera_colony/acquisition --help
# or
python -m rpi_camera_colony.acquisition --help
# or
rcc_acquisition --help

One-to-one mapping of local control to remote acquisition

from rpi_camera_colony.acquisition.remote_control import RemoteAcquisitionControl

or

python rpi_camera_colony/acquisition --help
# or
python -m rpi_camera_colony.acquisition.remote_control --help

Read acquisition metadata & check for video files

from rpi_camera_colony import read_session_data

Sandbox Conductor object in separate process (python multiprocessing)

See rpi_camera_colony.control.process_sandbox for example use of:

from rpi_camera_colony.control.process_sandbox import ConductorAsProcess

Citation

Rollik, Lars B. (2021). RPi Camera Colony: Central control for video acquisition with (many) Raspberry Pi cameras. doi: 10.5281/zenodo.4916007.

BibTeX

@misc{rollik2021rpi,
    author       = {Lars B. Rollik},
    title        = {{RPi Camera Colony: Central control for video acquisition with (many) Raspberry Pi cameras}},
    year         = {2021},
    month        = jun,
    publisher    = {Zenodo},
    url          = {https://doi.org/10.5281/zenodo.4916007},
    doi          = {10.5281/zenodo.4916007},
  }

License

This software is released under the BSD 3-Clause License

Related projects with similar architectures

  • Arne Meyer's RPiCameraPlugin for the OpenEphys GUI

    Specific API for one-to-one control mappings between OpenEphys GUI plugin instances and remote RPi cameras. Inspiration for use of ØMQ communication and camera TTL integration in encoder class.

  • Deshmukh lab's PicameraPaper

    Video acquisition with multiple RPi synchronised by a central TTL that is recorded with the camera timestamps.

  • Vidgear

    General package for different types of video acquisition and streaming.

Configuration file specification

-> Note: additional picamera attributes can be used, but not all types implemented. Check below.

-> Note: acquisition_group is not specified by default, but if acquisition_name contains __ double underscores, then the acquisition_group will get auto-populated from the first segment, when split on the __. This is to create an acquisition folder organisation like: /path_to_data/acquisition_group/acquisition_name/[files]

[general]
    acquisition_name = string(default="_test_rcc_name_config")    # base name for recording
    acquisition_time = string(default="dummy_time")
    acquisition_group = string(default="")
    remote_data_path = string(default="/home/pi/data/")             # where to store all recordings on RPi
    rpi_username = string(default="pi")
    remote_python_interpreter = string(default="/home/pi/miniconda3/envs/py36/bin/python")      # path to python
    remote_python_entrypoint = string(default="rpi_camera_colony.acquisition")      # path to __main__ entrypoint
    max_acquisition_time = integer(0, 7200, default=7200)           # seconds, shut down acquisition after expiration
    save_data = boolean(default=True)  # if False, then doesn't write files on RPi
    general_setting_has_priority = boolean(default=True)  # If False, does not patch in general settings
    general_settings_to_patch_into_controller = string_list(default=list("save_data", "acquisition_time", "acquisition_group"))  # Add variables here for patching into controllers

[log]
    address = string(max=15, default="192.168.100.10")
    port = integer(default=55555)
    level = string(default="DEBUG")
    log_to_console = boolean(default=True)
    log_to_file = boolean(default=True)
    log_file = string(default="/tmp/rpi_camera_colony__logging")

[control]
    address = string(default="192.168.100.10")
    port = integer(default=54545)

[controllers]
    [[__many__]]
        description = string(default="")
        address = string(max=15, default="")
        save_data = boolean(default=True)
        ttl_channel_external = integer(default=-1)  # metadata info if recording output TTL on specific channel of other acquisition system
        ttl_in_pin = integer(default=16)
        ttl_out_pin = integer(default=8)
        ttl_out_duration = float(default=.001)

        # See for list of ALL parameters https://picamera.readthedocs.io/en/latest/api_camera.html
        framerate = integer(min=1, max=90, default=90)
        resolution = int_list(default=list(640, 480))
        vflip = boolean(default=False)
        hflip = boolean(default=False)

        brightness = integer(min=0, max=100, default=50)
        # color_effects: (128, 128) == black and white acquisition. Default is None.
        color_effects = int_list(default=list(128, 128))
        contrast = integer(min=-100, max=100, default=0)
        image_denoise = boolean(default=True)
        iso = integer(min=0, max=1600, default=0)
        led = boolean(default=False)
        preview_alpha = integer(min=0, max=255, default=255)  # DEPRECATED
        saturation = integer(min=-100, max=100, default=0)
        sharpness = integer(min=-100, max=100, default=0)
        still_stats = boolean(default=False)
        video_denoise = boolean(default=True)
        video_stabilization = boolean(default=False)
        # zoom: (x, y, w, h)
        zoom = float_list(default=list(0.0, 0.0, 1.0, 1.0))

        # Other picamera attributes / not implemented / not tested, but might work
        # awb_gains
        # awb_mode = option(default="auto")
        # drc_strength
        # exposure_compensation
        # exposure_mode
        # exposure_speed = 0
        # flash_mode = option("off", "auto", "on", "redeye", "fillin", "torch", default="off")
        # framerate_delta  # new in 1.11
        # framerate_range  # new in 1.13
        # image_effect = "none"
        # image_effect_params  # https://picamera.readthedocs.io/en/release-1.13/api_camera.html#picamera.PiCamera.image_effect_params
        # meter_mode = option("average", "spot", "backlit", "matrix")
        # rotation = option(0, 90, 180, 270)
        # sensor_mode = integer(default=0)
        # shutter_speed  # microseconds

Specific install hints

HQ camera for RPi cannot acquire at resolutions or framerates outlined in the technical description

sudo rpi-update fixes this. - Be careful, this updates the RPi firmware and might have unexpected side effects!

Ip forwarding and routing on central machine

# IP forward
sysctl -w net.ipv4.ip_forward=1
# check with
cat /proc/sys/net/ipv4/ip_forward

# Package routing
# - outside interface (dhcp): enp7s0
# - inside interface (static): enp8s0
iptables -A FORWARD -i enp8s0 -o enp7s0 -j ACCEPT
iptables -A FORWARD -i enp7s0 -o enp8s0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o enp7s0 -j MASQUERADE

Update time for ssl certificates

# Check with
timedatectl status

# force update with NTP
sudo service ntp stop
sudo ntpd -gq
sudo service ntp start

# enable permanent updates
sudo systemctl restart systemd-timesyncd

Install miniconda on RPi

# Installing miniconda on RPi
wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-armv7l.sh
sudo md5sum Miniconda3-latest-Linux-armv7l.sh # (optional) check md5
sudo /bin/bash Miniconda3-latest-Linux-armv7l.sh # -> change default directory to /home/pi/miniconda3

# Add conda to path
echo 'export PATH="/home/pi/miniconda3/bin:$PATH"' >> .bashrc
source .bashrc # or log out and in again

# Change permissions for conda
sudo chown -R pi:pi /home/pi/miniconda3

# Create conda environment and install basic packages (e.g. dependencies for this package)
conda config --add channels rpi
conda create -y -n py36 python=3.6 numpy pandas pyzmq

echo 'source activate py36' >> .bashrc
source .bashrc # or log out and in again

pip install picamera RPi.GPIO

# Re/install RCC
pip uninstall rpi_camera_colony -y
pip install --upgrade git+https://github.com/larsrollik/rpi_camera_colony.git#egg=rpi_camera_colony

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rpi_camera_colony-0.4.4.tar.gz (37.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rpi_camera_colony-0.4.4-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file rpi_camera_colony-0.4.4.tar.gz.

File metadata

  • Download URL: rpi_camera_colony-0.4.4.tar.gz
  • Upload date:
  • Size: 37.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.0 CPython/3.10.4

File hashes

Hashes for rpi_camera_colony-0.4.4.tar.gz
Algorithm Hash digest
SHA256 5ab65be39562bbe4c3bf409f33b43acb7a8444548032ffbadfb48ff69d219c5d
MD5 801bfe778e0013775c116fcc56d4ff92
BLAKE2b-256 1b05c9030e59317d3d3ee4a86ca9b5cc6595f12f324e2fbb7a65224b1a6e696d

See more details on using hashes here.

File details

Details for the file rpi_camera_colony-0.4.4-py3-none-any.whl.

File metadata

File hashes

Hashes for rpi_camera_colony-0.4.4-py3-none-any.whl
Algorithm Hash digest
SHA256 3eee0ec6fa185ecc185a4c00fb87a9e21f01a4b1b60a27a8a4a03e78361517a4
MD5 a39436258a87f4ad5837aeb079c5502c
BLAKE2b-256 7eba9ed04e4c09c9e62a47d36587c29f5b3d56eacaeaf2cf4beac90ffd8c6469

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page