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 = 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(){ | |
| 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment