Navigation autonome d'un robot mobile

Il existe un grand nombre de façons dont un robot peut recevoir des informations du monde extérieur afin d'interagir avec lui. De plus, selon les tâches qui lui sont assignées, les méthodes de traitement de ces informations diffèrent. Dans cet article, je décrirai les principales étapes du travail effectué dans le cadre du projet scolaire, dont le but est de systématiser les informations sur les différentes méthodes de navigation autonome du robot et d'appliquer les connaissances acquises dans le processus de création du robot pour les compétitions «RTK Cup».



introduction


Aux compétitions «RTK Cup», il y a un bloc de tâches qui doivent être accomplies sans intervention de l'opérateur. Je crois que de nombreux participants évitent injustement ces tâches, car la complexité apparente de la création d'un robot et de la rédaction d'un programme cache des tâches largement simplifiées d'autres disciplines compétitives, combinées dans un seul terrain d'entraînement. Par mon projet, je veux montrer des solutions possibles à de tels problèmes, en prenant comme exemple ce qui suit le long de la ligne.

Pour atteindre l'objectif du projet, les tâches intermédiaires suivantes ont été formulées:

  • Analyse du règlement de la compétition «RTK Cup»
  • Analyse d'algorithmes existants pour l'orientation autonome d'un robot mobile
  • Création de logiciels

Analyse du règlement de la compétition «RTK Cup»


Lors des compétitions «RTK Cup», les participants se voient présenter un terrain d'entraînement sur lequel sont modélisées des sections de complexité variable. Le concours vise à stimuler la jeune robotique à créer des appareils pouvant fonctionner dans des conditions extrêmes, surmonter des obstacles, sous contrôle humain ou de manière autonome.



brièvement sur les éléments qui composent le polygone
«» , . , , (), , (), ..

:



:



– , «» ( ) , . , , , , .

. , , , , , , .

Les concours sont divisés en deux nominations fondamentalement différentes les unes des autres: «Seeker» et «Extreme». Ceci est fait pour s'assurer que la compétition a eu lieu entre les participants avec une différence d'âge et d'expérience minimale dans le développement de systèmes robotiques: "Seeker" pour les plus jeunes, et "Extreme" - pour les participants à partir de 14 ans et plus. Dans la nomination Seeker, l'opérateur peut se déplacer librement dans la cuisinière et avoir un contact visuel direct avec la machine, tandis que la nomination Extreme suppose que le robot dispose de systèmes de communication vidéo et / ou de vision par ordinateur, car l'opérateur doit naviguer dans le labyrinthe, en ne s'appuyant que sur le labyrinthe. la caméra et les capteurs intégrés au robot, tout en étant derrière un écran spécial.

Pour se qualifier en compétition, le robot doit soit passer la tâche de télécommande du manipulateur, soit effectuer l'un des éléments d'autonomie. Dans le cadre du projet, la tâche a été définie pour accomplir des tâches d'autonomie, car elles donnent le plus de points au moindre coût de l'opérateur. Les éléments de l'autonomie comprennent:

  • Conduite le long d'une ligne avec un capteur de lumière ambiante ou un système de visibilité directe
  • Capture de balise autonome à l'aide d'un capteur de distance ou de systèmes de vision
  • Mouvement le long d'une trajectoire complexe (par exemple, montée / descente d'escaliers) le long d'une ligne à l'aide d'une boussole, d'un gyroscope, d'un accéléromètre, d'un système de vision ou de méthodes combinées

De plus, les points pour surmonter les obstacles sont doublés si le robot les dépasse de manière autonome.

Dans le cadre de ce projet, la solution à la première des tâches sera envisagée - le déplacement le long de la ligne. Les méthodes les plus courantes utilisées pour se déplacer le long de la ligne sont des capteurs de lumière et une caméra. Les avantages des capteurs incluent la simplicité de création d'un programme - beaucoup d'entre eux sont équipés d'une résistance de réglage, de sorte qu'en réglant le capteur pour l'éclairage de fond, il donnera 0 ou 1, selon qu'il est sur la ligne ou non. Pour la même raison, les capteurs de lumière n'exigent pas la puissance de traitement du contrôleur utilisé. De plus, pour cette raison, résoudre le problème à l'aide de capteurs de lumière est le moins coûteux - le coût du capteur le plus simple est de 35 roubles, et pour une conduite relativement stable le long de la ligne, trois capteurs suffisent (un est installé sur la ligne et deux sur les côtés). cependant,L'un des principaux inconvénients de ces capteurs est les restrictions d'installation. Idéalement, le capteur doit être installé exactement au centre, à une petite distance du sol, sinon il donnera des valeurs incorrectes. Ce n'est pas un problème dans les compétitions spécialisées où le robot doit rouler aussi vite que possible le long de la piste, mais, dans les conditions de la compétition «RTK Cup», tous les défauts de capteur mentionnés ci-dessus peuvent être critiques - leur installation nécessite principalement la présence de pièces mécaniques supplémentaires sur le robot qui se soulèvent et abaisser les capteurs, ce qui nécessite un espace supplémentaire sur le robot, un moteur séparé déplaçant les capteurs, et est également un lieu de dommages potentiels et augmente la masse du robot.sinon, il donnera des valeurs incorrectes. Ce n'est pas un problème dans les compétitions spécialisées, où le robot doit rouler aussi vite que possible le long de la piste, mais, dans les conditions de la compétition «RTK Cup», tous les défauts de capteur mentionnés ci-dessus peuvent être critiques - leur installation nécessite principalement la présence de pièces mécaniques supplémentaires sur le robot qui se soulèvent et abaisser les capteurs, ce qui nécessite un espace supplémentaire sur le robot, un moteur séparé déplaçant les capteurs, et est également un lieu de dommages potentiels et augmente la masse du robot.sinon, il donnera des valeurs incorrectes. Ce n'est pas un problème dans les compétitions spécialisées où le robot doit rouler aussi vite que possible le long de la piste, mais, dans les conditions de la compétition «RTK Cup», tous les défauts de capteur mentionnés ci-dessus peuvent être critiques - leur installation nécessite principalement la présence de pièces mécaniques supplémentaires sur le robot qui se soulèvent et abaisser les capteurs, ce qui nécessite un espace supplémentaire sur le robot, un moteur séparé déplaçant les capteurs, et est également un lieu de dommages potentiels et augmente la masse du robot.tous les défauts de capteur mentionnés ci-dessus peuvent être critiques - leur installation nécessite principalement la présence de pièces mécaniques supplémentaires sur le robot qui soulèvent et abaissent les capteurs, et cela nécessite un espace supplémentaire sur le robot, un moteur séparé qui déplace les capteurs, et est également un lieu de dommages potentiels et augmente la masse du robot .tous les défauts de capteur mentionnés ci-dessus peuvent être critiques - leur installation nécessite principalement la présence sur le robot de pièces mécaniques supplémentaires soulevant et abaissant les capteurs, et cela nécessite un espace supplémentaire sur le robot, un moteur séparé déplaçant les capteurs, et est également un lieu de dommages potentiels et augmente la masse du robot .



La caméra, à son tour, présente les avantages suivants: elle a un rayon de mesure pratiquement illimité (par rapport aux capteurs), c'est-à-dire un seul module de caméra est capable de voir simultanément la ligne, à la fois directement sous le robot et à une distance suffisante de celui-ci, ce qui permet par exemple d'évaluer sa courbure et de sélectionner une action de commande proportionnelle. Dans le même temps, le module de caméra n'interfère pas avec l'avancement du robot dans d'autres parties de la décharge qui ne nécessitent pas d'autonomie, car la caméra est fixée à distance du sol. Le principal inconvénient de la caméra est que le traitement vidéo nécessite un puissant complexe informatique à bord du robot, et le logiciel en cours de développement a besoin de plus de réglages, car la caméra reçoit un ordre de grandeur plus d'informations du monde extérieur que trois capteurs de lumière, tandis que la caméra et l'ordinateurcapables de traiter les informations reçues sont plusieurs fois plus de trois capteurs et «Arduins».

Pour moi personnellement, la réponse est évidente pour moi - dans la nomination «extrême», le robot doit avoir une caméra directionnelle, avec laquelle l'opérateur naviguera. Si vous utilisez des solutions FPV prêtes à l'emploi, le coût total des «capteurs» peut être encore plus élevé, tout en nécessitant l'installation d'appareils supplémentaires. De plus, un robot avec framboise pi et une caméra a un plus grand potentiel pour le développement d'un mouvement autonome, car la caméra peut résoudre un large éventail de problèmes et peut être utilisée non seulement dans le mouvement en ligne, sans compliquer considérablement la conception.

Analyse des algorithmes de vision par ordinateur existants


La vision par ordinateur est la théorie de la création d'appareils qui peuvent recevoir des images d'objets du monde réel, traiter et utiliser les données obtenues pour résoudre divers types de problèmes appliqués sans intervention humaine.

Les systèmes de vision par ordinateur comprennent:

  • une ou plusieurs caméras
  • complexe informatique
  • Logiciel qui fournit des outils de traitement d'image
  • Canaux de communication pour la transmission d'informations sur la cible et la télémétrie.

Comme indiqué précédemment, il existe de nombreuses façons d'identifier les objets qui nous intéressent. Dans le cas de la conduite le long d'une ligne, il est nécessaire de séparer la ligne elle-même du fond contrasté (une ligne noire sur fond blanc ou une ligne blanche sur fond noir pour une ligne inverse). Les algorithmes utilisant un système de vision par ordinateur peuvent être divisés en plusieurs «étapes» de traitement de l'image d'origine:

Acquisition d'image : les images numériques sont obtenues directement à partir de la caméra, à partir d'un flux vidéo transmis à l'appareil, ou sous forme d'images distinctes. Les valeurs des pixels correspondent généralement à l'intensité lumineuse (images en couleur ou en niveaux de gris), mais peuvent être associées à diverses mesures physiques, telles que, par exemple, la température d'une caméra thermique.

Traitement préliminaire: Avant d'appliquer des méthodes de vision par ordinateur aux données vidéo, un prétraitement est nécessaire pour introduire certaines conditions, selon la méthode utilisée. Voici des exemples:

  • Suppression du bruit ou de la distorsion causés par le capteur utilisé
  • Flou d'image utilisé pour se débarrasser des petits artefacts qui se produisent lors du fonctionnement de l'appareil photo, des éléments de décompression, du bruit, etc.
  • Amélioration du contraste afin que les bonnes informations puissent être détectées plus probablement
  • Modifier l'exposition aux zones d'ombres ou de hautes lumières
  • Mise à l'échelle ou recadrage pour mieux distinguer les structures de l'image.
  • Conversion d'une image en monochrome ou modification de sa résolution pour des performances système plus rapides

Mise en évidence des détails : les détails de l'image de différents niveaux de difficulté sont extraits des données vidéo. Des exemples typiques de tels détails sont les lignes, les bordures, les arêtes, les points individuels, les zones caractéristiques de toute entité.
Détection : à un certain stade du travail du programme, les informations pertinentes au programme sont séparées du reste de l'image. Voici des exemples:

  • La sélection d'un certain ensemble de points d'intérêt en couleur, le nombre de pixels isolés qui se ressemblent en quelque sorte (courbure de la figure, couleur, luminosité, etc.)
  • Segmentation d'une ou plusieurs sections d'image contenant un objet caractéristique.

Traitement de haut niveau : à cette étape, l'abondance d'informations de l'image est réduite à une taille qui peut être facilement traitée, par exemple, un ensemble de certains pixels ou les coordonnées de la partie de l'image dans laquelle l'objet d'intérêt est censé se trouver. Voici des exemples:

  • Filtrage des valeurs par n'importe quel critère
  • Évaluation de paramètres tels que les dimensions physiques de l'objet, la forme, son emplacement dans le cadre ou par rapport à d'autres objets caractéristiques
  • Classification

Ensuite, il a fallu choisir la bibliothèque sur la base de laquelle le programme sera créé. Les facteurs clés de mon choix étaient:

  • La prise en charge de la bibliothèque pour l'interface Python en raison de la relative facilité d'apprentissage de ce langage par un débutant, est une syntaxe simple, qui a un effet bénéfique sur la lisibilité du programme.
  • Portabilité, c'est-à-dire la possibilité d'exécuter un programme en utilisant cette bibliothèque sur raspberry pi3.
  • La prévalence de la bibliothèque, qui garantit une communauté bien développée de programmeurs qui peuvent avoir déjà rencontré des problèmes qui peuvent survenir au cours de votre travail.

Parmi les options que j'ai examinées, j'ai mis en évidence la bibliothèque ouverte de vision par ordinateur OpenCV, car elle prend en charge Python, possède une documentation en ligne complète. Il existe de nombreux articles et instructions sur Internet qui décrivent toutes les subtilités du travail avec cette bibliothèque. Il existe un forum officiel de développeurs où tout le monde peut poser une question à ce sujet. De plus, cette bibliothèque est implémentée dans les langages C / C ++, ce qui garantit les performances du système, et sa structure prend en charge divers modules qui peuvent être désactivés afin d'augmenter les performances.

Développement de logiciels


Après avoir installé le système d'exploitation et la configuration initiale de Raspberry pi, mais avant de commencer à créer le programme, vous devez installer tous les packages nécessaires. La plupart de ces packages, à leur tour, sont installés à l'aide du gestionnaire de packages pip (dans le cas de Python 3, pip3)

$ sudo apt install python3-pip

Les bibliothèques suivantes sont installées, telles que:

  • picamera - bibliothèque pour travailler avec la caméra raspberry pi
  • numpy - une bibliothèque pour travailler avec des tableaux de données multidimensionnelles, sous forme d'images

$ sudo pip3 install picamera
$ sudo pip3 install numpy

cmake - Utilitaire pour construire automatiquement un programme à partir du code source
cmake-curses-gui - Package GUI (interface graphique) pour cmake

$ sudo apt-get install cmake cmake-curses-gui libgtk2.0-dev
$ sudo apt-get install cmake cmake-curses-gui libgtk2.0-dev

bibliothèques pour travailler avec différents formats d'image et vidéo et plus

$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libx264-dev libxvidcore-dev
$ sudo apt-get install libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev
$ sudo apt-get install gfortran libatlas-base-dev

Pour transmettre des données vidéo du robot à l'ordinateur, GStreamer sera utilisé - un cadre conçu pour recevoir, traiter et transmettre des données multimédias:

$ sudo apt install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

L'étape suivante consiste à installer la bibliothèque openCV elle-même à partir des sources, à la configurer et à la créer. Pour ce faire, un dossier de travail opencv est créé.

$ mkdir opencv
$ cd opencv

Afin de télécharger les dernières versions de la bibliothèque, wget est utilisé - un programme de console pour télécharger des fichiers depuis le réseau. Au moment de la création du programme, la dernière version stable d'openCV est 4.1.0, alors téléchargez et décompressez les sources:

$ wget https://github.com/opencv/opencv/archive/4.1.0.zip -O opencv_source.zip
$ unzip opencv_source.zip
$ wget https://github.com/opencv/opencv_contrib/archive/4.1.0.zip -O opencv_contrib.zip
$ unzip opencv_contrib.zip

Une fois le processus de décompression terminé, les archives source peuvent être supprimées.

$ rm opencv_source.zip
$ rm opencv_contrib.zip

Un répertoire est créé pour l'assemblage et la configuration.

$ cd /home/pi/opencv/opencv-4.1.0
$ mkdir build
$ cd build

Les paramètres de construction sont configurés à l'aide de l'utilitaire cmake. Pour ce faire, tous les paramètres significatifs sont passés en tant que variables d'utilité, avec les valeurs affectées:

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_PYTHON_EXAMPLES=ON -D INSTALL_C_EXAMPLES=OFF -D BUILD_opencv_python2=OFF -D WITH_GSTREAMER=ON -D BUILD_EXAMPLES=ON -DENABLE_VFPV3=ON -DENABLE_NEON=ON -DCPU_BASELINE=NEON ..

Après avoir configuré la configuration, l'utilitaire affichera tous les paramètres. Ensuite, vous devez compiler la bibliothèque. Pour ce faire, utilisez la commande console make –jN, où N est le nombre de cœurs qui seront impliqués dans le processus de compilation. Pour Raspberry Pi 3, le nombre de cœurs est de 4, mais vous pouvez certainement trouver ce nombre en écrivant la commande nproc dans la console.

$ make –j4

En raison des ressources limitées de la framboise, la compilation peut prendre un certain temps. Dans certains cas, les framboises peuvent même geler, mais si vous allez plus tard dans le dossier de construction et réenregistrez make, le travail continuera. Si cela se produit, cela vaut la peine de réduire le nombre de cœurs impliqués, cependant, ma compilation s'est déroulée sans problème. De plus, à ce stade, il vaut la peine de penser au refroidissement actif de la framboise, car même avec elle, la température du processeur a atteint environ 75 degrés.

Lorsque la compilation a réussi, la bibliothèque doit être installée. Cela se fait également à l'aide de l'utilitaire make. Ensuite, nous formerons toutes les connexions nécessaires avec l'utilitaire ldconfig:

$ sudo make install
$ sudo ldconfig

Nous vérifions l'installation en écrivant les commandes suivantes en mode interactif python:

import cv2
print(cv2.getBuildInformation())

La conclusion suivante du programme sera la preuve de l'installation correcte.



Il convient de noter que la procédure de compilation de la bibliothèque ci-dessus doit être effectuée à la fois sur le robot et sur le PC à partir duquel il est prévu de contrôler le robot et sur lequel la diffusion sera reçue du robot.

Création d'un schéma de distribution vidéo

Avant de commencer à écrire du code, vous devez développer un schéma selon lequel l'algorithme fonctionnera. Dans le cas considéré du développement de logiciels pour un robot créé pour participer aux compétitions de la RTK Cup dans la nomination Extreme, le programme entier sera divisé en deux parties: un robot et une télécommande, qui seront jouées par un ordinateur avec Linux installé. L'une des tâches les plus importantes ici consiste à créer un schéma approximatif de la façon dont les données vidéo seront transmises entre les différentes parties de l'algorithme. Le Wi-Fi sera utilisé comme canal de communication entre les deux appareils. Les paquets de données assurant le contrôle du robot et les données de retour seront transmis d'un appareil à un autre en utilisant le protocole UDP implémenté dans l'utilisation de la bibliothèque de sockets. Données vidéoen raison des limitations de la taille du paquet UDP sera transmis à l'aide de GStreamer. Pour faciliter le débogage, deux flux vidéo seront mis en œuvre:

  • flux vidéo principal - transfère les données vidéo directement de la caméra du robot vers un ordinateur pour garantir un délai de contrôle minimal.
  • flux vidéo auxiliaire - transfère les données vidéo traitées par le robot, nécessaires à la configuration et au débogage d'un programme qui met en œuvre la vision par ordinateur.

Deux flux vidéo seront simultanément actifs sur le robot et l'ordinateur affichera l'image souhaitée en fonction du mode d'entraînement activé. Le robot, à son tour, selon que le mode d'autonomie est activé ou désactivé, utilisera des données de contrôle reçues d'un ordinateur ou générées par un processeur d'images.



La télécommande du robot sera réalisée grâce au travail de deux flux parallèles sur le robot et sur l'ordinateur:

  • La «console» dans un cycle interroge tous les périphériques d'entrée disponibles et forme un paquet de données de contrôle composé des données elles-mêmes et de la somme de contrôle (au moment d'apporter les dernières modifications à l'article, j'ai refusé de créer des sommes de contrôle afin de réduire le délai, mais dans la source, que j'ai disposé à la fin de ce morceau de code est laissé) - d'une certaine valeur calculée à partir d'un ensemble de données par le fonctionnement d'un algorithme utilisé pour déterminer l'intégrité des données pendant la transmission
  • Robot - Attend l'accès aux données depuis l'ordinateur. Décompresse les données, recalcule la somme de contrôle et la compare avec celle envoyée et calculée côté ordinateur. Si les sommes de contrôle correspondent, les données sont transférées vers le programme principal.

Avant d'analyser l'algorithme de détection de ligne, je vous suggère de vous familiariser avec les fonctionnalités de conception du robot:

à propos du robot
.

— . (3 ) . , . 6 , . . . . , - . «» rasberry pi 3 b — .

, , , , Solidworks petg . , raspberry .

ubiquiti bullet M5 hp. ( ) , . , «» .


: «» thingiverse. , , , , .


, , . , . , , , , . , , , .





- ( - 200 ) , , 90 70 ( ), , « ». , VL53L0X , .


«» , , (rds3115). — , , , , .


, , , :


- , , , . . raspberry, , . , .

, USB. , , .




Création d'un algorithme de détection de ligne utilisant les méthodes de la bibliothèque OpenCV


I. Obtention de données

Étant donné que le processeur d'image ne reçoit pas de données vidéo directement de la caméra, mais du flux principal, il est nécessaire de les transférer du format utilisé pour la traduction vers le format utilisé pour le traitement d'image, à savoir un tableau numpy composé de valeurs rouges , vert et bleu pour chacun des pixels. Pour ce faire, vous avez besoin des données initiales - une trame reçue du module de caméra raspberry pi.

La façon la plus simple d'obtenir des images de l'appareil photo c pour un traitement ultérieur consiste à utiliser la bibliothèque picamera. Avant de commencer, vous devez autoriser l'accès à la caméra via raspi-config -> options d'interface caméra -> sélectionner oui.

sudo raspi-config

la section suivante de code est connectée à la caméra framboise et dans un cycle avec une fréquence donnée reçoit des trames sous la forme d'un tableau prêt à l'emploi par la bibliothèque opencv.

from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
#   
camera = PiCamera()
camera.resolution = (640, 480) 
camera.framerate = 30
cap = PiRGBArray(camera, size=(640, 480))

for frame in camera.capture_continuous(cap , format="bgr", use_video_port=True):
	new_frame = frame.array
	cap.truncate(0)
	if False: #   -   
		break

Il convient également de noter que cette méthode de capture d'images, bien qu'elle soit la plus simple, mais présente un inconvénient sérieux: elle n'est pas très efficace si vous devez diffuser des images via GStreamer, car cela nécessite plusieurs fois de réencoder la vidéo, ce qui réduit la vitesse du programme. Un moyen beaucoup plus rapide d'obtenir des images sera de sortir des images du flux vidéo à la demande du processeur d'image, cependant, les étapes ultérieures du traitement d'image ne dépendront pas de la méthode utilisée.

Un exemple d'image d'une caméra de cap de robot sans traitement:


II. Pré-traitement

Lorsque vous conduisez sur une ligne, il sera plus simple de séparer la zone de points qui contraste le plus avec la couleur d'arrière-plan. Cette méthode est idéale pour la compétition RTK Cup, car elle utilise une ligne noire sur fond blanc (ou une ligne blanche sur fond noir pour les sections inverses). Afin de réduire la quantité d'informations à traiter, vous pouvez lui appliquer un algorithme de binarisation, c'est-à-dire convertir l'image au format monochrome, où il n'y a que deux types de pixels - sombre et clair. Avant cela, l'image doit être traduite en niveaux de gris et également floue afin de supprimer les petits défauts et le bruit qui apparaît inévitablement lors du fonctionnement de l'appareil photo. Pour brouiller l'image, un filtre gaussien est utilisé.

gray = cv2.cvtColor(self._frame, cv2.COLOR_RGB2GRAY)
blur = cv2.GaussianBlur(gray, (ksize, ksize), 0)

où ksize est la taille du noyau gaussien, ce qui augmente, vous pouvez augmenter le degré de flou.

Exemple d'image après traduction en niveaux de gris et flou:


III. Sélection des détails Une

fois l'image traduite en niveaux de gris, il est nécessaire de la binariser à un seuil donné. Cette action vous permet de réduire encore la quantité de données. Cette valeur seuil sera ajustée avant chaque départ du robot dans un nouvel endroit, ou lorsque les conditions d'éclairage changent. Idéalement, la tâche de calibrage est de s'assurer que le contour de la ligne est défini sur l'image, mais en même temps, il ne devrait pas y avoir d'autres détails sur l'image qui ne sont pas une ligne:

thresh = cv2.threshold(blur, self._limit, 255, cv2.THRESH_BINARY_INV)[1]

Ici, tous les pixels plus sombres que la valeur seuil (self._limit) sont remplacés par 0 (noir), plus clair - par 255 (blanc).

Après le traitement, l'image se présente comme suit:


Comme vous pouvez le voir, le programme a identifié plusieurs des parties les plus sombres de l'image. Cependant, après avoir calibré la valeur de seuil de manière à «attraper» complètement le casque, d'autres éléments blancs apparaissent à l'écran en plus d'eux. Bien sûr, vous pouvez affiner le seuil, et sur le terrain d'entraînement compétitif, la caméra baissera les yeux, ne permettant pas la présence d'éléments inutiles dans le cadre, mais je considère qu'il est nécessaire pour moi de séparer la ligne de tout le reste.

IV.Détection

Dans l'image binarisée, j'ai appliqué un algorithme de recherche de bordure. Il est nécessaire pour déterminer les points autonomes et les transformer en un tableau pratique de valeurs de coordonnées de points qui composent la frontière. Dans le cas d'opencv, comme écrit dans la documentation, l'algorithme standard pour trouver des boucles utilise l'algorithme Suzuki85 (je n'ai pu trouver de références à l'algorithme avec ce nom nulle part sauf pour la documentation opencv, mais je suppose que c'est l'algorithme Suzuki-Abe ).

contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]

Et voici le cadre obtenu à ce stade:


V. Traitement de haut niveau

Après avoir trouvé tous les contours dans le cadre, le contour avec la plus grande zone est sélectionné et pris comme contour de la ligne. Connaissant les coordonnées de tous les points de ce contour, la coordonnée de son centre est trouvée. Pour cela, les soi-disant "moments d'image" sont utilisés. Le moment est la caractéristique totale du contour, calculée en additionnant les coordonnées de tous les pixels du contour. Il existe plusieurs types de moments - jusqu'au troisième ordre. Pour ce problème, seul le moment d'ordre zéro (m00) est nécessaire - le nombre de tous les points constituant le contour (périmètre de contour), le moment de premier ordre (m10), qui est la somme des coordonnées X de tous les points, et m01 est la somme des coordonnées Y de tous les points. En divisant la somme des coordonnées des points le long d'un des axes par leur nombre, la moyenne arithmétique est obtenue - la coordonnée approximative du centre du contour. Ensuite, l'écart du robot par rapport au parcours est calculé:le parcours correspond «directement» à la coordonnée du point central le long de X proche de la largeur du cadre divisée par deux. Si la coordonnée du centre de la ligne est proche du centre du cadre, l'action de contrôle est minimale et, par conséquent, le robot conserve sa trajectoire actuelle. Si le robot s'écarte de l'un des côtés, une action de contrôle proportionnelle à l'écart sera introduite jusqu'à son retour.

mainContour = max(contours, key = cv2.contourArea)
M = cv2.moments(mainContour)
if M['m00'] != 0:#     (..   -  )
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])

Ci-dessous, un schéma de la position du robot par rapport à la ligne et aux cadres, avec les résultats du programme superposés: le contour «principal», les lignes passant par le centre du contour, ainsi que le point situé au centre pour estimer l'écart. Ces éléments sont ajoutés à l'aide du code suivant:

cv2.line(frame, (cx, 0), (cx, self.height), (255, 0, 0), 1)    #    
cv2.line(frame, (0, cy), (self.width, cy), (255, 0, 0), 1)                  
cv2.circle(frame, (self.width//2, self.height//2), 3, (0, 0, 255), -1) #  
cv2.drawContours(frame, mainContour, -1, (0, 255, 0), 2, cv2.FILLED) #   

Pour faciliter le débogage, tous les éléments décrits précédemment sont ajoutés au cadre brut:





Ainsi, après avoir conduit le cadre à travers l'algorithme de traitement, nous avons obtenu les coordonnées X et Y du centre de l'objet qui nous intéresse, ainsi que l'image de débogage. Ensuite, la position du robot par rapport à la ligne est schématisée, ainsi que l'image qui a réussi l'algorithme de traitement.


L'étape suivante du programme consiste à convertir les informations obtenues à l'étape précédente en valeurs de puissance de deux moteurs.

Le moyen le plus simple de convertir la différence entre le décalage du centre de la tache de couleur par rapport au centre du cadre est le régulateur proportionnel (il existe également un régulateur à relais, mais, en raison des caractéristiques de son fonctionnement, il n'est pas très adapté pour la conduite le long de la ligne). Le principe de fonctionnement d'un tel algorithme est que le contrôleur génère une action de contrôle sur l'objet proportionnellement à l'ampleur de l'erreur. En plus du contrôleur proportionnel, il y en a aussi un intégral, où au fil du temps la composante intégrale "accumule" l'erreur et les différentielles, dont le principe est basé sur l'application de l'influence réglementaire uniquement avec un changement suffisant de la variable contrôlée. En pratique, ces contrôleurs P, I, D les plus simples sont combinés en contrôleurs de type PI, PD, PID.

Il convient de mentionner que sur mon robot, j'ai essayé de «démarrer» le contrôleur PID, mais son utilisation n'a pas donné d'avantages sérieux par rapport au contrôleur proportionnel habituel. J'avoue que je n'ai pas pu régler correctement le régulateur, mais il est également possible que ses avantages ne soient pas aussi clairement visibles dans le cas d'un robot lourd qui est incapable de développer physiquement des vitesses élevées. Dans la dernière version du programme au moment de la rédaction, un simple régulateur proportionnel est utilisé, mais avec une petite fonctionnalité qui vous permet d'utiliser plus d'informations de la caméra: lors de la génération de la valeur d'erreur, non seulement la position horizontale du milieu du spot a été prise en compte, mais aussi verticalement, ce qui a permis différentes manières répondre aux éléments de lignesitué "au loin" et immédiatement devant ou sous le robot (la caméra de direction du robot a un angle de vision énorme, donc en le tournant à seulement 45 degrés vers le bas, vous pouvez déjà voir une partie importante du champ sous le robot).

error= cx / (self.width/2) - 1  
#  ( 0   )  [-1; 1]
error*= cy / self.height + self.gain #

Le plus souvent, dans les conditions de la compétition "RTK Cup", les participants utilisent ce que l'on appelle le "circuit du réservoir" - un ou plusieurs moteurs contrôlent un côté du robot, et il fonctionne à la fois avec des chenilles et avec des roues. L'utilisation de ce schéma vous permet de vous débarrasser des éléments de transmission complexes qui augmentent les risques de casse (différentiels ou cardans), d'obtenir le plus petit rayon de braquage possible, ce qui donne un avantage dans un polygone confiné. Ce schéma implique le contrôle parallèle de deux «côtés» pour le mouvement le long d'un chemin complexe. Pour ce faire, le programme utilise deux variables - la puissance du moteur droit et gauche. Cette puissance dépend de la vitesse de base (BASE_SPEED), variant dans la plage de 0 à 100.Erreurs (erreur) - la différence entre le centre du cadre et les coordonnées du milieu de la ligne et le coefficient d'effet proportionnel (self._koof), qui est calibré par l'opérateur. Sa valeur absolue affecte la vitesse à laquelle le robot tentera de s'aligner sur la ligne. En raison du fait que sur un moteur, l'action de contrôle est soustraite de la vitesse de base, et sur l'autre - elle est ajoutée, un virage est effectué en s'écartant du cours. La direction dans laquelle l'inversion sera effectuée peut être ajustée en changeant le signe de la variable self._koof. En outre, vous pouvez remarquer qu'à la suite de la section de code suivante, une valeur de puissance peut apparaître supérieure à 100, mais dans mon programme, de tels cas sont en outre traités ultérieurement.Sa valeur absolue affecte la vitesse à laquelle le robot tentera de s'aligner sur la ligne. En raison du fait que sur un moteur, l'action de contrôle est soustraite de la vitesse de base, et sur l'autre - elle est ajoutée, un virage est effectué en s'écartant du cours. La direction dans laquelle l'inversion sera effectuée peut être ajustée en changeant le signe de la variable self._koof. En outre, vous pouvez remarquer qu'à la suite de la section de code suivante, une valeur de puissance peut apparaître supérieure à 100, mais dans mon programme, de tels cas sont en outre traités ultérieurement.Sa valeur absolue affecte la vitesse à laquelle le robot tentera de s'aligner sur la ligne. En raison du fait que sur un moteur, l'action de contrôle est soustraite de la vitesse de base, et sur l'autre - elle est ajoutée, un virage est effectué en s'écartant du cours. La direction dans laquelle l'inversion sera effectuée peut être ajustée en changeant le signe de la variable self._koof. En outre, vous pouvez remarquer qu'à la suite de la section de code suivante, une valeur de puissance peut apparaître supérieure à 100, mais dans mon programme, de tels cas sont en outre traités ultérieurement.dans lequel l'inversion sera effectuée, vous pouvez ajuster en changeant le signe de la variable self._koof. En outre, vous pouvez remarquer qu'à la suite de la section de code suivante, une valeur de puissance peut apparaître supérieure à 100, mais dans mon programme, de tels cas sont en outre traités ultérieurement.dans lequel l'inversion sera effectuée, vous pouvez ajuster en changeant le signe de la variable self._koof. En outre, vous pouvez remarquer qu'à la suite de la section de code suivante, une valeur de puissance peut apparaître supérieure à 100, mais dans mon programme, de tels cas sont en outre traités ultérieurement.

#if lineFound:
leftSpeed = round(self.base_speed + error*self.koof)
rightSpeed = round(self.base_speed - error*self.koof)

Conclusion


Après avoir testé le programme résultant, je peux dire que le principal moment difficile dans la mise en place du programme est l'étalonnage de l'algorithme aux caractéristiques d'éclairage. Étant donné que l'étape de création de l'article coïncidait avec l'auto-isolement déclaré, j'ai dû créer une vidéo avec une démonstration du travail dans une petite pièce. Cela m'a posé les difficultés suivantes:

  • -, , ( , ), . , , , . , , , ,
  • -, — , ,

Malgré le fait que ces deux problèmes soient absents dans les conditions des compétitions réelles, je prendrai des mesures pour que le travail du programme dépende au minimum de facteurs externes.
Aussi, à l'avenir, il est prévu de poursuivre les travaux sur la mise en œuvre d'algorithmes utilisant des méthodes de vision par ordinateur, en créant des logiciels capables de traverser les éléments d'autonomie restants décrits dans la première partie de l'article (capture de balise autonome, déplacement le long d'un chemin complexe). Il est prévu d'étendre les fonctionnalités du robot en ajoutant des capteurs supplémentaires: télémètre, gyroscope-accéléromètre, boussole. Malgré le fait que la publication de cet article mettra fin à mes travaux sur le projet en tant que matière scolaire obligatoire, je compte continuer à décrire ici les étapes ultérieures de développement. Par conséquent, j'aimerais recevoir des commentaires sur ce travail.

Après avoir mis en œuvre toutes les étapes visant à résoudre les problèmes du projet, il est sûr de dire que l'utilisation d'algorithmes de vision par ordinateur, avec toute sa complexité relative dans la programmation et le débogage, donne le plus grand gain au stade des compétitions elles-mêmes. Avec les petites dimensions de la caméra, elle a un énorme potentiel en termes de développement logiciel, car la caméra vous permet de remplacer plusieurs capteurs "traditionnels" à la fois, tout en recevant incroyablement plus d'informations du monde extérieur. Il a été possible de réaliser l'objectif du projet - créer un programme qui utilise la vision par ordinateur pour résoudre le problème de la navigation autonome du robot dans les conditions de la compétition «RTK Cup», ainsi que décrire le processus de création du programme et les principales étapes du traitement d'image.

Comme je l'ai dit précédemment, il n'a pas été possible de recréer la trajectoire complexe de la ligne de maison, et cet exemple montre comment l'algorithme remplit les virages. L'épaisseur de la ligne correspond ici à celle selon la réglementation, et la plus grande courbe des spires reflète approximativement la courbure de rotation de 90 degrés sur le polygone:


Vous pouvez voir le code du programme, ainsi que surveiller les travaux ultérieurs sur le projet, sur mon github ou ici, si je continue.

All Articles