155 lines
4.1 KiB
Python
155 lines
4.1 KiB
Python
|
#!/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
|
||
|
cameras = []
|
||
|
|
||
|
"""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
|
||
|
|
||
|
cameras.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))
|
||
|
|
||
|
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
|
||
|
for camera in cameras:
|
||
|
startCamera(camera)
|
||
|
|
||
|
# loop forever
|
||
|
while True:
|
||
|
time.sleep(10)
|