[PYTHON] Faisons une rumba distante [Logiciel]

introduction

Cet article est une suite de Faisons une rumba distante [Matériel]. Si vous n'avez pas encore vu la première partie, veuillez d'abord y jeter un coup d'œil.

Cible

Cette fois, nous contrôlerons effectivement la rumba préparée jusqu'à la dernière fois.

environnement

Le langage de programmation utilisé est ** Python 3.7 **. Je pense qu'il est installé en standard dans Raspeye OS. Généralement, il semble que beaucoup de gens utilisent ROS pour contrôler Rumba, mais je n'ai pas tellement utilisé ROS et je n'y suis pas habitué. Du point de vue de la flexibilité et de la facilité de compréhension du développement de Rumba à l'avenir, cet article contrôlera Rumba en utilisant uniquement Python.

Code source

1. Contrôle

1-1. Préparation de la machine réelle

Fondamentalement, le code qui contrôle la rumba se trouve dans la spécification iRobot Roomba 500 Open Interface (OI) Specification officiellement publiée par iRobot. Il est ouvert au public, et si vous l'envoyez à Rumba en tant que signal série, il fonctionnera tel quel. (Bien que la spécification indique 500, il n'y a aucun changement dans la commande dans aucune série)

Cependant, en lisant cette spécification, vous devrez écrire du code pour obtenir les détails les plus fins. Par conséquent, Martin Schaef a créé et publié l'API Rumba pour Python dans le passé, je vais donc l'emprunter.

martinschaef/roomba ↑ Le code source est ici.

Le problème est que le code lui-même est ancien et programmé pour ** Python 2.7 **. Par conséquent, copier et coller simplement le code correspondant ne fonctionnera pas du tout. ** Vous devez apporter des corrections vous-même **.

Le code à modifier est create.py. Il s'agit de l'API Rumba d'origine.

Premièrement, dans ce code, toutes les commandes série sont écrites en type «chr».

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

Lorsque j'exécute ce code en Python3, j'obtiens l'erreur suivante:

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

L'implication est que le type str ne prend pas en charge la communication série. Mais cela fonctionne bien dans Python 2.7. Qu'est-ce que c'est que ça? La réponse est que Python 2 et Python 3 gèrent le type chr différemment. Plus précisément, il a été modifié comme suit.

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

Je suis resté coincé dans le pot ici, mais si vous regardez attentivement, cela signifie que le type bytes doit décrire le nombre dans ** () en utilisant [] **. N'oubliez pas de l'écrire.

Au fait, si vous voulez simplement convertir le type chr en octets, vous pouvez penser que vous devriez ajouter .encode (). Bien sûr, cela éliminerait l'erreur dans le programme lui-même, mais Rumba ne fonctionnerait pas du tout. Par conséquent, si vous vérifiez la chaîne de caractères lorsque .encode () est attaché, il sera écrit comme suit.

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

À l'origine, lors de l'envoi d'une valeur numérique en hexadécimal, elle doit être écrite comme «0x80» ou «/ x80». Cependant, dans le résultat, toutes les valeurs sont accompagnées de la valeur «/ xc2». Cela signifie que les informations selon lesquelles il s'agit de «UTF-8 »sont ajoutées. Si vous y réfléchissez, au lieu de convertir le type «int» simple, vous convertissez le type «str» en octets, donc cette information a également été ajoutée. Par conséquent, dans ce cas, la valeur «U + 0081» a été convertie, et si vous ajoutez simplement «.encode ()» à partir de ce résultat, Rumba ne fonctionnera pas.

** Désolé pour vous tous, mais j'aimerais que vous convertissiez toutes les parties correspondant au type chr (i) en octets ([i]) dans ce code. ** **

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

De plus, avec la modification ci-dessus, l'opération elle-même sera exécutée, mais puisque le message initialement écrit par print est écrit dans la syntaxe python2, il est complètement ignoré. C'est trop terne, donc je pense que vous devriez le réécrire de la même manière.

create.py


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

À ce stade, essayons de voir si vous pouvez réellement vous connecter à Rumba. Utilisez le code suivant pour confirmation.

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()

Si vous connectez Raspai et Rumba et exécutez le code ci-dessus, vous obtiendrez la valeur du capteur de Rumba et l'afficherez sur la ligne de commande, et Rumba devrait tourner un peu.

Si une erreur est générée et que «Key Error:» s'affiche, il est possible que la rumba et la tarte à la râpe ne soient pas connectées correctement. Il y a deux causes possibles: 1. Rumba ne fonctionne pas et 2. Le câble est cassé. Dans le premier cas, appuyez légèrement sur le bouton «CLEAN» au centre de Rumba pour l'activer et réessayer. Dans ce dernier cas, vérifiez la continuité du câble.

De plus, si vous pouvez obtenir la valeur du capteur mais que la rumba ne fonctionne pas du tout, essayez d'exécuter le code ci-dessous.

test_roomba.py


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

Si Rumba commence à chercher une station de charge avec le code ci-dessus, la communication série peut être au niveau RS232C. Veuillez convertir au niveau TTL et vous reconnecter.

Ensuite, la rumba est contrôlée en entrant à partir du clavier. Une petite modification de game.py du code source martinschaef / roomba de Martin Schaef. Utiliser.

game.py


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

La destination de la connexion étant différente dans le code source d'origine, corrigez la 21e ligne comme ci-dessus.

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

Je voulais également pouvoir revenir automatiquement à la station de chargement pendant la télécommande, j'ai donc ajouté le code ci-dessus aux lignes 115 et 166, respectivement.

Enfin, créez un nouveau dossier ʻimgdans le répertoire contenant ces fichiers exécutables, mettez-yroomba.png`, et la préparation de la machine réelle est terminée.

1-2. Préparation de l'ordinateur hôte

Je veux contrôler la rumba à distance, donc je dois aussi me préparer ici. Utilisez VcXsrv (serveur X) pour déplacer l'écran de contrôle affiché sur le Raspeye vers l'ordinateur hôte.

Installez VcXsrv (serveur X) sur Windows et utilisez l'interface graphique Linux à distance ↑ Les détails de cet élément sont très détaillés sur cette page et sont résumés de manière facile à comprendre. Veuillez vous référer ici.

1-3. Contrôle de fonctionnement

Lorsque tous les éléments ci-dessus sont terminés, vous pouvez réellement contrôler la rumba. Essayez de l'exécuter sur Python 3 tout de suite. Je pense que la méthode de contrôle détaillée est décrite sur l'écran affiché, mais pour le moment, je vais expliquer brièvement, w pour avancer, s pour reculer, a, d pour se déplacer à gauche et à droite. C'est une rotation vers. C'est une pause temporaire avec «espace» et se termine par «esc». Je pense que les valeurs acquises en temps réel pour chaque autre capteur sont affichées.

2. Transfert vidéo

Ensuite, je voudrais créer un programme qui transfère les données vidéo acquises par la caméra Web vers l'ordinateur hôte. Au début, j'ai essayé d'ouvrir la vidéo sur Rasppie en utilisant open_cv et de transférer la fenêtre sur l'ordinateur hôte avec VcXsrv, mais cela ne fonctionnait pas très bien, j'ai donc décidé d'utiliser la méthode de transfert vidéo par communication par socket.

Installez ʻopencv-pythondans la bibliothèque avec pip. Si vous essayez d'installer la dernière version d'opencv4.4.0.42`, Python 3.7 peut ne pas terminer la construction pour toujours. Dans un tel cas, si vous abaissez un peu la version et installez-la autour de «4.1.0.25», cela semble être fluide.

pip3 install opencv-python==4.1.0.25

Voici le programme à exécuter sur Raspeye.

video_server.py


import socketserver
import cv2
import sys

HOST = "192.168.XXX.XXX"#Voici l'adresse IP de 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()

Voici le programme à exécuter sur l'ordinateur hôte.

video_client.py


import socket
import numpy
import cv2

HOST = "192.168.XXX.XXX"#Voici l'adresse IP de 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)

Démarrez ces programmes à partir de server.py, et s'ils sont connectés avec succès, la vidéo doit être transférée du côté de l'ordinateur hôte.

3. Démarrage automatique

Enfin, lorsque vous mettez Raspeye sous tension, configurez les programmes précédents pour qu'ils démarrent automatiquement. Nous allons créer un fichier de service selon Systemd.

Allez dans / etc / systemd / system / avec Raspeye et créez un fichier roomba.service. Veuillez décrire ce qui suit comme contenu.

[Unit]
Description = Roomba

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

[Install]
WantedBy=multi-user.target

La raison pour laquelle chaque programme est lancé par le script shell ici est de le rendre facile à éditer en tenant compte des changements futurs.

Alors créez ensuite le fichier / home / pi / roomba.sh.

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

Vérifiez le service, activez-le et vous avez terminé.

$ sudo systemctl enable roomba
$ sudo systemctl start roomba

Résumé

À ce stade, vous devriez pouvoir vérifier à la fois la vidéo et le contrôle de l'ordinateur hôte pour le moment. cap.png ↑ Je pense que c'est affiché comme ça.

Quand je l'utilise, c'est très difficile à faire avec l'image de la caméra seule, et le code existant «game.py» semble se comporter assez maladroitement en courbe.

Cependant, le degré de liberté doit être très élevé car tout le traitement est effectué en Python. Il existe de nombreux systèmes qui pourraient être ajoutés, tels que les programmes de conduite automatique et la détection de personne par traitement d'image, je voudrais donc les développer de différentes manières. Veuillez essayer.

Merci de rester avec nous jusqu'à la fin.

Les références

1.iRobot Roomba 500 Open Interface (OI) Specification 2.martinschaef/roomba 3. Notes sur les différences entre les chaînes Unicode et les chaînes d'octets Python 2 et Python 3 4. Envoyer une vidéo avec Python et OpenCV

Recommended Posts

Faisons une rumba distante [Logiciel]
Faisons une rumba distante [Matériel]
Faisons une interface graphique avec python.
Faisons un service de vente au comptant 2
Faisons une rupture de bloc avec wxPython
Faisons un service de vente au comptant 1
Faisons un robot qui résout le Rubik Cube! 3 Logiciel
Faisons un graphe avec python! !!
Faisons un spacon avec xCAT
Faisons un service de vente au comptant 3
Faisons un jeu de shiritori avec Python
[Développement à distance] Commençons par le faire !! (Pratique 1)
Faisons la voix lentement avec Python
Faisons un langage simple avec PLY 1
Faisons un site multilingue en utilisant flask-babel
Créez un framework Web avec Python! (1)
Faisons une IA à trois yeux avec Pylearn 2
Faisons un calcul de combinaison avec Python
Faisons un bot Twitter avec Python!
Créez un framework Web avec Python! (2)
Faisons un plug-in backend pour Errbot
[Ev3dev] Faisons un programme de contrôle à distance par Python avec le protocole RPyC
Remplaçons UWSC par Python (5) Faisons un robot
Faisons un module pour Python en utilisant SWIG
Faisons un jeu de squash
Faisons un service de vente au comptant 9 (édition Task Queue)
Faisons un Makefile et construisons-le (super débutant)
[Jouons avec Python] Créer un livre de comptes de ménage
Essayez de créer un jeu simple avec Python 3 et iPhone
Faire un décorateur de fonction
Faire une matrice de distance
Facilitons un peu la gestion des dépendances avec pip
[Pour jouer] Essayez de faire de Yuma un robot LINE (Python)
Je vais créer un mot de passe!
Créons une application Mac avec Tkinter et py2app
Essayez de créer une grille sphérique avec Rhinoceros / Grasshopper / GHPython
Faisons un service de vente au comptant 8 (édition de téléchargement d'image)
Créer un bouton Nyan
[Super facile] Faisons un LINE BOT avec Python.
Créons facilement un gif mathématique en utilisant Google Colaboratory
Créez un jeu à la Tetris!
Faisons un programme cron en Java! !! (Planificateur de tâches)
Créer un décodeur Base64
Créons un client de socket Web avec Python. (Authentification par jeton d'accès)
Faisons un robot qui résout le Rubik Cube! 2 Algorithme
Faisons un service de vente au comptant 4 (en Python mini Hack-a-thon)
Faisons un robot qui résout le Rubik Cube! 1. Vue d'ensemble
Faisons un diagramme sur lequel on peut cliquer avec IPython
Créons un bot LINE en utilisant divers services [ngrok edition]
Créer un backend Blueqat ~ Partie 1
Créer un backend Blueqat ~ Partie 2
Faisons Othello avec wxPython
Faisons un plugin Errbot
[Django] Créer un menu déroulant
Essayons un script shell
Créer un LINE BOT (chat)