-
-
Save ego008/98022d418a54ab83ccc284eaa950c9a9 to your computer and use it in GitHub Desktop.
Base for a Tornado based robot control UI. Allows to stream mjpeg in the HTML page returned.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
input, button { | |
background: #666; | |
font-size: 35px; | |
font-weight: bold; | |
color: #ccc; | |
width: 50px; | |
height: 50px; | |
vertical-align: middle; | |
} | |
</style> | |
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> | |
<script src="//code.jquery.com/jquery-1.10.2.js"></script> | |
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script> | |
<script type="text/javascript"> | |
var url = "{{ current_url }}"; | |
var go_forward; | |
var go_nw; | |
var go_ne; | |
var go_left; | |
var stop; | |
var go_right; | |
var go_sw; | |
var go_backward; | |
var go_se; | |
var set_speed; | |
var uid = "{{ guid }}"; | |
$(function() { | |
set_speed = $( "#slider" ).slider({ | |
value: 40, | |
step: 5, | |
min: 0, | |
max: 100 | |
}) | |
}); | |
go_nw = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "nw" | |
})); | |
return false; | |
}; | |
go_forward = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "n" | |
})); | |
return false; | |
}; | |
go_ne = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "ne" | |
})); | |
return false; | |
}; | |
go_left = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "w" | |
})); | |
return false; | |
}; | |
stop = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "stop" | |
})); | |
return false; | |
}; | |
go_right = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "e" | |
})); | |
return false; | |
}; | |
go_sw = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "sw" | |
})); | |
return false; | |
}; | |
go_backward = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "s" | |
})); | |
return false; | |
}; | |
go_se = function(e) { | |
socket.send(JSON.stringify({ | |
direction: "se" | |
})); | |
return false; | |
}; | |
$(window).keydown(function(e) { | |
switch (e.keyCode) { | |
case 37: // left | |
go_left(); | |
return false; | |
case 38: // up | |
go_forward(); | |
return false; | |
case 39: // right | |
go_right(); | |
return false; | |
case 40: // down | |
go_backward(); | |
return false; | |
case 32: // space | |
stop(); | |
return false; | |
/* | |
default: | |
$('#result').text(e.keyCode); | |
return false; | |
*/ | |
} | |
return; //using "return" other attached events will execute | |
}); | |
</script> | |
</head> | |
<body> | |
<img src="/video_stream" style="height: 480px; width: 640px;"/> | |
<div id="slider" style="height: 20px; width: 640px;"></div> | |
<div> | |
<div> | |
<input type="button" name="nw" value="↖"> | |
<input type="button" name="n" value="↑"> | |
<input type="button" name="ne" value="↗"> | |
</div> | |
<div> | |
<input type="button" name="w" value="←"> | |
<input type="button" name="stop" value="×"> | |
<input type="button" name="e" value="→"> | |
</div> | |
<div> | |
<input type="button" name="sw" value="↙"> | |
<input type="button" name="s" value="↓"> | |
<input type="button" name="se" value="↘"> | |
</div> | |
<div id="messages" style="height:200px;background:black;color:white;"></div> | |
<script> | |
var messageBox = document.getElementById("messages"); | |
var socket; | |
if ("WebSocket" in window) { | |
messageBox.innerHTML = "WebSocket is supported by your Browser!"; | |
socket = new WebSocket("ws://localhost:8888/socket?id=" + uid); | |
socket.onopen = function() { | |
socket.send(JSON.stringify({ | |
ping: uid | |
})); | |
}; | |
socket.onmessage = function (evt) { | |
messageBox.innerHTML = "Message received:<br/>" + evt.data + "<br/>" + messageBox.innerHTML; | |
}; | |
socket.onclose = function() { | |
messageBox.innerHTML = "Connection is closed.<br/>" + messageBox.innerHTML; | |
}; | |
$('input[name=nw]').bind('click', go_nw); | |
$('input[name=n]').bind('click', go_forward); | |
$('input[name=ne]').bind('click', go_ne); | |
$('input[name=w]').bind('click', go_left); | |
$('input[name=stop]').bind('click', stop); | |
$('input[name=e]').bind('click', go_right); | |
$('input[name=sw]').bind('click', go_sw); | |
$('input[name=s]').bind('click', go_backward); | |
$('input[name=se]').bind('click', go_se); | |
$('input[name=forward]').focus(); | |
$('#slider').on('slidechange', function(event, ui){ | |
socket.send(JSON.stringify({ | |
speed: ui.value | |
})) | |
return false; | |
}); | |
} else { | |
messageBox.innerHTML = "WebSocket NOT supported by your Browser!"; | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tornado.ioloop | |
import tornado.web | |
import tornado.websocket | |
import tornado.tcpserver | |
import tornado.tcpclient | |
import tornado.httpclient | |
import tornado.iostream | |
import tornado.gen | |
import uuid | |
import json | |
import logging | |
from tornado.options import define, options, parse_command_line | |
define("port", default=8888, help="run on the given port", type=int) | |
log = logging.getLogger("tornado.application") | |
log.setLevel(logging.DEBUG) | |
clients = dict() | |
class ForwardingRequestHandler(tornado.web.RequestHandler): | |
@tornado.web.asynchronous | |
@tornado.gen.coroutine | |
def get(self): | |
log.debug("Browser sent: %s", self.request) | |
host = "lwsnb160-cam.cs.purdue.edu" | |
uri = "/axis-cgi/mjpg/video.cgi" | |
client = tornado.tcpclient.TCPClient() | |
stream = yield client.connect(host, 80) | |
stream.write("GET %s HTTP/1.1\r\nHost: %s\r\n\r\n" % (uri, host)) | |
headers = yield stream.read_until(b"\r\n\r\n") | |
self.clear_header("Content-Type") | |
for line in headers.split(b"\r\n"): | |
parts = line.split(b":") | |
if len(parts) == 2: | |
self.add_header(parts[0].strip(), parts[1].strip()) | |
while True: | |
chunk = yield stream.read_bytes(1500) | |
self.write(chunk) | |
self.flush() | |
class IndexHandler(tornado.web.RequestHandler): | |
@tornado.web.asynchronous | |
def get(self): | |
uid = uuid.uuid1() | |
url = "http://%s" % self.request.host | |
log.debug("Serving index.html to %s", uid) | |
self.render("templates/index.html", guid=uid, current_url=url) | |
class WebSocketHandler(tornado.websocket.WebSocketHandler): | |
def ping(self, value): | |
log.debug("Received a ping from %s responding to this client", value) | |
self.write_message("Ping to " + value) | |
def set_direction(self, value): | |
log.debug("Changed direction to %s", value) | |
self.write_message("Setting direction to '%s'" % value) | |
def set_speed(self, value): | |
log.debug("Changed speed to %s", value) | |
self.write_message("Setting speed to %d" % value) | |
message_types = { | |
"ping": ping, | |
"direction": set_direction, | |
"speed": set_speed | |
} | |
def open(self, *args): | |
self.id = self.get_argument("id") | |
self.stream.set_nodelay(True) | |
clients[self.id] = {"id": self.id, "object": self} | |
log.debug("Connection from %s", self.id) | |
self.write_message("Connection from " + self.id) | |
def on_message(self, message): | |
log.debug("Client %s received a message : %s", self.id, message) | |
actions = json.loads(message) | |
for k in actions.keys(): | |
self.message_types[k](self, actions[k]) | |
def on_close(self): | |
if self.id in clients: | |
del clients[self.id] | |
app = tornado.web.Application([ | |
(r'/', IndexHandler), | |
(r'/socket', WebSocketHandler), | |
(r'/video_stream', ForwardingRequestHandler) | |
], debug=True) | |
if __name__ == '__main__': | |
parse_command_line() | |
app.listen(options.port) | |
tornado.ioloop.IOLoop.instance().start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment