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.