Uzzors2k Banner

Raspberry Pi based OpenROV

01.06.2016

On the dock In the water
Basking in the sun

Based on my previous two ROV projects, I had a number of improvements I wanted to implement in my next ROV project. However I now had a job, and not nearly as much time or desire to do engineering work in my spare time. Since I started building ROVs in 2010 the open-source community has come a long way, so I decided to become a part of it, and save myself a lot of work in the process. For this project I decided to use the open source ROV project OpenROV version 2.8, for the mechanical design and parts of the electronical design. This allowed me to focus on doing the software and electronics myself. I opted to design my own software and electronics partly because I didn't want this to be a kit build, and also because I wanted a very embedded system, with no need for a laptop in the field. I choose the Raspberry Pi because of it's low price, and since I had become familiar with it during my automatic cat feeder project. Support for wifi and bluetooth were also very important. I'll be honest though, I would have saved time and money by just out right buying a full kit and assembling it myself.

Maiden Voyage

For the first few tests I decided to try the ROV at our summer cabin. This was in part because I didn't manage to complete the ROV before my vacation started, so I had to bring my laptop, and half-ready ROV to the cabin. I had forgotten to program the electronic speed controllers, and after some nerve wracking Internet searches, I found that an Arduino could be used to save the day. As luck had it, I was able to order a cheap Arduino Uno, receive it in the mail, and successfully programmed the speed controllers in just a few days. In the end the ROV project was a success, though I have many things I would like to improve for next time.
Cabin life
The simple life at the cabin

In the video from the ROV, one can see cod, cuckoo wrasse, star fish, and sea urchins. For the first part of the video I explain a little about the ROV itself, the voyage begins about a quarter of the way into the video.



OpenROV construction and assembly

OpenROV has a webshop, which in addition to selling a full kit also sells replacement and development kits. From here I was able to order most of the hardware required, namely:
Which was lucky, as a large acrylic tube cut to the right (imperial!) dimensions was near impossible to find in Europe. Since it wasn't possible to order all of the OpenROV parts from their shop, I also had to order some laser cut acrylic to make the rest of the ROV. Since OpenROV is an open source project, I downloaded the hardware source files, found the parts I was missing, and ordered them from one of the many laser cutting services on the net. I chose to use use RazorLab based in the UK, and I am completely satisfied with their service. So much in fact, that I no longer fantasize about purchasing my own laser cutter.

End caps glued together OpenROV skeleton front OpenROV skeleton back
Bending the shroud Underside of the ROV
Assembling the OpenROV components


Besides gluing the pieces together, which was tricky, there was one other part of construction I was new to. And that was bending an acrylic sheet accurately. The main shroud which runs over the top of the ROV is made of a single piece of polypropylene plastic in the original kit, but I chose to use acrylic based on cost and the laser cutting services I had available. Getting the right color was of some importance. What I did (which was foolish in hindsight) was to first bend the sheet, and then try to fit it on the ROV skeleton. The bends weren't perfectly square, and I had lost a small amount of length along the top, so it fit much too snug. So snug, that some cracks appeared when I had finally gotten everything in place. In hindsight, bend one side first, then put the main housing inside before bending the other side. This will ensure all parts fit snuggly together, without stress. To bend the acrylic sheets, I made a jig consisting of some nichrome wire and an aluminum trough.

ROV side

I opted to design a simple interface board which connects to the standard OpenROV 2.8 connector, which in turn can be connected to a Raspberry Pi for control. That way if the electronics failed, I could always order an official OpenROV control board instead and simply plug it in. I decided to also use the same Power over Ethernet solution as the OpenROV, which is the most clever and cheap solution I've been able to find so far. Instead of the specified Homeplug modules I used some ZyXEL modules I found locally. Reverse-engineering the board to locate the low voltage generation section was easy, and I simply injected 12V in at this point. The nominal voltage was 11.4V from it's on-board transformer, but right afterwards this was regulated by a 5V and 3.3V DC-DC converter. The interface board simply holds the electronic speed controllers, a mosfet for switching power to the ESCs, a 5V regulator for powering the raspberry pi, and a comparator to sense when the battery voltage is too low. For light, I used a Bright Pi module, which can be interfaced with over I2C. A simple body was 3D printed to hold the electronics boards in place, and with that the custom ROV hardware was complete. I was having some trouble with my 3D printer at the time, so the print didn't turn out great. The Raspberry Pi on board the ROV was given a wifi dongle, so software upgrades and video downloads can be performed wirelessly.

Schematics, and gerber files for the interface board can be downloaded here. ROV_electronics.zip
The 3D models for the ROV housing can be downloaded here. ROV_3D_printed_parts.zip

Top layer of interface board Bottom layer of interface board
Front side of ROV brains Back side of ROV brains Back side of ROV brains, slanted view
ROV hardware construction


The ESCs I used are "Afro ESC 12Amp OPTO UltraLite Multirotor ESC V3" from Hobbyking, and the same reccomended by OpenROV. One thing I had neglected was that the Afro ESCs needed to be programmed for reverse mode before being used. To do this, one needs a Turnigy one-wire USB interface. However, a clever individual has made an Arduino one-wire interface, which can be used instead. Flashing the correct firmware on the ESC is then simply a matter of connecting the ESC to the Arduino as described on the GitHub page. Avrdude can then be used through the Arduino virtual serial port, to program the ESC. This is the avrdude command I used, for reference:
	avrdude -c stk500v2 -b 19200 -P COM3 -p m8 -v -v -U flash:w:afro_nfet.hex:i
I can no longer remember exactly where I obtained the correct hex file, or if I made some changes and compiled my own, so I've provided a download link to the exact file I used. Either way it was based on the source code and compiled hex files created by SimonK, which can be found on github under the name tgy -- Open Source Firmware for ATmega-based Brushless ESCs.

Assembled ROV
Assembled ROV

Tether

Once the ROV was constructed, I began work on the tether reel. An important goal for this project was ease of use, so the only user interface I wanted was a PS3 joystick, and a pair of standard FPV goggles. These are both wireless which make it easy to water-proof the tether assembly, and not having the operator cabled to the tether is very practical in a small boat. As with my previous ROV tethers I used a slip ring, so the tether can be coiled up and hopefully avoid tangles. An electronics box from AliExpress was used to house all of the tether electronics, which consist of a Raspberry Pi, Lipo battery, Ethernet interface, 5.8GHz FPV video transmitter, and voltage regulator. Two LEDs, and a power switch are the only external interaction points on the tether. Green for connection status, red for recording, and the button to safely shut down the raspberry pi in the tether, which at the same time sends a shutdown signal to the ROV.

Various 3D models can be found on my Thingiverse page. The reel handle, reel fasteners, and the slip ring holder.

Completed tether assembly Tether reel detail
Electronics contained in the tether
Tether construction

Software and System

To control the ROV and tether, I use a Raspberry Pi 2 running Raspbian Jessie Lite in each unit. All control scripts are started at boot time, ensuring no configuration is needed in the field. One raspberry pi in the ROV simply streams live video, using the Raspberry Pi camera, while at the same time listening for control packets. The control packets dictate how to control the ROV thrusters, LEDs, camera pitch, and also whether to start/stop recording. The tether Raspberry Pi attempts to connect to a Playstation 3 controller over bluetooth, and also connect to the ROV over Ethernet. Once both connections are established, the live video feed from the ROV is sent out to the goggles. Any changes in the PS3 controller state are translated into a control packet, which is sent down to the ROV. All functions on the ROV can be controlled via the PS3 controller.

Raspbian Setup

First of all setup Wifi, this is needed for installing various components, but also very useful for transferring files, and makes configuration changes. I copied files over SSH using WinSCP, and remote console using Putty. SSH is enabled by default in Raspbian Jessie.

Setting WiFi up via the command line
Proper configuration for wpa_supplicant.conf

In wpa_supplicant.conf I added a few wireless networks with Internet access, and also a "fake" network which I can use for debugging purposes in the field. This can be used by creating a local access point on my computer or smartphone, using the predefined SSID and password, if no router is available. I chose the following SSID and password.

SSID: "ROVDEBUG"
PSK: "UNDERTHESEA"

Since the two Raspberry Pi's communicate to each-other over Ethernet, they had to be set to have static IP addresses. This can be done by editing the file /etc/network/interfaces using any text editor.
	auto eth0
	allow-hotplug eth0
	iface eth0 inet static
	address 172.28.0.10	(for the topside module)	172.28.0.12	(for the subsea unit)
	netmask 255.240.0.0
Ethernet and wlan need to be on different network classes to work at the same time. Most routers use either 10.0.0.x or 192.168.1.x as their internal range, which is either network class A or C. I put the Ethernet of the pi's on class B (172.16.0.0) to avoid problems.

The final thing to setup is I2C for communication with the servo controller board. Run raspi-config, and enable I2C from the settings presented. To interface with the I2C controller with Python, additional support must be installed. Run these commands, and afterwards reboot.
	sudo apt-get install python-smbus
	sudo apt-get install i2c-tools

Windows 10 Wifi access point (for debugging in the field)

I found it strangely difficult to set up a useful Wifi access point on my Windows 10 laptop. In addition to only being possible to set up through a command prompt, I also had to install some third party software to act as a DHCP server. To set up the network itself, open an administer privileged command prompt, and enter the commands:
	netsh wlan set hostednetwork mode=allow ssid=”ROVDEBUG” key=”UNDERTHESEA”
	netsh wlan start hostednetwork
To see the current status of the connection, or shut it down again, use these commands:
	netsh wlan show hostednetwork
	netsh wlan stop hostednetwork
Once started, the network will appear in under the network connections in the control panel. From here you should configure the connection to have a static IP address, so the DHCP server can interface with it. I used the following settings:
IP address: 192.168.1.1
Network Mask: 255.255.255.0
Default Gateway: Blank

Preferred DNS server: 127.0.0.1
Alternate DNS Server: Blank

For the DHCP server, I installed dhcpsrv. Simply run the program to automatically assign IP addresses to connecting devices. The ini file should contain the correct config, but if not, download the .ini file I used and change the directories to match your set up.

Video Streaming

An important requirement for this project was the ability to stream live video with very low latency, while at the same time being able to record it for storage. To this end I found that some people were having success using gstreamer. The idea was that the raspberry pi camera encodes raw video in h264 format at a hardware level, which means there is very little overhead required in software to send the video feed. To install gstreamer, run these commands:
	sudo apt-get dist-upgrade
	sudo apt-get install gstreamer1.0-tools
	sudo apt-get install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-libav
I made some bash files to to control streaming and receiving of video. For the video transmitter I made two scripts, one for live feed, and one for live feed with storage to disk. Before starting each feed, I close any previous transmission which might be in progress using a pkill command. The first script simply pipelines the raw raspivid feed into gstreamer, whereas the second does the same, but at the same time splits the pipeline feed into a file for storage. Live feed with no storage
	#!/bin/bash
	pkill -INT tee
	pkill -INT raspivid
	pkill -INT gst-launch-1.0

	# Wait for the process to clean up and terminate
	sleep 1

	raspivid -t 0 -w 1080 -h 720 -fps 25 -hf -vf -awb off -awbg 1.9,1.6 -drc high -b 2000000 -o - |
	gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=172.28.0.12 port=5000 &
Live feed with video storage
	#!/bin/bash
	pkill -INT tee
	pkill -INT raspivid
	pkill -INT gst-launch-1.0

	# Find an available file name
	STORAGE_DIR="/home/pi/capturedVideo/"
	mkdir -p $STORAGE_DIR

	# Wait for the dir to be created. Also wait for the process to clean up and terminate
	sleep 1

	fileIndex="0"
	fileName="rov_video"
	extension=".h264"
	fullFilePath=$STORAGE_DIR$fileName$fileIndex$extension

	while [ -f $STORAGE_DIR$fileName$fileIndex$extension ]
	do
		fileIndex=$[$fileIndex+1]
		fullFilePath=$STORAGE_DIR$fileName$fileIndex$extension
	done
	safeFileName=$fileName$fileIndex$extension

	echo $safeFileName

	# Start piping video into the chosen file!
	raspivid -t 0 -w 1080 -h 720 -fps 25 -hf -vf -awb off -awbg 1.9,1.6 -drc high -b 2000000 -o - |
	tee $STORAGE_DIR$safeFileName |
	gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=172.28.0.12 port=5000 &
Receiving video is equally simple. For that I use a script which continuously tries to connect to the ROVs static IP address and video port defined in the above scripts. Once a connection is made the video feed is displayed.
	#!/bin/bash

	until 1; do
	   gst-launch-1.0 -v tcpclientsrc host=172.28.0.12 port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false
	   echo "Restarting process in 2 seconds..."
	   sleep 2
	done
If you have any problems streaming video, read these two pages. There may be some additional setup that is required.

Raspberry Pi camera board – Gstreamer
Gstreamer on latest Raspbian

PS3 Bluetooth control

For connecting a Playstation 3 controller (Sixaxis or Dualshock3) I used QtSixA. Installing and using this places the joystick in the system's native "/dev/input/js0" input. Raw data can be read using:
	jstest /dev/input/js0
QtSixA is installed using "checkinstall". It also requires a number of dependencies. Run the following commands:
	sudo apt-get install checkinstall
	sudo apt-get install bluez-utils bluez-compat bluez-hcidump
	sudo apt-get install libusb-dev  libbluetooth-dev joystick
Once all installations are complete, run the command hciconfig. Something like this should appear, but if not, you have an unsupported bluetooth dongle.
	pi@raspberrypi ~ $ hciconfig
	hci0: Type: BR/EDR Bus: USB
	 BD Address: 00:1F:81:00:06:20 ACL MTU: 1021:4 SCO MTU: 180:1
	UP RUNNING PSCAN
	RX bytes:1260 acl:0 sco:0 events:46 errors:0
	TX bytes:452 acl:0 sco:0 commands:45 errors:0
I found a bug in QtSixA, where disconnecting a connected controller would cause a hang. I fixed the bug, and the corrected source code can be downloaded here. uzzors2k - QtSixA.zip Create a new directory, and extract the above files into it. Enter the directory, and run the commands:
	make
	sudo mkdir -p /var/lib/sixad/profiles
	sudo checkinstall
A controller must be paired before use, and it MUST be a genuine controller. Chinese rip-offs do not work, for some reason. Connect with a USB cable, and run "sudo ./sixpair" If pairing is successful, then the bluetooth master address should be changed to that of the PS3 controller.
	Current Bluetooth master: 00:00:00:00:00:00
	Setting master bd_addr to: 00:1F:81:00:06:20
Now to test everything, launch temporary a sixad daemon.
	sudo sixad --start
Then press the "PS" button on the controller, and if everything works the controller should vibrate. To turn off the controller, press and hold the PS button for 12 seconds. To start the controller service automatically when booting the raspberry pi, run these commands:
	sudo update-rc.d sixad defaults
	reboot
After doing this it should simply be a matter of pressing the PS button whenever you want to use the controller. If a paired controller doesn't connect at start, run "hcitool dev". If no devices show up, then the bluetooth module failed to initialize. Need to reboot in that case.

Ethernet Communication and Servo Control

Servos are controlled using a Adafruit 16-Channel PWM/Servo HAT for Raspberry Pi. I wrote a number of scripts in Python for reading joystick signals from /dev/input/js0, receiving packets from the tether, and translating these to servo control signals. All of the code I used is hosted on github, under the project raspberrypi-openrov. I send TCP packets containing strings between the tether and ROV. These strings are in a set format, and interpreted by the ROV to control it's own outputs. The way I mapped the PS3 controller to the data in the packets is arbitrary, and can be configured to match most controllers. I've included code for a Nintendo Wii based controller also.

X defined as forward direction, Y as 90 degrees to this on the same plane, and Z as Upwards direction. Each field below can be separated by a semicolon ';' when chained together in a single string/packet. Packets start with a '<' character and end with a '>' character.
	SET_VIDEO_RECORD:<0-1>
	SET_LIGHT:<0 to 512>

	ROTATE_ROV_YAW:<-512 to 512>

	TRANSLATE_ROV_X:<-512 to 512>
	TRANSLATE_ROV_Y:<-512 to 512>
	TRANSLATE_ROV_Z:<-512 to 512>

	ROTATE_CAMERA_YAW:<-512 to 512>
	ROTATE_CAMERA_PITCH:<-512 to 512>

	SYSTEM_SHUTDOWN:<0-1>

Closing thoughts

After testing the ROV at my cabin, I discovered numerous points of improvement.
My user experience was:
I hope to revisit this project and improve upon these points for next time!

Update - 09.09.2017

During the past year I incorporated a number of fixes on the problems I had experienced after the first expeditions. Here's the list:

Velcro battery and power switch Potting LED module in epoxy External LED module assembled
Velcro battery holder, and power switch for the tether. External LED module for ROV.


This time I used a GoPro Hero 2 to record video, instead of the on-board raspberry pi camera. This greatly improved video quality, making me wonder why on earth I didn't do it for my earlier ROVs!



Similar projects and references:

OpenROV



Youtube Flickr Twitter LinkedIn


Disclaimer: I do not take responsibility for any injury, death, hurt ego, or other forms of personal damage which may result from recreating these experiments. Projects are merely presented as a source of inspiration, and should only be conducted by responsible individuals, or under the supervision of responsible individuals. It is your own life, so proceed at your own risk! All projects are for noncommercial use only.


Creative Commons License This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.


3569 unique visitors since 28th June 2020.