-
Notifications
You must be signed in to change notification settings - Fork 4
An NDI-based and VISCA-based pan-tilt-zoom controller for Raspberry Pi or Rock Pi (with limited support for debugging on macOS).
License
dgatwood/ndi_camera_control
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
NDI/VISCA PTZ Controller for Raspberry Pi and Rock Pi This code is a complete, but basic console-based pan-tilt-zoom controller for the Raspberry Pi 4 and Rock Pi 4. (In other words, this does not run in X11; it literally writes directly to the framebuffer.) --------- Features: --------- * Requires the Pimoroni I/O Expander for input purposes. * Supports three-axis analog joysticks. * Supports five pushbuttons for loading stored positions, and a set button for storing new positions. * Supports lights for showing which position was most recently loaded (reset when you move the camera) and for the set button (toggle) state. * Supports remote tally light polling to show whether the camera is in preview mode, program mode, inactive, or unresponsive (e.g. a network failure). (Requires a VISCA-compatible camera.) * Supports zooming at variable speed. * Supports both VISCA control and NDI control for maximum flexibility. ------------------- A Note About VISCA: ------------------- VISCA is a protocol for controlling PTZ cameras over IP. Almost every NDI camera that I have tested so far supports VISCA, though some devices may require you to use a different port. This code has been tested against cameras by AVKANS, NewTek, and Marshall. Your mileage may vary. Panasonic uses its own protocol, so those are not supported unless they also supports NDI control. The reason VISCA is required for full functionality is that the NDI protocol doesn't provide some required features. I've filed bugs with the NDI SDK team about some of these issues, and will continue to try to find ways to eliminate the need for VISCA, because it's kind of a bloated, unreliable mess (and this code is a particularly hackish implementation that I wrote very quickly to work around those limitations). Specifically, the following functionality does not work when working with a pure NDI camera: * Tally light support. The NDI SDK lets you set the tally light, but not obtain its current state. If you're using OBS, it would theoretically be possible to add OBS websocket support to this app, which would allow you to find out whether OBS has turned on the tally light or not. However, all of my cameras support VISCA, so it wasn't worth the effort to do that when I already had a mostly working VISCA implementation. * Zoom speed support. This should work; the NDI SDK lets you pass a zoom speed value from -1.0 to 1.0. However, in real-world testing, exactly none of the cameras I tested were able to zoom at multiple speeds when driven through that function call (from either the Linux/Raspbery Pi SDK or the macOS SDK). Presumably, this will get fixed at some point on the camera side, at which point VISCA will no longer be required for this purpose. * Exposure adjustment and manual exposure. The NDI SDK lacks exposure compensation APIs, though it does provide manual exposure settings. But because all my cameras support VISCA, it wasn't worth the extra effort to hook up the manual exposure calls via NDI. (It's would take only about two lines of code, though, so if you need it, it should be an easy change.) This PTZ controller software looks up the camera using Avahi, then connects to the VISCA UDP port on that same device. This may or may not be the best approach, but it works (with the caveat that you have to provide the VISCA port). This software can also be used with my VISCAPTZ software running on a second device, which provides pan and tilt support and position recall on custom motor-based hardware, along with zoom control for Panasonic cameras and tally light sourcing from Panasonic cameras (if connected by NDI to a source that sets the tally light properly) or directly from OBS or Tricaster mixing systems. (See https://github.com/dgatwood/VISCAPTZ for info.) -------------- Prerequisites: -------------- * Download my C translation of the Pimoroni I/O Expander library: https://github.com/dgatwood/ioe-c and symlink or copy the files constants.h and ioexpander.c into the source folder. * Disable X11 in raspi-config (Raspberry Pi) or equivalent. * Install the NDI SDK from NewTek (available separately) and move the resulting folder to /usr/local/NDISDK (or edit the Makefile for a different location). * Install Avahi (client and common libraries), which is typically one of the following: sudo apt-get install avahi-utils avahi-daemon libavahi-client-dev libnss-mdns sudo apt-get install avahi-client3 avahi-daemon libavahi-client-dev libnss-mdns * Install the correct GPIO library: - For Raspberry Pi, install pigpiod and enable the daemon. (libmraa may also work.) - For Rock Pi, install libmraa with apt: sudo apt-get install libmraa-rockpi4 or sudo apt-get install libmraa or build and install it from source code (https://github.com/eclipse/mraa). * Configure dhcpcd on your device to use a static IP fallback in the same IP range as your cameras (typically 192.168.100.x). For example, on Raspberry Pi: profile static_eth0 static ip_address=192.168.100.23/24 static routers=192.168.100.1 static domain_name_servers=192.168.100.1 interface eth0 fallback static_eth0 * Add NDI to the ld.so configuration file: - Create a file named /etc/ld.so.conf.d/ndi.conf and paste in one of the following: /usr/local/NDISDK/lib/arm-rpi4-linux-gnueabihf /usr/local/NDISDK/lib/aarch64-rpi4-linux-gnueabi depending on your CPU architecture, adjusting the path as needed based on where you installed the SDK. Then run sudo ldconfig to update the cache. * Follow the hardware-specific configuration instructions for your board below. * Build the custom hardware. -------------------------- Raspberry Pi Configuration -------------------------- * Configure the console to use 32 bpp if necessary (Raspberry Pi). In config.txt, add/change: disable_overscan=0 framebuffer_depth=32 display_rotate=2 dtparam=i2c_arm=on dtparam=spi=on * For HDMI panels (Raspberry Pi). In config.txt, add/change: max_usb_current=1 hdmi_force_hotplug=1 hdmi_group=1 hdmi_mode=16 hdmi_drive=2 * For DSI panels (Raspberry Pi). In config.txt, add/change: video=DSI-1:1920x1080@60 framebuffer_width=1920 framebuffer_height=1080 If this doesn't work, try 1920x1080@30. * Disable the videocore 3D driver (Raspberry Pi) by commenting out the following line in config.txt: # dtoverlay=vc4-fkms-v3d This may or may not be necessary. It was in the version of Raspbian that I was using, without which I couldn't force the display into 24bpp or the correct resolution, and I was always doing software scaling, which isn't ideal. But YMMV. * Disable the blinking cursor on the virtual console that you plan to use by editing cmdline.txt. Change the console to: console=tty3 to ensure the output doesn't get clobbered by log messages, then add: vt.global_cursor_default=0 to the end. Then disable console blanking so that your screen doesn't go black by adding consoleblank=0 to that line as well. --------------------- Rock Pi Configuration --------------------- I recommend starting with the official Debian distro, being sure to get the Bullseye version. Unfortunately, I was unable to get DSI working on Armbian, so I gave up. And the official Ubuntu Server distro has nonfunctional Wi-Fi, or at least I only got it to connect twice, with hundreds of failures in between. On Rock Pi, you must also perform the following changes: * Uncomment the following line in /etc/sysctl.conf to keep the console clean of kernel log messages: kernel.printk = 3 4 1 3 * Add the following to your /etc/rc.local: # Disable the flashing blue heartbeat LED that sinks so much power that your LEDs will # severely flash twice a second if you don't. echo none > /sys/class/leds/user-led2/trigger echo none > /sys/class/leds/status/trigger One of those two lines should work, depending on kernel version. * Downgrade to the 5.10.x kernel for HDMI or 4.4.154-90 for DSI. The 5.15.x kernel does not support GPIO correctly (10 pins are nonfunctional), and 5.10.x does not support DSI. * Enable I2C - Edit the file /boot/hw_intfc.conf as root. - Change: intfc:i2c7=off to: intfc:i2c7=on * Enable DSI (if not using HDMI) - Edit the file /boot/hw_intfc.conf as root and uncomment this line: intfc:dtoverlay=raspberrypi-7-inch-lcd - Edit the file extlinux/extlinux.conf as root. In each of the "append" lines, add: append ...existing arguments here... vt.global_cursor_default=0 fake_vsync_isr=1 consoleblank=0 all on one line. - If there's a console=tty1 in that line, change it to tty3 so that log messages won't clobber the video output. - There's no way to rotate the display in hardware on Rock Pi (that I could find), so you'll have to add the -F flag when running the tool if you need to flip the panel's output. * If you want to run as a non-root user: - Create a GPIO group and add yourself to it: sudo addgroup gpiouser sudo usermod -a -G gpiouser yourusername - Add yourself to the i2c group (or whatever group owns /dev/i2c-7). sudo usermod -a -G i2c yourusername - Create a file called /etc/udev/rules.d/99-gpio.rules and paste the following: SUBSYSTEM=="gpio", PROGRAM="/bin/sh -c '\ chown -R root:gpiouser /sys/devices/platform/pinctrl/gpio /sys/class/gpio &&\ chmod -R 770 /sys/devices/platform/pinctrl/gpio /sys/class/gpio'" KERNEL=="gpio*", GROUP="gpiouser" KERNEL=="gpiochip*", GROUP="gpiouser" - Add the following to /etc/rc.local: # Change ownership of various stuff so that you can touch GPIO as a non-root user. chown -R root:gpiouser /sys/class/gpio chmod -R ug+rw /sys/class/gpio - Reboot. ------------------- Command-line flags: ------------------- To see a list of available cameras, type ./cameracontroller and press return. This currently loops forever, because cameras may not appear instantly. Press Control-\ to terminate the app. We should probably fix this at some point. Usage: ./cameracontroller [flags] <camera_name> where <camera_name> is typically something like "NDIHX-PTZUHD (chan 1, 192.168.100.168)". Note that this tool searches for a camera with a matching name and IP address first, but then falls back to a name match at a different IP. Be certain that each camera has its own distinct name, because there is no guarantee that this software will correctly detect the camera in the initial scan before falling back and matching against identically named cameras at different IP addresses. General flags: -f / --fast -- Enables preview mode, in which a lower quality (typically 720p) stream is requested. This can be helpful for cameras that produce higher bitrate streams. (You can play NDI-HX streams from iOS devices without this flag.) -F / --flip -- Flips the screen while drawing. Proper framebuffer flipping is better, but this is all we have on some platforms. -D / --duty_cycle -- Sets the duty cycle that should be used for all LEDs (range 0 to 255). VISCA command-line flags: -V / --enable_visca -- Enables VISCA for camera control. To enable visca for tally light purposes while using NDI camera control, set a port with -p, but don't pass -V. -u / --visca_use_udp -- Enables UDP mode for VISCA and enables VISCA for tally light reporting. At this point, TCP support is untested, so you should always pass this flag. -p / --visca-port -- Sets the VISCA port and enables VISCA for tally light reporting. Most cameras use port 52381 UDP. However, this code defaults to the PTZOptics port, 1259 UDP. Note that PTZOptics cameras are entirely untested. -O / --onscreenlights -- Configures the code to use on-screen boxes instead of physical status LEDs. (Note that some status features are available only with VISCA.) VISCA-only features: -e / --exposure_compensation -- Sets exposure compensation amount (-5 to 5) -a / --auto_exposure -- Enables automatic exposure (disables -i/-ig/-s). -i / --iris -- Sets manual exposure with the specified iris (range 0 to 20). The meaning of these values is camera-dependent. -g / --gain -- Sets manual exposure with the specified gain (range 0 to 15). The meaning of these values is camera-dependent. -s / --shutter -- Sets manual exposure with the specified shutter (range 0 to 21). The meaning of these values is camera-dependent. Debugging: -d / --debug -- Enables some basic debugging -B / --buttondebug -- Enables button-specific debugging -P / --ptzdebug -- Enables PTZ (joystick) debugging -v / --verbose -- Enables more detailed debugging -------------------- Other Configuration: -------------------- The file LEDConfiguration.h lets you change the brightness of each LED individually. ---------------- Common Mistakes: ---------------- If the tool can see your camera but cannot receive video: 1. Reboot the camera. Some cameras have known bugs. 2. Make sure your IPv4 address is working. Most cameras support IPv6 for discovery, but do NOT support streaming over IPv6. 3. In particular, make sure that you aren't sharing an IP address with another camera or PTZ controller! 4. Make sure you aren't running any weird firewalls that might interfere. ---------------------- Building the Hardware: ---------------------- The custom hardware construction (for actual PTZ control) is documented here: https://docs.google.com/document/d/1Ss_mx8vgRw_ys8ocJK7LZhjXRocf9EI3qovyQXoxxJw/edit?usp=sharing or in the hardware directory. Enjoy!
About
An NDI-based and VISCA-based pan-tilt-zoom controller for Raspberry Pi or Rock Pi (with limited support for debugging on macOS).
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published