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.
Cette fois, nous contrôlerons effectivement la rumba préparée jusqu'à la dernière fois.
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.
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-y
roomba.png`, et la préparation de la machine réelle est terminée.
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.
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.
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'opencv
4.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.
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
À ce stade, vous devriez pouvoir vérifier à la fois la vidéo et le contrôle de l'ordinateur hôte pour le moment. ↑ 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.
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