Ça faisait plusieurs années que je voulais réaliser ce projet. En effet au lycée, je me suis lancé dans la magie et il fallait souvent s’assurer qu’un jeu était complet ou trié dans un ordre précis avant de se lancer dans un tour. Là intervient mon projet de robot trieur de cartes !
Au moment de démarrer le projet je n’avais aucune expérience avec l’Arduino, le contrôle des moteurs, le CAD et les Rasberry Pi. Un des objectifs principaux de ce projet d’un point de vue personnel était de manipuler tous ces éléments qui sont à la base du mouvement Makers. C’est aussi pour cela que j’ai choisi de faire ce projet « touche à tout », qui me permet de donner un corps à du travail informatique (reconnaissance des cartes) ce qui manquait un peu à ma formation jusque là.
I. Conception
Dans cette partie je vais détailler les objectifs du projet et la vision initiale que j’avais du projet.
- Reconnaitre une carte.
Lorsque j’étais au lycée et que ce projet m’était venu en tête, je venais de découvrir comment était encodé une image et comment la manipuler, pixel par pixel sous python. J’avais eu l’idée d’enfermer mes cartes dans une boite ce qui me permettrait de contrôler l’éclairage, de prendre une photo de chaque carte et au moment de déterminer la nature d’une carte de la comparer à chaque image de référence, pixel par pixel avec un certain seuil de tolérance (à déterminer empiriquement) pour des écarts de couleur et de position.
Cependant au moment de réaliser ce projet j’ai trouvé d’autres projet portant sur la reconnaissance de cartes qui se fondaient sur de l’intelligence artificielle et qui partageaient en détail le déroulé de leur projet. Au vu des résultats impressionnant de leur systèmes de détection de cartes j’ai décidé de me baser sur un de leurs projet pour la reconnaissance des cartes.
2. Trier les cartes :
Pour pouvoir trier les cartes je souhaitait que les cartes soient rangés une à une sur une étagère à un emplacement pré-déterminé. (par exemple on pourrait choisir de placer l’AS de pique sur la 13ème étagère, et le 7 de coeur sur la 14ème étagère, etc …). J’ai donc imaginé un que les étagères montraient et décenderaient dès que la carte aurait été reconnue pour qu’une carte puisse venir s’y insérer. La carte serait placée sur un toboggan à une hauteur fixe et glisserait pour s’insérer dans une étagère.
3. Récupérer les cartes du packet :
Au lieu de pousser une carte du haut du paquet ou depuis le bas du paquet avec une roue ce qui ne manquerait pas d’entrainer d’autres cartes (et créer un slot qui ne laisserait passer qu’une carte semblait très difficile aux vues du fait que les cartes s’épaississent de manière conséquente au cours de leur cycle de vie), j’ai décidé de soulever la carte avec un système de ventouse. C’est d’ailleurs la technique utilisée dans un autre projet de trieur de cartes ( disponible à l’adresse https://www.youtube.com/watch?v=MIF4T-9qe9c ) .
4. Déplacer les cartes :
Je pensais que des mouvements de translation seraient le plus facile à réaliser, j’ai donc pensé à faire une translation selon l’axe vertical au niveau du paquet de cartes (ventouse) et horizontale qui ramènerait ensuite la carte jusqu’au niveau du toboggan.
II. Organisation
de temps à se lancer dû à un problème de santé personnel. J’ai donc commencé par créer l’ascenseur à cartes car c’était une tâche bien moins compliquée et couteuse que la détection de cartes. De plus cette tâche me permettait d’apprendre à utiliser et manipuler tous les outils que je comptais utiliser pendant le projet, c’était donc un point de départ logique. Je me suis ensuite attaqué à la détection de carte et je n’ai malheureusement pas eu le temps de réellement chercher à résoudre le problème de prélèvement ou déplacement des cartes.
- Détection des cartes ( traitement de l’image, raspberry-pi, construction de base de données, machine learning )
- Ascenceur à cartes ( CAD, découpeuse laser, arduino, contrôle des moteurs )
- Communication Python/ Arduino
- Prélèvement des cartes du packet ( Arduino, contrôle de moteurs, Découpeuse laser )
- Déplacement des cartes ( Arduino, contrôle de moteurs, Découpeuse laser )
III. Ascenseur à cartes
Pour construire l’ascenseur à cartes j’ai pu récupérer des pièces d’une vieille imprimante cassée du fablab (deux guides en métal, un des roulements à billes adaptés aux guides et reliés par une pièce de métal et une visse sans fin) . J’ai donc commencé par concevoir sur OnShape (logiciel de CAD gratuit en ligne) une étagère à cartes. La première version devait pouvoir s’ouvrir une fois remplie de cartes afin que celles ci tombent les unes sur les autres. J’avais donc conçu un système où la partie de droite et de gauche auraient une crémaillère chacune se plaçant de part et d’autres d’un pignon qui serait relié à un petit moteur qui écarterait les deux moitiés symétriquement. Je me suis rapidement aperçu que c’était de l’ordre du détail et ait simplifié deux fois la conception. La dernière version n’a que 4 étages permettant de trier les cartes par couleur. Ces étagères ont un inclinaison de 20 degrés permettant au cartes de glisser jusqu’au fond plus facilement.
J’ai ensuite crée une plateforme capable de se fixer à la pièce métallique reliant les roulements à billes sur laquelle fixer la visse sans fin. La plateforme devait être très rigide afin que si la visse bloque un peu la pièce ne se déforme pas et force la rotation de la visse. Je l’ai ensuite étendue avec du bois plus fin et léger pour y déposer l’étagère à cartes. J’ai également fabriqué une boite en bois permettant de maintenir les tiges en métal en place. Toutes les pièces ont été découpés avec la découpeuse laser du fablab.
J’ai récupérer un moteur pas à pas « inconnu », une carte Arduino Uno et un Arduino motor shield rev3 permettant de contrôler le moteur (on aurait pu utiliser un driver à la place) . Afin de ne pas griller l’Arduino j’ai utilisé une alimentation stabilisée pour alimenter le moteur (au travers du Motor Shield) en me basant sur la fiche technique de l’Arduino motor shield rev 3 (<12 V, <2A). Je me suis appuyé sur le tutoriel suivant : https://www.makerguides.com/arduino-motor-shield-stepper-motor-tutorial/ pour apprendre à interagir avec mon moteur. J’ai néanmoins remarqué qu’une fois le code lancé sur le moteur se dernier continuait à demander 2A. J’ai d’abord pensé à un court circuit, après avoir changé toutes les composantes une à une et que le problème persistait j’ai découvert qu’il s’agissait ne s’agissait pas d’un problème matériel, mais de code. En effet le tutoriel sur lequel je m’appuyais « bloquait » activement le moteur au repos (certains électroaimants du moteurs étaient alimentés à pleins régime en continu). Ce blocage actif est d’ailleurs le comportement par défaut d’un moteur pas à pas. Après chaque déplacement du moteur j’ai donc ajouter un bloc de code coupant l’alimentation du moteur. J’ai également eu l’occasion d’étudier le schéma électrique du shield Arduino, afin de comprendre en détail ce que faisait mon code et comprendre l’origine des problèmes.
Finalement j’ai imprimé plusieurs coupleurs pour pouvoir y encastrer l’arbre du moteur sur une extrémité et visser la visse sans fin de l’autre (en rose dans l’image ci-dessous).
IV. Reconnaissance de cartes
Après avoir cherché à exploiter le travail déjà fait en reconnaissance de cartes (de nombreux projets exploitant des technologies différentes sont accessibles sur internet), j’ai choisi les deux pistes qui me semblaient les plus prometteuses, la première « prête à l’emploi », conçue pour être lancé sur une Raspberry Pie (bibliothèques de caméra Raspberry Pie utilisé) reposant sur du traitement de l’image « classique » et l’autre reposant sur l’entrainement d’un (gros) réseau de neurones s’attardant sur la conception d’une base de données pour l’entrainement
1. Expérience avec Raspberry Pie
Après avoir installé un OS sur une Raspberry-Pie 3, réussi à me connecter à internet, trouvé son adresse IP, me connecter en SSH, transférer mon dépôt et finalement lancer le code ça ne parvenait pas à extraire les symboles des la cartes et renvoyait sans cesses des images blanches. Après avoir essayé de débugué de façon minimale j’ai abandonné cette piste car je n’éttait pas sur d’en tirer des résultats et au vues du petit nombre de commentaires je risquerait de perdre beaucoup de temps à comprendre le fonctionnement de cet algorithme. Et anexement j’avais très envie de répondre à ce problème avec de l’inteligence artificielle.
2. Génération d’une base de données
En me basant sur le projet de geaxgx ( disponible sur https://github.com/geaxgx/playing-card-detection ) je me suis lancé dans la création d’une base de données. Le framework est le suivant:
- Prendre une vidéo de chaque carte avec un éclairage variable et donner un label (nom de la carte) à chaque vidéo.
- Extraire un certain nombre de frames.
- Extraire, grâce à des fonctions de la bibliothèque CV2, les cartes de chaque frames.
- Extraire la position des coins de la carte (partie nécessaire pour la reconnaître).
- Importer une base de données d’images de fonds (bibliothèque de textures générées procéduralement)
- Insérer 2,3 ou 4 cartes sur un fond, de façon à ce que les cartes se chevauchent plus ou moins de façon à ce qu’un coin au moins reste visible (d’où l’importance de connaître la position des coins sur l’image initiale).
- Générer un fichier .txt contenant l’ensemble des informations cités ci-dessus.
J’ai réussi après quelques tentatives à générer une base de données correcte et il ne me restait plus qu’à faire tourner le réseau de neurones sur ces données avec les paramètres utilisé par geaxgx pour reproduire ces résultats.
3. Prise en main du réseau de neurones
J’ai fait l’erreur de n’ouvrir le dépôt ( https://github.com/AlexeyAB/darknet ) contenant l’implémentation du réseau de neurones pour lequel ce dataset avait été conçu qu’après avoir pris le temps de créer mon dataset (car tout laissait à penser que la réseau de neurone était prêt à entrainer sous condition qu’on lui donne les données sous la bonne forme). Loin de là ! Le dépot implémentait une architecture de réseau de neurones (YOLO Darknet) et avait en fait le but de s’adapter à n’importe quel type de données en entrée. Le dépôt était monstrueux et aurait pris beaucoup trop de temps à prendre en main et le projet touchait à sa fin. J’ai donc abandonné cette piste car j’estimait qu’il serait plus rapide d’adapter la construction de ma base de données pour un plus petit réseau de neurones « fait à la main » ou de poursuivre une autre piste que de prendre en main ce dépôt.
4. Algorithme naïf.
Comme dit précédemment le projet touchait à sa fin et mon robot ne reconnaissait pas les cartes, j’ai donc décidé d’implémenter l’algorithme que j’avais en tête au lycée qui comparait les images pixels par pixels (car j’étais certain de pouvoir le réaliser de bout en bout en quelques heures seulement). J’ai donc récupérer une partie du code utilisé pour générer la base de données qui permettait d’extraire les cartes d’une image. J’ai re-crée un mini base de données ne contenant qu’une image par carte, prise dans les meilleurs condition d’éclairage. À l’execution du comparateur de carte, les images seraient prisent dans les même conditions que lors de la création de la base de données et seraient comparés aux images de référence, pixel par pixel (distance euclidienne) et cette dont la somme des distances euclidienne pixel par pixel était la plus petite correspondrait à celle retenue. Sur une douze d’essais la bonne carte n’a été reconnue que 5 fois, avec 3 résultats incohérents (roi de pique au lieu de 7 de carreau par exemple) et 4 résultats proches (3 de carreau au lieu de 3 de coeur par exemple). On imagine bien que cette solution est très sensible aux conditions d’éclairages.
V. Prélèvement des cartes
Une fois capable de contrôler un moteur sans soucis, en contrôler un deuxième ne me faisait plus peur ! J’ai donc penser à faire un deuxième système comme celui de l’ascenceur qui tirerait sur une seringue reliée à un tube, relié à un entonnoir pour essayé d’aspirer la carte par depression. J’ai commencé à fabriquer ça dans l’optique d’avoir des résultats rapidement et pouvoir présenter quelque chose de plus, mais j’ai abandonné dès que j’ai vu que ça serait compliqué à faire marcher et avant d’y avoir passé trop de temps.
Conclusion
Si ce projet m’a permit de découvrir de nombreux outils et techniques qui me serviront à continuer ce projet et tout au long de ma vie pour d’autres projets. Je suis notamment déçu de ne pas avoir pû reconnaître une carte de manière fiable. Néanmoins je ne regrette donc pas d’avoir procéder à tâtons dans ce projet très ouvert. Ceci m’a appris à utiliser tous les outils que je voulais utiliser et j’ai une idée clair de ce que je veux faire pour continuer ce projet et de comment le faire. Je souhaite entre autre entrainer un réseau de neurones « fait maison » avec un base de données elle aussi « fait maison » en me basant sur les techniques que j’ai utilisé précédemment avant de pouvoir m’attaquer à chaque étape du déplacement de la carte du paquet au trieur qui auront sans doute leur part de défis.
Remerciements
Un grand merci à Adrien du fablab pour toute l’aide précieuse que tu m’a apporté .
Un grand merci à Julien Allali sans qui cette option n’aurait jamais eu lieux.