Capture temps réel des mouvements et animation d'un robot

De fablab
Aller à : navigation, rechercher

Contexte et objectifs du projet

L'idée de ce projet est d'utiliser une caméra 3D (kinect) pour disposer en temps réel de la modélisation d'un squelette virtuel.

Cette modélisation obtenue, il s'agira alors de construire un modèle physique de robot qui pourra reproduire une partie des mouvements obtenus.

Il s'agira donc :

- de se documenter sur les caméras et dispositifs de capture,
- de mettre en oeuvre la capture temps réel d'une modélisation de la personne filmée,
- de choisir un ensemble d'actionneurs et de construire un pantin motorisé ou un robot existant,
- de mettre en oeuvre la partie commande du robot,
- d'assurer la communication entre les 2 modules (acquisition et commande).

Sources du projet

Pour les personnes qui souhaiteraient reproduire (et améliorer !) ce projet, l'ensemble de nos productions (code, schémas, etc.) se trouve dans le dépôt git suivant :

voir le gitlab

Traitement d’image

Matériel utilisé

Pour notre projet, nous avons choisi d’utiliser une caméra comportant un capteur de profondeur (type kinect) afin d’avoir déjà des informations 3D (nous ne ferons donc pas de reconnaissance de formes dans une image).

Nous nous sommes d’abord dirigés vers la caméra Xtion PRO LIVE, fonctionnant sur Windows et Linux et fournie avec les logiciels OpenNI et NITE, destinés à permettre aux programmeurs de manipuler les données récupérées par la caméra. Cependant nous avons eu du mal à faire fonctionner cette caméra, notamment à cause d’inclusions de librairies manquantes ou mal répertoriées. Nous avons finalement décidé de changer de caméra et d’utiliser la Kinect, plus documentée et également opérationnelle sur Linux. OpenNI et NITE n’étant pas fournis avec la Kinect, nous avons dû les télécharger par nous-mêmes. Il existe de nombreux tutoriels sur internet, mais nous avons encore une fois rencontré des problèmes de librairies. Vous pourrez trouver plus d’informations dans le fichier Documentation/KinectProgrammation du dépôt git donné.

Réarrangement de la structure du code

Le code téléchargé contient plusieurs exemples de code récupérant les coordonnées des articulations de l’utilisateur au cours du temps (ce qu’on appelle le squelette). Nous avons donc décidé de modifier directement un de ces exemples afin d’avoir déjà les coordonnées à disposition. Il nous restera donc plus qu’à traiter ces coordonnées pour les passer à la partie commande sous un format qu’on se sera fixé.

Nous travaillons donc avec l’exemple qui se situe dans le dossier HandTrack/src/NiTE-Linux-x64-2.2/Samples/UserViewer. Le fichier sur lequel nous travaillons se nomme Viewer.cpp. Cependant nous avons encore rencontré des problèmes de librairies, que nous avons pu corriger en modifiant le Makefile également (voir les fichiers Documentation/KinectProgrammation et CodeTI/Makefile du dépôt git donné).

Avant de compiler, il est également nécessaire d’exécuter en ligne de commande (ou d’intégrer au .bashrc) les deux lignes se trouvant dans le fichier HandTrack/src/NiTE-Linux-x64-2.2/NiTEDevEnvironment.

L’exécutable généré après compilation se trouve dans HandTrack/src/NiTE-Linux-x64-2.2/Samples/Bin/x64-Release. Dans le cas où l’exécution ne fonctionne pas, il faut déplacer l’exécutable vers HandTrack/src/NiTE-Linux-x64-2.2/Samples/Bin, où toutes les librairies nécessaires se trouvent.

Enfin, il sera éventuellement nécessaire de lancer l’exécutable à plusieurs reprises si celui-ci ne fonctionne pas du premier coup.

Traitement des coordonnées

Objectif

Le principal objectif de la partie traitement d’image est de transmettre les coordonnées des articulations du squelette à la partie commande, dans un format et un système de coordonnées qu’on se sera fixés.

Première tentative

Concernant la transmission des informations, nous avons décidé d’écrire dans un fichier les coordonnées (après traitement des coordonnées) à chaque temps t (t_next = t + 1 seconde) qui sera lu au fur et à mesure par la partie commande. Les coordonnées sont écrites de la manière suivante :

LH: x y z

LH signifiant Left Hand.

Au niveau de la transformation des coordonnées, l’idée était de transformer les coordonnées exprimées dans le repère de la caméra (c’est sous cette forme que les coordonnées sont récupérées dans le code) dans un autre repère cartésien situé au niveau des pieds de l’utilisateur :

CTRM-TI-1.jpg
CTRM-TI-2.jpg

En plus du changement de repère, le problème qui se posait alors était le suivant : au vu de la diversité de taille des utilisateurs, comment garantir la cohérence des coordonnées calculées lors du changement de repère ? Nous avons alors choisi de réaliser un calibrage préalable, afin d’adapter notre repère à la morphologie de chacun. Concrètement, à l’appui sur la touche “a”, le squelette de l’utilisateur pieds joints et les bras tendus (T-pose) est mémorisé. Cela nous permet de récupérer des données comme la hauteur de l’utilisateur, ou sa longueur de bras, données qui seront nécessaires pour calculer par la suite les coordonnées de la personne de façon adaptée. L’opération mathématique appliquée à chaque coordonnée est une simple remise à l’échelle (rescale) : dans le cas d’une hauteur, recentrage sur l’origine, division par la hauteur max de l’utilisateur, puis multiplication par la hauteur max dans le repère Arduino. Puis, le passage du repère Arduino au repère du pantin est une simple affaire de convention (X_arduino = -Z_pantin).

CTRM-TI-3.jpg

Cependant même si ce changement de coordonnées paraissait relativement naturel et assez simple en termes de calculs, nous nous sommes rendu compte qu’il n’était pas adapté pour notre problème. En effet, puisque nous nous sommes restreints au mouvement d’un seul élément qui consistait à tourner autour et se rapprocher/s’éloigner d’un même point, un système de coordonnées sphériques situé au niveau de l’épaule était bien plus adapté. D’autant plus que les deux angles correspondraient alors directement aux angles des moteurs et que le rayon r se calculerait facilement en faisant la différence entre les coordonnées de la main et celles de l’épaule (on a donc un calcul indépendant du repère dans lequel on se trouve). Toutefois un système de coordonnées cartésiennes aurait pu être pertinent pour d’autres mouvements comme des translations (par exemple si la personne faisait un pas sur le côté) ou comme étape intermédiaire pour exprimer des mouvements combinés (par exemple un pas sur le côté combiné à une rotation du bras).

Solution retenue

Dans la version finale de notre projet, nous reprenons le même protocole, à quelques changements près principalement dûs au changement de systèmes de coordonnées.

Le format de l’écriture des coordonnées ne change pas, on obtient des lignes de la forme :

LH: r phi theta

En revanche la méthode mise en place pour discrétiser le temps d’écriture dans le fichier a été modifiée. Nous demandions auparavant à notre programme d’attendre 1 seconde avant de continuer, ce qui perturbait tout le reste du programme et le fonctionnement de la caméra (parties du programme qui étaient déjà codées dans le “sample” que nous avons modifié). A présent, le programme contient un compteur sur les données mesurées par la caméra qui permet de ne faire le traitement et l’écriture dans le fichier que pour 1 donnée sur 10. Ainsi nous n’empêchons pas le programme de fonctionner entre deux traitements.

Ensuite comme évoqué précédemment, nous choisissons de centrer le repère sur l’épaule et de passer en coordonnées sphériques pour obtenir un repère adapté à la géométrie de notre problème (attention, il existe 2 conventions pour les coordonnées sphériques, nous utilisons la convention “physique” et non “mathématique”).

Enfin la remise à l’échelle se résume à appliquer un rapport au niveau de r, puisque les angles ne sont pas affectés par le changement d’échelle.

CTRM-TI-4.jpg


Améliorations

Dans cette partie, nous ne voyons pas de raison de changer fondamentalement d’approche. La Kinect reste définitivement de notre point de vue le meilleur choix de capteur (documentation en ligne existante, compatibilité, simplicité d’utilisation). Au niveau du traitement des coordonnées, il conviendra de choisir des repères adaptés, en particulier dans le cas où un futur projet viendrait à ajouter d’autres parties du corps (il faudra veiller à définir des repères intuitifs pour chaque articulation et envoyer des coordonnées cohérentes à la partie Arduino). Enfin, une amélioration conséquente du projet actuel serait d’implémenter soi-même la partie fondamentalement orientée traitement d’image, à savoir la reconnaissance de squelette. Nous n’avons pas eu le temps de nous pencher sur un tel algorithme, qui devrait faire appel à des notions croisées de traitement d’image et de classification (cf Bibliographie).


Conception mécanique

Choix du robot

La conception mécanique peut se diviser en trois parties: la structure, le robot et les pièces pour le mouvement des moteurs. Il nous fallait tout d’abord décider de ce que nous souhaitions faire : un véritable robot entièrement motorisé ou un pantin qui serait dirigé grâce à des fils.

Nous nous sommes mis d’accord sur le modèle du pantin qui nous permettait d’éviter en partie les problèmes d’équilibre qui pouvaient se poser pour un robot motorisé puisque dans ce dernier cas, le robot devrait pouvoir tenir debout tout seul. L’utilisation d’un pantin nous permet donc de s’affranchir de cette difficulté. Un autre problème se posait pour le robot motorisé qui est la taille des moteurs: en effet chaque articulation doit être pourvue de trois moteurs si l’on souhaite conserver les trois degrés de liberté. Or pour réaliser cela, l’articulation doit être suffisamment grande pour contenir les trois moteurs, mais étant donné les moteurs que l’on avait à notre disposition, les dimensions du robot le rendait impossible à mettre en oeuvre.

La structure

Pour supporter les mouvements du pantin et les moteurs, nous avons choisi une structure composée de quatre poteaux et de plusieurs étages afin de pouvoir moduler la hauteur des étages et leur nombre. Sur chacun des étages on peut disposer les moteurs qui régiront les mouvements.

CTRM-Conception-1.jpg

Il est facilement envisageable d’ajouter des étages, de rallonger les poteaux ou de changer la composition de l’étage. Des petits taquets ont été ajouté afin de fixer les étages.

CTRM-Conception-2.jpg

Le pantin

Nous avons décidé de faire un pantin en impression 3D, nous avons tout d’abord testé des versions en ligne comme par exemple sur l’image ci-dessous:

CTRM-Conception-3.jpg

Mais nous avons eu de nombreux problèmes liés aux articulations qui ne fonctionnaient pas comme nous le souhaitions donc nous avons décidé de construire notre propre modèle. C’est un modèle très simplifié qui pourrait bien être embelli et qui ne possède pas de tête. Il est uniquement constitué d’une série de cylindres creux de tailles différentes pour les bras et les jambes et d’un torse creux. Des fils passent à travers ces cylindres pour les rattacher entre eux. De plus nous avons mis des écrous aux extrémités, car pour que les fils soient tendus, il est nécessaire qu’il y ait du poids. Nous avons choisi des écrous car c’était facile à trouver et d’un rapport taille/poids convenable. Nous avons voulu ajouter des articulations comme les épaules (impression 3D) et les coudes (point de colle afin de tenir le départ d’une nouvelle corde) pour éviter qu’une trop grande surface de fil ne soit exposée.

CTRM-Conception-4.jpg

Les moteurs et leurs supports

Pour l’instant nous gérons uniquement un bras avec deux servomoteurs classiques et un servomoteur à rotation continue pour la main et deux servomoteurs pour le coude. Les moteurs du coude se trouvent sur le premier étage et les moteurs de la main sur le second. Nous avons créé des “boîtes” pour chacun des servomoteurs afin de pouvoir les accrocher ensembles plus facilement.

Le schéma ci-dessous décrit les mouvements effectués par chacun des moteurs:

CTRM-Conception-5.jpg
CTRM-Conception-6.jpg
CTRM-Conception-7.jpg

Nous avons trois types de mouvements :

- le servomoteur rouge qui supporte les autres et va effectuer des mouvements latéraux,
- le servomoteur bleu qui fait fonctionner un système de pignon-crémaillère. A la base nous étions plutôt partis sur une vis sans fin, ce mécanisme fonctionnait parfaitement bien mais il était beaucoup trop lent pour notre projet. Nous aurions dû faire des vis avec un pas d’environ quatre centimètres tout en gardant un diamètre correct, ce qui était difficilement réalisable.
- le servomoteur rose remonte et relâche le fil grâce à une poulie. Il serait envisageable de remplacer ce servomoteur par un moteur pas à pas afin de diminuer la taille de la poulie.

Pour le coude nous enlevons le pignon crémaillère car les mouvements du coude sont beaucoup plus limités dans cet axe et nous pensons pouvoir nous en passer. Cela va faciliter et alléger l’assemblage total et éviter un nouveau moteur à gérer par la carte arduino. Toutefois il faudra faire de nombreux tests pour adapter la position du coude par rapport à celle de la main. Bien que tous les matériels soient prêts à être installé, le coude n’ayant pas été implémenté par la suite, il n’a pas été mis en oeuvre.

Il serait très facile de tout dupliquer pour gérer l’autre main en ajoutant un nouvel étage. Du fait de la taille du pignon-crémaillère, il aurait été difficile de mettre en place la même structure symétrique, sans que les deux s’entrechoquent.

Les limites

Les explications précédentes sont valables avec des limitations de mouvements que nous avons choisi en commençant le projet:

- les bras restent dans leur demi-hémisphère, c’est à dire qu’on ne peut pas croiser les bras,
- les articulations du pantin ne correspondent clairement pas à celle d’un homme, il est complétement possible de dépointer son coude ou son genou,
- les rotations du buste ne sont pas du tout prises en compte.

Les améliorations

Il serait très bénéfique de créer un modèle plus stable pour le soutien de moteurs. Nous avons une implémentation actuelle qui consiste en un assemblage d’une série de petites boîtes les unes sur les autres avec un rail pour le passage, et le tout n’est clairement pas des plus stables. Cela résulte du fait que nous avons beaucoup bougé ces moteurs afin de trouver une configuration optimale. Maintenant que la configuration est bonne, il serait judicieux de consolider tout ça.


Lien entre l’image et la structure mécanique

Choix de la carte et code principal

Afin de relier la partie traitement d’image et reproduction des mouvements par le pantin, nous avions dû choisir entre utiliser une carte Arduino Uno ou une Raspberry Pi. Le choix s’est finalement porté sur une Arduino Uno, d’une part pour sa simplicité de prise en main et d’autre part pour la multiplicité des ports d’entrée - sortie avec les moteurs.

Ce choix étant fait, la première étape fut de prendre en main la carte Arduino et de la faire fonctionner avec des moteurs indépendants de la structure, en générant des valeurs aléatoires. Par la suite, l’objectif fut de relier la carte Arduino avec la structure mécanique de manière à pouvoir commander les moteurs qui permettent de faire bouger le pantin et de vérifier que les mouvements souhaités se font de manière relativement fonctionnelle.

Une fois ces vérifications préliminaires réalisées, il nous fallait réfléchir au moyen de pouvoir envoyer les commandes de position à la carte Arduino. L’idée fut alors d’écrire la position en coordonnées polaires de l’articulation souhaitée dans un fichier texte; ce fichier est lu et après traitement la commande de déplacement est alors envoyée vers le port USB.

Le traitement des données lues consiste à identifier l’articulation correspondante grâce à un simple parseur, et ensuite adapter ces données pour la carte Arduino. Dans notre cas il fallait envoyer 3 paramètres (la direction de rotation, le moteur, l’angle de rotation). Au départ on envoyait les paramètres à la suite mais vu que la taille de chaque paramètre est différente, il était difficile d’adapter son traitement dans le programme de la carte. On a ainsi décidé d’envoyer les trois paramètres dans un seul nombre de 5 chiffres comme le montre le tableau ci-dessous:

Position du chiffre 1 2 3 4 5
Signification direction de rotation numéro du moteur angle de rotation


exemple : on envoie (10120) signifie on tourne le moteur (0) vers les veleur base (1) avec un degré de rotation de (120)


Afin de relier la partie capture de mouvement et la commande des moteurs du pantin, la position des articulations souhaitées devait être écrite sur ce fichier texte au fur et mesure qu’elles étaient “capturées” (ie en temps réel).

Calculs des angles de moteurs

Les données récupérées par la caméra étant sous forme de coordonnées polaires, aucun calcul n’est nécessaire pour la rotation des servomoteurs (mouvement du bras de haut en bas et de droite à gauche). Le seul moteur qui nécessite un calcul est le moteur gérant la crémaillère.

Le calcul du temps de fonctionnement du moteur est effectué par une simple règle de trois : on a la longueur totale du bras L = 90mm pour un temps de fonctionnement de T = 2000ms donc:

temps de fonctionnement = distance capturée par la caméra * L / T.

Mais vu qu’on était contraints par la taille des données à envoyer vers la carte arduino ( temps de fonctionnement < 1000ms ), on a adapté le calcul de sorte à avoir un temps de fonctionnement à envoyer égal à 1/20 du temps de fonctionnement et on le réajuste directement dans le code de l’arduino de la façon suivante :

temps de fonctionnement envoyé vers la carte = distance capturée par la caméra * 100 / 90.

Et dans la carte arduino on calcule le temps de fonctionnement réel :

temps de fonctionnement = temps de fonctionnement envoyé vers la carte * 20.


Problèmes rencontrés

Plusieurs problèmes se sont posés suite à ces choix  :

- La fréquence d’ouverture et de fermeture du fichier texte était au départ tellement grande que certaines valeurs de commande aberrantes pouvaient se glisser, ce qui empêchait le fonctionnement de l’Arduino. Il a donc fallu jouer sur la fréquence d’écriture de la position dans le fichier texte et la fréquence d’envoi des commandes vers les moteurs afin “d’arriver à un comportement acceptable”. Finalement, les coordonnées transmises à la carte sont actualisées à hauteur de la fréquence de la caméra. C’est la carte Arduino qui réduit cette fréquence pour aboutir à une rapidité d’exécution de 5 traitements par seconde (une fréquence pas tant limitée par la Arduino que par le traitement des données).
- Le choix de la carte Arduino apporte avec elle un certain désavantage qui réside dans l’impossibilité de réaliser des commandes parallèles. Nous avons alors cherché à faire du “pseudo” parallélisme en envoyant des commandes vers des moteurs différents de manière alternée à une fréquence suffisamment grande pour que cela donne une impression de parallélisme.
- A l’état présent, nous avons enlevé ces contraintes sur la fréquence d’envoi de données. Nous avons laissé la gestion des données écrites dans le fichier au programme arduino qui fait la lecture de ces données depuis le fichier.
- La commande de trois moteurs responsables de l’articulation du poignet et permettant de déplacer le bras nous a mis face un problème d’alimentation des moteurs. En effet ces derniers n’étaient pas suffisamment alimentés pour pouvoir fonctionner à leur pleine puissance. Par conséquent, nous avons dû faire usage d’une alimentation externe afin de pouvoir accélérer les mouvements de pantin.


Démonstration et résultats

Démonstration

Lien vers la vidéo Youtube de la démonstration: https://youtu.be/ANbzcvtsFZ8

Avancement et difficultés rencontrées

- Système de vis sans fin conservé pendant très (trop) longtemps,
- Erreur de calcul sur la taille de la poulie,
- Impression d’un mauvais pantin (erreur articulation),
- Perte de temps pour faire fonctionner la XTion Pro Live, finalement abandonnée au profit de la Kinect,
- Erreurs de calcul dans le traitement des coordonnées dues à un système de coordonnées mal choisi,
- Connexion entre le port USB et la carte Arduino


Améliorations et possibilités d’ouverture

Il reste plusieurs améliorations et pistes d’ouverture possibles pour ce projet. Celles-ci sont décrites dans les points suivants.

Au niveau du traitement d’image :

- Le code relatif au traitement des données par la caméra peut être optimisé, par exemple dans le cas où les données sont fausses, une approximation peut être envisagée, voire une meilleure reconnaissance.
- Il faudrait rajouter une possibilité de re-calibrer la caméra en cours de route, dans le cas où la détection ne se fait plus correctement par exemple, qui est un cas qui peut se produire assez régulièrement. Associé à cette calibration, il faudrait que la motorisation du pantin puisse également être réinitialisée à un état de départ prédéfini.
- Dans le cas où on choisirait de fabriquer un robot plus complet, traiter les coordonnées des autres articulations. Il faudra alors porter une attention particulière aux systèmes de coordonnées, qui pourront être différents selon les articulations et les mouvements voulus.
- Pour mettre l’accent sur l’aspect « traitement d’image », on pourra éventuellement chercher à implémenter la reconnaissance de formes et de mouvements par soi-même. Cela peut se faire avec des librairies/logiciels tels que Open CV (cf bibliographie).

Au niveau de la structure mécanique :

- Au vu de l’état actuel de la structure, il reste tout à fait envisageable d’ajouter le bras droit et le coude gauche au système.
- De plus nous pourrions ajouter des moteurs pour les jambes éventuellement sur les étages déjà présents. L’idée de base était de se limiter à des mouvements d’avant en arrière. En mettant des servomoteurs comme le rose (avec des poulies) à l’avant et à l’arrière, on peut ainsi rembobiner les fils pour pouvoir plier les jambes.
CTRM-Amelioration-1.jpg
- Dans l’état actuel de notre configuration, nous avons utilisé des boulons pour ajouter un peu de poids à notre pantin afin de rendre les mouvements plus corrects et fluides. Cependant, il aurait été plus esthétique de penser à un autre moyen d’ajouter du poids.
- Il est également possible de diminuer la hauteur de la structure en utilisant un moteur pas à pas pour la poulie qui permet de lever le bras, puisqu’on s’affranchirait alors de la contrainte des 180° de rotation des servomoteurs.

Au niveau du code Arduino et de la commande des moteurs :

- Certains effets de bords peuvent conduire à un mouvement chaotique. Il faudrait alors analyser quels effets peuvent conduire à de telles situations, et comment régler cela au niveau du code.
- Une amélioration envisageable est également de tester le fonctionnement des moteurs avec une fréquence plus importante d’envoi de données vers l’Arduino, afin de vérifier si l’on peut gagner en fluidité par exemple.


Bilan de la gestion de projet

Organisation

Répartition des équipes selon les motivations de chacun:

- Conception: Elia, Manon, Maryam
- Arduino: Wassim
- Traitement d’image: Borana, Clara, Romain

Réunions et travail au moins une fois par semaine tous ensemble le lundi après-midi au fablab.

Difficultés

- Les horaires d’ouverture du Fablab et la présence de Germain obligatoire ont rendu les impressions difficiles au début et à la fin (parfois impossible d’imprimer pendant une ou deux semaines),
- Le stockage de notre structure volumineuse, finalement stockée au fablab mais donc inaccessible pendant le week-end ou les vacances,
- Les moteurs pas forcément adaptés et le matériel pas forcément présent,
- Pas assez d’entraide au début, mais nette amélioration par la suite,
- Manque de communication entre les équipes (le problème ci-dessus aurait dû être détecté plus tôt), manque de réunions,
- Manque d’organisation entre les équipes  : pas de tâche unitaire pour la caméra, la partie Arduino commencée trop tôt (début trouvé inutile), l’équipe peut être un peu trop grande,
- Avancement très différent entre les équipes,
- Partage de la caméra contraignant en terme d’organisation du travail

Enseignements

- Confrontation à un problème concret et matériel avec des expérimentations et des apprentissages sur le terrain,
- Manipulation des machines du fablab et découverte du fonctionnement du fablab,
- Prise en main d’une interface matérielle et logicielle professionnelle,
- Travailler en l’absence de guide (pas de polycopié auquel se référer, en autonomie), savoir partir de “zéro”
- Fonctionnement global d’une caméra 3D,
- Utilisation Arduino,
- Travailler dans une équipe nombreuse sur un projet conséquent,

Bibliographie

- http://www.edu.upmc.fr/sdi/isi/fr/img_auth.php/1/10/RdF_slides.pdf (Introduction à la reconnaissance de formes)
- Tutoriel pour la reconnaissance de formes à l’aide d’OpenNI et de la Kinect : http://robotica.unileon.es/index.php/PCL/OpenNI_tutorial_1:_Installing_and_testing#Installing_the_software
- La plupart des sites consultés (réellement utilisés ou utiles pour des possibles ouvertures) se trouvent dans la section Documentation du dépôt git.