eduROV - Educational Remotely Operated Vehicle¶
Stream camera feed from a Raspberry Pi camera to any web browser on the network. Control the robot with your keyboard directly in the browser.
The eduROV project is all about spreading the joy of technology and learning. The eduROV is being developed as a DIY ROV kit meant to be affordable and usable by schools, hobbyists, researchers and others as they see fit. We are committed to be fully open-source, both software and hardware-wise, everything we develop will be available to you. Using other open-source and or open-access tools and platforms.
GitHub: | https://github.com/trolllabs/eduROV |
---|---|
PyPI: | https://pypi.org/project/edurov/ |
Documentation: | http://edurov.readthedocs.io |
Engage eduROV: | https://www.edurov.no/ |

Main features¶
Low video latency
You can stream HD video from the Raspberry Pi camera to any unit on the same network with a video delay below 200ms.
No setup required
The package works by displaying the video feed and other content in a web browser. This means that you can use any device to display your interface.
Very easy to use
With the exception of Pyro4 (which is installed automatically), edurov doesn’t require any other packages or software. Everything is written in python and html. 4 lines of code is everything needed to get started!
Highly customizable
Since you define the html page yourself, you can make it look and work exactly the way you want. Use css and javascript as much as you want.
True parallelism
Need to control motors, read sensor values and display video feed at the same time? edurov can spawn your functions on multiple CPU cores while still maintaining the possibility to share variables.
Prerequisites¶
- eduROV requires python 3, if you don’t have python installed, you can download it here: https://www.python.org/downloads/
- the camera on the raspberry pi has to be enabled, see https://www.raspberrypi.org/documentation/configuration/camera.md
Installation¶
Run the following commands in a terminal on the Raspberry Pi.:
sudo pip3 install edurov
For a more in depth description visit the official documentation.
Usage¶
Engage eduROV submersible¶
On the Raspberry Pi, run the following command:
edurov-web
This will start the web server and print the ip where the web page can be
viewed, e.g. Visit the webpage at 192.168.0.197:8000
.
Create your own¶
The eduROV package includes multiple classes and functions to facilitate easy robot communication with video feed. It will get you up and running in a matter of minutes. Visit the official documentation for a getting started, examples and API.
Performance¶
The eduROV package were created with a strong focus on keeping the latency at a minimum. When deploying on a wireless network the actual performance will vary depending on factors such as distance, interference and hardware.

Author¶
The package is created by Martin Løland as part of the master thesis at Norwegian University of Science and Technology 2018
Installation¶
Raspbian¶
First, you will need a raspberry pi with an operating system running on it. Visit the official software guide for a step by step guide on how to do that..
Remote control¶
In most cases it is more practical to control the Raspberry Pi using another computer. The two most popular methods are with either SSH or VNC.
Update system¶
Make sure that your Raspberry Pi is up to date:
sudo apt-get update
sudo apt-get dist-upgrade
Python version¶
The edurov package requires python 3. If python 3 si not your default python
version (check by running python --version
), you can either (1) change the
default python version, or (2) use pip3 and python3 instead.
Change default python version
Take a look at this page.
Use pip3 and python3
If you don’t want to make any changes, you can call
pip3
instead ofpip
andpython3
instead ofpython
. This will use version 3 when installing and running python scripts instead.
Install using pip¶
Install edurov, sudo rights are needed to enable console scripts:
sudo pip install edurov
Static IP¶
If you are remotely connected to the Pi it can be very useful with a static ip so that you can find the Pi on the network. How you should configure this depends how your network is setup. A guide can be found here.
Start at system startup¶
If you want the edurov-web command to run automatically when the raspberry pi has started. Run the following command:
sudo nano /etc/rc.local
Then add the following line to the bottom of the screen, but before the line
that says exit 0
:
edurov-web &
Exit and save by pressing CTRL+C, y, ENTER. The system then needs to be rebooted:
sudo shutdown -r now
Engage eduROV¶
Terminal command¶
By calling edurov-web
in the terminal the edurov-web example will be
launched. This command also supports multiple flags that can be displayed by
running edurov-web -h
-r | resolution, use format WIDTHxHEIGHT (default 1024x768) |
-fps | framerate for the camera (default 30) |
-port | which port the server should serve it’s content (default 8000) |
-d | set to print debug information |
Example
edurov-web -r 640x480 -fps 10
Will then set the the video to 640x480 @ 10 fps
Getting started¶
Tip
If you came here to find out how to to use the Engage ROV submersible, the Engage eduROV page is probably for you. If you instead plan to create your own ROV or make some kind of modifications, you are in the right place.
Note
Not all details at explained on this page. You should check the API page for more information on the classes, methods and parameters when you need.
On this page we will walk through the features example, one feature at a time. This example was created with the intention of describing all the features of the edurov package. Let’s get started!
Displaying the video feed¶
There are two main parts needed in any edurov project. First, it’s the python
file that creates the WebMethod
class and starts serving the server.
Secondly, a index.html file that describes how the different objects will be
displayed in the browser.
In the two code blocks underneath you can see how simple they can be created.
The index.html file needs to be called exactly this. We use the os.path()
library to ensure correct file path description.
1 2 3 4 5 6 7 8 9 | import os
from edurov import WebMethod
# Create the WebMethod class
web_method = WebMethod(
index_file=os.path.join(os.path.dirname(__file__), 'index.html'),
)
# Start serving the web page, blocks the program after this point
web_method.serve()
|
The index.html file must have an img element with src="stream.mjpg"
.
The server will then populate this image with the one coming from the camera.
1 2 3 4 5 6 7 8 9 | <!DOCTYPE html>
<html>
<head>
<title>Features</title>
</head>
<body>
<img src="stream.mjpg">
</body>
</html>
|
Our file structure now looks like this:
project
├── features.py
└── index.html
If you wanted to have a security camera system this is all you had to do. If you instead want to control you robot through the browser or display other information, keep reading.
Moving a robot¶
This section will let us control the ROV from within the web browser. In computer technology there is something called parallelism. It basically means that the CPU does multiple things at the same time in different processes. This is an important feature of the edurov package as it let’s us do many things without interrupting the video feed. (It wouldn’t be very practical if the video stopped each time we moved the robot).
Reading keystrokes¶
First, we have to ask the browser to send us information when keys
are pressed. We do this by including keys.js
inside the
index.html
file. We have put it inside a folder called static as this
is the convention for these kind of files.
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html>
<html>
<head>
<title>Features</title>
<script src="./static/keys.js"></script>
</head>
<body>
<img src="stream.mjpg">
</body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var last_key;
document.onkeydown = function(evt) {
evt = evt || window.event;
if (evt.keyCode != last_key){
last_key = evt.keyCode;
send_keydown(evt.keyCode);
}
}
document.onkeyup = function(evt) {
last_key = 0;
send_keyup(evt.keyCode);
}
function send_keydown(keycode){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "/keydown="+keycode, true);
xhttp.setRequestHeader("Content-Type", "text/html");
xhttp.send(null);
}
function send_keyup(keycode){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "/keyup="+keycode, true);
xhttp.setRequestHeader("Content-Type", "text/html");
xhttp.send(null);
}
|
Controlling motors (or anything)¶
In this example we will not show how to move the motors, instead the program will print out which arrow key you are pressing. You can then change the code to do whatever you want!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import os
import Pyro4
from edurov import WebMethod
def control_motors():
"""Will be started in parallel by the WebMethod class"""
with Pyro4.Proxy("PYRONAME:KeyManager") as keys:
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
while rov.run:
if keys.state('K_UP'):
print('Forward')
elif keys.state('K_DOWN'):
print('Backward')
elif keys.state('K_RIGHT'):
print('Right')
elif keys.state('K_LEFT'):
print('left')
# Create the WebMethod class
web_method = WebMethod(
index_file=os.path.join(os.path.dirname(__file__), 'index.html'),
runtime_functions=control_motors,
)
# Start serving the web page, blocks the program after this point
web_method.serve()
|
On line 22 we are telling the WebMethod
that
control_motors
should be a runtime_function
. This starts the
function in another process and shuts it down when we stop the ROV. For more
information visit the API page. Since this function is running in another
process it needs to communicate with the server. It does this by the help of
Pyro4
(line 2). We then connect to the KeyManager
and
ROVSyncer
on line 7-8. This let’s us access the variables we need.
The resulting file structure:
project
├── features.py
├── index.html
└── static
└── keys.js
Making it pretty¶
At this point our web page is very boring. It is white with one image. Since it’s a html file we can add whatever we want to it! This time we are adding a header, a button to stop the server and some information. In addition we are adding some styling that will center the content and make it look nicer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <!DOCTYPE html>
<html>
<head>
<title>Features</title>
<link rel="stylesheet" type="text/css" href="./static/style.css">
<script src="./static/keys.js"></script>
</head>
<body>
<main>
<h2>Welcome to the features example</h2>
<img src="stream.mjpg">
<p>
<a href="stop">Stop server</a>
</p>
<p>
Use arrow keys to print statements in the terminal window.
</p>
</main>
</body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | body {
margin: 0;
padding: 0;
font-family: Verdana;
}
a {
text-decoration: none;
}
img {
width: 100%;
height: auto;
}
main{
width: 700px;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
|
project
├── features.py
├── index.html
└── static
├── keys.js
└── style.css
Displaying sensor values¶
Coming soon
Custom responses¶
In some cases you want to display information in the browser that you want to
create yourself in a python function. The WebMethod
has
a parameter exactly for this purpose.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import os
import subprocess
import Pyro4
from edurov import WebMethod
def my_response(not_used, path):
"""Will be called by the web server if it not able to process by itself"""
if path.startswith('/cpu_temp'):
cmds = ['/opt/vc/bin/vcgencmd', 'measure_temp']
return subprocess.check_output(cmds).decode()
else:
return None
def control_motors():
"""Will be started in parallel by the WebMethod class"""
with Pyro4.Proxy("PYRONAME:KeyManager") as keys:
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
while rov.run:
if keys.state('K_UP'):
print('Forward')
elif keys.state('K_DOWN'):
print('Backward')
elif keys.state('K_RIGHT'):
print('Right')
elif keys.state('K_LEFT'):
print('left')
# Create the WebMethod class
web_method = WebMethod(
index_file=os.path.join(os.path.dirname(__file__), 'index.html'),
runtime_functions=control_motors,
custom_response=my_response
)
# Start serving the web page, blocks the program after this point
web_method.serve()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!DOCTYPE html>
<html>
<head>
<title>Features</title>
<link rel="stylesheet" type="text/css" href="./static/style.css">
<script src="./static/keys.js"></script>
<script src="./static/extra.js"></script>
</head>
<body>
<main>
<h2>Welcome to the features example</h2>
<img src="stream.mjpg">
<p>
<a href="stop">Stop server</a>
<button onclick="cpuTemp()">Display CPU temp</button>
</p>
<p>
Use arrow keys to print statements in the terminal window.
</p>
</main>
</body>
</html>
|
1 2 3 4 5 6 7 8 9 | function cpuTemp(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.stat == 200) {
alert('The CPU temperature is '+this.responseText);
};
xhttp.open("GET", "cpu_temp", true);
xhttp.send();
}
|
As an example we have created a button in index.html
(line 15) which
calls a function in extra.js
that asks the server what the CPU
temperature is. The new .js file is included as usual (index.html
(line 7)). On line 7 in extra.js
we send a GET request with a value of
cpu_temp. The server does not know how it should answer this request, but
since we have defined a custom_response
(line 37) in
features.py
the request is forwarded to this function and we can
create the response our self!
Note that this function needs to accept two parameters whereas the last one
is path that is requested. If the path starts with /cpu_temp
we can
return the value, else return None
.
project
├── features.py
├── index.html
└── static
├── keys.js
├── style.css
└── extra.js
Adding more pages¶
Coming soon.
Examples¶
Tip
The following examples can be downloaded from the eduROV examples folder.
Minimal working code¶
This is a bare minimum example so that the image stream and nothing more can be seen in the browser. A great starting point if you want to expand the functionality yourself.
from os import path
from edurov import WebMethod
web_method = WebMethod(
index_file=path.join(path.dirname(__file__), 'index.html')
)
web_method.serve()
<!DOCTYPE html>
<html>
<head>
<title>Minimal</title>
</head>
<body>
<img src="stream.mjpg" style="transform:rotate(180deg)">
<a href="stop">Stop Server</a>
</body>
</html>
project
├── minimal.py
└── index.html
Features¶
An example created to explain most of the features in the edurov package. See the Getting started page in the official documentation for a full walkthrough.
import os
import subprocess
import Pyro4
from edurov import WebMethod
def my_response(not_used, path):
"""Will be called by the web server if it not able to process by itself"""
if path.startswith('/cpu_temp'):
cmds = ['/opt/vc/bin/vcgencmd', 'measure_temp']
return subprocess.check_output(cmds).decode()
else:
return None
def control_motors():
"""Will be started in parallel by the WebMethod class"""
with Pyro4.Proxy("PYRONAME:KeyManager") as keys:
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
while rov.run:
if keys.state('K_UP'):
print('Forward')
elif keys.state('K_DOWN'):
print('Backward')
elif keys.state('K_RIGHT'):
print('Right')
elif keys.state('K_LEFT'):
print('left')
# Create the WebMethod class
web_method = WebMethod(
index_file=os.path.join(os.path.dirname(__file__), 'index.html'),
runtime_functions=control_motors,
custom_response=my_response
)
# Start serving the web page, blocks the program after this point
web_method.serve()
<!DOCTYPE html>
<html>
<head>
<title>Features</title>
<link rel="stylesheet" type="text/css" href="./static/style.css">
<script src="./static/keys.js"></script>
<script src="./static/extra.js"></script>
</head>
<body>
<main>
<h2>Welcome to the features example</h2>
<img src="stream.mjpg">
<p>
<a href="stop">Stop server</a>
<button onclick="cpuTemp()">Display CPU temp</button>
</p>
<p>
Use arrow keys to print statements in the terminal window.
</p>
</main>
</body>
</html>
project
├── features.py
├── index.html
└── static
├── keys.js
├── extra.js
└── style.css
Wireless RC car with camera feed¶

Create your very own wireless RC car with camera! The streaming video can be viewed in a browser on any device on the same network, it is controlled by using the arrow keys on the keyboard.
Bill of materials¶
Name | Price USD | Comment |
---|---|---|
Raspberry Pi Zero WH | 18 | A full size board can also be used |
Raspberry Pi Camera Module V2 | 33 | |
DC 6V 210RPM Geard Motor Wheel Kit | 23 | found on eBay |
L298N Dual H Bridge Motor Controller Board | 1.8 | found on eBay |
DC-DC 5V 12V Step Down Module Converter 3A | 1.6 | found on eBay |
Total | 76 |
In addition you will need a swivel wheel, M3/M2.5 bolts and nuts, cables and connectors, 12V battery and a car frame. The car frame used in the picture above was cut from 3mm MDF with a laser cutter and can be found here.
CAD files¶
Visit https://grabcad.com/library/772279
project
├── rc_car.py
├── index.html
├── electronics.py
└── static
└── keys.js
Engage eduROV¶
This example is used to control the ROV used in the eduROV project, see www.edurov.no.
import os
import time
import Pyro4
from edurov import WebMethod
from edurov.utils import detect_pi, serial_connection, send_arduino, \
receive_arduino, free_drive_space, cpu_temperature
if detect_pi():
from sense_hat import SenseHat
def valid_arduino_string(arduino_string):
if arduino_string:
if arduino_string.count(':') == 2:
try:
[float(v) for v in arduino_string.split(':')]
return True
except:
return False
return False
def arduino():
lastState = '0000'
ser = serial_connection()
# 'letter': [position, value]
config = {'w': [0, 1],
's': [0, 2],
'a': [1, 1],
'q': [1, 2],
'd': [2, 1],
'e': [2, 2]}
with Pyro4.Proxy("PYRONAME:KeyManager") as keys:
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
keys.set_mode(key='l', mode='toggle')
while rov.run:
dic = keys.qweasd_dict
states = [0, 0, 0, 0]
for key in config:
if dic[key]:
states[config[key][0]] = config[key][1]
states[3] = int(keys.state('l'))
state = ''.join([str(n) for n in states])
if state != lastState:
lastState = state
if ser:
send_arduino(msg=state, serial_connection=ser)
else:
print(state)
if ser:
arduino_string = receive_arduino(serial_connection=ser)
if valid_arduino_string(arduino_string):
v1, v2, v3 = arduino_string.split(':')
rov.sensor = {
'tempWater': float(v1),
'pressureWater': float(v2),
'batteryVoltage': float(v3)
}
def senser():
sense = SenseHat()
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
while rov.run:
orientation = sense.get_orientation()
rov.sensor = {'temp': sense.get_temperature(),
'pressure': sense.get_pressure() / 10,
'humidity': sense.get_humidity(),
'pitch': orientation['pitch'],
'roll': orientation['roll'] + 180,
'yaw': orientation['yaw']}
def system_monitor():
with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov:
while rov.run:
rov.sensor = {'free_space': free_drive_space(),
'cpu_temp': cpu_temperature()}
time.sleep(10)
def main(video_resolution='1024x768', fps=30, server_port=8000, debug=False):
web_method = WebMethod(
index_file=os.path.join(os.path.dirname(__file__), 'index.html'),
video_resolution=video_resolution,
fps=fps,
server_port=server_port,
debug=debug,
runtime_functions=[arduino, senser, system_monitor]
)
web_method.serve()
if __name__ == '__main__':
main()
<html>
<head>
<title>eduROV</title>
<script src="./static/dynamic.js"></script>
<script src="./static/general.js"></script>
<script src="./static/keys.js"></script>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="./static/style.css">
<link rel="stylesheet" type="text/css" href="./static/bootstrap.css">
</head>
<body onload="set_size()">
<div class="grid-container">
<div class="d-none d-md-block side-panel " style="display:none;">
<div class="card bg-light cinema">
<h5 class="card-header">Sensors</h5>
<div class="card-body">
<h5>ROV</h5>
<table class="table table-hover table-sm">
<tbody>
<tr>
<th scope="row">Temperature</th>
<td id="temp"></td>
<td>℃</td>
</tr>
<tr>
<th scope="row">Pressure</th>
<td id="pressure"></td>
<td>kPa</td>
</tr>
<tr>
<th scope="row">Humidity</th>
<td id="humidity"></td>
<td>%</td>
</tr>
<tr>
<th scope="row">Pitch</th>
<td id="pitch"></td>
<td>°</td>
</tr>
<tr>
<th scope="row">Roll</th>
<td id="roll"></td>
<td>°</td>
</tr>
<tr>
<th scope="row">Yaw</th>
<td id="yaw"></td>
<td>°</td>
</tr>
</tbody>
</table>
<h5>Water</h5>
<table class="table table-sm">
<tbody>
<tr>
<th scope="row">Temperature</th>
<td id="tempWater"></td>
<td>℃</td>
</tr>
<tr>
<th scope="row">Pressure</th>
<td id="pressureWater"></td>
<td>kPa</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="card bg-light cinema">
<h5 class="card-header">System</h5>
<div class="card-body">
<table class="table table-sm">
<tbody class="table-borderless">
<tr id="voltageTr">
<th scope="row">Battery</th>
<td id="batteryVoltage"></td>
<td>V</td>
</tr>
<tr id="diskTr">
<th scope="row">Disk space</th>
<td id="free_space"></td>
<td>MB</td>
</tr>
<tr id="cpuTr">
<th scope="row">CPU temp</th>
<td id="cpu_temp"></td>
<td>℃</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="center-panel">
<img id="image" src="stream.mjpg">
<img class="rollOverlay" id="rollOverlay" src="./static/roll.png">
</div>
<div class="d-none d-md-block side-panel">
<div class="card bg-light cinema">
<h5 class="card-header">Options</h5>
<div class="card-body">
<button type="button" onclick="toggle_armed()" id="armBtn"
class="btn btn-outline-success btn-sm btn-block"
title="Use this to arm the robot">
Arm
</button>
<button type="button" onclick="rotate_image()"
class="btn btn-outline-primary btn-sm btn-block"
title="Will rotate the video 180 degrees">
Flip video
</button>
<button type="button" onclick="toggle_roll()" id="rollBtn"
class="btn btn-outline-primary btn-sm btn-block active"
title="Toggle the roll indicator on/off">
Roll
</button>
<button type="button" onclick="toggle_cinema()"
class="btn btn-outline-primary btn-sm btn-block"
title="Toggle cinema mode which hides everything except video">
Cinema
</button>
<button type="button" onclick="set_update_frequency()"
class="btn btn-outline-primary btn-sm btn-block"
title="Changes the sensor update frequency to desired value">
Sensor frequency
</button>
<button type="button" onclick="toggle_light()" id="lightBtn"
class="btn btn-outline-warning btn-sm btn-block"
title="Toggle the light on the ROV on/off">Light
</button>
<button type="button" onclick="stop_rov()"
class="btn btn-outline-danger btn-sm btn-block"
title="Stops the ROV, this page will stop working">
Shutdown
</button>
</div>
</div>
<div class="card bg-light cinema">
<h5 class="card-header">Hotkeys</h5>
<div class="card-body">
<table class="table table-sm">
<tbody>
<tr>
<td><b>F11</b></td>
<td>Fullscreen</td>
</tr>
<tr>
<td><b>L</b></td>
<td>Lights</td>
</tr>
<tr>
<td><b>C</b></td>
<td>Cinema</td>
</tr>
<tr>
<td><b>ENTER</b></td>
<td>Arm</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</body>
</html>
project
├── entry.py
├── start.py
├── index.html
└── static
├── keys.js
├── general.js
├── dynamic.js
├── roll.png
├── bootstrap.css
└── style.css
API¶
Tip
If you are having a hard time, you can always have a look at the examples page where the classes, methods and parameters are used in practice.
WebMethod¶
-
class
edurov.core.
WebMethod
(index_file, video_resolution='1024x768', fps=30, server_port=8000, debug=False, runtime_functions=None, custom_response=None)[source]¶ Starts a video streaming from the rasparry pi and a webserver that can handle user input and other requests.
Parameters: - index_file (str) – Absolute path to the frontpage of the webpage, must be called
index.html
. For more information, see Displaying the video feed. - video_resolution (str, optional) – A string representation of the wanted video resolution in the format WIDTHxHEIGHT.
- fps (int, optional) – Wanted framerate, may not be achieved depending on available resources and network.
- server_port (int, optional) – The web page will be served at this port
- debug (bool, optional) – If set True, additional information will be printed for debug purposes.
- runtime_functions (callable or list, optional) – Should be a callable function or a list of callable functions, will be started as independent processes automatically. For more information, see Controlling motors (or anything).
- custom_response (callable, optional) – If set, this function will be called if default web server is not able
to handle a GET request, should return a str or None. If returned value
starts with
redirect=
followed by a path, the server will redirect the browser to this path. The callable must accept two parameters whereas the second one is the requested path. For more information, see Custom responses.
Examples
>>> import os >>> from edurov import WebMethod >>> >>> file = os.path.join(os.path.dirname(__file__), 'index.html', ) >>> web_method = WebMethod(index_file=file) >>> web_method.serve()
- index_file (str) – Absolute path to the frontpage of the webpage, must be called
ROVSyncer¶
-
class
edurov.sync.
ROVSyncer
[source]¶ Holds all variables for ROV related to control and sensors
Examples
>>> import Pyro4 >>> >>> with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov: >>> while rov.run: >>> print('The ROV is still running')
-
actuator
¶ Dictionary holding actuator values
Getter: Returns actuator values as dict Setter: Update actuator values with dict Type: dict
-
run
¶ Bool describing if the ROV is still running
Getter: Returns bool describing if the ROV is running Setter: Set to False if the ROV should stop Type: bool
-
sensor
¶ Dictionary holding sensor values
Getter: Returns sensor values as dict Setter: Update sensor values with dict Type: dict
-
KeyManager¶
-
class
edurov.sync.
KeyManager
[source]¶ Keeps control of all user input from keyboard.
Examples
>>> import Pyro4 >>> >>> with Pyro4.Proxy("PYRONAME:KeyManager") as keys: >>> with Pyro4.Proxy("PYRONAME:ROVSyncer") as rov: >>> keys.set_mode(key='l', mode='toggle') >>> while rov.run: >>> if keys.state('up arrow'): >>> print('You are pressing the up arrow') >>> if keys.state('l'): >>> print('light on') >>> else: >>> print('light off')
Note
When using the methods below a key identifier must be used. Either the keycode (int) or the KeyASCII or Common Name (str) from the table further down on this page can be used. Using keycode is faster.
-
arrow_dict
¶ Dictionary with the state of the keys up arrow, down arrow, left arrow and right arrow
-
qweasd_dict
¶ Dictionary with the state of the letters q, w, e, a, s and d
-
Keys table¶
KeyASCII ASCII Common Name Keycode
K_BACKSPACE \b backspace 8
K_TAB \t tab 9
K_CLEAR clear
K_RETURN \r return 13
K_PAUSE pause
K_ESCAPE ^[ escape 27
K_SPACE space 32
K_EXCLAIM ! exclaim
K_QUOTEDBL " quotedbl
K_HASH # hash
K_DOLLAR $ dollar
K_AMPERSAND & ampersand
K_QUOTE quote
K_LEFTPAREN ( left parenthesis
K_RIGHTPAREN ) right parenthesis
K_ASTERISK * asterisk
K_PLUS + plus sign
K_COMMA , comma
K_MINUS - minus sign
K_PERIOD . period
K_SLASH / forward slash
K_0 0 0 48
K_1 1 1 49
K_2 2 2 50
K_3 3 3 51
K_4 4 4 52
K_5 5 5 53
K_6 6 6 54
K_7 7 7 55
K_8 8 8 56
K_9 9 9 57
K_COLON : colon
K_SEMICOLON ; semicolon
K_LESS < less-than sign
K_EQUALS = equals sign
K_GREATER > greater-than sign
K_QUESTION ? question mark
K_AT @ at
K_LEFTBRACKET [ left bracket
K_BACKSLASH \ backslash
K_RIGHTBRACKET ] right bracket
K_CARET ^ caret
K_UNDERSCORE _ underscore
K_BACKQUOTE ` grave
K_a a a 65
K_b b b 66
K_c c c 67
K_d d d 68
K_e e e 69
K_f f f 70
K_g g g 71
K_h h h 72
K_i i i 73
K_j j j 74
K_k k k 75
K_l l l 76
K_m m m 77
K_n n n 78
K_o o o 79
K_p p p 80
K_q q q 81
K_r r r 82
K_s s s 83
K_t t t 84
K_u u u 85
K_v v v 86
K_w w w 87
K_x x x 88
K_y y y 89
K_z z z 90
K_DELETE delete
K_KP0 keypad 0
K_KP1 keypad 1
K_KP2 keypad 2
K_KP3 keypad 3
K_KP4 keypad 4
K_KP5 keypad 5
K_KP6 keypad 6
K_KP7 keypad 7
K_KP8 keypad 8
K_KP9 keypad 9
K_KP_PERIOD . keypad period
K_KP_DIVIDE / keypad divide
K_KP_MULTIPLY * keypad multiply
K_KP_MINUS - keypad minus
K_KP_PLUS + keypad plus
K_KP_ENTER \r keypad enter
K_KP_EQUALS = keypad equals
K_UP up arrow 38
K_DOWN down arrow 40
K_RIGHT right arrow 39
K_LEFT left arrow 37
K_INSERT insert 45
K_HOME home 36
K_END end 35
K_PAGEUP page up 33
K_PAGEDOWN page down 34
K_F1 F1
K_F2 F2
K_F3 F3
K_F4 F4
K_F5 F5
K_F6 F6
K_F7 F7
K_F8 F8
K_F9 F9
K_F10 F10
K_F11 F11
K_F12 F12
K_F13 F13
K_F14 F14
K_F15 F15
K_NUMLOCK numlock
K_CAPSLOCK capslock
K_SCROLLOCK scrollock
K_RSHIFT right shift
K_LSHIFT left shift
K_RCTRL right control
K_LCTRL left control
K_RALT right alt
K_LALT left alt
K_RMETA right meta
K_LMETA left meta
K_LSUPER left Windows key
K_RSUPER right Windows key
K_MODE mode shift
K_HELP help
K_PRINT print screen
K_SYSREQ sysrq
K_BREAK break
K_MENU menu
K_POWER power
K_EURO Euro
Utilities¶
Different utility functions practical for ROV control
-
edurov.utils.
cpu_temperature
()[source]¶ Checks and returns the on board CPU temperature
Returns: temperature – the temperature Return type: float
-
edurov.utils.
free_drive_space
(as_string=False)[source]¶ Checks and returns the remaining free drive space
Parameters: as_string (bool, optional) – set to True if you want the function to return a formatted string. 4278 -> 4.28 GB Returns: space – the remaining MB in float or as string if as_string=True Return type: float or str
-
edurov.utils.
receive_arduino
(serial_connection)[source]¶ Returns a message received over serial_connection
Expects that the message received starts with a 6 bytes long number describing the size of the remaining data. “0x000bhello there” -> “hello there”.
Parameters: serial_connection (object) – the serial.Serial
object you want to use for receivingReturns: msg – the message received or None Return type: str or None
-
edurov.utils.
receive_arduino_simple
(serial_connection, min_length=1)[source]¶ Returns a message received over serial_connection
Same as
receive_arduino
but doesn’t expect that the message starts with a hex number.Parameters: Returns: msg – the message received or None
Return type: str or None
-
edurov.utils.
send_arduino
(msg, serial_connection)[source]¶ Send the msg over the serial_connection
Adds a hexadecimal number of 6 bytes to the start of the message before sending it. “hello there” -> “0x000bhello there”
Parameters:
-
edurov.utils.
send_arduino_simple
(msg, serial_connection)[source]¶ Send the msg over the serial_connection
Same as
send_arduino
, but doesn’t add anything to the message before sending it.Parameters: