Avouons-le, les robots sont cool. Ils vont également diriger le monde un jour, et avec un peu de chance, à ce moment-là, ils auront pitié de leurs pauvres créateurs charnus et doux (a.k.a. développeurs de robotique) et aidez-nous à construire une utopie spatiale remplie d’abondance. Je plaisante bien sûr, mais seulement en quelque sorte.
Dans mon ambition d’avoir une petite influence sur la question, j’ai pris une cours de théorie du contrôle des robots autonomes l’année dernière, qui a abouti à ma construction d’un simulateur robotique basé sur Python qui m’a permis de pratiquer la théorie du contrôle sur un robot simple, mobile et programmable.
Dans cet article, je vais montrer comment utiliser un framework de robot Python pour développer un logiciel de contrôle, décrire le schéma de contrôle que j’ai développé pour mon robot simulé, illustrer comment il interagit avec son environnement et atteindre ses objectifs, et discuter de certains des défis fondamentaux de la programmation robotique que j’ai rencontrés en cours de route.
Afin de suivre ce tutoriel sur la programmation robotique pour les débutants, vous devez avoir une connaissance de base de deux choses:
- Mathématiques – nous utiliserons des fonctions trigonométriques et des vecteurs
- Python – puisque Python fait partie des langages de programmation de base de robots les plus populaires – nous utiliserons des bibliothèques et des fonctions Python de base
Les extraits de code présentés ici ne sont qu’une partie de l’ensemble du simulateur, qui repose sur des classes et des interfaces, donc pour lire le code directement, vous devrez peut-être une certaine expérience en Python et programmation orientée objet.
Enfin, les rubriques facultatives qui vous aideront à mieux suivre ce didacticiel sont de savoir ce qu’est une machine à états et comment fonctionnent les capteurs de plage et les encodeurs.
Le défi du robot programmable: perception versus réalité et fragilité du contrôle
Le défi fondamental de toute robotique est le suivant: il est impossible de connaître le véritable état de l’environnement. Le logiciel de contrôle du robot ne peut que deviner l’état du monde réel sur la base des mesures retournées par ses capteurs. Il ne peut tenter de changer l’état du monde réel que par la génération de signaux de commande.

Ainsi, l’une des premières étapes de la conception des commandes est de proposer une abstraction du monde réel, connue sous le nom de modèle, avec lequel interpréter nos lectures de capteur et prendre des décisions. Tant que le monde réel se comporte selon les hypothèses du modèle, nous pouvons faire de bonnes suppositions et exercer un contrôle. Cependant, dès que le monde réel s’écartera de ces hypothèses, nous ne serons plus en mesure de faire de bonnes suppositions et le contrôle sera perdu. Souvent, une fois le contrôle perdu, il ne peut jamais être repris. (Sauf si une force extérieure bienveillante la restaure.)
C’est l’une des principales raisons pour lesquelles la programmation robotique est si difficile. Nous voyons souvent des vidéos du dernier robot de recherche en laboratoire, réalisant des exploits fantastiques de dextérité, de navigation ou de travail d’équipe, et nous sommes tentés de demander: « Pourquoi n’est-ce pas utilisé dans le monde réel? » Eh bien, la prochaine fois que vous verrez une telle vidéo, regardez à quel point l’environnement de laboratoire est hautement contrôlé. Dans la plupart des cas, ces robots ne sont capables d’exécuter ces tâches impressionnantes que tant que les conditions environnementales restent dans les limites étroites de son modèle interne. Ainsi, l’une des clés de l’avancement de la robotique est le développement de modèles plus complexes, flexibles et robustes – et cet avancement est soumis aux limites des ressources informatiques disponibles.
L’une des clés de l’avancement de la robotique est le développement de modèles plus complexes, flexibles et robustes.
[Side Note: Philosophers and psychologists alike would note that living creatures also suffer from dependence on their own internal perception of what their senses are telling them. Many advances in robotics come from observing living creatures and seeing how they react to unexpected stimuli. Think about it. What is your internal model of the world? It is different from that of an ant, and that of a fish? (Hopefully.) However, like the ant and the fish, it is likely to oversimplify some realities of the world. When your assumptions about the world are not correct, it can put you at risk of losing control of things. Sometimes we call this “danger.” The same way our little robot struggles to survive against the unknown universe, so do we all. This is a powerful insight for roboticists.]
Le simulateur de robot programmable
Le simulateur que j’ai construit est écrit en Python et très habilement surnommé Sobot Rimulator. Vous pouvez trouver la v1.0.0 sur GitHub. Il n’a pas beaucoup de cloches et de sifflets mais il est conçu pour faire une chose très bien: fournir une simulation précise d’un robot mobile et donner à un aspirant robotique un cadre simple pour pratiquer la programmation de logiciels de robot. Bien qu’il soit toujours préférable d’avoir un vrai robot avec lequel jouer, un bon simulateur de robot Python est beaucoup plus accessible et est un excellent point de départ.
Dans les robots du monde réel, le logiciel qui génère les signaux de contrôle (le «contrôleur») doit fonctionner à très grande vitesse et effectuer des calculs complexes. Cela affecte le choix des langages de programmation de robot à utiliser: Habituellement, C ++ est utilisé pour ces types de scénarios, mais dans les applications robotiques plus simples, Python est un très bon compromis entre la vitesse d’exécution et la facilité de développement et de test.
Le logiciel que j’ai écrit simule un robot de recherche réel appelé Khepera mais il peut être adapté à une gamme de robots mobiles de différentes dimensions et capteurs. Depuis que j’ai essayé de programmer le simulateur aussi similaire que possible aux capacités du vrai robot, la logique de contrôle peut être chargée dans un vrai robot Khepera avec un refactoring minimal, et il fonctionnera de la même manière que le robot simulé. Les caractéristiques spécifiques mises en œuvre se réfèrent au Khepera III, mais elles peuvent être facilement adaptées au nouveau Khepera IV.
En d’autres termes, la programmation d’un robot simulé est analogue à la programmation d’un robot réel. Ceci est essentiel si le simulateur doit être d’une quelconque utilité pour développer et évaluer différentes approches logicielles de contrôle.
Dans ce didacticiel, je décrirai l’architecture du logiciel de commande de robot fournie avec la v1.0.0 de Sobot Rimulator, et en fournissant des extraits de la source Python (avec de légères modifications pour plus de clarté). Cependant, je vous encourage à plonger dans la source et à vous amuser. Le simulateur a été bifurqué et utilisé pour contrôler différents robots mobiles, y compris un Roomba2 de je robot. De même, n’hésitez pas à bifurquer le projet et à l’améliorer.
La logique de contrôle du robot est limitée à ces classes / fichiers Python:
-
models/supervisor.py
– cette classe est responsable de l’interaction entre le monde simulé autour du robot et le robot lui-même. Il fait évoluer notre robot machine d’état et déclenche les contrôleurs pour calculer le comportement souhaité. -
models/supervisor_state_machine.py
—Cette classe représente les différents États dans lequel le robot peut être, selon son interprétation des capteurs. - Les fichiers du
models/controllers
répertoire: ces classes implémentent différents comportements du robot en fonction d’un état connu de l’environnement. En particulier, un contrôleur spécifique est sélectionné en fonction de la machine d’état.
Le but
Les robots, comme les gens, ont besoin d’un but dans la vie. L’objectif de notre logiciel contrôlant ce robot sera très simple: il tentera de se frayer un chemin vers un objectif prédéterminé. C’est généralement la caractéristique de base que tout robot mobile devrait avoir, des voitures autonomes aux aspirateurs robotiques. Les coordonnées de l’objectif sont programmées dans le logiciel de contrôle avant l’activation du robot mais pourraient être générées à partir d’une application Python supplémentaire qui supervise les mouvements du robot. Par exemple, pensez à cela en passant par plusieurs points de cheminement.
Cependant, pour compliquer les choses, l’environnement du robot peut être semé d’obstacles. Le robot NE PEUT PAS entrer en collision avec un obstacle sur son chemin vers le but. Par conséquent, si le robot rencontre un obstacle, il devra trouver son chemin afin de pouvoir continuer sa route vers le but.
Le robot programmable
Chaque robot est livré avec différentes capacités et préoccupations de contrôle. Familiarisons-nous avec notre robot programmable simulé.
La première chose à noter est que, dans ce guide, notre robot sera un robot mobile autonome. Cela signifie qu’il se déplacera librement dans l’espace et qu’il le fera sous son propre contrôle. Cela contraste, disons, avec un robot télécommandé (qui n’est pas autonome) ou un bras de robot d’usine (qui n’est pas mobile). Notre robot doit trouver par lui-même comment atteindre ses objectifs et survivre dans son environnement. Cela s’avère être un défi étonnamment difficile pour les programmeurs débutants en robotique.
Entrées de contrôle: capteurs
Il existe de nombreuses façons dont un robot peut être équipé pour surveiller son environnement. Il peut s’agir de capteurs de proximité, de capteurs de lumière, de pare-chocs, de caméras, etc. De plus, les robots peuvent communiquer avec des capteurs externes qui leur donnent des informations qu’ils ne peuvent pas observer directement.
Notre robot de référence est équipé de neuf capteurs infrarouges – le nouveau modèle possède huit capteurs infrarouges et cinq capteurs de proximité ultrasoniques – disposés en «jupe» dans toutes les directions. Il y a plus de capteurs face à l’avant du robot qu’à l’arrière car il est généralement plus important pour le robot de savoir ce qui est devant lui que ce qui est derrière.
En plus des capteurs de proximité, le robot dispose d’une paire de tickers de roue qui suivent le mouvement des roues. Ceux-ci vous permettent de suivre le nombre de rotations effectuées par chaque roue, avec un tour complet vers l’avant d’une roue représentant 2 765 ticks. Les tours dans le sens opposé comptent vers l’arrière, diminuant le nombre de ticks au lieu de l’augmenter. Vous n’avez pas à vous soucier de nombres spécifiques dans ce didacticiel, car le logiciel que nous allons écrire utilise la distance parcourue exprimée en mètres. Plus tard, je vous montrerai comment le calculer à partir de ticks avec une fonction Python simple.
Sorties de contrôle: mobilité
Certains robots se déplacent sur les jambes. Certains roulent comme une balle. Certains glissent même comme un serpent.
Notre robot est un entraînement différentiel robot, ce qui signifie qu’il roule sur deux roues. Lorsque les deux roues tournent à la même vitesse, le robot se déplace en ligne droite. Lorsque les roues se déplacent à des vitesses différentes, le robot tourne. Ainsi, contrôler le mouvement de ce robot revient à contrôler correctement les vitesses de rotation de chacune de ces deux roues.
API
Dans Sobot Rimulator, la séparation entre «l’ordinateur» du robot et le monde physique (simulé) est matérialisée par le fichier robot_supervisor_interface.py
, qui définit l’intégralité de l’API pour interagir avec les capteurs et moteurs du «vrai robot»:
-
read_proximity_sensors()
renvoie un tableau de neuf valeurs au format natif des capteurs -
read_wheel_encoders()
renvoie un tableau de deux valeurs indiquant le nombre total de ticks depuis le début -
set_wheel_drive_rates( v_l, v_r )
prend deux valeurs (en radians par seconde) et définit la vitesse gauche et droite des roues sur ces deux valeurs
Cette interface utilise en interne un objet robot qui fournit les données des capteurs et la possibilité de déplacer des moteurs ou des roues. Si vous souhaitez créer un robot différent, il vous suffit de fournir une classe de robot Python différente qui peut être utilisée par la même interface, et le reste du code (contrôleurs, superviseur et simulateur) fonctionnera immédiatement!
Le simulateur
Comme vous utiliseriez un vrai robot dans le monde réel sans trop prêter attention aux lois de la physique impliquées, vous pouvez ignorer la façon dont le robot est simulé et passer directement à la façon dont le logiciel du contrôleur est programmé, car il sera presque le même entre le monde réel et une simulation. Mais si vous êtes curieux, je vais le présenter brièvement ici.
Le fichier world.py
est une classe Python qui représente le monde simulé, avec des robots et des obstacles à l’intérieur. La fonction pas à pas dans cette classe s’occupe de faire évoluer notre monde simple en:
- Appliquer des règles de physique aux mouvements du robot
- Prise en compte des collisions avec des obstacles
- Fournir de nouvelles valeurs pour les capteurs du robot
En fin de compte, il appelle les superviseurs de robots chargés d’exécuter le logiciel du cerveau du robot.
La fonction step est exécutée en boucle afin que robot.step_motion()
déplace le robot en utilisant la vitesse de la roue calculée par le superviseur à l’étape de simulation précédente.
le apply_physics()
La fonction met à jour en interne les valeurs des capteurs de proximité du robot afin que le superviseur puisse estimer l’environnement à l’étape de simulation actuelle. Les mêmes concepts s’appliquent aux codeurs.
Un modèle simple
Tout d’abord, notre robot aura un modèle très simple. Il fera de nombreuses hypothèses sur le monde. Certains des plus importants comprennent:
- Le terrain est toujours plat et uniforme
- Les obstacles ne sont jamais ronds
- Les roues ne glissent jamais
- Rien ne va jamais pousser le robot
- Les capteurs ne tombent jamais en panne ou ne donnent pas de fausses lectures
- Les roues tournent toujours quand on leur dit de
Bien que la plupart de ces hypothèses soient raisonnables dans un environnement semblable à une maison, des obstacles ronds pourraient être présents. Notre logiciel d’évitement d’obstacles a une implémentation simple et suit la frontière des obstacles afin de les contourner. Nous suggérerons aux lecteurs comment améliorer le cadre de contrôle de notre robot avec une vérification supplémentaire pour éviter les obstacles circulaires.
La boucle de contrôle
Nous allons maintenant entrer dans le cœur de notre logiciel de contrôle et expliquer les comportements que nous voulons programmer à l’intérieur du robot. Des comportements supplémentaires peuvent être ajoutés à ce cadre, et vous devriez essayer vos propres idées après avoir fini de lire! Robotique basée sur le comportement le logiciel a été proposé il y a plus de 20 ans et il reste un outil puissant pour la robotique mobile. À titre d’exemple, en 2007 un ensemble de comportements a été utilisé dans le DARPA Urban Challenge, le premier concours de voitures autonomes!
Un robot est un système dynamique. L’état du robot, les lectures de ses capteurs et les effets de ses signaux de contrôle sont en constante évolution. Le contrôle du déroulement des événements implique les trois étapes suivantes:
- Appliquer des signaux de contrôle.
- Mesurez les résultats.
- Générez de nouveaux signaux de contrôle calculés pour nous rapprocher de notre objectif.
Ces étapes sont répétées encore et encore jusqu’à ce que nous ayons atteint notre objectif. Plus nous pouvons le faire par seconde, plus nous aurons de contrôle sur le système. Le robot Sobot Rimulator répète ces étapes 20 fois par seconde (20 Hz), mais de nombreux robots doivent le faire des milliers ou des millions de fois par seconde afin d’avoir un contrôle adéquat. Rappelez-vous notre introduction précédente sur les différents langages de programmation de robot pour différents systèmes robotiques et exigences de vitesse.
En général, chaque fois que notre robot prend des mesures avec ses capteurs, il utilise ces mesures pour mettre à jour son estimation interne de l’état du monde, par exemple la distance de son objectif. Il compare cet état à un référence valeur de ce qu’il veut l’état à être (pour la distance, il veut qu’il soit nul), et calcule l’erreur entre l’état souhaité et l’état réel. Une fois ces informations connues, la génération de nouveaux signaux de contrôle peut être réduite à un problème de minimisation de l’erreur qui finira par déplacer le robot vers le but.
Une astuce astucieuse: simplifier le modèle
Pour contrôler le robot que nous voulons programmer, nous devons envoyer un signal à la roue gauche lui indiquant la vitesse à laquelle tourner, et un signal séparé à la roue droite indiquant il à quelle vitesse tourner. Appelons ces signaux vL et vR. Cependant, en pensant constamment en termes de vL et vR est très encombrant. Au lieu de demander: «À quelle vitesse voulons-nous que la roue gauche tourne, et à quelle vitesse voulons-nous que la roue droite tourne?» il est plus naturel de demander: «À quelle vitesse voulons-nous que le robot avance, et à quelle vitesse voulons-nous qu’il tourne ou change de cap?» Appelons ces paramètres la vitesse v et vitesse angulaire (rotationnelle) ω (lire «oméga»). Il se trouve que nous pouvons baser notre modèle entier sur v et ω au lieu de vL et vR, et seulement une fois que nous avons déterminé comment nous voulons que notre robot programmé se déplace, transformez mathématiquement ces deux valeurs en vL et vR nous devons contrôler les roues du robot. Ceci est connu comme un modèle de monocycle de contrôle.
Voici le code Python qui implémente la transformation finale dans supervisor.py
. Notez que si ω est 0, les deux roues tourneront à la même vitesse:
Estimation de l’état: robot, connais-toi toi-même
À l’aide de ses capteurs, le robot doit essayer d’estimer l’état de l’environnement ainsi que son propre état. Ces estimations ne seront jamais parfaites, mais elles doivent être assez bonnes car le robot basera toutes ses décisions sur ces estimations. À l’aide de ses capteurs de proximité et de ses tickers de roue, il doit essayer de deviner ce qui suit:
- La direction des obstacles
- La distance des obstacles
- La position du robot
- La tête du robot
Les deux premières propriétés sont déterminées par les lectures du capteur de proximité et sont assez simples. La fonction API read_proximity_sensors()
renvoie un tableau de neuf valeurs, une pour chaque capteur. On sait à l’avance que la septième lecture, par exemple, correspond au capteur qui pointe à 75 degrés à droite du robot.
Ainsi, si cette valeur montre une lecture correspondant à 0,1 mètre de distance, on sait qu’il y a un obstacle à 0,1 mètre de distance, 75 degrés à gauche. S’il n’y a pas d’obstacle, le capteur retournera une lecture de sa portée maximale de 0,2 mètre. Ainsi, si nous lisons 0,2 mètre sur le capteur sept, nous supposerons qu’il n’y a en fait aucun obstacle dans cette direction.
En raison du fonctionnement des capteurs infrarouges (mesure de la réflexion infrarouge), les nombres qu’ils renvoient sont une transformation non linéaire de la distance réelle détectée. Ainsi, la fonction Python pour déterminer la distance indiquée doit convertir ces lectures en mètres. Cela se fait en supervisor.py
comme suit:
Encore une fois, nous avons un modèle de capteur spécifique dans ce cadre de robot Python, tandis que dans le monde réel, les capteurs sont livrés avec un logiciel d’accompagnement qui devrait fournir des fonctions de conversion similaires des valeurs non linéaires en mètres.
Déterminer la position et le cap du robot (ensemble connu sous le nom de pose dans la programmation robotique) est un peu plus difficile. Notre robot utilise odométrie pour estimer sa pose. C’est là que les tickers des roues entrent en jeu. En mesurant le nombre de tours de chaque roue depuis la dernière itération de la boucle de contrôle, il est possible d’obtenir une bonne estimation de la façon dont la pose du robot a changé, mais seulement si le changement est faible.
C’est une des raisons pour lesquelles il est important d’itérer la boucle de contrôle très fréquemment dans un robot du monde réel, où les moteurs déplaçant les roues peuvent ne pas être parfaits. Si nous avons attendu trop longtemps pour mesurer les tics de roue, les deux roues auraient pu faire beaucoup de choses, et il sera impossible d’estimer où nous en sommes arrivés.
Compte tenu de notre simulateur logiciel actuel, nous pouvons nous permettre d’exécuter le calcul de l’odométrie à 20 Hz, la même fréquence que les contrôleurs. Mais ce pourrait être une bonne idée d’avoir un thread Python séparé plus rapide pour capturer les mouvements plus petits des tickers.
Vous trouverez ci-dessous la fonction d’odométrie complète dans supervisor.py
qui met à jour l’estimation de la pose du robot. Notez que la pose du robot est composée des coordonnées x
et y
et le titre theta
, qui est mesurée en radians à partir de l’axe X positif. Positif x
est à l’est et positif y
est au nord. Ainsi une rubrique de 0
indique que le robot fait face directement à l’est. Le robot suppose toujours que sa pose initiale est (0, 0), 0
.
Maintenant que notre robot est capable de générer une bonne estimation du monde réel, utilisons ces informations pour atteindre nos objectifs.
Méthodes de programmation du robot Python: comportement Go-to-Goal
Le but suprême de l’existence de notre petit robot dans ce tutoriel de programmation est d’arriver au but. Alors, comment faire tourner les roues pour y arriver? Commençons par simplifier un peu notre vision du monde et supposons qu’il n’y ait aucun obstacle.
Cela devient alors une tâche simple et peut être facilement programmé en Python. Si nous allons de l’avant tout en faisant face au but, nous y arriverons. Grâce à notre odométrie, nous savons quelles sont nos coordonnées et cap actuels. Nous savons également quelles sont les coordonnées de l’objectif car elles ont été préprogrammées. Par conséquent, en utilisant une petite algèbre linéaire, nous pouvons déterminer le vecteur de notre emplacement au but, comme dans go_to_goal_controller.py
:
Notez que nous obtenons le vecteur vers l’objectif dans le cadre de référence du robot, et PAS en coordonnées mondiales. Si l’objectif est sur l’axe X dans le cadre de référence du robot, cela signifie qu’il est directement en face du robot. Ainsi, l’angle de ce vecteur par rapport à l’axe X est la différence entre notre cap et le cap sur lequel nous voulons être. En d’autres termes, c’est la Erreur entre notre état actuel et ce que nous voulons que notre état actuel soit. Nous voulons donc ajuster notre taux de rotation ω de sorte que l’angle entre notre cap et l’objectif passera à 0. Nous voulons minimiser l’erreur:
self.kP
dans l’extrait ci-dessus de l’implémentation Python du contrôleur est un gain de contrôle. C’est un coefficient qui détermine la vitesse à laquelle nous tournons proportion à quelle distance du but auquel nous sommes confrontés. Si l’erreur dans notre rubrique est 0
, le taux de rotation est également 0
. Dans la vraie fonction Python à l’intérieur du fichier go_to_goal_controller.py
, vous verrez des gains plus similaires, car nous avons utilisé un Contrôleur PID au lieu d’un simple coefficient proportionnel.
Maintenant que nous avons notre vitesse angulaire ω, comment pouvons-nous déterminer notre vitesse avant v? Une bonne règle générale est celle que vous connaissez probablement instinctivement: si nous ne faisons pas de virage, nous pouvons avancer à pleine vitesse, puis plus nous tournons vite, plus nous devons ralentir. Cela nous aide généralement à maintenir notre système stable et à agir dans les limites de notre modèle. Donc, v est fonction de ω. Dans go_to_goal_controller.py
l’équation est:
Une suggestion pour développer cette formule est de considérer que nous ralentissons généralement lorsque nous nous approchons du but afin de l’atteindre à vitesse nulle. Comment cette formule changerait-elle? Il doit inclure en quelque sorte un remplacement de v_max()
avec quelque chose de proportionnel à la distance. OK, nous avons presque terminé une seule boucle de contrôle. Il ne reste plus qu’à transformer ces deux paramètres du modèle monocycle en vitesses de roue différentielles et à envoyer les signaux aux roues. Voici un exemple de la trajectoire du robot sous le contrôleur go-to-goal, sans obstacle:
Comme nous pouvons le voir, le vecteur de l’objectif est une référence efficace sur laquelle baser nos calculs de contrôle. Il s’agit d’une représentation interne de «où nous voulons aller». Comme nous le verrons, la seule différence majeure entre l’objectif et d’autres comportements est que parfois, aller vers l’objectif est une mauvaise idée, nous devons donc calculer un vecteur de référence différent.
Méthodes de programmation du robot Python: comportement d’éviter les obstacles
Aller vers le but quand il y a un obstacle dans cette direction est un bon exemple. Au lieu de nous lancer tête baissée dans les choses sur notre chemin, essayons de programmer une loi de contrôle qui oblige le robot à les éviter.
Pour simplifier le scénario, oublions maintenant complètement le point de but et faisons simplement ce qui suit notre objectif: Quand il n’y a aucun obstacle devant nous, avancez. Lorsqu’un obstacle est rencontré, éloignez-vous de lui jusqu’à ce qu’il ne soit plus devant nous.
Par conséquent, lorsqu’il n’y a pas d’obstacle devant nous, nous voulons que notre vecteur de référence pointe simplement vers l’avant. ensuite ω sera nul et v sera la vitesse maximale. Cependant, dès que nous détectons un obstacle avec nos capteurs de proximité, nous voulons que le vecteur de référence pointe dans la direction la plus éloignée de l’obstacle. Cela entraînera ω tirer pour nous détourner de l’obstacle et provoquer v laisser tomber pour nous assurer que nous ne rencontrons pas accidentellement l’obstacle dans le processus.
Une bonne façon de générer notre vecteur de référence souhaité est de transformer nos neuf lectures de proximité en vecteurs et de prendre une somme pondérée. Lorsqu’aucun obstacle n’est détecté, les vecteurs seront sommés symétriquement, ce qui donne un vecteur de référence qui pointe tout droit comme vous le souhaitez. Mais si un capteur sur, par exemple, le côté droit détecte un obstacle, il apportera un vecteur plus petit à la somme, et le résultat sera un vecteur de référence décalé vers la gauche.
Pour un robot général avec un placement différent des capteurs, la même idée peut être appliquée mais peut nécessiter des changements de poids et / ou des soins supplémentaires lorsque les capteurs sont symétriques à l’avant et à l’arrière du robot, car la somme pondérée pourrait devenir nulle .
Voici le code qui le fait dans avoid_obstacles_controller.py
:
Utilisation du résultat ao_heading_vector
comme référence pour le robot à essayer de faire correspondre, voici les résultats de l’exécution du logiciel du robot en simulation en utilisant uniquement le contrôleur d’évitement d’obstacles, en ignorant complètement le point de but. Le robot rebondit sans but, mais il n’entre jamais en collision avec un obstacle et parvient même à naviguer dans des espaces très restreints:
Méthodes de programmation du robot Python: automates hybrides (machine à états de comportement)
Jusqu’à présent, nous avons décrit deux comportements – aller au but et éviter les obstacles – isolément. Les deux remplissent admirablement leur fonction, mais pour réussir à atteindre l’objectif dans un environnement plein d’obstacles, nous devons les combiner.
La solution que nous allons développer réside dans une classe de machines qui a la désignation extrêmement cool de automates hybrides. Un automate hybride est programmé avec plusieurs comportements ou modes différents, ainsi qu’une machine d’état de supervision. La machine d’état de supervision passe d’un mode à un autre à des moments discrets (lorsque les objectifs sont atteints ou que l’environnement change trop soudainement), tandis que chaque comportement utilise des capteurs et des roues pour réagir en continu aux changements de l’environnement. La solution a été appelée hybride car il évolue à la fois de manière discrète et continue.
Notre framework de robot Python implémente la machine d’état dans le fichier supervisor_state_machine.py
.
Dotée de nos deux comportements pratiques, une logique simple se propose: Quand aucun obstacle n’est détecté, utilisez le comportement Go-to-Goal. Lorsqu’un obstacle est détecté, passez au comportement éviter-obstacles jusqu’à ce que l’obstacle ne soit plus détecté.
Il s’avère cependant que cette logique engendrera de nombreux problèmes. Ce que ce système aura tendance à faire quand il rencontrera un obstacle, c’est de s’en détourner, puis dès qu’il s’en sera éloigné, de faire demi-tour à droite et de s’y heurter à nouveau. Le résultat est une boucle sans fin de commutation rapide qui rend le robot inutile. Dans le pire des cas, le robot peut basculer entre des comportements avec chaque itération de la boucle de contrôle – un état appelé Zeno état.
Il existe plusieurs solutions à ce problème, et les lecteurs qui recherchent des connaissances plus approfondies devraient vérifier, par exemple, l’architecture logicielle DAMN.
Ce dont nous avons besoin pour notre robot simulé simple est une solution plus simple: un comportement de plus spécialisé dans la tâche autour un obstacle et atteindre l’autre côté.
Méthodes de programmation du robot Python: comportement de suivi de mur
Voici l’idée: lorsque nous rencontrons un obstacle, prenez les deux relevés de capteur les plus proches de l’obstacle et utilisez-les pour estimer la surface de l’obstacle. Ensuite, définissez simplement notre vecteur de référence pour qu’il soit parallèle à cette surface. Continuez à suivre ce mur jusqu’à ce que A) l’obstacle ne soit plus entre nous et le but, et B) nous sommes plus près du but que nous ne l’étions lorsque nous avons commencé. Nous pourrons alors être certains d’avoir correctement traversé l’obstacle.
Avec nos informations limitées, nous ne pouvons pas dire avec certitude s’il sera plus rapide de contourner l’obstacle à gauche ou à droite. Pour nous décider, nous choisissons la direction qui nous rapprochera immédiatement de l’objectif. Pour comprendre de quelle manière il s’agit, nous devons connaître les vecteurs de référence du comportement aller-but et le comportement éviter-obstacle, ainsi que les deux vecteurs de référence possibles du mur de suivi. Voici une illustration de la façon dont la décision finale est prise (dans ce cas, le robot choisira d’aller à gauche):
La détermination des vecteurs de référence du mur de suivi s’avère être un peu plus complexe que les vecteurs de référence à éviter ou à atteindre. Jetez un oeil au code Python dans follow_wall_controller.py
pour voir comment c’est fait.
Conception du contrôle final
La conception du contrôle final utilise le comportement du mur de suivi pour presque toutes les rencontres avec des obstacles. Cependant, si le robot se trouve dans un endroit restreint, dangereusement proche d’une collision, il passera en mode pur éviter les obstacles jusqu’à ce qu’il soit à une distance plus sûre, puis reviendra au mur de suivi. Une fois les obstacles franchis avec succès, le robot passe à l’objectif. Voici le diagramme d’état final, qui est programmé à l’intérieur du supervisor_state_machine.py
:
Voici le robot naviguant avec succès dans un environnement surpeuplé en utilisant ce schéma de contrôle:
Une fonctionnalité supplémentaire de la machine d’état que vous pouvez essayer d’implémenter est un moyen d’éviter les obstacles circulaires en passant au but le plus tôt possible au lieu de suivre la frontière d’obstacles jusqu’à la fin (ce qui n’existe pas pour les objets circulaires! )
Tweak, tweak, tweak: essais et erreurs
Le schéma de contrôle fourni avec Sobot Rimulator est très finement réglé. Il a fallu plusieurs heures pour peaufiner une petite variable ici, et une autre équation là, pour le faire fonctionner d’une manière dont j’étais satisfait. La programmation en robotique implique souvent beaucoup de vieux essais et erreurs. Les robots sont très complexes et il y a peu de raccourcis pour les amener à se comporter de manière optimale dans un environnement de simulateur de robot… du moins, pas beaucoup de machine learning pur et simple, mais c’est une toute autre boîte de vers.
La robotique implique souvent beaucoup de vieux essais et erreurs.
Je vous encourage à jouer avec les variables de contrôle dans Sobot Rimulator et à observer et tenter d’interpréter les résultats. Les modifications apportées aux éléments suivants ont tous des effets profonds sur le comportement du robot simulé:
- Le gain d’erreur
kP
dans chaque contrôleur - Les gains du capteur utilisés par le contrôleur d’évitement d’obstacles
- Le calcul de v en tant que fonction de ω dans chaque contrôleur
- La distance de séparation d’obstacles utilisée par le contrôleur de mur suiveur
- Les conditions de commutation utilisées par
supervisor_state_machine.py
- À peu près tout le reste
Quand les robots programmables tombent en panne
Nous avons fait beaucoup de travail pour arriver à ce point, et ce robot semble assez intelligent. Pourtant, si vous exécutez Sobot Rimulator sur plusieurs cartes aléatoires, il ne vous faudra pas longtemps pour en trouver une que ce robot ne pourra pas gérer. Parfois, il s’enfonce directement dans les virages serrés et entre en collision. Parfois, il oscille simplement d’avant en arrière du mauvais côté d’un obstacle. Parfois, il est légitimement emprisonné sans aucun chemin possible vers le but. Après tous nos tests et ajustements, nous devons parfois arriver à la conclusion que le modèle avec lequel nous travaillons n’est pas à la hauteur, et nous devons changer la conception ou ajouter des fonctionnalités.
Dans l’univers des robots mobiles, le «cerveau» de notre petit robot se trouve à l’extrémité la plus simple du spectre. De nombreux cas d’échec rencontrés pourraient être surmontés en ajoutant des logiciels plus avancés au mélange. Des robots plus avancés utilisent des techniques telles que cartographie, pour se rappeler où il a été et éviter d’essayer les mêmes choses encore et encore; heuristique, pour générer des décisions acceptables lorsqu’il n’y a pas de décision parfaite à trouver; et apprentissage automatique, pour mieux régler les différents paramètres de contrôle régissant le comportement du robot.
Un échantillon de ce qui est à venir
Les robots font déjà tellement de choses pour nous, et ils n’en feront plus qu’à l’avenir. Même si la programmation robotique de base est un domaine d’étude difficile nécessitant une grande patience, elle est également fascinante et extrêmement enrichissante.
Dans ce tutoriel, nous avons appris à développer un logiciel de contrôle réactif pour un robot en utilisant le langage de programmation de haut niveau Python. But there are many more advanced concepts that can be learned and tested quickly with a Python robot framework similar to the one we prototyped here. I hope you will consider getting involved in the shaping of things to come.
le Toptal Engineering Blog is a hub for in-depth development tutorials and new technology announcements created by professional software engineers in the Toptal network. You can read the original piece written by Nick McCrea here. Follow the Toptal Design Blog on Twitter et LinkedIn.
Pssst, hé vous!
Voulez-vous recevoir la newsletter technique quotidienne la plus sassée chaque jour, dans votre boîte de réception, GRATUITEMENT? Bien sûr que vous le faites: inscrivez-vous à Big Spam ici.