- Labornetzteil AliExpress         
Ergebnis 1 bis 9 von 9

Thema: Roboter in Echtzeit über den Browser steuern

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.703
    ... Roboter in Echtzeit übers Netzwerk steuern, idealerweise über den Browser ...
    Im WLAN habe ich mit ner Steuerung eines Controllers keine Probleme (vermutlich auch nicht über die heimatliche Routergrenze hinweg).

    Ansatz: Raspberry Pi ohne Bildschirm und ohne Tastatur, mit WLAN-Stick, USB-UART-Adapter und CuteCom (graphisches Terminal, ähnlich dem br@y-Terminal). Die UART-Verbindung geht an den Controller.

    Der RasPi ist so eingestellt, dass er bis zur GUI "alleine" startet - es sind keine zusätzlichen Eingaben nötig. Auf meinem (Windows)PC starte ich den RemoteDesktop - da bekomme ich die Linuxoberfläche auf den Schirm und starte CuteCom. Nun kann ich alle möglichen Befehlstelegramme per Terminal/USB-UART an den Controller senden . . . Das Ganze ist sicher eine ziemliche KrückenLösung; sie läuft mit kaum erkennbarer Zeitverzögerung. Pings habe ich noch nicht gemessen.
    Ciao sagt der JoeamBerg

  2. #2
    So wie ich das verstehe, will -schumi- das nicht einfach über WLan, sondern übers Internet steuern. Und da kommt dann, wie ja auch schon beim Skype Beispiel erwähnt wurde, durchaus einiges an Latenz zusammen. Selebst wenn alles optimiert wird wird das auch bei einer guten Verbidnung kaum unter eine Sekunde sinken. Nur über Wlan als "Sender" sozusagen ist das wohl weniger ein Problem.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    30.12.2008
    Beiträge
    1.427
    zu den latenzen im Netzwerk sind das eine,
    ich bin ja für die in html5 vorhande websocket funktion und javascript (stichwort onkeydown)

    python websocket server + serielle

    javascript ständig befehle senden lassen und am µC watchdog nutzen und immer zurücksetzen wenn befehl mit prüfsumme angekommen ist
    was gibt es noch zu sagen

  4. #4
    Erfahrener Benutzer Roboter-Spezialist Avatar von -schumi-
    Registriert seit
    30.12.2009
    Ort
    Wasserburg am Inn / Bayern
    Alter
    31
    Beiträge
    449
    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>
    Klicke auf die Grafik für eine größere Ansicht

Name:	Screenshot from 2014-04-12 14:19:44.png
Hits:	33
Größe:	89,8 KB
ID:	27966

    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..

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von i_make_it
    Registriert seit
    29.07.2008
    Ort
    Raum DA
    Alter
    57
    Beiträge
    2.814
    1234567890
    Geändert von i_make_it (03.02.2015 um 06:48 Uhr)

Ähnliche Themen

  1. RP6 über Funk und Tastatur echtzeit steuern
    Von cmani2009 im Forum Robby RP6
    Antworten: 21
    Letzter Beitrag: 05.06.2010, 08:28
  2. schrittmotor und 2 hubmagnete über den pc steuern
    Von fabianzenger im Forum Bauanleitungen, Schaltungen & Software nach RoboterNetz-Standard
    Antworten: 2
    Letzter Beitrag: 21.04.2008, 06:57
  3. RC-Fernsteuerung über den PC - Steuern
    Von www.joachimdieterich.de im Forum PIC Controller
    Antworten: 8
    Letzter Beitrag: 31.12.2004, 09:25
  4. Roboter über PC steuern
    Von jens84 im Forum Elektronik
    Antworten: 17
    Letzter Beitrag: 03.07.2004, 10:03
  5. Antworten: 14
    Letzter Beitrag: 23.02.2004, 16:46

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress