Danke für eure Antworten
(Und ein extra Danke für Thomas für die guten Schlagwörter)
Also ich möchte das ganze nur im heimischen (W)Lan machen, d.h. Stecke sind maximal zwei Router.
Die Lösung oben mit dem Python-Webserver war schon man nicht schlecht. Dann habe ich mein Python3-Buch herausgekram und mit Sockets angefangen. Dann kam Thomas$ mit Websockets und da bin ich jetzt.
Und zwar habe ich jetzt einen Tornado-Python-Websocket-Server:
Code:
#!/usr/bin/env python3
# import the libraries
import tornado.web
import tornado.websocket
import tornado.ioloop
import threading
from RobotLibrary import I2C as I2C
from RobotLibrary import robot_motorctrl as motor
from RobotLibrary import robot_servoctrl as servo
class WebSocketHandler(tornado.websocket.WebSocketHandler):
# the client connected
def open(self):
print("New client connected")
self.write_message("You are connected")
# the client sent the message
def on_message(self, message):
print("Got a message: "+message+", parsing it..")
requestlist = eval(message)
self.write_message(RobotRequestHandler(requestlist))
# client disconnected
def on_close(self):
print("Client disconnected")
motorr = 0
motorl = 0
def RobotRequestHandler(requestlist):
global motorr
global motorl
global watchdogctr
i2c.OPEN('/dev/i2c-0')
returnlist = {}
for request in requestlist:
if request == "command":
commandlist = requestlist[request]
returncommandlist = {}
for command in commandlist:
if command == "set":
setlist = commandlist[command]
returnsetlist = {}
for thisset in setlist:
if thisset == "motorr":
motorr = int(setlist[thisset])
returnsetlist[thisset]="Done"
elif thisset == "motorl":
motorl = int(setlist[thisset])
returnsetlist[thisset]="Done"
else:
returnsetlist[thisset]="Not Found"
try:
motor.SET_MOTORS(motorl,motorr)
except:
pass
returncommandlist[command]=returnsetlist
elif command == "get":
getlist = commandlist[command]
returngetlist = {}
for thisget in getlist:
if thisget == "motorr":
returngetlist[thisget]=str(motorr)
elif thisget == "motorl":
returngetlist[thisget]=str(motorl)
else:
returngetlist[thisget]="Not Found"
returncommandlist[command]=returngetlist
else:
returncommandlist[command] = "Not Found"
returnlist[request]=returncommandlist
elif request == "ping":
watchdogctr = 500
returnlist[request]="Done"
print(returnlist)
i2c.CLOSE()
return returnlist
watchdogctr = 500
def watchdog():
global watchdogctr
watchdogctr -= 100
if watchdogctr <= 0:
RobotRequestHandler({"command":{"set":{"motorl":"0", "motorr":"0"}}})
watchdogctr = 500
threading.Timer(0.1, watchdog).start()
watchdog()
# start a new WebSocket Application
# use "/" as the root, and the
# WebSocketHandler as our handler
application = tornado.web.Application([
(r"/", WebSocketHandler),
])
# start the tornado server on port 8888
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Alles sehr klein und einfach, nur die RobotRequestHandler() ist etwas größer, weil meine Befehle im Moment z.B. so aussehen: {"command":{"set":{"motorl":"20", "motorr":"20"}}}
Das parst diese Funktion und gibt zurück was sie alles gemacht hat: {"command": {"set": {"motorr": "Done", "motorl": "Done"}}}
Auf der Client-Seite siehts im Moment so aus:
HTML-Code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Robot-Control</title>
<script type="text/javascript">
var ws;
function WebSocket_Close()
{
ws.close();
}
function WebSocket_Open()
{
ws = new WebSocket("ws://192.168.0.251:8888");
ws.onerror = function(error)
{
console.log('Error detected: ' + error);
}
ws.onopen = function()
{
console.log('Connection opened!');
}
ws.onclose = function()
{
console.log('Connection closed!');
}
ws.onmessage = function(e)
{
var message = e.data;
console.log('Received message: '+message);
}
}
function WebSocket_Send(data)
{
ws.send(data);
console.log('Sent data: '+data)
}
function Robot_move(direction)
{
if(direction == "forwards")
WebSocket_Send('{"command":{"set":{"motorl":"20", "motorr":"20"}}}')
if(direction == "backwards")
WebSocket_Send('{"command":{"set":{"motorl":"-20", "motorr":"-20"}}}')
if(direction == "left")
WebSocket_Send('{"command":{"set":{"motorl":"-20", "motorr":"20"}}}')
if(direction == "right")
WebSocket_Send('{"command":{"set":{"motorl":"20", "motorr":"-20"}}}')
if(direction == "stop")
WebSocket_Send('{"command":{"set":{"motorl":"0", "motorr":"0"}}}')
}
function verifyKey(e)
{
var keycode;
if (window.event)
keycode = window.event.keyCode;
else if (e)
keycode = e.which;
if (keycode == 38)
Robot_move('forwards')
else if (keycode == 40)
Robot_move('backwards')
else if (keycode == 37)
Robot_move('left')
else if (keycode == 39)
Robot_move('right')
else if (keycode == 32)
Robot_move('stop');
else
console.log(keycode)
return false;
}
setInterval(Robot_ping, 300);
function Robot_ping()
{
WebSocket_Send('{"ping"}')
}
// Gamepad support:
var mygamepad;
var gamepadconnected = false;
var x = 0;
var y = 0;
function gamepadConnected(e) {
gamepadconnected = true;
mygamepad = e.gamepad
function pollAxis() {
//console.log(" Axis " + mygamepad.axes);
x = parseInt(mygamepad.axes[3]*20)
y = parseInt(-mygamepad.axes[2]*20)
//console.log(x+" : "+y)
}
setInterval(pollAxis, 30);
function GamepadRobotControl()
{
if ( gamepadconnected == true)
{
WebSocket_Send('{"command":{"set":{"motorl":"'+(y+x)+'", "motorr":"'+(y-x)+'"}}}')
}
}
setInterval(GamepadRobotControl, 400);
}
function gamepadDisconnected() {
gamepadconnected = false;
}
window.addEventListener("gamepadconnected", gamepadConnected, false);
window.addEventListener("gamepaddisconnected", gamepadDisconnected, false);
</script>
</head>
<body>
<input type="button" value="Connect" onclick="WebSocket_Open();" />
<input type="button" value="Disconnect" onclick="WebSocket_Close();" />
<br/><br/>
<input type="button" style="height:80px; width:80px" value="⇧ " onclick="Robot_move('forwards');" />
<input type="button" style="height:80px; width:80px" value="⇩ " onclick="Robot_move('backwards');" />
<input type="button" style="height:80px; width:80px" value="⇦ " onclick="Robot_move('left');" />
<input type="button" style="height:80px; width:80px" value="⇨ " onclick="Robot_move('right');" />
<input type="button" style="height:80px; width:80px" value="Stop" onclick="Robot_move('stop');" />
<br/><br/>
Keyboard-control:
<input type="text" style="height:15px; width:15px" onkeydown="return verifyKey(event)">
</body>
</html>

Es funktioniert alles einwandfrei (auch wenns bisher eher ein proof-of-concept ist):
- Watchdog funktioniert
- Latenz sehr sehr klein
- Steuerung über Buttons geht
- Steuerung über Pfeiltasten der Tastatur geht
- Steuerung über Gamepad geht
Aber als erstes werde ich noch meinen Fahrcontroller/-regler etwas umprogrammieren, damit er schneller beschleunigt. Bei dem dauert es jetzt mit Abstand am längsten bis was passiert 
PS: Schade, dass es hier kein Syntaxhighlighting für Python gibt..
Lesezeichen