Skip to content

Instantly share code, notes, and snippets.

@reclosedev
Last active December 14, 2015 09:28
Show Gist options
  • Save reclosedev/5064616 to your computer and use it in GitHub Desktop.
Save reclosedev/5064616 to your computer and use it in GitHub Desktop.

Revisions

  1. reclosedev revised this gist Mar 4, 2013. 1 changed file with 71 additions and 63 deletions.
    134 changes: 71 additions & 63 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -25,67 +25,35 @@ def mediaPlay(path):
    COMMAND_SEND_INTERVAL = 1.0 # seconds
    COMMAND_TIMEOUT = COMMAND_SEND_INTERVAL * 2

    PAGE_TEMPLATE = '''
    PAGE_TEMPLATE = string.Template('''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>DroidBot Remote Control</title>
    </head>
    <FRAMESET ROWS="50%,50%">
    <FRAME SRC="frame_a.html">
    <FRAME SRC="frame_b.html">
    </FRAMESET>
    </html>
    '''

    PAGE_TEMPLATE_A = '''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    </head>
    <body>
    <h1>DroidBot Remote Control</h1>
    <iframe width="640" height="480" src ="http://%s:9091">No iframes?</iframe>"
    </body>
    </html>
    '''

    PAGE_TEMPLATE_B = string.Template('''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>DroidBot Remote Control</title>
    <style type="text/css">
    #action {
    background:yellow;
    border:0px solid #555;
    color:#555;
    width:0px;
    height:0px;
    padding:0px;
    }
    #joystick {
    background: black;
    color: white;
    width: 100%;
    height: 100%;
    overflow: hidden;
    padding: 0;
    body {
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    }
    .btn{
    .btn {
    width: 7em;
    height: 2em;
    }
    div#leftcolumn, div#rightcolumn {
    float: left;
    width: 50%;
    height: 100%;
    }
    .center {
    display:block;
    margin-left: auto;
    margin-right: auto;
    }
    .dull {color: #a9a9a9}
    </style>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="//jeromeetienne.github.com/virtualjoystick.js/virtualjoystick.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="http://jeromeetienne.github.com/virtualjoystick.js/virtualjoystick.js"></script>
    <script>
    $(document).ready(function(){
    function CommandSender(cmdInterval){
    this.cmdInterval = cmdInterval;
    this.lastCmd = "";
    @@ -145,11 +113,11 @@ def mediaPlay(path):
    });
    sender.run();
    })();
    (function joystickHandler(){
    $("#joystickframe").load(function(){
    var container = $('#joystickframe').contents().find('#joystick')[0];
    var joystick = new VirtualJoystick({
    container : document.getElementById('joystick'),
    mouseSupport : true
    container : container,
    mouseSupport: true
    });
    var sender = new CommandSender(cmdInterval);
    setInterval(function(){
    @@ -168,13 +136,15 @@ def mediaPlay(path):
    }
    sender.updateState(state, cmd);
    }, 1/30 * 1000);
    })();
    });
    });
    </script>
    </head>
    <body>
    <table border=0>
    <div id="leftcolumn">
    <iframe src="http://${IP_ADDRESS}:8080/videofeed" class="center" scrolling="no" width="640" height="480" >No iframes?</iframe>
    <table border=0 class="center">
    <tr>
    <td></td>
    <td><button class="btn" data-command="up">Up</button></td>
    @@ -191,10 +161,45 @@ def mediaPlay(path):
    <td></td>
    </tr>
    </table>
    <div id="joystick">Joystick area. Press and drag (touch or mouse). Or use keyboard arrows</div>
    <p class="dull">Press and hold buttons or use keyboard arrows.</p>
    </div>
    <div id="rightcolumn">
    <iframe id="joystickframe" src="joystick.html" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" width="100%" height="100%" frameborder="0">
    </iframe>
    </div>
    </body>
    </html>
    ''').safe_substitute(COMMAND_SEND_INTERVAL=int(COMMAND_SEND_INTERVAL * 1000))
    ''')

    PAGE_JOYSTICK_TEMPLATE = '''
    <html>
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <style type="text/css">
    body {
    overflow: hidden;
    padding: 0;
    margin: 0;
    }
    div#joystick {
    background: black;
    color: white;
    width: 100%;
    height: 100%;
    overflow: hidden;
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    }
    </style>
    </head>
    <body>
    <div id="joystick" style="">Joystick area. Press and drag (touch or mouse)</div>
    </body>
    '''


    class CarControllerThread(Thread):
    @@ -254,14 +259,17 @@ def do_GET(self):
    self.end_headers()

    url = urlparse.urlsplit(self.path)
    print url.path
    if url.path == '/frame_a.html':
    ip, port = self.headers.get('Host').split(":", 2)
    self.wfile.write(PAGE_TEMPLATE_A % ip)
    elif url.path == '/frame_b.html':
    self.wfile.write(PAGE_TEMPLATE_B)

    if url.path == '/joystick.html':
    self.wfile.write(PAGE_JOYSTICK_TEMPLATE)
    else:
    self.wfile.write(PAGE_TEMPLATE)
    ip, port = self.headers.get('Host').split(":", 2)
    self.wfile.write(
    PAGE_TEMPLATE.safe_substitute(
    IP_ADDRESS=ip,
    COMMAND_SEND_INTERVAL=int(COMMAND_SEND_INTERVAL * 1000),
    )
    )

    def do_POST(self):
    self.send_response(200)
  2. reclosedev revised this gist Mar 3, 2013. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,7 @@
    from threading import Thread
    import urlparse
    import time
    import string

    try:
    import android
    @@ -21,7 +22,8 @@ def mediaPlay(path):

    HOST_NAME = ''
    PORT_NUMBER = 9090
    COMMAND_TIMEOUT = 1.0 # seconds
    COMMAND_SEND_INTERVAL = 1.0 # seconds
    COMMAND_TIMEOUT = COMMAND_SEND_INTERVAL * 2

    PAGE_TEMPLATE = '''
    <html>
    @@ -48,7 +50,7 @@ def mediaPlay(path):
    </html>
    '''

    PAGE_TEMPLATE_B = '''
    PAGE_TEMPLATE_B = string.Template('''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    @@ -116,7 +118,7 @@ def mediaPlay(path):
    });
    }
    var cmdInterval = 500;
    var cmdInterval = ${COMMAND_SEND_INTERVAL};
    (function buttonsHandler(){
    var sender = new CommandSender(cmdInterval);
    @@ -192,7 +194,7 @@ def mediaPlay(path):
    <div id="joystick">Joystick area. Press and drag (touch or mouse). Or use keyboard arrows</div>
    </body>
    </html>
    '''
    ''').safe_substitute(COMMAND_SEND_INTERVAL=int(COMMAND_SEND_INTERVAL * 1000))


    class CarControllerThread(Thread):
  3. reclosedev revised this gist Mar 2, 2013. 1 changed file with 30 additions and 25 deletions.
    55 changes: 30 additions & 25 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -83,47 +83,53 @@ def mediaPlay(path):
    <script>
    $(document).ready(function(){
    function sendCommand(state, cmd){
    $.post('command/' + state + ':' + cmd, function(resp){
    console.log(resp);
    });
    }
    function CommandSender(cmdInterval){
    this.cmdInterval = cmdInterval;
    this.lastCmd = "";
    this.lastState = "";
    this.lastTime = new Date();
    }
    CommandSender.prototype.run = function(){
    var $this = this;
    setInterval(function(){
    $this.updateState($this.lastState, $this.lastCmd);
    }, this.cmdInterval);
    }
    CommandSender.prototype.updateState = function(state, cmd){
    if((new Date() - this.lastTime) < this.cmdInterval &&
    cmd == this.lastCmd && state == this.lastState)
    return;
    if (cmd){
    sendCommand(state, cmd);
    if (state == "begin" && cmd){
    this.sendCommand(state, cmd);
    }
    else if (cmd != this.lastCmd) {
    sendCommand("end", cmd);
    else if (state != this.lastState) {
    this.sendCommand("end", cmd);
    }
    this.lastState = state;
    this.lastCmd = cmd;
    this.lastTime = new Date();
    }
    var intervalId;
    CommandSender.prototype.sendCommand = function(state, cmd){
    $.post('command/' + state + ':' + cmd, function(resp){
    console.log(resp);
    });
    }
    var cmdInterval = 500;
    $(".btn").mousedown(function(){
    var cmd = $(this).data("command");
    var task = function(){
    sendCommand("begin", cmd);
    }
    task();
    intervalId = setInterval(task, cmdInterval);
    }).mouseup(function(){
    sendCommand("end", $(this).data("command"));
    clearInterval(intervalId);
    }).mouseleave(function(){
    clearInterval(intervalId);
    });
    (function buttonsHandler(){
    var sender = new CommandSender(cmdInterval);
    $(".btn").mousedown(function(){
    sender.updateState("begin", $(this).data("command"));
    }).mouseup(function(){
    sender.updateState("end", $(this).data("command"));
    }).mouseleave(function(){
    sender.updateState("end", "");
    });
    sender.run();
    })();
    (function keyBoardHandler(){
    var sender = new CommandSender(cmdInterval);
    var arrow = {37: 'left', 38: 'up', 39: 'right', 40:'down'};
    @@ -135,10 +141,9 @@ def mediaPlay(path):
    }).keyup(function (e) {
    sender.updateState("end", "");
    });
    sender.run();
    })();
    // ---------------------------------------------
    // Optional joystick functionality
    (function joystickHandler(){
    var joystick = new VirtualJoystick({
    container : document.getElementById('joystick'),
  4. reclosedev revised this gist Mar 2, 2013. 1 changed file with 60 additions and 30 deletions.
    90 changes: 60 additions & 30 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -83,13 +83,34 @@ def mediaPlay(path):
    <script>
    $(document).ready(function(){
    var sendCommand = function(state, cmd){
    function sendCommand(state, cmd){
    $.post('command/' + state + ':' + cmd, function(resp){
    console.log(resp);
    });
    }
    function CommandSender(cmdInterval){
    this.cmdInterval = cmdInterval;
    this.lastCmd = "";
    this.lastState = "";
    this.lastTime = new Date();
    }
    CommandSender.prototype.updateState = function(state, cmd){
    if((new Date() - this.lastTime) < this.cmdInterval &&
    cmd == this.lastCmd && state == this.lastState)
    return;
    if (cmd){
    sendCommand(state, cmd);
    }
    else if (cmd != this.lastCmd) {
    sendCommand("end", cmd);
    }
    this.lastState = state;
    this.lastCmd = cmd;
    this.lastTime = new Date();
    }
    var intervalId;
    var cmdInterval = 500;
    $(".btn").mousedown(function(){
    var cmd = $(this).data("command");
    var task = function(){
    @@ -103,36 +124,45 @@ def mediaPlay(path):
    }).mouseleave(function(){
    clearInterval(intervalId);
    });
    (function keyBoardHandler(){
    var sender = new CommandSender(cmdInterval);
    var arrow = {37: 'left', 38: 'up', 39: 'right', 40:'down'};
    $(document).keydown(function (e) {
    var keyCode = e.keyCode || e.which;
    var cmd = arrow[keyCode];
    if (cmd)
    sender.updateState("begin", cmd);
    }).keyup(function (e) {
    sender.updateState("end", "");
    });
    })();
    // ---------------------------------------------
    // Optional joystick functionality
    var lastDirection = "";
    var joystick = new VirtualJoystick({
    container : document.getElementById('joystick'),
    mouseSupport : true
    });
    setInterval(function(){
    var dir = "";
    if(joystick.up()){
    dir = "up";
    }
    else if (joystick.down()) {
    dir = "down";
    }
    else if (joystick.left()) {
    dir = "left";
    }
    else if (joystick.right()) {
    dir = "right";
    }
    if (dir){
    sendCommand("begin", dir);
    }
    else if (dir != lastDirection) {
    sendCommand("end", dir);
    }
    lastDirection = dir;
    }, cmdInterval);
    (function joystickHandler(){
    var joystick = new VirtualJoystick({
    container : document.getElementById('joystick'),
    mouseSupport : true
    });
    var sender = new CommandSender(cmdInterval);
    setInterval(function(){
    var cmd = ""
    var state = "begin";
    if(joystick.up()){
    cmd = "up";
    } else if (joystick.down()) {
    cmd = "down";
    } else if (joystick.left()) {
    cmd = "left";
    } else if (joystick.right()) {
    cmd = "right";
    } else {
    state = "end";
    }
    sender.updateState(state, cmd);
    }, 1/30 * 1000);
    })();
    });
    </script>
    </head>
    @@ -154,7 +184,7 @@ def mediaPlay(path):
    <td></td>
    </tr>
    </table>
    <div id="joystick">Joystick area. Press and drag</div>
    <div id="joystick">Joystick area. Press and drag (touch or mouse). Or use keyboard arrows</div>
    </body>
    </html>
    '''
  5. reclosedev revised this gist Mar 2, 2013. 1 changed file with 15 additions and 14 deletions.
    29 changes: 15 additions & 14 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,7 @@

    try:
    import android
    droid = droid = android.Android()
    droid = android.Android()
    except ImportError:
    def mediaPlay(path):
    print "PLAY", path
    @@ -216,14 +216,11 @@ def do_GET(self):
    self.send_header("Content-type", "text/html; charset=utf-8")
    self.end_headers()

    my_full_addr = self.headers.get('Host')
    my_addr = my_full_addr.split(":", 2)
    my_ip_addr = my_addr[0]

    url = urlparse.urlsplit(self.path)
    print url.path
    if url.path == '/frame_a.html':
    self.wfile.write(PAGE_TEMPLATE_A % my_ip_addr)
    ip, port = self.headers.get('Host').split(":", 2)
    self.wfile.write(PAGE_TEMPLATE_A % ip)
    elif url.path == '/frame_b.html':
    self.wfile.write(PAGE_TEMPLATE_B)
    else:
    @@ -233,14 +230,18 @@ def do_POST(self):
    self.send_response(200)
    self.send_header("Content-type", "text/plain; charset=utf-8")
    self.end_headers()
    try:
    state, cmd = self.path.split("/")[-1].split(":")
    except ValueError:
    print "ERROR", self.path
    self.wfile.write("fail")
    return
    controller.update_state(state, cmd)
    self.wfile.write("ok")
    if self.path.startswith("/command/"):
    try:
    #/command/state:up
    state, cmd = self.path.split("/")[-1].split(":")
    except ValueError:
    print "ERROR", self.path
    self.wfile.write("fail")
    return
    controller.update_state(state, cmd)
    self.wfile.write("ok")
    elif self.path.startswith("/ping"):
    self.wfile.write("pong")


    controller = CarControllerThread(COMMAND_TIMEOUT)
  6. reclosedev revised this gist Mar 1, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ def mediaPlay(path):
    </head>
    <body>
    <h1>DroidBot Remote Control</h1>
    <asdf width="640" height="480" src ="http://%s:9091">No iframes?</iframe>"
    <iframe width="640" height="480" src ="http://%s:9091">No iframes?</iframe>"
    </body>
    </html>
    '''
  7. reclosedev created this gist Mar 1, 2013.
    257 changes: 257 additions & 0 deletions droid_audio_car.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,257 @@
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Based on http://www.marsohod.org/index.php/projects/plata1/205-carctrlandr
    import os
    import BaseHTTPServer
    from threading import Thread
    import urlparse
    import time

    try:
    import android
    droid = droid = android.Android()
    except ImportError:
    def mediaPlay(path):
    print "PLAY", path

    import mock
    droid = mock.Mock()
    droid.mediaPlay = mediaPlay


    HOST_NAME = ''
    PORT_NUMBER = 9090
    COMMAND_TIMEOUT = 1.0 # seconds

    PAGE_TEMPLATE = '''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>DroidBot Remote Control</title>
    </head>
    <FRAMESET ROWS="50%,50%">
    <FRAME SRC="frame_a.html">
    <FRAME SRC="frame_b.html">
    </FRAMESET>
    </html>
    '''

    PAGE_TEMPLATE_A = '''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    </head>
    <body>
    <h1>DroidBot Remote Control</h1>
    <asdf width="640" height="480" src ="http://%s:9091">No iframes?</iframe>"
    </body>
    </html>
    '''

    PAGE_TEMPLATE_B = '''
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>DroidBot Remote Control</title>
    <style type="text/css">
    #action {
    background:yellow;
    border:0px solid #555;
    color:#555;
    width:0px;
    height:0px;
    padding:0px;
    }
    #joystick {
    background: black;
    color: white;
    width: 100%;
    height: 100%;
    overflow: hidden;
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    }
    .btn{
    width: 7em;
    height: 2em;
    }
    </style>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="//jeromeetienne.github.com/virtualjoystick.js/virtualjoystick.js"></script>
    <script>
    $(document).ready(function(){
    var sendCommand = function(state, cmd){
    $.post('command/' + state + ':' + cmd, function(resp){
    console.log(resp);
    });
    }
    var intervalId;
    var cmdInterval = 500;
    $(".btn").mousedown(function(){
    var cmd = $(this).data("command");
    var task = function(){
    sendCommand("begin", cmd);
    }
    task();
    intervalId = setInterval(task, cmdInterval);
    }).mouseup(function(){
    sendCommand("end", $(this).data("command"));
    clearInterval(intervalId);
    }).mouseleave(function(){
    clearInterval(intervalId);
    });
    // ---------------------------------------------
    // Optional joystick functionality
    var lastDirection = "";
    var joystick = new VirtualJoystick({
    container : document.getElementById('joystick'),
    mouseSupport : true
    });
    setInterval(function(){
    var dir = "";
    if(joystick.up()){
    dir = "up";
    }
    else if (joystick.down()) {
    dir = "down";
    }
    else if (joystick.left()) {
    dir = "left";
    }
    else if (joystick.right()) {
    dir = "right";
    }
    if (dir){
    sendCommand("begin", dir);
    }
    else if (dir != lastDirection) {
    sendCommand("end", dir);
    }
    lastDirection = dir;
    }, cmdInterval);
    });
    </script>
    </head>
    <body>
    <table border=0>
    <tr>
    <td></td>
    <td><button class="btn" data-command="up">Up</button></td>
    <td></td>
    </tr>
    <tr>
    <td><button class="btn" data-command="left">Left</button></td>
    <td></td>
    <td><button class="btn" data-command="right">Right</button></td>
    </tr>
    <tr>
    <td></td>
    <td><button class="btn" data-command="down">Down</button></td>
    <td></td>
    </tr>
    </table>
    <div id="joystick">Joystick area. Press and drag</div>
    </body>
    </html>
    '''


    class CarControllerThread(Thread):

    path_to_audio = '/mnt/sdcard/droid_car/'
    command_to_audio = {
    'up': 'up.wav',
    'down': 'down.wav',
    'left': 'left.wav',
    'right': 'right.wav',
    }

    def __init__(self, timeout=1):
    super(CarControllerThread, self).__init__()
    self.timeout = timeout
    self.pool_timeout = timeout / 3.0
    self.current_state = ""
    self.current_command = ""
    self.last_cmd_timestamp = time.time()

    def run(self):
    while True:
    elapsed = time.time() - self.last_cmd_timestamp
    if self.current_state == "begin" and elapsed > self.timeout:
    self.update_state("end", "")
    time.sleep(self.pool_timeout)

    def update_state(self, state, command):
    self.last_cmd_timestamp = time.time()
    if state == self.current_state and command == self.current_command:
    return
    self.current_state = state
    self.current_command = command
    if state == "end":
    print "PAUSE"
    droid.mediaPlaySetLooping(False)
    droid.mediaPlayPause()
    elif state == "begin":
    print "PLAY", command
    audio = self.command_to_audio.get(command)
    if audio:
    droid.mediaPlay(os.path.join(self.path_to_audio, audio))
    droid.mediaPlaySetLooping(True)
    else:
    print "wrong command:", command


    class DroidHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_HEAD(self):
    self.send_response(200)
    self.send_header("Content-type", "text/html; charset=utf-8")
    self.end_headers()

    def do_GET(self):
    self.send_response(200)
    self.send_header("Content-type", "text/html; charset=utf-8")
    self.end_headers()

    my_full_addr = self.headers.get('Host')
    my_addr = my_full_addr.split(":", 2)
    my_ip_addr = my_addr[0]

    url = urlparse.urlsplit(self.path)
    print url.path
    if url.path == '/frame_a.html':
    self.wfile.write(PAGE_TEMPLATE_A % my_ip_addr)
    elif url.path == '/frame_b.html':
    self.wfile.write(PAGE_TEMPLATE_B)
    else:
    self.wfile.write(PAGE_TEMPLATE)

    def do_POST(self):
    self.send_response(200)
    self.send_header("Content-type", "text/plain; charset=utf-8")
    self.end_headers()
    try:
    state, cmd = self.path.split("/")[-1].split(":")
    except ValueError:
    print "ERROR", self.path
    self.wfile.write("fail")
    return
    controller.update_state(state, cmd)
    self.wfile.write("ok")


    controller = CarControllerThread(COMMAND_TIMEOUT)
    controller.start()
    try:
    droid.wakeLockAcquireBright()
    droid.webcamStart(0, 10, 9091)
    droid.webcamAdjustQuality(0, 10)
    except Exception as e:
    print "Webcam error", e

    my_srv = BaseHTTPServer.HTTPServer((HOST_NAME, PORT_NUMBER), DroidHandler)
    print 'web server running on port %s' % PORT_NUMBER
    my_srv.serve_forever()