Last active
December 14, 2015 09:28
-
-
Save reclosedev/5064616 to your computer and use it in GitHub Desktop.
Droid audio car
http://python.su/forum/topic/20832/
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
| #!/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 = 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> | |
| <iframe 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(){ | |
| 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(){ | |
| sendCommand("begin", cmd); | |
| } | |
| task(); | |
| intervalId = setInterval(task, cmdInterval); | |
| }).mouseup(function(){ | |
| sendCommand("end", $(this).data("command")); | |
| clearInterval(intervalId); | |
| }).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 | |
| (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> | |
| <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 (touch or mouse). Or use keyboard arrows</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() | |
| 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) | |
| 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() | |
| 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) | |
| 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment