[PYTHON] Lassen Sie uns eine Remote-Rumba erstellen [Software]

Einführung

Dieser Artikel ist eine Fortsetzung von Lassen Sie uns eine Remote-Rumba [Hardware] erstellen. Wenn Sie den ersten Teil noch nicht gesehen haben, schauen Sie bitte zuerst dort nach.

Ziel

Dieses Mal werden wir die Rumba kontrollieren, die bis zum letzten Mal vorbereitet wurde.

Umgebung

Die verwendete Programmiersprache ist ** Python 3.7 **. Ich denke, dass es standardmäßig in Raspeye OS installiert ist. Im Allgemeinen scheinen viele Leute ROS zu verwenden, um Rumba zu kontrollieren, aber ich habe ROS nicht so oft verwendet und bin nicht daran gewöhnt. Unter dem Gesichtspunkt der Flexibilität und des einfachen Verständnisses bei der zukünftigen Entwicklung von Rumba wird dieser Artikel Rumba nur mit Python steuern.

Quellcode

1. Kontrolle

1-1. Vorbereitung der eigentlichen Maschine

Grundsätzlich befindet sich der Code, der Rumba steuert, in der von iRobot offiziell herausgegebenen Spezifikation iRobot Roomba 500 Open Interface (OI) -Spezifikation. Es ist für die Öffentlichkeit zugänglich, und wenn Sie es als serielles Signal an Rumba senden, funktioniert es so, wie es ist. (Obwohl in der Spezifikation 500 angegeben ist, ändert sich der Befehl in keiner Reihe.)

Wenn Sie diese Spezifikation lesen, müssen Sie jedoch Code schreiben, um die feineren Details zu erhalten. Aus diesem Grund hat Martin Schaef in der Vergangenheit die Rumba-API für Python erstellt und veröffentlicht, daher werde ich sie ausleihen.

martinschaef/roomba ↑ Der Quellcode ist hier.

Das Problem ist, dass der Code selbst alt und für ** Python 2.7 ** programmiert ist. Daher funktioniert das Kopieren und Einfügen des entsprechenden Codes überhaupt nicht. ** Sie müssen einige Korrekturen selbst vornehmen **.

Der zu ändernde Code lautet "create.py". Dies ist die ursprüngliche Rumba-API.

Zunächst werden in diesem Code alle seriellen Befehle vom Typ "chr" geschrieben.

create.py


START = chr(128)    # already converted to bytes...
BAUD = chr(129)     # + 1 byte
CONTROL = chr(130)  # deprecated for Create
SAFE = chr(131)
FULL = chr(132)
POWER = chr(133)
SPOT = chr(134)     # Same for the Roomba and Create
CLEAN = chr(135)    # Clean button - Roomba
etc...

Wenn ich diesen Code in Python3 ausführe, wird folgende Fehlermeldung angezeigt:

TypeError: unicode strings are not supported, please encode to bytes: '\x80'

Die Implikation ist, dass der Typ "str" keine serielle Kommunikation unterstützt. Dies funktioniert jedoch in Python 2.7 einwandfrei. Was um alles in der Welt ist das? Die Antwort ist, dass Python 2 und Python 3 den Typ "chr" unterschiedlich behandeln. Insbesondere wurde es wie folgt geändert.

Python2 Python3
int to bytes chr(i) bytes([i])

Ich bin hier im Topf stecken geblieben, aber wenn Sie genau hinschauen, bedeutet dies, dass der Typ "Bytes" die Zahl in ** () mit [] ** beschreiben muss. Bitte vergessen Sie nicht, es aufzuschreiben.

Übrigens, wenn Sie nur den Typ "chr" in "Bytes" konvertieren möchten, sollten Sie ".encode ()" hinzufügen. Sicher, das würde den Fehler im Programm selbst beseitigen, aber Rumba würde überhaupt nicht funktionieren. Wenn Sie die Zeichenfolge beim Anhängen von ".encode ()" überprüfen, wird sie daher wie folgt geschrieben.

128 b'\xc2\x80'
129 b'\xc2\x81'
130 b'\xc2\x82'
131 b'\xc2\x83'
132 b'\xc2\x84'
133 b'\xc2\x85'

Wenn eine Zahl hexadezimal gesendet wird, sollte sie ursprünglich als "0x80" oder "/ x80" geschrieben werden. Im Ergebnis werden jedoch alle Werte vom Wert "/ xc2" begleitet. Dies bedeutet, dass die Information, dass es sich um "UTF-8" handelt, hinzugefügt wird. Wenn Sie darüber nachdenken, haben Sie nicht den einfachen Typ "int" konvertiert, sondern den Typ "str" in Bytes konvertiert, sodass auch Informationen hinzugefügt wurden. Daher wurde in diesem Fall der Wert "U + 0081" konvertiert, und wenn Sie einfach ".encode ()" aus diesem Ergebnis hinzufügen, funktioniert Rumba nicht.

** Tut mir allen leid, aber ich möchte, dass Sie alle Teile, die dem Typ "chr (i)" entsprechen, in "Bytes ([i])" in diesem Code konvertieren. ** ** **

create.py


START = bytes([128]) # already converted to bytes...
BAUD = bytes([129]) # + 1 byte
CONTROL = bytes([130]) # deprecated for Create
SAFE = bytes([131])
FULL = bytes([132])
POWER = bytes([133])
SPOT = bytes([134]) # Same for the Roomba and Create
CLEAN = bytes([135]) # Clean button - Roomba
etc...

Mit der obigen Änderung wird auch die Operation selbst ausgeführt, aber da die ursprünglich geschriebene Nachricht von "print" in der Python2-Syntax geschrieben ist, wird alles ignoriert. Es ist zu langweilig, also denke ich, dass Sie es auf die gleiche Weise umschreiben sollten.

create.py


print 'Serial port did open, presumably to a roomba...'
                          ↓
print('Serial port did open, presumably to a roomba...')

Lassen Sie uns an dieser Stelle versuchen, festzustellen, ob Sie tatsächlich eine Verbindung zu Rumba herstellen können. Verwenden Sie zur Bestätigung den folgenden Code.

test_roomba.py


import create
import time

ROOMBA_PORT="/dev/ttyAMA0"
robot = create.Create(ROOMBA_PORT)

robot.printSensors() 
robot.toSafeMode()
robot.go(0,10)

robot.close()

Wenn Sie Raspai und Rumba verbinden und den obigen Code ausführen, erhalten Sie den Wert des Rumba-Sensors und dieser wird in der Befehlszeile angezeigt, und Rumba sollte sich ein wenig drehen.

Wenn ein Fehler ausgegeben wird und "Key Error:" angezeigt wird, sind Rumba und Rasp Pie möglicherweise nicht richtig verbunden. Es gibt zwei mögliche Ursachen: 1. Rumba läuft nicht und 2. Das Kabel ist gebrochen. Drücken Sie im ersten Fall leicht die Taste "REINIGEN" in der Mitte von Rumba, um sie zu aktivieren und erneut zu versuchen. Überprüfen Sie im letzteren Fall den Durchgang des Kabels.

Wenn Sie den Sensorwert erhalten können, die Rumba jedoch überhaupt nicht funktioniert, führen Sie den folgenden Code aus.

test_roomba.py


import serial
ser = serial.Serial('/dev/ttyAMA0', 115200)
ser.write(b'0x80')

Wenn Rumba nach einer Ladestation mit dem oben genannten Code sucht, befindet sich die serielle Kommunikation möglicherweise auf RS232C-Ebene. Bitte konvertieren Sie auf TTL-Ebene und stellen Sie erneut eine Verbindung her.

Als nächstes wird die Rumba durch Eingabe über die Tastatur gesteuert. Eine kleine Modifikation von game.py aus dem Quellcode martinschaef / roomba von Martin Schaef. Benutzen.

game.py


ROOMBA_PORT = "/dev/tty.usbserial-DA017V6X"
              ↓
ROOMBA_PORT = "/dev/ttyAMA0"

Da sich das Verbindungsziel im ursprünglichen Quellcode unterscheidet, korrigieren Sie die 21. Zeile wie oben.

game.py


if event.key == pygame.K_x:
   robot.seekDock()
   time.sleep(2.0)
   pygame.quit()
   return

game.py


screen.blit(
  font.render("Clean Mode Roomba with c, press key x make Roomba back to the dock.",
                        1, (10, 10, 10)), (10, 580))

Ich wollte auch die Möglichkeit, während der Fernbedienung automatisch zur Ladestation zurückzukehren, und fügte den obigen Code den Zeilen 115 bzw. 166 hinzu.

Erstellen Sie abschließend einen neuen Ordner "img" in dem Verzeichnis, in dem sich diese ausführbaren Dateien befinden, legen Sie "roomba.png " darin ab, und die Vorbereitung des eigentlichen Computers ist abgeschlossen.

1-2. Vorbereitung des Host-Computers

Ich möchte die Rumba fernsteuern, also muss ich mich auch hier vorbereiten. Verwenden Sie VcXsrv (X-Server), um den auf dem Raspeye angezeigten Steuerungsbildschirm auf den Host-Computer zu verschieben.

Installieren Sie VcXsrv (X-Server) unter Windows und betreiben Sie die Linux-GUI remote ↑ Die Details zu diesem Artikel sind auf dieser Seite sehr detailliert und leicht verständlich zusammengefasst. Bitte beziehen Sie sich hier.

1-3. Funktionsprüfung

Wenn alle oben genannten Punkte erledigt sind, können Sie die Rumba tatsächlich steuern. Versuchen Sie es sofort auf Python 3. Ich denke, dass die detaillierte Steuermethode auf dem angezeigten Bildschirm beschrieben wird, aber vorerst werde ich kurz erklären, "w", um sich vorwärts zu bewegen, "s", um sich rückwärts zu bewegen, "a", "d", um sich nach links und rechts zu bewegen. Es ist eine Rotation zu. Es ist eine vorübergehende Pause mit "Leerzeichen" und endet mit "Esc". Ich denke, dass die in Echtzeit für jeden anderen Sensor erfassten Werte angezeigt werden.

2. Videoübertragung

Als nächstes möchte ich ein Programm erstellen, das die von der Webkamera erfassten Videodaten auf den Host-Computer überträgt. Zuerst habe ich versucht, das Video auf Rasppie mit open_cv zu öffnen und das Fenster mit VcXsrv auf den Host-Computer zu übertragen, aber es hat nicht so gut funktioniert, also habe ich mich für die Methode der Videoübertragung per Socket-Kommunikation entschieden.

Installieren Sie "opencv-python" mit pip in der Bibliothek. Wenn Sie versuchen, die neueste Version von opencv 4.4.0.42 zu installieren, wird Python 3.7 möglicherweise nicht für immer fertiggestellt. In einem solchen Fall scheint es reibungslos zu sein, wenn Sie die Version ein wenig absenken und um 4.1.0.25 installieren.

pip3 install opencv-python==4.1.0.25

Das folgende Programm soll auf Raspeye ausgeführt werden.

video_server.py


import socketserver
import cv2
import sys

HOST = "192.168.XXX.XXX"#Dies ist die IP-Adresse von Raspeye
PORT = 5569

class TCPHandler(socketserver.BaseRequestHandler):
    videoCap = ''

    def handle(self):
        self.data = self.request.recv(1024).strip()
        ret, frame = videoCap.read()
        encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]
        jpegsByte = cv2.imencode('.jpeg', frame, encode_param)[1].tostring()
        self.request.send(jpegsByte)

videoCap = cv2.VideoCapture(0)
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((HOST, PORT), TCPHandler)

try:
    server.serve_forever()
except KeyboardInterrupt:
    server.shutdown()
    sys.exit()

Das folgende Programm wird auf dem Host-Computer ausgeführt.

video_client.py


import socket
import numpy
import cv2

HOST = "192.168.XXX.XXX"#Dies ist die IP-Adresse von Raspeye
PORT = 5569

def getimage():

    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect((HOST,PORT))

    buf=b''
    recvlen=100
    while recvlen>0:
        receivedstr=sock.recv(1024*8)
        recvlen=len(receivedstr)
        buf += receivedstr
    sock.close()

    narray=numpy.fromstring(buf,dtype='uint8')
    return cv2.imdecode(narray,1)

while True:
    img = getimage()
    cv2.imshow('Capture',img)

Starten Sie diese Programme von "server.py". Wenn sie erfolgreich verbunden sind, sollte das Video auf die Seite des Hostcomputers übertragen werden.

3. Automatischer Start

Wenn Sie Raspeye einschalten, stellen Sie die vorherigen Programme so ein, dass sie automatisch gestartet werden. Wir werden eine Servicedatei gemäß Systemd erstellen.

Gehen Sie mit Raspeye zu / etc / systemd / system / und erstellen Sie eine roomba.service-Datei. Bitte beschreiben Sie Folgendes als Inhalt.

[Unit]
Description = Roomba

[Service]
ExecStart=/bin/bash /home/pi/roomba.sh
Restart=always

[Install]
WantedBy=multi-user.target

Der Grund, warum jedes Programm hier vom Shell-Skript gestartet wird, besteht darin, die Bearbeitung im Hinblick auf zukünftige Änderungen zu vereinfachen.

Erstellen Sie als Nächstes die Datei / home / pi / roomba.sh.

#!/bin/sh
sudo python3 /home/pi/roomba/server.py &
sudo python3 /home/pi/roomba/game.py &

Überprüfen Sie den Dienst, aktivieren Sie ihn und Sie sind fertig.

$ sudo systemctl enable roomba
$ sudo systemctl start roomba

Zusammenfassung

Zu diesem Zeitpunkt sollten Sie in der Lage sein, vorerst sowohl Video als auch Steuerung vom Host-Computer aus zu überprüfen. cap.png ↑ Ich denke, es wird so angezeigt.

Wenn ich es tatsächlich bediene, scheint es, dass es nur mit dem Bild der Kamera sehr schwierig ist, und der vorhandene Code game.py verhält sich beim Biegen ziemlich unangenehm.

Der Freiheitsgrad sollte jedoch sehr hoch sein, da die gesamte Verarbeitung in Python erfolgt. Es gibt viele Systeme, die hinzugefügt werden könnten, wie z. B. automatische Fahrprogramme und Personenerkennung durch Bildverarbeitung. Daher möchte ich sie auf verschiedene Arten entwickeln. Bitte probieren Sie es aus.

Vielen Dank, dass Sie bis zum Ende bei uns bleiben.

Verweise

1.iRobot Roomba 500 Open Interface (OI) Specification 2.martinschaef/roomba 3. Hinweise zu Unterschieden zwischen Python 2- und Python 3-Unicode-Zeichenfolgen und Byte-Zeichenfolgen 4. Video mit Python und OpenCV senden

Recommended Posts

Lassen Sie uns eine Remote-Rumba erstellen [Software]
Machen wir eine Remote-Rumba [Hardware]
Lassen Sie uns eine GUI mit Python erstellen.
Machen wir einen Spot Sale Service 2
Machen wir einen Blockbruch mit wxPython
Machen wir einen Spot Sale Service 1
Lassen Sie uns einen Roboter bauen, der den Zauberwürfel löst! 3 Software
Lassen Sie uns ein Diagramm mit Python erstellen! !!
Machen wir mit xCAT einen Spacon
Machen wir einen Spot Sale Service 3
Lassen Sie uns mit Python ein Shiritori-Spiel machen
[Fernentwicklung] Machen wir es zuerst !! (Übung 1)
Lassen Sie uns mit Python langsam sprechen
Lassen Sie uns mit PLY 1 eine einfache Sprache erstellen
Lassen Sie uns mit flask-babel eine mehrsprachige Site erstellen
Erstellen Sie ein Webframework mit Python! (1)
Machen wir mit Pylearn 2 eine dreiäugige KI
Lassen Sie uns eine Kombinationsberechnung mit Python durchführen
Machen wir einen Twitter-Bot mit Python!
Erstellen Sie ein Webframework mit Python! (2)
Lassen Sie uns ein Backend-Plug-In für Errbot erstellen
[Ev3dev] Lassen Sie uns ein Fernsteuerungsprogramm von Python mit dem RPyC-Protokoll erstellen
Ersetzen wir UWSC durch Python (5) Machen wir einen Roboter
Lassen Sie uns mit SWIG ein Modul für Python erstellen
Lass uns ein Squashspiel machen
Machen wir einen Spot Sale Service 9 (Task Queue Edition)
Lass uns ein Makefile machen und es bauen (super Anfänger)
[Lass uns mit Python spielen] Ein Haushaltsbuch erstellen
Versuchen Sie, ein einfaches Spiel mit Python 3 und iPhone zu erstellen
Machen Sie einen Funktionsdekorateur
Erstellen Sie eine Distanzmatrix
Lassen Sie uns das Abhängigkeitsmanagement mit pip etwas einfacher machen
[Zum Spielen] Versuche Yuma zu einem LINE Bot zu machen (Python)
Ich mache ein Passwort!
Lassen Sie uns eine Mac-App mit Tkinter und py2app erstellen
Versuchen Sie, mit Rhinoceros / Grasshopper / GHPython ein sphärisches Gitter zu erstellen
Machen wir einen Spot Sale Service 8 (Image Uploader Edition)
Machen Sie einen Nyan-Knopf
[Super einfach] Machen wir einen LINE BOT mit Python.
Lassen Sie uns mit Google Colaboratory ganz einfach ein mathematisches GIF erstellen
Mach ein Spiel im Tetris-Stil!
Lassen Sie uns ein Cron-Programm in Java erstellen! !! (TaskScheduler)
Erstellen Sie einen Base64-Decoder
Lassen Sie uns mit Python einen Web-Socket-Client erstellen. (Zugriffstoken-Authentifizierung)
Lassen Sie uns einen Roboter bauen, der den Zauberwürfel löst! 2 Algorithmus
Machen wir einen Spot Sale Service 4 (in Python Mini Hack-a-thon)
Lassen Sie uns einen Roboter bauen, der den Zauberwürfel löst! 1. Übersicht
Lassen Sie uns ein Diagramm erstellen, auf das mit IPython geklickt werden kann
Lassen Sie uns einen LINE-Bot mit verschiedenen Diensten erstellen [ngrok edition]
Erstellen Sie ein Blueqat-Backend ~ Teil 1
Erstellen Sie ein Blueqat-Backend ~ Teil 2
Machen wir Othello mit wxPython
Lassen Sie uns ein Errbot-Plugin erstellen
[Django] Erstellen Sie ein Pulldown-Menü
Versuchen wir es mit einem Shell-Skript
Machen Sie einen LINE BOT (Chat)