burrow-pi-img/deps/examples/python-multiCameraServer/multiCameraServer.py

158 lines
4.2 KiB
Python
Executable File

#!/usr/bin/env python3
#----------------------------------------------------------------------------
# Copyright (c) 2018 FIRST. All Rights Reserved.
# Open Source Software - may be modified and shared by FRC teams. The code
# must be accompanied by the FIRST BSD license file in the root directory of
# the project.
#----------------------------------------------------------------------------
import json
import time
import sys
from cscore import CameraServer, VideoSource
from networktables import NetworkTablesInstance
# JSON format:
# {
# "team": <team number>,
# "ntmode": <"client" or "server", "client" if unspecified>
# "cameras": [
# {
# "name": <camera name>
# "path": <path, e.g. "/dev/video0">
# "pixel format": <"MJPEG", "YUYV", etc> // optional
# "width": <video mode width> // optional
# "height": <video mode height> // optional
# "fps": <video mode fps> // optional
# "brightness": <percentage brightness> // optional
# "white balance": <"auto", "hold", value> // optional
# "exposure": <"auto", "hold", value> // optional
# "properties": [ // optional
# {
# "name": <property name>
# "value": <property value>
# }
# ]
# }
# ]
# }
configFile = "/boot/frc.json"
class CameraConfig: pass
team = None
server = False
cameraConfigs = []
"""Report parse error."""
def parseError(str):
print("config error in '" + configFile + "': " + str, file=sys.stderr)
"""Read single camera configuration."""
def readCameraConfig(config):
cam = CameraConfig()
# name
try:
cam.name = config["name"]
except KeyError:
parseError("could not read camera name")
return False
# path
try:
cam.path = config["path"]
except KeyError:
parseError("camera '{}': could not read path".format(cam.name))
return False
cam.config = config
cameraConfigs.append(cam)
return True
"""Read configuration file."""
def readConfig():
global team
global server
# parse file
try:
with open(configFile, "rt") as f:
j = json.load(f)
except OSError as err:
print("could not open '{}': {}".format(configFile, err), file=sys.stderr)
return False
# top level must be an object
if not isinstance(j, dict):
parseError("must be JSON object")
return False
# team number
try:
team = j["team"]
except KeyError:
parseError("could not read team number")
return False
# ntmode (optional)
if "ntmode" in j:
str = j["ntmode"]
if str.lower() == "client":
server = False
elif str.lower() == "server":
server = True
else:
parseError("could not understand ntmode value '{}'".format(str))
# cameras
try:
cameras = j["cameras"]
except KeyError:
parseError("could not read cameras")
return False
for camera in cameras:
if not readCameraConfig(camera):
return False
return True
"""Start running the camera."""
def startCamera(config):
print("Starting camera '{}' on {}".format(config.name, config.path))
camera = CameraServer.getInstance() \
.startAutomaticCapture(name=config.name, path=config.path)
camera.setConfigJson(json.dumps(config.config))
return camera
if __name__ == "__main__":
if len(sys.argv) >= 2:
configFile = sys.argv[1]
# read configuration
if not readConfig():
sys.exit(1)
# start NetworkTables
ntinst = NetworkTablesInstance.getDefault()
if server:
print("Setting up NetworkTables server")
ntinst.startServer()
else:
print("Setting up NetworkTables client for team {}".format(team))
ntinst.startClientTeam(team)
# start cameras
cameras = []
for cameraConfig in cameraConfigs:
cameras.append(startCamera(cameraConfig))
# loop forever
while True:
time.sleep(10)