From 7ab0ba412e897532178479f4bc6d95da0a074c80 Mon Sep 17 00:00:00 2001
From: Martin C <78377730+MilkManMaki@users.noreply.github.com>
Date: Mon, 8 Apr 2024 22:45:45 -0400
Subject: [PATCH 1/4] refactor: moving examples into an examples folder in the
root directory
---
.../pyntcore/examples/pubsub_client.py | 41 ------
.../pyntcore/examples/pubsub_server.py | 36 -----
.../pyntcore/examples/simple_client.py | 52 -------
.../pyntcore/examples/simple_poller.py | 59 --------
subprojects/pyntcore/examples/simple_robot.py | 34 -----
.../robotpy-cscore/examples/CameraServer.java | 127 ------------------
.../robotpy-cscore/examples/cvstream.py | 39 ------
.../examples/dual_cameraserver.py | 35 -----
.../robotpy-cscore/examples/enum_usb.py | 62 ---------
.../robotpy-cscore/examples/httpcvstream.py | 41 ------
.../examples/intermediate_cameraserver.py | 63 ---------
.../examples/quick_cameraserver.py | 33 -----
.../robotpy-cscore/examples/settings.py | 102 --------------
.../examples/switched_cameraserver.py | 51 -------
.../robotpy-cscore/examples/usbcvstream.py | 46 -------
.../robotpy-cscore/examples/usbstream.py | 12 --
16 files changed, 833 deletions(-)
delete mode 100755 subprojects/pyntcore/examples/pubsub_client.py
delete mode 100755 subprojects/pyntcore/examples/pubsub_server.py
delete mode 100755 subprojects/pyntcore/examples/simple_client.py
delete mode 100755 subprojects/pyntcore/examples/simple_poller.py
delete mode 100755 subprojects/pyntcore/examples/simple_robot.py
delete mode 100644 subprojects/robotpy-cscore/examples/CameraServer.java
delete mode 100755 subprojects/robotpy-cscore/examples/cvstream.py
delete mode 100755 subprojects/robotpy-cscore/examples/dual_cameraserver.py
delete mode 100755 subprojects/robotpy-cscore/examples/enum_usb.py
delete mode 100755 subprojects/robotpy-cscore/examples/httpcvstream.py
delete mode 100755 subprojects/robotpy-cscore/examples/intermediate_cameraserver.py
delete mode 100755 subprojects/robotpy-cscore/examples/quick_cameraserver.py
delete mode 100755 subprojects/robotpy-cscore/examples/settings.py
delete mode 100755 subprojects/robotpy-cscore/examples/switched_cameraserver.py
delete mode 100755 subprojects/robotpy-cscore/examples/usbcvstream.py
delete mode 100755 subprojects/robotpy-cscore/examples/usbstream.py
diff --git a/subprojects/pyntcore/examples/pubsub_client.py b/subprojects/pyntcore/examples/pubsub_client.py
deleted file mode 100755
index f67257fc..00000000
--- a/subprojects/pyntcore/examples/pubsub_client.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#
-# A client that publishes some synchronized values periodically
-
-import argparse
-import os
-from os.path import basename
-import logging
-import time
-
-import ntcore
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
-
- parser = argparse.ArgumentParser()
- parser.add_argument("ip", type=str, help="IP address to connect to")
- args = parser.parse_args()
-
- # Initialize NT4 client
- inst = ntcore.NetworkTableInstance.getDefault()
-
- identity = f"{basename(__file__)}-{os.getpid()}"
- inst.startClient4(identity)
-
- inst.setServer(args.ip)
-
- # publish two values
- table = inst.getTable("data")
- pub1 = table.getDoubleTopic("1").publish()
- pub2 = table.getDoubleTopic("2").publish()
-
- i = 3
-
- while True:
- # These values are being published fast than the server is polling
- pub1.set(i)
- pub2.set(i + 100)
-
- time.sleep(0.5)
- i += 1
diff --git a/subprojects/pyntcore/examples/pubsub_server.py b/subprojects/pyntcore/examples/pubsub_server.py
deleted file mode 100755
index 6356b0c5..00000000
--- a/subprojects/pyntcore/examples/pubsub_server.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python3
-#
-# A server that reads from the subscription
-#
-
-import logging
-import time
-
-import ntcore
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
-
- # initialize networktables server (on a robot this is already done)
- inst = ntcore.NetworkTableInstance.getDefault()
- inst.startServer()
-
- # Initialize two subscriptions
- table = inst.getTable("data")
-
- # only keep the latest value for this topic
- sub1 = table.getDoubleTopic("1").subscribe(-1.0)
-
- # keep the last 10 values for this topic
- sub2 = table.getDoubleTopic("2").subscribe(
- -2.0, ntcore.PubSubOptions(pollStorage=10)
- )
-
- # Periodically read from them
- # - note sub1 only has 1 value, but sub2 sometimes has more than 1
- while True:
- print("---", ntcore._now())
- print("/data/1:", sub1.readQueue())
- print("/data/2:", sub2.readQueue())
-
- time.sleep(1.2)
diff --git a/subprojects/pyntcore/examples/simple_client.py b/subprojects/pyntcore/examples/simple_client.py
deleted file mode 100755
index d49155b7..00000000
--- a/subprojects/pyntcore/examples/simple_client.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python3
-#
-# This is a NetworkTables client (eg, the DriverStation/coprocessor side).
-# You need to tell it the IP address of the NetworkTables server (the
-# robot or simulator).
-#
-# When running, this will continue incrementing the value 'dsTime', and the
-# value should be visible to other networktables clients and the robot.
-#
-
-import argparse
-from os.path import basename
-import logging
-import time
-
-import ntcore
-
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
-
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "-p",
- "--protocol",
- type=int,
- choices=[3, 4],
- help="NT Protocol to use",
- default=4,
- )
- parser.add_argument("ip", type=str, help="IP address to connect to")
- args = parser.parse_args()
-
- inst = ntcore.NetworkTableInstance.getDefault()
-
- identity = basename(__file__)
- if args.protocol == 3:
- inst.startClient3(identity)
- else:
- inst.startClient4(identity)
-
- inst.setServer(args.ip)
-
- sd = inst.getTable("SmartDashboard")
-
- i = 0
- while True:
- print("robotTime:", sd.getNumber("robotTime", -1))
-
- sd.putNumber("dsTime", i)
- time.sleep(1)
- i += 1
diff --git a/subprojects/pyntcore/examples/simple_poller.py b/subprojects/pyntcore/examples/simple_poller.py
deleted file mode 100755
index 3c7c78e8..00000000
--- a/subprojects/pyntcore/examples/simple_poller.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python3
-#
-# This is a NetworkTables client (eg, the DriverStation/coprocessor side).
-# You need to tell it the IP address of the NetworkTables server (the
-# robot or simulator).
-#
-# This is intended to be ran at the same time as the simple_robot.py
-# and simple_client.py examples. It will output values as they change.
-#
-
-import argparse
-from os.path import basename
-import logging
-import time
-
-import ntcore
-
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
-
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "-p",
- "--protocol",
- type=int,
- choices=[3, 4],
- help="NT Protocol to use",
- default=4,
- )
- parser.add_argument("ip", type=str, help="IP address to connect to")
- args = parser.parse_args()
-
- inst = ntcore.NetworkTableInstance.getDefault()
-
- identity = basename(__file__)
- if args.protocol == 3:
- inst.startClient3(identity)
- else:
- inst.startClient4(identity)
-
- inst.setServer(args.ip)
-
- # Create a poller
- poller = ntcore.NetworkTableListenerPoller(inst)
-
- # Listen for all connection events
- poller.addConnectionListener(True)
-
- # Listen to all changes
- msub = ntcore.MultiSubscriber(inst, [""])
- poller.addListener(msub, ntcore.EventFlags.kValueRemote)
-
- while True:
- # periodically read from the queue
- for event in poller.readQueue():
- print(event)
-
- time.sleep(1)
diff --git a/subprojects/pyntcore/examples/simple_robot.py b/subprojects/pyntcore/examples/simple_robot.py
deleted file mode 100755
index 1eeb6ebc..00000000
--- a/subprojects/pyntcore/examples/simple_robot.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env python3
-#
-# This is a NetworkTables server (eg, the robot or simulator side).
-#
-# On a real robot, you probably would create an instance of the
-# wpilib.SmartDashboard object and use that instead -- but it's really
-# just a passthru to the underlying NetworkTable object.
-#
-# When running, this will continue incrementing the value 'robotTime',
-# and the value should be visible to networktables clients such as
-# Shuffleboard or simple_client.py
-#
-
-import logging
-import time
-
-import ntcore
-
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
-
- inst = ntcore.NetworkTableInstance.getDefault()
-
- inst.startServer()
- sd = inst.getTable("SmartDashboard")
-
- i = 0
- while True:
- print("dsTime:", sd.getNumber("dsTime", -1))
-
- sd.putNumber("robotTime", i)
- time.sleep(1)
- i += 1
diff --git a/subprojects/robotpy-cscore/examples/CameraServer.java b/subprojects/robotpy-cscore/examples/CameraServer.java
deleted file mode 100644
index af9bc72a..00000000
--- a/subprojects/robotpy-cscore/examples/CameraServer.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package io.github.robotpy.cscore;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ProcessBuilder.Redirect;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-
-import edu.wpi.first.wpilibj.DriverStation;
-
-/**
- * Provides a way to launch an out of process Python robotpy-cscore based
- * camera service instance from a Java robot program.
- *
- * You must have Python and python36-robotpy-cscore installed, or this
- * just simply won't work. Refer to the RobotPy documentation for details.
- *
- * The python code should be a single file, and must compiled into your java
- * jar file. If your file was in the src directory as 'vision.py', you would
- * add this to the 'project' section of build.xml:
- */
-//
-//
-// [athena-jar] Making jar ${dist.jar}.
-//
-//
-//
-// [athena-jar] Copying jars to ${build.jars}.
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-public class CameraServer {
-
- public static String visionPath = "/home/lvuser/vision.py";
- private static boolean isAlive = false;
- private static boolean launched = false;
-
- /**
- * @return true if the vision process is (probably) alive
- */
- public static boolean isAlive() {
- return isAlive;
- }
-
- /**
- * Launches an embedded resource called "vision.py" which contains a
- * "main" function.
- */
- public static void startPythonVision() {
- startPythonVision("/vision.py", "main");
- }
-
- /**
- * Call this function to launch a python vision program in an external
- * process.
- *
- * @param resource The resource built into the jar (see above), such as /vision.py
- * @param functionName The name of the function to call
- */
- public static void startPythonVision(String resource, String functionName) {
- // don't allow restart
- if (launched) {
- return;
- }
-
- launched = true;
-
- System.out.println("Launching python process from " + resource);
-
- try {
- // extract the resource and write it to vision.py
- InputStream is = CameraServer.class.getResourceAsStream(resource);
- if (is == null) {
- throw new IOException("Resource " + resource + " not found");
- }
-
- Files.copy(is, Paths.get(visionPath), StandardCopyOption.REPLACE_EXISTING);
-
- // launch the process
- ProcessBuilder pb = new ProcessBuilder();
- pb.command("/usr/local/bin/python3", "-m", "cscore", visionPath + ":" + functionName);
-
- // we open a pipe to it so that when the robot program exits, the child dies
- pb.redirectInput(Redirect.PIPE);
-
- // and let us see stdout/stderr
- pb.redirectOutput(Redirect.INHERIT);
- pb.redirectError(Redirect.INHERIT);
-
- final Process p = pb.start();
- isAlive = true;
-
- Thread t = new Thread(()-> {
- try {
- p.waitFor();
- } catch (InterruptedException e) {
- // empty
- }
-
- isAlive = false;
- });
- t.setDaemon(true);
- t.start();
-
- } catch (IOException e) {
- System.out.println("Error launching vision! " + e.toString());
- //if (!DriverStation.getInstance().isFMSAttached()) {
- // throw new RuntimeException("Error launching vision", e);
- //}
- }
- }
-}
diff --git a/subprojects/robotpy-cscore/examples/cvstream.py b/subprojects/robotpy-cscore/examples/cvstream.py
deleted file mode 100755
index 67dbe3cb..00000000
--- a/subprojects/robotpy-cscore/examples/cvstream.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python3
-#
-# WARNING: You should only use this approach for testing cscore on platforms that
-# it doesn't support using UsbCamera
-#
-
-import cscore as cs
-
-if hasattr(cs, "UsbCamera"):
- camera = cs.UsbCamera("usbcam", 0)
- camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
-else:
- import cv2
- import threading
-
- camera = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
-
- # tell OpenCV to capture video for us
- cap = cv2.VideoCapture(0)
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
-
- # Do it in another thread
- def _thread():
- img = None
- while True:
- retval, img = cap.read(img)
- if retval:
- camera.putFrame(img)
-
- th = threading.Thread(target=_thread, daemon=True)
- th.start()
-
-
-mjpegServer = cs.MjpegServer("httpserver", 8081)
-mjpegServer.setSource(camera)
-
-print("mjpg server listening at http://0.0.0.0:8081")
-input("Press enter to exit...")
diff --git a/subprojects/robotpy-cscore/examples/dual_cameraserver.py b/subprojects/robotpy-cscore/examples/dual_cameraserver.py
deleted file mode 100755
index 74bf59cc..00000000
--- a/subprojects/robotpy-cscore/examples/dual_cameraserver.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python3
-#
-# Uses the CameraServer class to automatically capture video from two USB
-# webcams and send it to the FRC dashboard without doing any vision
-# processing.
-#
-# Warning: If you're using this with a python-based robot, do not run this
-# in the same program as your robot code!
-#
-
-from cscore import CameraServer as CS
-
-
-def main():
- CS.enableLogging()
-
- usb1 = CS.startAutomaticCapture(dev=0)
- usb2 = CS.startAutomaticCapture(dev=1)
-
- CS.waitForever()
-
-
-if __name__ == "__main__":
- # To see messages from networktables, you must setup logging
- import logging
-
- logging.basicConfig(level=logging.DEBUG)
-
- # You should uncomment these to connect to the RoboRIO
- # import ntcore
- # nt = ntcore.NetworkTableInstance.getDefault()
- # nt.setServerTeam(XXXX)
- # nt.startClient4(__file__)
-
- main()
diff --git a/subprojects/robotpy-cscore/examples/enum_usb.py b/subprojects/robotpy-cscore/examples/enum_usb.py
deleted file mode 100755
index 1dd937aa..00000000
--- a/subprojects/robotpy-cscore/examples/enum_usb.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python3
-
-import cscore as cs
-
-
-def main():
- for caminfo in cs.UsbCamera.enumerateUsbCameras():
- print("%s: %s (%s)" % (caminfo.dev, caminfo.path, caminfo.name))
- if caminfo.otherPaths:
- print("Other device paths:")
- for path in caminfo.otherPaths:
- print(" ", path)
-
- camera = cs.UsbCamera("usbcam", caminfo.dev)
-
- print("Properties:")
- for prop in camera.enumerateProperties():
- kind = prop.getKind()
- if kind == cs.VideoProperty.Kind.kBoolean:
- print(
- prop.getName(),
- "(bool) value=%s default=%s" % (prop.get(), prop.getDefault()),
- )
- elif kind == cs.VideoProperty.Kind.kInteger:
- print(
- prop.getName(),
- "(int): value=%s min=%s max=%s step=%s default=%s"
- % (
- prop.get(),
- prop.getMin(),
- prop.getMax(),
- prop.getStep(),
- prop.getDefault(),
- ),
- )
- elif kind == cs.VideoProperty.Kind.kString:
- print(prop.getName(), "(string):", prop.getString())
- elif kind == cs.VideoProperty.Kind.kEnum:
- print(prop.getName(), "(enum): value=%s" % prop.get())
- for i, choice in enumerate(prop.getChoices()):
- if choice:
- print(" %s: %s" % (i, choice))
-
- print("Video Modes")
- for mode in camera.enumerateVideoModes():
- if mode.pixelFormat == cs.VideoMode.PixelFormat.kMJPEG:
- fmt = "MJPEG"
- elif mode.pixelFormat == cs.VideoMode.PixelFormat.kYUYV:
- fmt = "YUYV"
- elif mode.pixelFormat == cs.VideoMode.PixelFormat.kRGB565:
- fmt = "RGB565"
- else:
- fmt = "Unknown"
-
- print(" PixelFormat:", fmt)
- print(" Width:", mode.width)
- print(" Height:", mode.height)
- print(" FPS: ", mode.fps)
-
-
-if __name__ == "__main__":
- main()
diff --git a/subprojects/robotpy-cscore/examples/httpcvstream.py b/subprojects/robotpy-cscore/examples/httpcvstream.py
deleted file mode 100755
index 9acfbbfa..00000000
--- a/subprojects/robotpy-cscore/examples/httpcvstream.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#
-# Demonstrates streaming from a HTTP camera server
-#
-
-
-import cscore as cs
-import numpy as np
-import cv2
-
-
-def main():
- camera = cs.HttpCamera("httpcam", "http://localhost:8081/?action=stream")
- camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
-
- cvsink = cs.CvSink("cvsink")
- cvsink.setSource(camera)
-
- cvSource = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
- cvMjpegServer = cs.MjpegServer("cvhttpserver", 8083)
- cvMjpegServer.setSource(cvSource)
-
- print("OpenCV output mjpg server listening at http://0.0.0.0:8083")
-
- test = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
- flip = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
-
- while True:
- time, test = cvsink.grabFrame(test)
- if time == 0:
- print("error:", cvsink.getError())
- continue
-
- print("got frame at time", time, test.shape)
-
- cv2.flip(test, flipCode=0, dst=flip)
- cvSource.putFrame(flip)
-
-
-if __name__ == "__main__":
- main()
diff --git a/subprojects/robotpy-cscore/examples/intermediate_cameraserver.py b/subprojects/robotpy-cscore/examples/intermediate_cameraserver.py
deleted file mode 100755
index c6bd2b1a..00000000
--- a/subprojects/robotpy-cscore/examples/intermediate_cameraserver.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python3
-#
-# This is a demo program showing CameraServer usage with OpenCV to do image
-# processing. The image is acquired from the USB camera, then a rectangle
-# is put on the image and sent to the dashboard. OpenCV has many methods
-# for different types of processing.
-#
-# Warning: If you're using this with a python-based robot, do not run this
-# in the same program as your robot code!
-#
-
-import cv2
-import numpy as np
-
-from cscore import CameraServer as CS
-
-
-def main():
- CS.enableLogging()
-
- camera = CS.startAutomaticCapture()
-
- camera.setResolution(640, 480)
-
- # Get a CvSink. This will capture images from the camera
- cvSink = CS.getVideo()
-
- # (optional) Setup a CvSource. This will send images back to the Dashboard
- outputStream = CS.putVideo("Rectangle", 640, 480)
-
- # Allocating new images is very expensive, always try to preallocate
- img = np.zeros(shape=(480, 640, 3), dtype=np.uint8)
-
- while True:
- # Tell the CvSink to grab a frame from the camera and put it
- # in the source image. If there is an error notify the output.
- time, img = cvSink.grabFrame(img)
- if time == 0:
- # Send the output the error.
- outputStream.notifyError(cvSink.getError())
- # skip the rest of the current iteration
- continue
-
- # Put a rectangle on the image
- cv2.rectangle(img, (100, 100), (400, 400), (255, 255, 255), 5)
-
- # Give the output stream a new image to display
- outputStream.putFrame(img)
-
-
-if __name__ == "__main__":
- # To see messages from networktables, you must setup logging
- import logging
-
- logging.basicConfig(level=logging.DEBUG)
-
- # You should uncomment these to connect to the RoboRIO
- # import ntcore
- # nt = ntcore.NetworkTableInstance.getDefault()
- # nt.setServerTeam(XXXX)
- # nt.startClient4(__file__)
-
- main()
diff --git a/subprojects/robotpy-cscore/examples/quick_cameraserver.py b/subprojects/robotpy-cscore/examples/quick_cameraserver.py
deleted file mode 100755
index db39fa67..00000000
--- a/subprojects/robotpy-cscore/examples/quick_cameraserver.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python3
-#
-# Uses the CameraServer class to automatically capture video from a USB webcam
-# and send it to the FRC dashboard without doing any vision processing.
-#
-# Warning: If you're using this with a python-based robot, do not run this
-# in the same program as your robot code!
-#
-
-
-from cscore import CameraServer as CS
-
-
-def main():
- CS.enableLogging()
-
- CS.startAutomaticCapture()
- CS.waitForever()
-
-
-if __name__ == "__main__":
- # To see messages from networktables, you must setup logging
- import logging
-
- logging.basicConfig(level=logging.DEBUG)
-
- # You should uncomment these to connect to the RoboRIO
- # import ntcore
- # nt = ntcore.NetworkTableInstance.getDefault()
- # nt.setServerTeam(XXXX)
- # nt.startClient4(__file__)
-
- main()
diff --git a/subprojects/robotpy-cscore/examples/settings.py b/subprojects/robotpy-cscore/examples/settings.py
deleted file mode 100755
index 2b800f76..00000000
--- a/subprojects/robotpy-cscore/examples/settings.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import time
-
-import cscore as cs
-
-
-def _usage():
- print("Usage: settings.py camera [prop val] ... -- [prop val]", file=sys.stderr)
- print(" Example: settings.py brightness 30 raw_contrast 10", file=sys.stderr)
-
-
-def main():
- if not hasattr(cs, "UsbCamera"):
- print("ERROR: This platform does not currently have cscore UsbCamera support")
- exit(1)
-
- if len(sys.argv) < 3:
- _usage()
- exit(1)
-
- try:
- cid = int(sys.argv[1])
- except ValueError:
- print("ERROR: Expected first argument to be a number, got '%s'" % sys.argv[1])
- _usage()
- exit(2)
-
- camera = cs.UsbCamera("usbcam", cid)
-
- # Set prior to connect
- argc = 2
- propName = None
-
- for arg in sys.argv[argc:]:
- argc += 1
- if arg == "--":
- break
-
- if propName is None:
- propName = arg
- else:
- try:
- propVal = int(arg)
- except ValueError:
- camera.getProperty(propName).setString(arg)
- else:
- camera.getProperty(propName).set(propVal)
-
- propName = None
-
- # Wait to connect
- while not camera.isConnected():
- time.sleep(0.010)
-
- # Set rest
- for arg in sys.argv[argc:]:
- if propName is None:
- propName = arg
- else:
- try:
- propVal = int(arg)
- except ValueError:
- camera.getProperty(propName).setString(arg)
- else:
- camera.getProperty(propName).set(propVal)
-
- propName = None
-
- # Print settings
- print("Properties:")
- for prop in camera.enumerateProperties():
- kind = prop.getKind()
- if kind == cs.VideoProperty.Kind.kBoolean:
- print(
- prop.getName(),
- "(bool) value=%s default=%s" % (prop.get(), prop.getDefault()),
- )
- elif kind == cs.VideoProperty.Kind.kInteger:
- print(
- prop.getName(),
- "(int): value=%s min=%s max=%s step=%s default=%s"
- % (
- prop.get(),
- prop.getMin(),
- prop.getMax(),
- prop.getStep(),
- prop.getDefault(),
- ),
- )
- elif kind == cs.VideoProperty.Kind.kString:
- print(prop.getName(), "(string):", prop.getString())
- elif kind == cs.VideoProperty.Kind.kEnum:
- print(prop.getName(), "(enum): value=%s" % prop.get())
- for i, choice in enumerate(prop.getChoices()):
- if choice:
- print(" %s: %s" % (i, choice))
-
-
-if __name__ == "__main__":
- main()
diff --git a/subprojects/robotpy-cscore/examples/switched_cameraserver.py b/subprojects/robotpy-cscore/examples/switched_cameraserver.py
deleted file mode 100755
index 10e8d94a..00000000
--- a/subprojects/robotpy-cscore/examples/switched_cameraserver.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python3
-#
-# Uses the CameraServer class to automatically capture video from two USB
-# webcams and send one of them to the dashboard without doing any processing.
-# To switch between the cameras, change the /CameraPublisher/selected value in NetworkTables
-#
-# Warning: If you're using this with a python-based robot, do not run this
-# in the same program as your robot code!
-#
-
-from cscore import CameraServer as CS
-from cscore import UsbCamera
-import ntcore
-
-
-def main():
- CS.enableLogging()
-
- usb0 = UsbCamera("Camera 0", 0)
- usb1 = UsbCamera("Camera 1", 1)
-
- server = CS.addSwitchedCamera("Switched")
- server.setSource(usb0)
-
- # Use networktables to switch the source
- # -> obviously, you can switch them however you'd like
- def _listener(source, key, value, isNew):
- if str(value) == "0":
- server.setSource(usb0)
- elif str(value) == "1":
- server.setSource(usb1)
-
- table = ntcore.NetworkTableInstance.getDefault().getTable("/CameraPublisher")
- table.putString("selected", "0")
- table.addEntryListener(_listener, key="selected")
-
- CS.waitForever()
-
-
-if __name__ == "__main__":
- # To see messages from networktables, you must setup logging
- import logging
-
- logging.basicConfig(level=logging.DEBUG)
-
- # You should change this to connect to the RoboRIO
- nt = ntcore.NetworkTableInstance.getDefault()
- nt.setServer("localhost")
- nt.startClient4(__file__)
-
- main()
diff --git a/subprojects/robotpy-cscore/examples/usbcvstream.py b/subprojects/robotpy-cscore/examples/usbcvstream.py
deleted file mode 100755
index 65651721..00000000
--- a/subprojects/robotpy-cscore/examples/usbcvstream.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python3
-#
-# Demonstrates streaming and modifying the image via OpenCV
-#
-
-
-import cscore as cs
-import numpy as np
-import cv2
-
-
-def main():
- camera = cs.UsbCamera("usbcam", 0)
- camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
-
- mjpegServer = cs.MjpegServer("httpserver", 8081)
- mjpegServer.setSource(camera)
-
- print("mjpg server listening at http://0.0.0.0:8081")
-
- cvsink = cs.CvSink("cvsink")
- cvsink.setSource(camera)
-
- cvSource = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
- cvMjpegServer = cs.MjpegServer("cvhttpserver", 8082)
- cvMjpegServer.setSource(cvSource)
-
- print("OpenCV output mjpg server listening at http://0.0.0.0:8082")
-
- test = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
- flip = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
-
- while True:
- time, test = cvsink.grabFrame(test)
- if time == 0:
- print("error:", cvsink.getError())
- continue
-
- print("got frame at time", time, test.shape)
-
- cv2.flip(test, flipCode=0, dst=flip)
- cvSource.putFrame(flip)
-
-
-if __name__ == "__main__":
- main()
diff --git a/subprojects/robotpy-cscore/examples/usbstream.py b/subprojects/robotpy-cscore/examples/usbstream.py
deleted file mode 100755
index ded3a399..00000000
--- a/subprojects/robotpy-cscore/examples/usbstream.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python3
-
-import cscore as cs
-
-camera = cs.UsbCamera("usbcam", 0)
-camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
-
-mjpegServer = cs.MjpegServer("httpserver", 8081)
-mjpegServer.setSource(camera)
-
-print("mjpg server listening at http://0.0.0.0:8081")
-input("Press enter to exit...")
From 6b55743dd3f9b9011a4afe9ca8e21593ea147c35 Mon Sep 17 00:00:00 2001
From: Martin C <78377730+MilkManMaki@users.noreply.github.com>
Date: Mon, 8 Apr 2024 22:47:02 -0400
Subject: [PATCH 2/4] refactor: moving examples to an example folder in the
root directory
---
EXAMPLES/examplecscore/CameraServer.java | 127 ++++++++++++++++++
EXAMPLES/examplecscore/cvstream.py | 39 ++++++
EXAMPLES/examplecscore/dual_cameraserver.py | 35 +++++
EXAMPLES/examplecscore/enum_usb.py | 62 +++++++++
EXAMPLES/examplecscore/httpcvstream.py | 41 ++++++
.../intermediate_cameraserver.py | 63 +++++++++
EXAMPLES/examplecscore/quick_cameraserver.py | 33 +++++
EXAMPLES/examplecscore/settings.py | 102 ++++++++++++++
.../examplecscore/switched_cameraserver.py | 51 +++++++
EXAMPLES/examplecscore/usbcvstream.py | 46 +++++++
EXAMPLES/examplecscore/usbstream.py | 12 ++
EXAMPLES/examplentcore/pubsub_client.py | 41 ++++++
EXAMPLES/examplentcore/pubsub_server.py | 36 +++++
EXAMPLES/examplentcore/simple_client.py | 52 +++++++
EXAMPLES/examplentcore/simple_poller.py | 59 ++++++++
EXAMPLES/examplentcore/simple_robot.py | 34 +++++
16 files changed, 833 insertions(+)
create mode 100644 EXAMPLES/examplecscore/CameraServer.java
create mode 100644 EXAMPLES/examplecscore/cvstream.py
create mode 100644 EXAMPLES/examplecscore/dual_cameraserver.py
create mode 100644 EXAMPLES/examplecscore/enum_usb.py
create mode 100644 EXAMPLES/examplecscore/httpcvstream.py
create mode 100644 EXAMPLES/examplecscore/intermediate_cameraserver.py
create mode 100644 EXAMPLES/examplecscore/quick_cameraserver.py
create mode 100644 EXAMPLES/examplecscore/settings.py
create mode 100644 EXAMPLES/examplecscore/switched_cameraserver.py
create mode 100644 EXAMPLES/examplecscore/usbcvstream.py
create mode 100644 EXAMPLES/examplecscore/usbstream.py
create mode 100644 EXAMPLES/examplentcore/pubsub_client.py
create mode 100644 EXAMPLES/examplentcore/pubsub_server.py
create mode 100644 EXAMPLES/examplentcore/simple_client.py
create mode 100644 EXAMPLES/examplentcore/simple_poller.py
create mode 100644 EXAMPLES/examplentcore/simple_robot.py
diff --git a/EXAMPLES/examplecscore/CameraServer.java b/EXAMPLES/examplecscore/CameraServer.java
new file mode 100644
index 00000000..af9bc72a
--- /dev/null
+++ b/EXAMPLES/examplecscore/CameraServer.java
@@ -0,0 +1,127 @@
+package io.github.robotpy.cscore;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ProcessBuilder.Redirect;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+import edu.wpi.first.wpilibj.DriverStation;
+
+/**
+ * Provides a way to launch an out of process Python robotpy-cscore based
+ * camera service instance from a Java robot program.
+ *
+ * You must have Python and python36-robotpy-cscore installed, or this
+ * just simply won't work. Refer to the RobotPy documentation for details.
+ *
+ * The python code should be a single file, and must compiled into your java
+ * jar file. If your file was in the src directory as 'vision.py', you would
+ * add this to the 'project' section of build.xml:
+ */
+//
+//
+// [athena-jar] Making jar ${dist.jar}.
+//
+//
+//
+// [athena-jar] Copying jars to ${build.jars}.
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+public class CameraServer {
+
+ public static String visionPath = "/home/lvuser/vision.py";
+ private static boolean isAlive = false;
+ private static boolean launched = false;
+
+ /**
+ * @return true if the vision process is (probably) alive
+ */
+ public static boolean isAlive() {
+ return isAlive;
+ }
+
+ /**
+ * Launches an embedded resource called "vision.py" which contains a
+ * "main" function.
+ */
+ public static void startPythonVision() {
+ startPythonVision("/vision.py", "main");
+ }
+
+ /**
+ * Call this function to launch a python vision program in an external
+ * process.
+ *
+ * @param resource The resource built into the jar (see above), such as /vision.py
+ * @param functionName The name of the function to call
+ */
+ public static void startPythonVision(String resource, String functionName) {
+ // don't allow restart
+ if (launched) {
+ return;
+ }
+
+ launched = true;
+
+ System.out.println("Launching python process from " + resource);
+
+ try {
+ // extract the resource and write it to vision.py
+ InputStream is = CameraServer.class.getResourceAsStream(resource);
+ if (is == null) {
+ throw new IOException("Resource " + resource + " not found");
+ }
+
+ Files.copy(is, Paths.get(visionPath), StandardCopyOption.REPLACE_EXISTING);
+
+ // launch the process
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command("/usr/local/bin/python3", "-m", "cscore", visionPath + ":" + functionName);
+
+ // we open a pipe to it so that when the robot program exits, the child dies
+ pb.redirectInput(Redirect.PIPE);
+
+ // and let us see stdout/stderr
+ pb.redirectOutput(Redirect.INHERIT);
+ pb.redirectError(Redirect.INHERIT);
+
+ final Process p = pb.start();
+ isAlive = true;
+
+ Thread t = new Thread(()-> {
+ try {
+ p.waitFor();
+ } catch (InterruptedException e) {
+ // empty
+ }
+
+ isAlive = false;
+ });
+ t.setDaemon(true);
+ t.start();
+
+ } catch (IOException e) {
+ System.out.println("Error launching vision! " + e.toString());
+ //if (!DriverStation.getInstance().isFMSAttached()) {
+ // throw new RuntimeException("Error launching vision", e);
+ //}
+ }
+ }
+}
diff --git a/EXAMPLES/examplecscore/cvstream.py b/EXAMPLES/examplecscore/cvstream.py
new file mode 100644
index 00000000..67dbe3cb
--- /dev/null
+++ b/EXAMPLES/examplecscore/cvstream.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+#
+# WARNING: You should only use this approach for testing cscore on platforms that
+# it doesn't support using UsbCamera
+#
+
+import cscore as cs
+
+if hasattr(cs, "UsbCamera"):
+ camera = cs.UsbCamera("usbcam", 0)
+ camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+else:
+ import cv2
+ import threading
+
+ camera = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+
+ # tell OpenCV to capture video for us
+ cap = cv2.VideoCapture(0)
+ cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
+ cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
+
+ # Do it in another thread
+ def _thread():
+ img = None
+ while True:
+ retval, img = cap.read(img)
+ if retval:
+ camera.putFrame(img)
+
+ th = threading.Thread(target=_thread, daemon=True)
+ th.start()
+
+
+mjpegServer = cs.MjpegServer("httpserver", 8081)
+mjpegServer.setSource(camera)
+
+print("mjpg server listening at http://0.0.0.0:8081")
+input("Press enter to exit...")
diff --git a/EXAMPLES/examplecscore/dual_cameraserver.py b/EXAMPLES/examplecscore/dual_cameraserver.py
new file mode 100644
index 00000000..74bf59cc
--- /dev/null
+++ b/EXAMPLES/examplecscore/dual_cameraserver.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Uses the CameraServer class to automatically capture video from two USB
+# webcams and send it to the FRC dashboard without doing any vision
+# processing.
+#
+# Warning: If you're using this with a python-based robot, do not run this
+# in the same program as your robot code!
+#
+
+from cscore import CameraServer as CS
+
+
+def main():
+ CS.enableLogging()
+
+ usb1 = CS.startAutomaticCapture(dev=0)
+ usb2 = CS.startAutomaticCapture(dev=1)
+
+ CS.waitForever()
+
+
+if __name__ == "__main__":
+ # To see messages from networktables, you must setup logging
+ import logging
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ # You should uncomment these to connect to the RoboRIO
+ # import ntcore
+ # nt = ntcore.NetworkTableInstance.getDefault()
+ # nt.setServerTeam(XXXX)
+ # nt.startClient4(__file__)
+
+ main()
diff --git a/EXAMPLES/examplecscore/enum_usb.py b/EXAMPLES/examplecscore/enum_usb.py
new file mode 100644
index 00000000..1dd937aa
--- /dev/null
+++ b/EXAMPLES/examplecscore/enum_usb.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+
+import cscore as cs
+
+
+def main():
+ for caminfo in cs.UsbCamera.enumerateUsbCameras():
+ print("%s: %s (%s)" % (caminfo.dev, caminfo.path, caminfo.name))
+ if caminfo.otherPaths:
+ print("Other device paths:")
+ for path in caminfo.otherPaths:
+ print(" ", path)
+
+ camera = cs.UsbCamera("usbcam", caminfo.dev)
+
+ print("Properties:")
+ for prop in camera.enumerateProperties():
+ kind = prop.getKind()
+ if kind == cs.VideoProperty.Kind.kBoolean:
+ print(
+ prop.getName(),
+ "(bool) value=%s default=%s" % (prop.get(), prop.getDefault()),
+ )
+ elif kind == cs.VideoProperty.Kind.kInteger:
+ print(
+ prop.getName(),
+ "(int): value=%s min=%s max=%s step=%s default=%s"
+ % (
+ prop.get(),
+ prop.getMin(),
+ prop.getMax(),
+ prop.getStep(),
+ prop.getDefault(),
+ ),
+ )
+ elif kind == cs.VideoProperty.Kind.kString:
+ print(prop.getName(), "(string):", prop.getString())
+ elif kind == cs.VideoProperty.Kind.kEnum:
+ print(prop.getName(), "(enum): value=%s" % prop.get())
+ for i, choice in enumerate(prop.getChoices()):
+ if choice:
+ print(" %s: %s" % (i, choice))
+
+ print("Video Modes")
+ for mode in camera.enumerateVideoModes():
+ if mode.pixelFormat == cs.VideoMode.PixelFormat.kMJPEG:
+ fmt = "MJPEG"
+ elif mode.pixelFormat == cs.VideoMode.PixelFormat.kYUYV:
+ fmt = "YUYV"
+ elif mode.pixelFormat == cs.VideoMode.PixelFormat.kRGB565:
+ fmt = "RGB565"
+ else:
+ fmt = "Unknown"
+
+ print(" PixelFormat:", fmt)
+ print(" Width:", mode.width)
+ print(" Height:", mode.height)
+ print(" FPS: ", mode.fps)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/EXAMPLES/examplecscore/httpcvstream.py b/EXAMPLES/examplecscore/httpcvstream.py
new file mode 100644
index 00000000..9acfbbfa
--- /dev/null
+++ b/EXAMPLES/examplecscore/httpcvstream.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# Demonstrates streaming from a HTTP camera server
+#
+
+
+import cscore as cs
+import numpy as np
+import cv2
+
+
+def main():
+ camera = cs.HttpCamera("httpcam", "http://localhost:8081/?action=stream")
+ camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+
+ cvsink = cs.CvSink("cvsink")
+ cvsink.setSource(camera)
+
+ cvSource = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+ cvMjpegServer = cs.MjpegServer("cvhttpserver", 8083)
+ cvMjpegServer.setSource(cvSource)
+
+ print("OpenCV output mjpg server listening at http://0.0.0.0:8083")
+
+ test = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
+ flip = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
+
+ while True:
+ time, test = cvsink.grabFrame(test)
+ if time == 0:
+ print("error:", cvsink.getError())
+ continue
+
+ print("got frame at time", time, test.shape)
+
+ cv2.flip(test, flipCode=0, dst=flip)
+ cvSource.putFrame(flip)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/EXAMPLES/examplecscore/intermediate_cameraserver.py b/EXAMPLES/examplecscore/intermediate_cameraserver.py
new file mode 100644
index 00000000..c6bd2b1a
--- /dev/null
+++ b/EXAMPLES/examplecscore/intermediate_cameraserver.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+#
+# This is a demo program showing CameraServer usage with OpenCV to do image
+# processing. The image is acquired from the USB camera, then a rectangle
+# is put on the image and sent to the dashboard. OpenCV has many methods
+# for different types of processing.
+#
+# Warning: If you're using this with a python-based robot, do not run this
+# in the same program as your robot code!
+#
+
+import cv2
+import numpy as np
+
+from cscore import CameraServer as CS
+
+
+def main():
+ CS.enableLogging()
+
+ camera = CS.startAutomaticCapture()
+
+ camera.setResolution(640, 480)
+
+ # Get a CvSink. This will capture images from the camera
+ cvSink = CS.getVideo()
+
+ # (optional) Setup a CvSource. This will send images back to the Dashboard
+ outputStream = CS.putVideo("Rectangle", 640, 480)
+
+ # Allocating new images is very expensive, always try to preallocate
+ img = np.zeros(shape=(480, 640, 3), dtype=np.uint8)
+
+ while True:
+ # Tell the CvSink to grab a frame from the camera and put it
+ # in the source image. If there is an error notify the output.
+ time, img = cvSink.grabFrame(img)
+ if time == 0:
+ # Send the output the error.
+ outputStream.notifyError(cvSink.getError())
+ # skip the rest of the current iteration
+ continue
+
+ # Put a rectangle on the image
+ cv2.rectangle(img, (100, 100), (400, 400), (255, 255, 255), 5)
+
+ # Give the output stream a new image to display
+ outputStream.putFrame(img)
+
+
+if __name__ == "__main__":
+ # To see messages from networktables, you must setup logging
+ import logging
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ # You should uncomment these to connect to the RoboRIO
+ # import ntcore
+ # nt = ntcore.NetworkTableInstance.getDefault()
+ # nt.setServerTeam(XXXX)
+ # nt.startClient4(__file__)
+
+ main()
diff --git a/EXAMPLES/examplecscore/quick_cameraserver.py b/EXAMPLES/examplecscore/quick_cameraserver.py
new file mode 100644
index 00000000..db39fa67
--- /dev/null
+++ b/EXAMPLES/examplecscore/quick_cameraserver.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+#
+# Uses the CameraServer class to automatically capture video from a USB webcam
+# and send it to the FRC dashboard without doing any vision processing.
+#
+# Warning: If you're using this with a python-based robot, do not run this
+# in the same program as your robot code!
+#
+
+
+from cscore import CameraServer as CS
+
+
+def main():
+ CS.enableLogging()
+
+ CS.startAutomaticCapture()
+ CS.waitForever()
+
+
+if __name__ == "__main__":
+ # To see messages from networktables, you must setup logging
+ import logging
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ # You should uncomment these to connect to the RoboRIO
+ # import ntcore
+ # nt = ntcore.NetworkTableInstance.getDefault()
+ # nt.setServerTeam(XXXX)
+ # nt.startClient4(__file__)
+
+ main()
diff --git a/EXAMPLES/examplecscore/settings.py b/EXAMPLES/examplecscore/settings.py
new file mode 100644
index 00000000..2b800f76
--- /dev/null
+++ b/EXAMPLES/examplecscore/settings.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+import sys
+import time
+
+import cscore as cs
+
+
+def _usage():
+ print("Usage: settings.py camera [prop val] ... -- [prop val]", file=sys.stderr)
+ print(" Example: settings.py brightness 30 raw_contrast 10", file=sys.stderr)
+
+
+def main():
+ if not hasattr(cs, "UsbCamera"):
+ print("ERROR: This platform does not currently have cscore UsbCamera support")
+ exit(1)
+
+ if len(sys.argv) < 3:
+ _usage()
+ exit(1)
+
+ try:
+ cid = int(sys.argv[1])
+ except ValueError:
+ print("ERROR: Expected first argument to be a number, got '%s'" % sys.argv[1])
+ _usage()
+ exit(2)
+
+ camera = cs.UsbCamera("usbcam", cid)
+
+ # Set prior to connect
+ argc = 2
+ propName = None
+
+ for arg in sys.argv[argc:]:
+ argc += 1
+ if arg == "--":
+ break
+
+ if propName is None:
+ propName = arg
+ else:
+ try:
+ propVal = int(arg)
+ except ValueError:
+ camera.getProperty(propName).setString(arg)
+ else:
+ camera.getProperty(propName).set(propVal)
+
+ propName = None
+
+ # Wait to connect
+ while not camera.isConnected():
+ time.sleep(0.010)
+
+ # Set rest
+ for arg in sys.argv[argc:]:
+ if propName is None:
+ propName = arg
+ else:
+ try:
+ propVal = int(arg)
+ except ValueError:
+ camera.getProperty(propName).setString(arg)
+ else:
+ camera.getProperty(propName).set(propVal)
+
+ propName = None
+
+ # Print settings
+ print("Properties:")
+ for prop in camera.enumerateProperties():
+ kind = prop.getKind()
+ if kind == cs.VideoProperty.Kind.kBoolean:
+ print(
+ prop.getName(),
+ "(bool) value=%s default=%s" % (prop.get(), prop.getDefault()),
+ )
+ elif kind == cs.VideoProperty.Kind.kInteger:
+ print(
+ prop.getName(),
+ "(int): value=%s min=%s max=%s step=%s default=%s"
+ % (
+ prop.get(),
+ prop.getMin(),
+ prop.getMax(),
+ prop.getStep(),
+ prop.getDefault(),
+ ),
+ )
+ elif kind == cs.VideoProperty.Kind.kString:
+ print(prop.getName(), "(string):", prop.getString())
+ elif kind == cs.VideoProperty.Kind.kEnum:
+ print(prop.getName(), "(enum): value=%s" % prop.get())
+ for i, choice in enumerate(prop.getChoices()):
+ if choice:
+ print(" %s: %s" % (i, choice))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/EXAMPLES/examplecscore/switched_cameraserver.py b/EXAMPLES/examplecscore/switched_cameraserver.py
new file mode 100644
index 00000000..10e8d94a
--- /dev/null
+++ b/EXAMPLES/examplecscore/switched_cameraserver.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Uses the CameraServer class to automatically capture video from two USB
+# webcams and send one of them to the dashboard without doing any processing.
+# To switch between the cameras, change the /CameraPublisher/selected value in NetworkTables
+#
+# Warning: If you're using this with a python-based robot, do not run this
+# in the same program as your robot code!
+#
+
+from cscore import CameraServer as CS
+from cscore import UsbCamera
+import ntcore
+
+
+def main():
+ CS.enableLogging()
+
+ usb0 = UsbCamera("Camera 0", 0)
+ usb1 = UsbCamera("Camera 1", 1)
+
+ server = CS.addSwitchedCamera("Switched")
+ server.setSource(usb0)
+
+ # Use networktables to switch the source
+ # -> obviously, you can switch them however you'd like
+ def _listener(source, key, value, isNew):
+ if str(value) == "0":
+ server.setSource(usb0)
+ elif str(value) == "1":
+ server.setSource(usb1)
+
+ table = ntcore.NetworkTableInstance.getDefault().getTable("/CameraPublisher")
+ table.putString("selected", "0")
+ table.addEntryListener(_listener, key="selected")
+
+ CS.waitForever()
+
+
+if __name__ == "__main__":
+ # To see messages from networktables, you must setup logging
+ import logging
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ # You should change this to connect to the RoboRIO
+ nt = ntcore.NetworkTableInstance.getDefault()
+ nt.setServer("localhost")
+ nt.startClient4(__file__)
+
+ main()
diff --git a/EXAMPLES/examplecscore/usbcvstream.py b/EXAMPLES/examplecscore/usbcvstream.py
new file mode 100644
index 00000000..65651721
--- /dev/null
+++ b/EXAMPLES/examplecscore/usbcvstream.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# Demonstrates streaming and modifying the image via OpenCV
+#
+
+
+import cscore as cs
+import numpy as np
+import cv2
+
+
+def main():
+ camera = cs.UsbCamera("usbcam", 0)
+ camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+
+ mjpegServer = cs.MjpegServer("httpserver", 8081)
+ mjpegServer.setSource(camera)
+
+ print("mjpg server listening at http://0.0.0.0:8081")
+
+ cvsink = cs.CvSink("cvsink")
+ cvsink.setSource(camera)
+
+ cvSource = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+ cvMjpegServer = cs.MjpegServer("cvhttpserver", 8082)
+ cvMjpegServer.setSource(cvSource)
+
+ print("OpenCV output mjpg server listening at http://0.0.0.0:8082")
+
+ test = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
+ flip = np.zeros(shape=(240, 320, 3), dtype=np.uint8)
+
+ while True:
+ time, test = cvsink.grabFrame(test)
+ if time == 0:
+ print("error:", cvsink.getError())
+ continue
+
+ print("got frame at time", time, test.shape)
+
+ cv2.flip(test, flipCode=0, dst=flip)
+ cvSource.putFrame(flip)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/EXAMPLES/examplecscore/usbstream.py b/EXAMPLES/examplecscore/usbstream.py
new file mode 100644
index 00000000..ded3a399
--- /dev/null
+++ b/EXAMPLES/examplecscore/usbstream.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+
+import cscore as cs
+
+camera = cs.UsbCamera("usbcam", 0)
+camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30)
+
+mjpegServer = cs.MjpegServer("httpserver", 8081)
+mjpegServer.setSource(camera)
+
+print("mjpg server listening at http://0.0.0.0:8081")
+input("Press enter to exit...")
diff --git a/EXAMPLES/examplentcore/pubsub_client.py b/EXAMPLES/examplentcore/pubsub_client.py
new file mode 100644
index 00000000..f67257fc
--- /dev/null
+++ b/EXAMPLES/examplentcore/pubsub_client.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# A client that publishes some synchronized values periodically
+
+import argparse
+import os
+from os.path import basename
+import logging
+import time
+
+import ntcore
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("ip", type=str, help="IP address to connect to")
+ args = parser.parse_args()
+
+ # Initialize NT4 client
+ inst = ntcore.NetworkTableInstance.getDefault()
+
+ identity = f"{basename(__file__)}-{os.getpid()}"
+ inst.startClient4(identity)
+
+ inst.setServer(args.ip)
+
+ # publish two values
+ table = inst.getTable("data")
+ pub1 = table.getDoubleTopic("1").publish()
+ pub2 = table.getDoubleTopic("2").publish()
+
+ i = 3
+
+ while True:
+ # These values are being published fast than the server is polling
+ pub1.set(i)
+ pub2.set(i + 100)
+
+ time.sleep(0.5)
+ i += 1
diff --git a/EXAMPLES/examplentcore/pubsub_server.py b/EXAMPLES/examplentcore/pubsub_server.py
new file mode 100644
index 00000000..6356b0c5
--- /dev/null
+++ b/EXAMPLES/examplentcore/pubsub_server.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# A server that reads from the subscription
+#
+
+import logging
+import time
+
+import ntcore
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+
+ # initialize networktables server (on a robot this is already done)
+ inst = ntcore.NetworkTableInstance.getDefault()
+ inst.startServer()
+
+ # Initialize two subscriptions
+ table = inst.getTable("data")
+
+ # only keep the latest value for this topic
+ sub1 = table.getDoubleTopic("1").subscribe(-1.0)
+
+ # keep the last 10 values for this topic
+ sub2 = table.getDoubleTopic("2").subscribe(
+ -2.0, ntcore.PubSubOptions(pollStorage=10)
+ )
+
+ # Periodically read from them
+ # - note sub1 only has 1 value, but sub2 sometimes has more than 1
+ while True:
+ print("---", ntcore._now())
+ print("/data/1:", sub1.readQueue())
+ print("/data/2:", sub2.readQueue())
+
+ time.sleep(1.2)
diff --git a/EXAMPLES/examplentcore/simple_client.py b/EXAMPLES/examplentcore/simple_client.py
new file mode 100644
index 00000000..d49155b7
--- /dev/null
+++ b/EXAMPLES/examplentcore/simple_client.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+#
+# This is a NetworkTables client (eg, the DriverStation/coprocessor side).
+# You need to tell it the IP address of the NetworkTables server (the
+# robot or simulator).
+#
+# When running, this will continue incrementing the value 'dsTime', and the
+# value should be visible to other networktables clients and the robot.
+#
+
+import argparse
+from os.path import basename
+import logging
+import time
+
+import ntcore
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-p",
+ "--protocol",
+ type=int,
+ choices=[3, 4],
+ help="NT Protocol to use",
+ default=4,
+ )
+ parser.add_argument("ip", type=str, help="IP address to connect to")
+ args = parser.parse_args()
+
+ inst = ntcore.NetworkTableInstance.getDefault()
+
+ identity = basename(__file__)
+ if args.protocol == 3:
+ inst.startClient3(identity)
+ else:
+ inst.startClient4(identity)
+
+ inst.setServer(args.ip)
+
+ sd = inst.getTable("SmartDashboard")
+
+ i = 0
+ while True:
+ print("robotTime:", sd.getNumber("robotTime", -1))
+
+ sd.putNumber("dsTime", i)
+ time.sleep(1)
+ i += 1
diff --git a/EXAMPLES/examplentcore/simple_poller.py b/EXAMPLES/examplentcore/simple_poller.py
new file mode 100644
index 00000000..3c7c78e8
--- /dev/null
+++ b/EXAMPLES/examplentcore/simple_poller.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# This is a NetworkTables client (eg, the DriverStation/coprocessor side).
+# You need to tell it the IP address of the NetworkTables server (the
+# robot or simulator).
+#
+# This is intended to be ran at the same time as the simple_robot.py
+# and simple_client.py examples. It will output values as they change.
+#
+
+import argparse
+from os.path import basename
+import logging
+import time
+
+import ntcore
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-p",
+ "--protocol",
+ type=int,
+ choices=[3, 4],
+ help="NT Protocol to use",
+ default=4,
+ )
+ parser.add_argument("ip", type=str, help="IP address to connect to")
+ args = parser.parse_args()
+
+ inst = ntcore.NetworkTableInstance.getDefault()
+
+ identity = basename(__file__)
+ if args.protocol == 3:
+ inst.startClient3(identity)
+ else:
+ inst.startClient4(identity)
+
+ inst.setServer(args.ip)
+
+ # Create a poller
+ poller = ntcore.NetworkTableListenerPoller(inst)
+
+ # Listen for all connection events
+ poller.addConnectionListener(True)
+
+ # Listen to all changes
+ msub = ntcore.MultiSubscriber(inst, [""])
+ poller.addListener(msub, ntcore.EventFlags.kValueRemote)
+
+ while True:
+ # periodically read from the queue
+ for event in poller.readQueue():
+ print(event)
+
+ time.sleep(1)
diff --git a/EXAMPLES/examplentcore/simple_robot.py b/EXAMPLES/examplentcore/simple_robot.py
new file mode 100644
index 00000000..1eeb6ebc
--- /dev/null
+++ b/EXAMPLES/examplentcore/simple_robot.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# This is a NetworkTables server (eg, the robot or simulator side).
+#
+# On a real robot, you probably would create an instance of the
+# wpilib.SmartDashboard object and use that instead -- but it's really
+# just a passthru to the underlying NetworkTable object.
+#
+# When running, this will continue incrementing the value 'robotTime',
+# and the value should be visible to networktables clients such as
+# Shuffleboard or simple_client.py
+#
+
+import logging
+import time
+
+import ntcore
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+
+ inst = ntcore.NetworkTableInstance.getDefault()
+
+ inst.startServer()
+ sd = inst.getTable("SmartDashboard")
+
+ i = 0
+ while True:
+ print("dsTime:", sd.getNumber("dsTime", -1))
+
+ sd.putNumber("robotTime", i)
+ time.sleep(1)
+ i += 1
From e0b7ae61654d21a0542f766ddf3e7fccc6524779 Mon Sep 17 00:00:00 2001
From: Martin C <78377730+MilkManMaki@users.noreply.github.com>
Date: Sun, 9 Jun 2024 02:46:56 -0400
Subject: [PATCH 3/4] fix: fix naming convention
---
EXAMPLES/{examplecscore => cscore}/CameraServer.java | 0
EXAMPLES/{examplecscore => cscore}/cvstream.py | 0
EXAMPLES/{examplecscore => cscore}/dual_cameraserver.py | 0
EXAMPLES/{examplecscore => cscore}/enum_usb.py | 0
EXAMPLES/{examplecscore => cscore}/httpcvstream.py | 0
EXAMPLES/{examplecscore => cscore}/intermediate_cameraserver.py | 0
EXAMPLES/{examplecscore => cscore}/quick_cameraserver.py | 0
EXAMPLES/{examplecscore => cscore}/settings.py | 0
EXAMPLES/{examplecscore => cscore}/switched_cameraserver.py | 0
EXAMPLES/{examplecscore => cscore}/usbcvstream.py | 0
EXAMPLES/{examplecscore => cscore}/usbstream.py | 0
EXAMPLES/{examplentcore => ntcore}/pubsub_client.py | 0
EXAMPLES/{examplentcore => ntcore}/pubsub_server.py | 0
EXAMPLES/{examplentcore => ntcore}/simple_client.py | 0
EXAMPLES/{examplentcore => ntcore}/simple_poller.py | 0
EXAMPLES/{examplentcore => ntcore}/simple_robot.py | 0
16 files changed, 0 insertions(+), 0 deletions(-)
rename EXAMPLES/{examplecscore => cscore}/CameraServer.java (100%)
rename EXAMPLES/{examplecscore => cscore}/cvstream.py (100%)
rename EXAMPLES/{examplecscore => cscore}/dual_cameraserver.py (100%)
rename EXAMPLES/{examplecscore => cscore}/enum_usb.py (100%)
rename EXAMPLES/{examplecscore => cscore}/httpcvstream.py (100%)
rename EXAMPLES/{examplecscore => cscore}/intermediate_cameraserver.py (100%)
rename EXAMPLES/{examplecscore => cscore}/quick_cameraserver.py (100%)
rename EXAMPLES/{examplecscore => cscore}/settings.py (100%)
rename EXAMPLES/{examplecscore => cscore}/switched_cameraserver.py (100%)
rename EXAMPLES/{examplecscore => cscore}/usbcvstream.py (100%)
rename EXAMPLES/{examplecscore => cscore}/usbstream.py (100%)
rename EXAMPLES/{examplentcore => ntcore}/pubsub_client.py (100%)
rename EXAMPLES/{examplentcore => ntcore}/pubsub_server.py (100%)
rename EXAMPLES/{examplentcore => ntcore}/simple_client.py (100%)
rename EXAMPLES/{examplentcore => ntcore}/simple_poller.py (100%)
rename EXAMPLES/{examplentcore => ntcore}/simple_robot.py (100%)
diff --git a/EXAMPLES/examplecscore/CameraServer.java b/EXAMPLES/cscore/CameraServer.java
similarity index 100%
rename from EXAMPLES/examplecscore/CameraServer.java
rename to EXAMPLES/cscore/CameraServer.java
diff --git a/EXAMPLES/examplecscore/cvstream.py b/EXAMPLES/cscore/cvstream.py
similarity index 100%
rename from EXAMPLES/examplecscore/cvstream.py
rename to EXAMPLES/cscore/cvstream.py
diff --git a/EXAMPLES/examplecscore/dual_cameraserver.py b/EXAMPLES/cscore/dual_cameraserver.py
similarity index 100%
rename from EXAMPLES/examplecscore/dual_cameraserver.py
rename to EXAMPLES/cscore/dual_cameraserver.py
diff --git a/EXAMPLES/examplecscore/enum_usb.py b/EXAMPLES/cscore/enum_usb.py
similarity index 100%
rename from EXAMPLES/examplecscore/enum_usb.py
rename to EXAMPLES/cscore/enum_usb.py
diff --git a/EXAMPLES/examplecscore/httpcvstream.py b/EXAMPLES/cscore/httpcvstream.py
similarity index 100%
rename from EXAMPLES/examplecscore/httpcvstream.py
rename to EXAMPLES/cscore/httpcvstream.py
diff --git a/EXAMPLES/examplecscore/intermediate_cameraserver.py b/EXAMPLES/cscore/intermediate_cameraserver.py
similarity index 100%
rename from EXAMPLES/examplecscore/intermediate_cameraserver.py
rename to EXAMPLES/cscore/intermediate_cameraserver.py
diff --git a/EXAMPLES/examplecscore/quick_cameraserver.py b/EXAMPLES/cscore/quick_cameraserver.py
similarity index 100%
rename from EXAMPLES/examplecscore/quick_cameraserver.py
rename to EXAMPLES/cscore/quick_cameraserver.py
diff --git a/EXAMPLES/examplecscore/settings.py b/EXAMPLES/cscore/settings.py
similarity index 100%
rename from EXAMPLES/examplecscore/settings.py
rename to EXAMPLES/cscore/settings.py
diff --git a/EXAMPLES/examplecscore/switched_cameraserver.py b/EXAMPLES/cscore/switched_cameraserver.py
similarity index 100%
rename from EXAMPLES/examplecscore/switched_cameraserver.py
rename to EXAMPLES/cscore/switched_cameraserver.py
diff --git a/EXAMPLES/examplecscore/usbcvstream.py b/EXAMPLES/cscore/usbcvstream.py
similarity index 100%
rename from EXAMPLES/examplecscore/usbcvstream.py
rename to EXAMPLES/cscore/usbcvstream.py
diff --git a/EXAMPLES/examplecscore/usbstream.py b/EXAMPLES/cscore/usbstream.py
similarity index 100%
rename from EXAMPLES/examplecscore/usbstream.py
rename to EXAMPLES/cscore/usbstream.py
diff --git a/EXAMPLES/examplentcore/pubsub_client.py b/EXAMPLES/ntcore/pubsub_client.py
similarity index 100%
rename from EXAMPLES/examplentcore/pubsub_client.py
rename to EXAMPLES/ntcore/pubsub_client.py
diff --git a/EXAMPLES/examplentcore/pubsub_server.py b/EXAMPLES/ntcore/pubsub_server.py
similarity index 100%
rename from EXAMPLES/examplentcore/pubsub_server.py
rename to EXAMPLES/ntcore/pubsub_server.py
diff --git a/EXAMPLES/examplentcore/simple_client.py b/EXAMPLES/ntcore/simple_client.py
similarity index 100%
rename from EXAMPLES/examplentcore/simple_client.py
rename to EXAMPLES/ntcore/simple_client.py
diff --git a/EXAMPLES/examplentcore/simple_poller.py b/EXAMPLES/ntcore/simple_poller.py
similarity index 100%
rename from EXAMPLES/examplentcore/simple_poller.py
rename to EXAMPLES/ntcore/simple_poller.py
diff --git a/EXAMPLES/examplentcore/simple_robot.py b/EXAMPLES/ntcore/simple_robot.py
similarity index 100%
rename from EXAMPLES/examplentcore/simple_robot.py
rename to EXAMPLES/ntcore/simple_robot.py
From 0b258b713e54aa9a1cb52634c732d4df4059c516 Mon Sep 17 00:00:00 2001
From: Martin C <78377730+MilkManMaki@users.noreply.github.com>
Date: Sun, 9 Jun 2024 03:03:58 -0400
Subject: [PATCH 4/4] fix: rename examples case
---
{EXAMPLES => examples}/cscore/CameraServer.java | 0
{EXAMPLES => examples}/cscore/cvstream.py | 0
{EXAMPLES => examples}/cscore/dual_cameraserver.py | 0
{EXAMPLES => examples}/cscore/enum_usb.py | 0
{EXAMPLES => examples}/cscore/httpcvstream.py | 0
{EXAMPLES => examples}/cscore/intermediate_cameraserver.py | 0
{EXAMPLES => examples}/cscore/quick_cameraserver.py | 0
{EXAMPLES => examples}/cscore/settings.py | 0
{EXAMPLES => examples}/cscore/switched_cameraserver.py | 0
{EXAMPLES => examples}/cscore/usbcvstream.py | 0
{EXAMPLES => examples}/cscore/usbstream.py | 0
{EXAMPLES => examples}/ntcore/pubsub_client.py | 0
{EXAMPLES => examples}/ntcore/pubsub_server.py | 0
{EXAMPLES => examples}/ntcore/simple_client.py | 0
{EXAMPLES => examples}/ntcore/simple_poller.py | 0
{EXAMPLES => examples}/ntcore/simple_robot.py | 0
16 files changed, 0 insertions(+), 0 deletions(-)
rename {EXAMPLES => examples}/cscore/CameraServer.java (100%)
rename {EXAMPLES => examples}/cscore/cvstream.py (100%)
rename {EXAMPLES => examples}/cscore/dual_cameraserver.py (100%)
rename {EXAMPLES => examples}/cscore/enum_usb.py (100%)
rename {EXAMPLES => examples}/cscore/httpcvstream.py (100%)
rename {EXAMPLES => examples}/cscore/intermediate_cameraserver.py (100%)
rename {EXAMPLES => examples}/cscore/quick_cameraserver.py (100%)
rename {EXAMPLES => examples}/cscore/settings.py (100%)
rename {EXAMPLES => examples}/cscore/switched_cameraserver.py (100%)
rename {EXAMPLES => examples}/cscore/usbcvstream.py (100%)
rename {EXAMPLES => examples}/cscore/usbstream.py (100%)
rename {EXAMPLES => examples}/ntcore/pubsub_client.py (100%)
rename {EXAMPLES => examples}/ntcore/pubsub_server.py (100%)
rename {EXAMPLES => examples}/ntcore/simple_client.py (100%)
rename {EXAMPLES => examples}/ntcore/simple_poller.py (100%)
rename {EXAMPLES => examples}/ntcore/simple_robot.py (100%)
diff --git a/EXAMPLES/cscore/CameraServer.java b/examples/cscore/CameraServer.java
similarity index 100%
rename from EXAMPLES/cscore/CameraServer.java
rename to examples/cscore/CameraServer.java
diff --git a/EXAMPLES/cscore/cvstream.py b/examples/cscore/cvstream.py
similarity index 100%
rename from EXAMPLES/cscore/cvstream.py
rename to examples/cscore/cvstream.py
diff --git a/EXAMPLES/cscore/dual_cameraserver.py b/examples/cscore/dual_cameraserver.py
similarity index 100%
rename from EXAMPLES/cscore/dual_cameraserver.py
rename to examples/cscore/dual_cameraserver.py
diff --git a/EXAMPLES/cscore/enum_usb.py b/examples/cscore/enum_usb.py
similarity index 100%
rename from EXAMPLES/cscore/enum_usb.py
rename to examples/cscore/enum_usb.py
diff --git a/EXAMPLES/cscore/httpcvstream.py b/examples/cscore/httpcvstream.py
similarity index 100%
rename from EXAMPLES/cscore/httpcvstream.py
rename to examples/cscore/httpcvstream.py
diff --git a/EXAMPLES/cscore/intermediate_cameraserver.py b/examples/cscore/intermediate_cameraserver.py
similarity index 100%
rename from EXAMPLES/cscore/intermediate_cameraserver.py
rename to examples/cscore/intermediate_cameraserver.py
diff --git a/EXAMPLES/cscore/quick_cameraserver.py b/examples/cscore/quick_cameraserver.py
similarity index 100%
rename from EXAMPLES/cscore/quick_cameraserver.py
rename to examples/cscore/quick_cameraserver.py
diff --git a/EXAMPLES/cscore/settings.py b/examples/cscore/settings.py
similarity index 100%
rename from EXAMPLES/cscore/settings.py
rename to examples/cscore/settings.py
diff --git a/EXAMPLES/cscore/switched_cameraserver.py b/examples/cscore/switched_cameraserver.py
similarity index 100%
rename from EXAMPLES/cscore/switched_cameraserver.py
rename to examples/cscore/switched_cameraserver.py
diff --git a/EXAMPLES/cscore/usbcvstream.py b/examples/cscore/usbcvstream.py
similarity index 100%
rename from EXAMPLES/cscore/usbcvstream.py
rename to examples/cscore/usbcvstream.py
diff --git a/EXAMPLES/cscore/usbstream.py b/examples/cscore/usbstream.py
similarity index 100%
rename from EXAMPLES/cscore/usbstream.py
rename to examples/cscore/usbstream.py
diff --git a/EXAMPLES/ntcore/pubsub_client.py b/examples/ntcore/pubsub_client.py
similarity index 100%
rename from EXAMPLES/ntcore/pubsub_client.py
rename to examples/ntcore/pubsub_client.py
diff --git a/EXAMPLES/ntcore/pubsub_server.py b/examples/ntcore/pubsub_server.py
similarity index 100%
rename from EXAMPLES/ntcore/pubsub_server.py
rename to examples/ntcore/pubsub_server.py
diff --git a/EXAMPLES/ntcore/simple_client.py b/examples/ntcore/simple_client.py
similarity index 100%
rename from EXAMPLES/ntcore/simple_client.py
rename to examples/ntcore/simple_client.py
diff --git a/EXAMPLES/ntcore/simple_poller.py b/examples/ntcore/simple_poller.py
similarity index 100%
rename from EXAMPLES/ntcore/simple_poller.py
rename to examples/ntcore/simple_poller.py
diff --git a/EXAMPLES/ntcore/simple_robot.py b/examples/ntcore/simple_robot.py
similarity index 100%
rename from EXAMPLES/ntcore/simple_robot.py
rename to examples/ntcore/simple_robot.py