IMA5 2018/2019 P44

De Wiki de Projets IMA

Présentation du projet

Ce wiki est mis à jour régulièrement par le binôme Erwan Dufresne et Eloi Zalczer, lors des différentes évolutions du projet
Voiture sans modification

Dans un premier temps, il nous semble nécessaire de préciser que nous étions chacun en semestre à l'étranger. Ainsi, nous pouvions chacun choisir des cours "à la carte" et façonner une formation un peu différente que celle proposée à polytech Lille. Ce pourquoi nous avons tous deux choisi des cours ayant un rapport de près ou de loin avec l'intelligence artificielle. Forts de ces différentes expériences plus ou moins approfondies dans ce domaine, nous jugions judicieux de les mettre en pratique lors du PFE de 5ème année. Suite à différentes propositions jugées non adéquates par les professeurs, monsieur Vantroys nous a finalement proposé un projet, original, qui nous permettrait de mettre à bien les nouvelles connaissances acquises dans le domaine de l'IA lors du semestre d'échange.


Le projet consiste à réaliser une voiture autonome miniature capable de s'orienter via de l'intelligence artificielle. Cette voiture ainsi réalisée devrait pouvoir être conforme aux différentes normes lui permettant de participer à la compétition IRONCAR. Cette compétition regroupe les véhicules miniaturisés de différentes équipes et a pour but de les confronter entre eux.


Description

La compétition IRONCAR permet de faire s'affronter différentes équipes entre elles plusieurs fois dans l'année. Chaque équipe a le droit d'avoir une voiture avec une ou deux Raspberry Pi/Arduino, une caméra ainsi que le nécessaire électronique pour faire avancer la voiture. Le bolide doit être totalement autonome et entraîné par intelligence artificielle en apprentissage profond, deep learning en anglais.

La voiture est seule sur la piste et doit réaliser 3 tours de celle-ci en un temps minimum. La piste est large de 1 m 80 avec des bandes blanches latérales continues et possède également une ligne jaune pointillée centrale.

Le classement final est du type "championnat" et chaque compétition selon son importance rapporte plus ou moins de points. A la fin de l'année, l'équipe ayant le plus de points gagne. Le projet de l'Ironcar étant de progresser via l'opensource, le gagnant est tenu de partager le projet Github contenant les fichiers qui lui ont permis de gagner. Cela permet aux autres concurrents de s'en inspirer et d'améliorer constamment les algorithmes de deep learning. Cette compétition est vraiment orientée vers le partage et la progression commune.

Plus d'informations sur le site de la compétition : ironcar

Objectifs

Notre objectif principal est avant tout d'avoir une voiture fonctionnelle. En effet, la victoire du championnat parait difficilement envisageable pour une première participation, d'autant que la "saison" a déjà débuté depuis un bon moment et certaines équipes comptabilisent déjà plusieurs dizaine de points à leur compteur.

L'objectif technique est surtout de pouvoir gagner en compétences dans le domaine du deep learning et de l'intelligence artificielle afin de mettre en pratique les cours étudiés lors de nos échanges universitaires respectifs.

Nous partirons dons dans l'idée d'avoir une voiture la plus aboutie possible et permettant de faire le meilleur score possible lors de la course.

De plus, Monsieur Vantroys souhaiterait organiser la prochaine compétition Ironcar début Mars. S'ajoute donc au projet finale, l'objectif d'organiser au mieux la compétition afin que les concurrents puisse participer dans les meilleures conditions.

Analyse du projet

Analyse des concurrents

Analyse des premiers concurrents

autres voitures en compétition

Bien sûr les premiers concurrents directs seront les autres participants à la course de l'Ironcar. Ces différents concurrents peuvent chacun déployer le dispositif qu'ils souhaitent, selon leurs moyens et leur envie. Sous réserve que le prototype final respecte les conditions requises pour participer à la compétition, bien évidemment.

Chaque équipe est généralement associée à une école. Ils ont plus ou moins de temps et de moyens à consacrer à cette compétition. Il est difficile de pouvoir analyser nos concurrents directs sans les avoir encore affrontés en compétition, cependant certains score obtenus et certaines vidéos à l'appui témoignent d'une réussite certaine de la part de certaines équipes. Nous tâcherons d'être assez compétitifs pour pouvoir les inquiéter dans leur course (nous espérons même pouvoir les battre ! Qui sait ?! )

Analyse des seconds concurrents

Voiture autonome Google

D'autre part, il y aussi d'autre type de concurrents, notamment des grandes entreprises comme Google, Uber ou Tesla qui conceptualisent et déploient des voitures autonomes depuis plusieurs années. En effet, la voiture autonome est déjà une réalité dans certains pays, notamment en Californie aux USA. Les résultats sont plus qu’impressionnants. On dénombre moins d'une dizaine d'accidents responsables pour les voitures autonomes ces deux dernières années. Les réseaux de neurones (deep learning) sont entraînés avec des datasets de plusieurs milliers d'heures de conduite et peuvent ainsi répondent à chaque cas possible. Ces datasets sont parfois disponibles gratuitement sur internet.

Bien que la technologie soit déjà utilisable et fiable, les recherches dans ce domaine sont en constante expansion. L'idée d'améliorer l'intelligence artificielle des véhicules continue de croître dans la tête des hauts décisionnaires des grandes entreprises comme Google. C'est pourquoi nous pouvons actuellement rencontrer des entraînements de réseaux de neurones sujets à controverses, parfois à la limite de l'éthique morale. C'est notamment le cas avec des recherches qui sont effectuées sur "Qui doit on sacrifier?" en cas d'accidents inévitables. Cet algorithme prend en compte le nombre, l'âge des protagonistes, mais aussi le lien d'affection éventuel avec le propriétaire de la voiture (donc conducteur potentiel). Par exemple faut-il percuter trois personnes âgées pour sauver le propriétaire quadragénaire de la voiture ainsi que sa file en bas âge ? Des questions dérangeantes, qui suscitent beaucoup de réactions. Le MIT à publié une étude sur le sujet : ici

Préparation

Cahier des charges

Notre cahier des charges sera assez simpliste :

- Obtenir une voiture améliorée mécaniquement, via impression 3D ou découpe laser, afin de maintenir correctement les composants ajoutés nécessaires à l'apprentissage de la voiture.

- Obtenir une voiture fonctionnelle en orientation et en mouvement (qui se déplace correctement).

- Faire en sorte que le réseau de neurones de la voiture soit fonctionnel et performant.

- Obtenir un score satisfaisant (le plus haut possible) lors de la participation de la voiture à la prochaine course Ironcar.

- Organiser le mieux possible (si elle a lieu), la prochaine Ironcar, dans le hall de l'école.

- Faire en sorte que le travail réalisé sur la voiture soit propre et que le bolide ait un design final agréable.

Choix matériels et technologiques

resau de neurones
Pytorch

Pour ce qui est du matériel, nous avons une voiture à l'échelle 1/10, achetée par un des tuteurs de stage. Nous y ajouterons une Raspberry pi 3B+ pour permettre de traiter au mieux les besoins du deep learning, ainsi qu'une Arduino pour contrôler les moteurs proprement avec une PWM uniquement prévue à cette effet. Il y aura également une caméra grand angle, essentielle pour la vision et l'enregistrement de la piste dans son intégralité pour l’entraînement de la voiture. Une alimentation (qui était déjà à notre disposition à l'école) sera utilisée pour fournir le courant à la Raspberry Pi, qui alimentera elle même l'Arduino. Les pièces mécaniques ajoutées seront quant à elles soit imprimées en 3D, soit découpées via la découpeuse laser du Fabricarium. C'est en effet ce qui permet le travail sur des matières rigides le plus net et le plus facilement accessible.

Pour ce qui est du software, nous utiliserons une méthode d’intelligence artificielle, imposée par la compétition : le deep learning. Cette méthode, l' apprentissage profond en français, consiste à entraîner un réseau de neurones en lui fournissant une grande quantité de données. Dans notre cas, les données seront des exemples de vidéos de pilotage, filmés avec la caméra, lorsque nous contrôlons la voiture via la télécommande. L'algorithme de deep learning analysera alors les diverses situations et s'en inspirera pour pouvoir ensuite réagir de la façon la plus adéquate, au moment du pilotage autonome, lorsque la voiture sera confrontée à une situation similaire ou identique. Nous utiliserons la librairie python Pytorch pour construire notre algorithme. L'avantage de cette technologie est qu'elle donne un contrôle et un accès beaucoup plus fin du réseau de neurones, offrant une API beaucoup plus "pythonesque" là où les autres ont un fonctionnement beaucoup plus obscur. Elle fait notamment concurrence à Caffe ou encore au fameux TensorFlow de Google.

Réalisation du projet

Avancement préalable

Puisque nous étions tous deux en semestre à l'étranger, il était compliqué de pouvoir avancer concrètement le projet avant notre retour à Polytech Lille. Cependant nous nous sommes tout de même renseignés sur les composants nécessaires à la réalisation du projet afin de pouvoir anticiper leur commande et ainsi commencer le projet dès la rentrée des vacances de noël. De plus nous avons fait de nombreuses recherches afin d'orienter les choix que nous serions obligés de faire par la suite une fois le projet entamé. Ce qui nous à donc amenés à prendre connaissance du projet DeepPiCar qui consiste lui aussi à créer une voiture miniature autonome à partir d'une Raspberry Pi et d'une caméra.

Semaine 1 (7-11 janvier)

Partie informatique

Cette première semaine nous a permis d'établir les bases qui nous permettront de nous attaquer au vif du projet. Nous avons commencé par installer Raspbian sur la Raspberry Pi 3B+, et par installer les librairies et paquets nécessaires. Pour Python, nous avons utilisé le gestionnaire de paquets Conda. Il nous permet d'installer et de gérer facilement les versions des librairies scientifiques que nous utiliserons (numpy, scipy, scikit-learn...). Ce gestionnaire de paquets est compatible avec l'architecture ARMv7 de la Raspberry Pi. L'installation de ces packages n'a donc pas posé de problèmes. Le plus difficile à été de mettre en place Pytorch, la librairie de machine learning sur laquelle sera basé notre projet. Cette librairie n'est en effet pas compilée pour Raspberry Pi par défaut, nous avons donc du le faire nous-mêmes. Après avoir récupéré le code depuis le dépôt GitHub du projet, nous avons du initialiser les bonnes variables d'environnement pour paramétrer la compilation. La compilation sur Raspberry Pi implique de se passer de certains fonctionnalités comme CUDA. Nous avons utilisé ce guide pour nous aider. Il a également été nécessaire d'augmenter la taille de la partition de swap pour que la compilation puisse se finir. La compilation a pris plusieurs heures, et nous l'avons étalée sur une nuit. Cette étape a été la plus difficile du setup. Certaines autres librairies, comme engineio pour les websockets, ont demandé des démarches d'installation un peu différentes car les versions disponibles sur anaconda n'étaient pas les bonnes. Nous avons donc du construire l'arbre des dépendances séparément.

Interface web

Le deuxième jour, nous avons commencé à établir l'architecture du projet et à développer. Le plus urgent était d'établir un système de contrôle de la voiture qui nous permettra de capturer d'entraîner le réseau. Nous avons donc développé une petite application web et un serveur websockets en Node.js afin de faire communiquer la Raspberry Pi avec une interface de contrôle en HTML. Nous avons d'abord envisagé d'utiliser la Raspberry Pi comme serveur, mais par souci de légèreté nous avons choisi d'héberger le serveur sur un PC portable. La voiture et l'application client se connectent tous les deux en tant que clients sur le serveur, qui se charge de rediriger les messages reçus depuis l'appli web. Dans un premier temps, nous avons supposé que les angles de rotation de la voiture ne seraient pas supérieurs à 30°. Nous avons également normalisé la vitesse entre 0 et 30 sur le système de contrôle. La première version de ce dernier était très simple et consistait en un cercle sur un canvas qui suit les déplacements de la souris. Si le cercle est lâché, il retourne à sa position d'origine et arrête donc la voiture. L'interface ressemblait alors à l'image à droite.

L'application a fonctionné sans problème majeur, cependant il nous a fallu un certain temps pour déterminer la façon optimale d'utiliser la librairie python-socketio. La réception des commandes est en event-based, ce qui n'est pas habituel en Python et nous a demandé quelques recherches. Nous avions commencé par mettre la réception des commandes dans un thread séparé, puis nous nous sommes aperçus que ce n'était pas nécessaire. Le jeudi, nous avons essayé pour la première fois la voiture. Après quelques courses dans les couloirs et le hall, nous avons démonté une partie du capot pour observer les branchements à l'intérieur. La documentation est pratiquement introuvable sur internet, donc cela nous a permis de nous faire une idée du fonctionnement du système et du protocole à utiliser. Suite à une discussion avec le tuteur de projet, nous avons décidé d'utiliser une Arduino pour générer les PWM car elle sera plus stable que sur un Raspberry Pi.

Une autre partie du travail a été de préparer la partie Machine Learning qui se fera dans quelques semaines. Nous avons modifié le code principal du projet pour enregistrer les images capturées par la caméra et les commandes correspondantes pendant la course. Pour cela, nous avons également ajouté un bouton Lancer/Arrêter l'enregistrement sur l'application Web. L'enregistrement pourra ainsi être contrôlé et arrêté si la voiture sort des traces. Lorsque la voiture est arrêtée définitivement, les données sont enregistrées dans un fichier horodaté au format hdf5 qui est optimisé pour le stockage de datasets. Les images et les commandes sont enregistrées sous forme de tableaux numpy qui sont facilement lisibles et re-convertibles en images. Nous avons écrit un petit code pour vérifier que les images n'étaient pas corrompues et que les commandes étaient correctement enregistrées, ce qui nous a permis de détecter un bug.

En effectuant ce travail, nous avons pris certains risques concernant l’entraînement futur du réseau. Nous avons en effet décidé de travailler avec des valeurs de vitesse et de direction continues, alors que tous les projets trouvables en ligne utilisent un set de valeurs discrètes. Notre approche peut nous permettre d'obtenir une voiture plus précise, mais demandera également plus de données pour l'entraîner efficacement. De plus, la qualité des données dépendra de la qualité de notre pilotage. Il est possible que cette décision doive être modifiée à l'avenir si les performances obtenues ne sont pas satisfaisantes.

Partie électronique

telecommande

Bien que les premiers tests sur la voiture concernaient l’orientation et la vitesse de pointe max, il fallait tester la télécommande dans son intégralité. Nous nous sommes donc longuement référés à la notice de la voiture. Finalement, voici l fonctionnalité des différentes commandes de ma télécommande.


La gâchette sert à accélérer ou reculer et à jauger la vitesse. La molette latérale droite sert à orienter les roues avant. La molette centrale sert à régler l’angle du servo moteurs contrôlant les roues avant (nous les mettront par défaut à 30 degrés, quitte à remodifier cette valeur par la suite) Le bouton en haut à droite change le sens de d’orientation des roues directrices (tourner à droite fais désormais tourner la voiture à gauche) Celui d’en bas à droite, permet de corriger l'orientation des roues "au repos", la position par défaut. Celui en bas à gauche permet de re-calibrer la tension de la voiture, si celle-ci n’est pas totalement à l’arrêt losqu’on ne lui donne aucune indications. Le bouton en haut à gauche permet d'inverser le sens de rotation des moteurs (inverser la tête et la queue de la voiture) Enfin le bouton power sert à alimenter la télécommande (pas trop compliqué celui-là)

Partie mécanique

Ensuite il était essentiel de prévoir un support pour les différents composants que nous allions ajouter à la voiture. Effectivement, il faut pouvoir fixer les différents contrôleurs pour remplacer la télécommande. L’utilisation d’une raspberry était évidente. Pour ce qui est du contrôleur des moteurs, notre tuteur nous a fait remarquer qu’il s’agissait d’une simple PWM. Ainsi, une arduino serait judicieuse afin d’avoir une PWM de bonne qualité. Pour alimenter le tout une batterie est également essentielle. Le choix des iles à était rapidement écarté puisque nous avons à notre disposition des batteries externe. Le but est donc de faire tenir l’ensemble de ces composants, finalement assez volumineux, dans la voiture. Il était évident que la « carcasse » en plastique original ne suffirait pas à contenir l’ensemble des éléments. Il sera donc nécessaire d’en modéliser une plus tard, sans doute imprimé en 3D (mais nous y reviendront plus tard). Pour ce qui est du maintien des différents composants, il fallait quelque chose de précis pour être fixer correctement sur l’emplacement confiné du châssis, rapide (nous ne pouvions pas risqué de perdre trop de temps via l’impression 3D par exemple), et surtout résistant au choc et stable face aux différentes vibrations engendrées par la voiture. Le choix d’utiliser la découpe laser était donc presque évident. Il est vrai que nous aurions pu choisir un bois résistant ou divers couche de contreplaqué. Finalement nous avons choisi par simplicité, de faire ce support en plexiglas épais de 6mm. Pour cela, on reprend les bonnes habitudes de Onshape pour modéliser les fichiers .dxf nécessaires à la découpe ! Le travail n’était pas très dur, mais assez fastidieux, et il fallait surtout être très rigoureux dans les mesures. Nous obtenu donc finalement un plaque aux mesures de la voiture, perforé pour recevoir l’arduino et la raspberry. La plaque possède également une encoche pour laisser passer éventuellement la nappe de la caméra de la raspi. Nous y avons ajouté quelques perforations pour laisser passer quelques câbles par la suite si nécessaire. Finalement, certains trous n’étant pas placés parfaitement ou étant oubliés, nous avons corrigés certaines perforations manuellement, à l’aide de la perceuse et d’un foret.

plaque de plexi schema
cache "bloc batterie"

Nous avions fait le choix de fixer les deux cartes arduino et raspi via un système classique de vis et d’écrous. Cela nous permettait d’utiliser les perforations déjà faites aux préalables sur les deux cartes. En revanche la batterie externe ne pouvant pas être percée, il nous fallait un système d’accroche plus proche de celui de l’encastrement. L’idée était donc de modéliser et d’imprimer en 3D, des sorte de « cache » dans lesquelles ont placerait les quatre coins de la batterie externes. Ces caches seraient quant à eux percés et fixés directement sur la plaque de plexi. Nous obtenions ainsi cette version finale à imprimer en quatre exemplaires.

plaque de plexiglas finale avec les cartes de contrôles fixées


Malheureusement après une première impression test, nous nous sommes aperçus que le la précision de l’impression laissait à désirer. Ce qui n’était pas acceptable dans notre cas. En effet, le fait de devoir imprimer une sorte de « boite », nécessitait soit l’impressions d’un support de non affaissement qui venait alors créer certaines bavures sur l’intérieur de la pièce, et donc laisser un certain jeu de battement, pouvant laisser s’échapper la batterie, ou même la rayer. Cependant sans ce support, la pièce était inclinée et donc pas exploitable non plus.

Semaine 2 (14-18 janvier)

Partie informatique

L'objectif principal de cette semaine était de réussir à faire rouler et contrôler la voiture via notre propre système. Nous avons donc essayé de connecter une Arduino et de faire fonctionner la voiture avec une PWM que nous générons, mais sans succès. Nous avons donc décidé d'observer la sortie du récepteur à l'oscilloscope pour déterminer la différence. Nos observations ne correspondaient pas du tout à nos attentes, car la sortie du récepteur de la voiture ne ressemblait pas à une PWM. En attendant de pouvoir discuter avec le tuteur du projet, nous avons fait une nouvelle version de l'application sur une autre branche dans laquelle les commandes sont des valeurs discrètes. Nous avons ainsi deux versions fonctionnelles, ce qui nous permettra de choisir l'architecture de réseau donnant les meilleurs résultats. Nous avons décidé d'utiliser 5 valeurs de direction et 2 valeurs de vitesse différentes, ce qui était également les choix faits par l'équipe gagnante de l'an dernier. Nous avons également modifié le script de vérification du fichier h5 pour l'adapter à ces modifications.

Le mercredi, nous avons enfin réglé les problèmes qui nous empêchaient de faire avancer la voiture. Le premier problème était la fréquence de la PWM, qui était beaucoup trop élevée sur l'Arduino (500Hz au lieu des 50~60Hz pour un servomoteur). Nous avons découvert ce problème après avoir contacté un technicien chez T2M et avoir discuté avec les tuteurs de projet. Pour corriger ce problème, nous avons simplement utilisé la librairie Servo de Arduino qui est conçue exprès pour notre cas. Après cette première correction, la voiture ne fonctionnait toujours pas et nous avons supposé que l'alimentation de l'Arduino n'était pas suffisante. Une mesure au voltmètre nous a permis de déterminer que l'alimentation était en 6.5V soit au-dessus et ce que peut fournir l'Arduino. Nous avons testé avec une alimentation 7.5V et avons pour la première fois réussi à faire bouger les servomoteurs. Enfin, nous avons établi un petit circuit pour réutiliser l'alimentation fournie par le récepteur et remplacer le signal par celui en sortie de l'Arduino. Le dernier dysfonctionnement était du aux masses qui n'étaient pas connectées, ce que nous avons corrigé rapidement. Une fois que les servomoteurs bougeaient, nous avons entrepris de calibrer les valeurs pour les contrôler. Comme nous l'attendions, les angles de rotation pour les servomoteurs sont compris entre -30° et 30°. La valeur moyenne étant 90, la plage de valeurs va de 60 à 120. Une fois cette première étape finie, nous avons répété la procédure pour le moteur brushless principal. Le système a rapidement fonctionné, et nous avons pu déterminer que le moteur commençait à tourner pour une valeur de 100. Nous avons supposé que la valeur maximale était 180 mais nous n'avons pas testé jusque là car la voiture était en position instable.


Partie mécanique

Une fois ces problèmes réglés, le reste a été assez rapide. Nous avons réalisé un code Arduino pour contrôler la voiture en fonction des instructions reçues sur le port série, et nous avons refait une partie de mécanique pour améliorer le chassis et la gestion des câbles. Le vendredi, nous avons pu faire rouler la voiture pour la première fois sans aucun lien extérieur. Cela nous a permis de faire les premiers tests de caméra et d'apprécier certaines caractéristiques, notamment le rayon de braquage qui est assez élevé. L'orientation de la caméra sera essentielle, d'autant plus que nous n'avons pas un modèle grand angle. Parmi les prochaines étapes, nous allons devoir trouver un système d'attache de la caméra (peut-être imprimé en 3D), construire une piste de test et éventuellement adapter le code de capture d'images. Une fois que nous aurons conduit la voiture suffisamment pour obtenir des données conséquentes, nous passerons à la partie Deep Learning du projet. Pour finir la semaine, nous avons construit un tronçon de piste à taille réelle pour apprécier la vision que la caméra aurait. Nous avons remarqué que la voiture ne voyait la piste qu'environ 1.50m devant elle, ce que nous avons jugé trop lointain. Nous avons donc décidé de commander une caméra grand angle pour remplacer le Camera Module V2. Nous avons également commandé une nouvelle nappe de connexion de 30 centimètres pour avoir plus de liberté au niveau du placement de la caméra.

résultat final du mode de fixation de la batterie
coupe à suivre en découpe laser


Il nous fallait donc une nouvelle idée de fixation. Finalement, l’idée d’accumuler les découpe de plexiglas pour un faire une pièce volumineuse en 3D nous paraissait être une bien meilleure idée. Le hasard a en effet bien fait les choses puisque l’épaisseur de la batterie (15mm) était pile un multiple de l’épaisseur du plexi (3mm). De plus le tout parait bien plus propre et esthétique.

Nous avons juste pris soin de découper certaines branches pour pouvoir faciliter l’accès aux ports USB de la batterie. Nous avons donc un squelette global permettant de fixer nos trois pièces maitresses c’est-à-dire l’alim, l’arduino et la raspi. Le montage final ressemble à ceci.


Les pièces sont correctement maintenues et la plaque est fixable facilement sur la voiture sans encombrer les flans. De puis elle ne demande pas beaucoup d’espace nécessaire supplémentaire en comparaison à l’ancienne configuration.


Partie électronique

Finalement nous avons eu quelques soucis avec l’alimentation, que nous n’avons su expliquer. A chaque branchement, s’effectuait un reboot de la raspi mais s’en suivait rapidement une mise en arrêt. Nous n’arrivons toujours pas à comprendre l’origine du problème puisque le lendemain tout cela fonctionnait correctement. Nous soupçonnons un câble USB défectueux à l’origine de cet incident jumelé à un faux contact lors du branchement, et peut être aussi une batterie trop peu chargée. Cependant ce détail nous a fait perdre un peu de temps sur notre expérimentation. Le problème est cependant résolu, n’en parlons plus.


gaine thermique appliquée le plus proprement possible
alimentation de la raspi, version finale via pin 2 et 6


Nous arrivions facilement à alimenter la raspberry avec le port mini usb. Cependant notre câble était trop long. S’ajoute à ceci, le fait que le port mini usb est sur le flanc de la carte et donc élargit l’espace nécessaire latérale (car on le peut pas plier un câble usb à 90 degrés sans l’endommager sérieusement. De plus, le câble reliant la raspi à l’arduino (lui permettant par ailleurs de l’alimenter) prend déjà beaucoup d’espace. Aussi le volume disponible dans la carcasse de la voiture est assez limité. Pour gagner de la place et limité l’encombrement filaire, nous avons décidé de couper un de nos câbles USB de téléphone afin de pouvoir en dénuder le fil « plus » et la « masse ». Les câbles de transfert de données ne nous intéressent pas dans le cas d’une simple alimentation. Nous envisageons alors d’alimenter la raspi via les pins 2 et 6. Après avoir minutieusement dénudé les câbles concernés et soudé des pins à leurs extrémités, nous avions un système fonctionnel. Cependant le tout étant assez fragile, il nous fallait un système permettant de solidifier le tout. Pour cela nous avons suivi les conseils de Thierry qui nous a conseillé d’utiliser la gaine thermique qu’il avait à disposition. Le résultat final est plus que satisfaisant : propre et solide, parfait !

Pour ce qui est d’une éventuelle carte électronique, nous nous interrogeons sur la nécessité et le coté judicieux de cette dernière. En effet, reliant des pins très proches, nous ne savons pas si nous avons réellement besoin d’une faire notre propre circuit imprimé. Des soudures renforcées pour les pins devraient être suffisante. Nous reviendrons éventuellement sur la conception d’une carte électronique si il nous reste du temps en fin de projet, dans un souci de perfections de prototype final. Enfin, nous avons commencé une conception d’une coque profilé pour la voiture. L’ancienne n’est en effet plus fixable suite aux rajouts de la plaque de plexi. Et puis il faut avouer aussi que ça nous amuse de le faire ! Bon… cette première version est plus dans un but d’apprentissage des différentes fonctionnalités que nous offre onshape à vrai dire… Bien que le résultats ne soit pas rebutant, il ne constitue rien d’existant pour autant.

premier jet de la modélisatin de la coque de la voiture
montage final

Nous reprendrons la conception d’une nouvelle coque lorsque nous en auront le temps et lorsque nous auront un idée précise de ce que nous souhaitons concevoir. Ce n’est pas la priorité du projet pour le moment.

Semaine 3 (21-25 janvier)

Partie informatique

En attendant de recevoir la nouvelle caméra qui nous permettra de passer au Deep Learning, l'objectif de cette semaine sera de faire en sorte que tout soit prêt pour cette seconde étape. Nous devons donc finir la partie mécanique (support de la caméra, ajustements divers) et tenter d'optimiser la partie informatique pour s'assurer qu'elle fonctionne bien le moment venu. Nous allons utiliser un simulateur déjà existant ici pour générer des images d'entraînement avant de pouvoir créer les nôtres. Ces images nous permettront de tester et éventuellement d'adapter notre réseau de neurones. Le simulateur génère une série d'images au format jpg et les commandes associées sont encodées dans le nom du fichier (format frame_<nb_frame>_gas_<vitesse>_dir_<direction>.jpg). L'inconvénient de ce simulateur est que la seule vitesse possible est de 0.5, ce paramètre n'est donc pas pertinent. Les directions fournies sont globalement comprises entre -2 et 2, nous devons donc également normaliser ces valeurs pour matcher nos paramètres. Enfin, nous devons transformer le dossier d'images jpeg en un fichier h5 que nous utilisons dans notre cas.

Sans surprise, les premiers entraînements du réseau de neurones n'ont pas donné les résultats espérés. En effet, quelles que soient les données en entrées, les sorties du réseau convergeaient toujours vers une valeur constante. De plus, cette valeur n'était pas constante selon les entraînements, ce qui signifie qu'elle était issue de facteurs stochastiques. Nous avons donc tenté de mettre en place un autre réseau plus simple, et avons obtenu le même type de résultats. Après avoir longuement vérifié l'algorithme d'entraînement et s'être assurés que les données en entrée étaient bien différentes et correspondaient bien aux images, nous avons remis en cause la qualité des données en entrée. Après vérification, les images générées étaient très incomplètes et il nous était impossible de leur assigner manuellement une commande. Nous avons donc décidé de régénérer tout le jeu de données et passant plus de temps à comprendre le simulateur. Cela nous a également donné l'occasion d'y trouver quelques bugs et d'ouvrir une Issue sur Github. Les images générées cette fois étaient nettement plus intéressantes, et nous les avons à nouveau converties au format h5 pour les uploader sur Google Drive et les utiliser dans notre modèle Google Colaboratory.

Ce changement n'a pas amélioré la situation, et nous avons fini par trouver une piste de solution en fin de semaine. Cette dernière était liée au taux d'apprentissage utilisé pour l'optimisation du réseau, qui était trop élevé. En diminuant cette valeur d'un facteur 100, les valeurs en sortie n'étaient plus toutes similaires. Après divers ajustements du modèle et en augmentant le nombre d'époques de l'entraînement, nous avons enfin obtenu des résultats encourageants. Nous avons utilisé une métrique considérant les prédictions à +/-3 de la commande comme des succès et les autres comme des échecs. Avec un entraînement sur 2000 images et 30 époques, nous avons obtenu un score de 81% avec cette métrique. Ce n'est pas suffisant, mais étant donné la taille du jeu d'entraînement, cela correspondait à nos espérances. Nous avons donc lancé un second entraînement, cette fois sur un jeu de 20 000 images et 50 époques. Cet entraînement avait pour but de vérifier que le réseau ne faisait pas de sur-apprentissage ou ne se mettait pas à régresser après un certain nombre d'époques, ce qui peut arriver pour un réseau convolutionnel. A l'issue de l'entraînement, nous avons testé le réseau sur le même jeu de test que précédemment (2000 images) et avons obtenu un score de 90.25%. En assouplissant la métrique jusqu'aux valeurs à +/-5, ce score augmente à 94.5% et à 97% si l'on porte la valeur à 8. Ces résultats commencent à devenir très acceptables, cependant il reste visiblement des valeurs aberrantes qu'il nous faudra filtrer. On pourrait envisager un contrôle qui empêche à la voiture d'accepter des commandes trop contradictoires avec les précédentes. Par exemple, si la direction actuelle est de +20 et que le réseau retourne une valeur de -30, cette valeur serait soit ignorée soit moyennée avec la valeur actuelle.

La dernière chose que nous avons fait cette semaine était d'inclure le réseau de neurones dans l'algorithme sur la Raspberry Pi. Après un certain nombre d'ajustements, nous avons réussi à faire tourner le modèle. Cependant, à première vue il était capable de traiter environ une image par seconde, ce qui n'est évidemment pas suffisant pour conduire une voiture en situation de course. La semaine prochaine sera donc consacrée à trouver des optimisations pour faire tourner l'algorithme de façon plus performante. L'article de recherche DeepPicar cité précédemment en propose deux, que nous allons devoir essayer. Il y a probablement aussi certaines modifications à effectuer dans notre code pour l'alléger ou utiliser des API plus performantes. Même si nous aimerions l'éviter, il nous sera probablement nécessaire de nous orienter vers une architecture de réseau plus simple en sacrifiant un peu de performance au profit de la réactivité du système.

Partie mécanique

L’idée en début de semaine était de créer un support pour la caméra. Seulement après quelques essais sur une piste improvisée, nous avons constaté que la caméra offrait une vision trop étroite et restreinte de la piste. Il nous fallait donc une caméra grand angle. De plus la nappe à disposition est trop courte pour permettent une aisance des mouvements et des tests. Il nous en faudrait donc une un peu plus longue. Ces différents imprévus ont donc faits que nous devions prendre en considération une éventuelle marge d’erreur. Nous avons donc cherché de l’inspiration sur les différents sites de partage communautaire de fichiers .stl imprimables par une imprimante 3D. Nous étions donc partis pour s’inspirer du modèle suivant :

exemple de bras de support pour la caméra
emplcement potentiel de la caméra dans le par-buffle

Nous avions ensuite songé à éventuellement faire un prolongement de support via du pleglis découpé au laser. Mais cela était très vite limité par l’incapicité de cette méthode de créer des pièces complexes en 3D (le cumul des différentes couches d’épaisseur est rapidement insuffisant). Surtout que cette partie doit être la partie la plus fixe de la voiture, on ne peut pas se permettre que la caméra tremble lors de la mise en mouvement de la voiture.

Pourtant, après avoir longuement observé la voiture, nous avons remarqué un « trou » (volontaire de la part des designers de la voiture bien entendu) juste derrière le par-buffle, qui permettait de fixer la caméra très facilement. Ceci nous faciliterait vraiment le travail et rendrait en plus la caméra très discrète, tout en la protégeant de tout éventuel choc. Cependant, nous craignons que l’angle soit trop incliné et filme trop près de la piste, sans avoir une vision en profondeur correcte sur le reste de la piste. Nous n’avons actuellement aucun moyen de savoir si cette configuration sera fonctionnelle avec une caméra grande angle et une nappe plus longue. Nous décidons tout de même de supposer que cela sera suffisant. Si ce n’est pas le cas, nous modéliseront et imprimeront rapidement un nouveau support pour la caméra.

En attendant, nous avons décidé de reprendre un nouveau jet de la conception de la « coque » finale de la voiture. Après avoir regardé différents modèle existant dans la vraie vie, nous sommes tombés sur l’image d’un bus scolaire américain version 4x4. Comme cela n’avait aucun rapport avec quoi que ce soit dans notre projet mais nous a bien fait rire, nous avons décidé d’essayer de le reproduire.

second jet de la modélisation de la coque du bus 4x4


Nous n’avons pas encore terminé cette étape car elle demande beaucoup de précisions, de rigueur et de maitrise de Onshape. Ce que nous n’avons pas encore forcément. Cependant, notre création s’approche peu à peu du modèle original.


Enfin nous avons profité de ce léger temps d’ « attente de composants » pour mettre à jour notre wiki.

Semaine 4 (28 janvier - 2 Février)

Partie informatique

La priorité de cette semaine était de trouver un moyen de faire tourner notre modèle à une vitesse suffisante pour que la voiture puisse se conduire. En fin de semaine dernière et en début de cette semaine, nous avons essayé certaines optimisations suggérées dans l'article de recherche DeepPicar. Parmi ces dernières étaient notamment :

  • Désactiver l'adaptation dynamique de la fréquence de la Raspberry Pi
  • Utiliser l'ordonnanceur SCHED_FIFO avec priorité maximale
  • Configurer PyTorch pour utiliser 4 threads pour les 4 coeurs du processeur.

Nous avons également amélioré le système de capture d'images en supprimant certaines synchronisations d'événements pour bloquer le moins possible les processus. Aucune de ces optimisations n'a donné des résultats miraculeux, et nous avons à peine atteint le cap des 2 images par seconde. Il nous faudrait un système 10 fois plus rapide pour espérer une conduite fluide. Deux solutions s'offrent alors à nous, et nous avons décidé d'explorer les deux. La première consiste à utiliser un autre backend en espérant de meilleures performances sur Raspberry Pi, en rappelant que nous avons compilé PyTorch nous-mêmes et que la librairie est probablement mal optimisée pour cette plateforme. En suivant l'exemple de pratiquement tous les participants à IronCar avant nous, nous nous sommes donc tournés vers TensorFlow et Keras. La seconde possibilité est de modifier et simplifier notre modèle en essayant de conserver les meilleures performances possibles. Ces deux solutions ne sont par ailleurs pas incompatibles, et un modèle plus simple sur un backend plus performant sera probablement notre résultat final.

Après une journée à essayer d'implémenter le modèle sur Keras, nous n'avons pas réussi à le rendre fonctionnel. Le modèle était exactement semblable, cependant Keras implémente une API de plus haut niveau qui nous empêche d'avoir un contrôle fin sur certains paramètres. Nous n'avons pas totalement abandonné l'idée de changer de Backend, car Keras a effectivement l'air beaucoup plus performant sur Raspberry Pi, cependant le temps de montée en compétence nécessaire a fait que nous nous sommes concentrés en priorité sur de nouvelles architectures. Par ailleurs, il existe des projets GitHub pour convertir un modèle PyTorch en Keras, que nous devrons tester dans la semaine. Nous avons donc essayé plusieurs modèles, que nous avons entraînés chacun sur 10 époques, et avons obtenu les statistiques de tests suivantes :

Couches convolutionnelles Couches fully-connected Précision avec tolérance 3 Précision avec tolérance 5 Précision avec tolérance 8 Précision avec tolérance 10 Temps d'inférence du réseau
Modèle 1
  • (3->9) layers, 5x5, stride 2;
  • (9->12) layers, 5x5, stride 2;
  • (12->18) layers, 5x5, stride 2;
  • (18->24) layers, 3x3;
  • (24->32) layers, 3x3
  • (576 -> 50);
  • (50 -> 10);
  • (10 -> 1)
0.854 0.9155 0.951 0.958 0.078s
Modèle 2
  • (3->9) layers, 5x5, stride 2;
  • (9->12) layers, 5x5, stride 2;
  • (12->18) layers, 5x5, stride 2;
  • (18->24) layers, 3x3;
  • (24->64) layers, 3x3
  • (1152 -> 50);
  • (50 -> 10);
  • (10 -> 1)
0.8425 0.9185 0.955 0.9546 0.08s
Modèle 3
  • (3->9) layers, 5x5, stride 2;
  • (9->12) layers, 5x5, stride 2;
  • (12->18) layers, 5x5, stride 2;
  • (18->24) layers, 3x3;
  • (24->64) layers, 3x3
  • (1152 -> 100);
  • (100 -> 50;
  • (50 -> 10)
  • (10 -> 1);
0.8735 0.9245 0.948 0.9535 0.08s
Modèle 4
  • (3->12) layers, 5x5, stride 2;
  • (12->18) layers, 5x5, stride 2;
  • (18->24) layers, 5x5, stride 2;
  • (24->32) layers, 3x3;
  • (32->64) layers, 3x3
  • (1152 -> 100);
  • (100 -> 50);
  • (50 -> 10);
  • (10 -> 1)
0.818 0.902 0.938 0.9515 0.13s

La limite des 0.08s par inférence, soit environ 12.5 images par seconde, semble difficile à franchir même en mettant en place toutes les optimisations évoquées précédemment. Dans un premier temps, cette fréquence nous parait acceptable, sachant qu'elle risque d'être nettement améliorée si l'on parvient à convertir le modèle en Keras. Il nous faut maintenant choisir la meilleure architecture pour l'entraîner plus avant. La précision à 3 nous paraît une métrique secondaire, car une telle précision sur un réseau de neurones ne fait pas vraiment de sens. En nous concentrant sur les métriques supérieures, les modèles 2 et 3 semblent obtenir les meilleurs résultats. Après un nouvel entraînement sur 50 époques, la précision du modèle 2 monte à 0.8885 pour une tolérance de 3 et 0.932 pour une tolérance de 5. Le modèle 3 obtiens des résultats quasi-exactement similaires.

Le format ONNX est un format récemment créé dans le but de normaliser les représentation des réseaux de neurones entre les différentes librairies. Le format n'est pas encore complètement supporté par toutes les librairies, cependant PyTorch est capable d'exporter des modèles à ce format. La version 1.0.0 de PyTorch (nous utilisons la 0.4.1) nous permettrait d'exporter notre modèle et le réimporter dans TensorFlow par exemple. Cependant, nous pensons que le modèle n'est pas en cause et que le problème de l'entraînement avec Keras vient du reste du code (normalisation des données, optimiseur etc...).

Vers la fin de la semaine, nous avons enfin réussi à tirer des résultats du modèle Keras. Sans appliquer de pré-traitement sur les données, les résultats étaient légèrement moins bons que ceux du modèle PyTorch, ce qui était attendu, la difficulté restante est de trouver un pré-traitement permettant d'augmenter significativement les performances. Pour une image, cela consiste souvent à ramener la moyenne des valeurs à 0 et à ramener un écart-type unitaire. Cette transformation est implémentée par défaut dans PyTorch, mais dans Keras il nous faudra l'implémenter nous-mêmes. Les premiers essais que nous avons faits ont eu pour effet de dégrader les performances au lieu de les améliorer faisant tomber la précision à +/-5 à quasiment 80%. En parallèle, nous avons testé les performances sur la Raspberry Pi pour nous assurer que notre choix était bon. Les résultats sont sans appel, la fréquence de fonctionnement étant d'environ 15 images/seconde avec le modèle non simplifié (environ 2 images/secondes sur PyTorch). En simplifiant le modèle, nous avons réussi à atteindre et dépasser la barre visée de 20 images par seconde.

Enfin, nous avons profité de la dernière journée de la semaine pour faire un refactoring massif du code embarqué qui devenait très difficile à lire. Nous avons séparé les pilotes automatique et manuel en deux enfants d'une même classe avec une API normalisée. Le code principal est donc beaucoup plus court qu'avant et beaucoup plus lisible. Ce refactoring n'a pas provoqué de changement visible en performances.

Partie électronique

N'ayant pas encore reçu la caméra grand angle, nous n'avons pas retouché aux composants éléctroniques, qui était déjà fonctionnel la semaine dernière. Nous n'avons donc pas touché à la partie électronique du projet cette semaine.

Partie mécanique

"squelette" du car


La suite de la modélisation a en revanche été bien plus chronophage que prévue. Effectivement, la fonction "coque" sur onshape, qui permet de creuser une pièce en supprimant une des faces (dans notre cas la face inférieure), ne fonctionnait pas ou mal. La pièce du bus était sûrement un peu trop complexe pour cette fonction coque. Il est aussi possible que notre manière de designer le bus était non conventionnelle, ou non optimisée. Il est vrai que nous sommes finalement encore débutants sur ce logiciel. Toujours est-il qu'il a fallu creuser la pièce manuellement, en extrudant différentes formes, tout en veillant à ne pas créer de trou dans la carcasse à forme complexe. Bien que la tâche soit simple à comprendre, nous avons passé plusieurs heures sur cette étape... Heureusement, à force de perseverance, de rigueur et de minutie, nous avons enfin pu avoir notre "carcasse" finale, creuse et quasiment finalisée, comme ci contre, à gauche.

De plus, nous avons fait une erreur dans la manière de modéliser le car. En effet, la convention voudrait de faire différente partie (toit, arrière, capot,...) et de les assembler par la suite. Cela facilite les retouches, corrections, et surtout permet une impression 3D en plusieurs pièces, donc faciltée. Nous avons malheureusement fait tout en une seule et même pièce... Il a fallu donc faire une sorte de "fork" de la pièce unique, et la découper autant de fois que nous voulions une pièce partielle.encore une fois cette étape est dûe au fait que nous n'avions pas prévu ceci lors de la conception. On le saura pour la prochaine fois ! En attendant il a fallu tout découper pièce par pièce, et encore une fois, ceci n'est pas prévu à la base dans onshape. Nous avons donc perdu encore du temps à faire quelquechose qui aurait était très rapide si nous avions confectionné correctement le modèle.

assemblage virtuel avec la plaque de plexiglas

Et comme si tout cela ne suffisait pas, nous avions une coque de car trop petite... lors d'une simulation d'assemblage avec un modèle 3D de la plaque de plexiglas, celle ci ne pouvais pas s'encastrer dans le car ce dernier dernier était trop étroit. Il a donc fallu reprendre la pièce de base, creusée mais non séparée en différentes pièces, pour modifier l'échelle de manière non uniforme (si nous faisions ça de façon uniforme selon les axes x, y et z, la pièce finale aurait était bien trop grande (environ 70 cm de long pour 25 de haut). Nous avons donc finalement réussi à obtenir le résultat escompté, comme si contre à droite de l'écran. Et bien entendu une fois les échelles des différents axes enregistrés, nous devions recommencer l'étape de découpage en différentes pièces partielles. Tout le découpage précédent, n'étant pas aux bonnes dimensions, n'a donc servi absolument à rien. Enfin, toujours est-il que la modélisation est terminée (si elle est fonctionnelle une fois imprimée), c'est déjà ça.

Cependant, le plus compliqué reste à venir... l'impression en 3D. En effet, ceci constitue la pièce la plus garnde que nous ayons jamais imprimé dans nos petites vie ! Le "car" fait en effet une taille de 46 cm de long, 18 de large et 20 de haut ! Ces dimensions risquent d'être une calamité à imprimer. Effectivement, il suffit de constater le pourcentage d'erreur lors d'une impression de petite pièce. La plupart du temps il faut s'y reprendre à une ou deux fois avant d'avoir une impression "parfaite", sans bavure, et fonctionnelle pour notre projet. Alors imaginez avec un bébé de cette taille ... Nous nous sommes rapproché du fabricarium pour imaginer les différentes possibilités d'impressions. Comme anticipé, la pièce est bien trop grande pour une impression en 1 fois, et cela serait trop risqué pour imaginer un perfect du premier coup. Nous en étions conscient et c'est pour cela que nous avons "découper" notre car en différentes pièces.

Nous avons réservé plusieurs crénaux pour utiliser les différentes imprimantes 3D, mais cela risque d'être très long. Cependant nous gardons bon espoir d'avoir imprimé toute nos pièces avant la fin de la semaine, on croise les doigts !

Mise à jour en fin de semaine : finalement la première impression à planté. Nous tentons de réimprimer l'arrière du bus dans la nuit de jeudi à vendredi. Nous verons par la uite quand les imprimantes sont disponibles pour faire de même avec les autres pièces. Cependant le temps d'impression est considérable... pour la face arrière du bus il faut compter pas moins de 14h d'impression. Et il en faut 18 pour l'avant du bus... Nous espérons que ces impressions seront possibles et seront réussies du premier coup. Dans le cas contraire nous risquons de gaspiller beaucoup de PLA...

Semaine 5 (4-8 Février)

Afin de ne pas trop perdre de temps en attendant la fameuse caméra grand angle, nous avons donc commencé à rédiger le rapport final. Bien que le projet soit loin d'être terminé, nous pouvons d'ores et déjà développer la premmière partie du rapport en expliquant les choix techniques par exemple.

Partie informatique

Dans l'attente de recevoir la caméra, nous avons décidé de prendre de l'avance pour avoir tous les outils à notre disposition lorsque nous serons en mesure de capturer de vraies images. Une des questions principales à résoudre est la quantité de données d'entraînement. En effet, le générateur peut nous fournir un jeu de 20 000 images en quelques minutes, mais il sera beaucoup plus difficile d'en produire 20 000 par nous-mêmes. En capturant une image par seconde pendant la conduite de la voiture, cela prendrait 5h30, en admettant que nous ne fassions aucune erreur de conduite. Il est donc essentiel de trouver des moyens pour "augmenter" artificiellement nos données. Nous avons donc écrit un code permettant d'appliquer diverses transformations aléatoires aux images, selon un système de calques totalement paramétrables. Ces transformations consistent en une variation du contraste et de l'exposition (simulant les variations de luminosité pendant la course), un cropping aléatoire dans l'image simulant un angle de vue légèrement différent, l'ajout d'un "obstacle" consistant en un rectangle noir à un endroit aléatoire de l'image et un ajout de bruit. Ces variations permettront, nous l'espérons, au réseau de mieux apprendre le concept général des images et de ne pas faire de sur-apprentissage sur le parcours précis de notre course.

Nous avons également continué d'expérimenter dans l'objectif d'améliorer les performances de notre réseau de neurones. Nous avons modifié les pré-traitements, le taux d'apprentissage, et avons tenté de l'entraîner sur des images en noir et blanc au lieu d'images en couleur. Dans chacun des cas, les résultats n'ont pas été améliorés, et l'entraînement ne convergeait en général même pas. Seule l'utilisation des vraies données nous apprendra si le problème vient de notre utilisation de Keras ou des données générées par le simulateur.

En fin de semaine, nous avons pensé à la façon d'entraîner la voiture. Afin de la conduire dans des conditions proches de la course réelle, il nous faut un endroit suffisamment grand et abrité pour pouvoir tracer une piste. Nous avons pensé au parking couvert du Stade Pierre Mauroy, qui est désert lorsqu'il n'y a pas d'événement et dont la surface nous permettrait de dessiner facilement à la craie. Cependant, nous n'aurons pas de moyen de brancher nos PC. Nous avons donc profité de la matinée du vendredi pour modifier l'application et la rendre utilisable sur mobile. Cela permettra de limiter l'utilisation des ordinateurs et donc d'améliorer leur autonomie. Nous espérons réussir à conduire la voiture pendant au moins une heure afin de récolter des données suffisantes.

Partie électronique

neon tunning Jacky Style

Pour ce qui est de la "partie élec", nous souhaitions simplement ajouté un néon sur notre voiture pour le faire un peu plus "tunning". Cet ajout nous aurait permis de gagner de précieux points lors des rassemblement Johnny-tunning de picardie. A noter que ce néon était normalement un néon de PC, abandonné dans notre réserve de matériel depuis plusieurs années. Malheureusement après avoir fini les soudures et fais le montage final, il s'avère que la raspi sort du 5V, et étant donné le faible niveau de lumière produit par le néon, celui ci doit sûrement nécessiter du 12v en entrée. Nous n'avons pas sous la main un élévateur de tension 5v-12v. Nous verrons si nous en achetons un par la suite, mais ce n'est clairement pas une priorité pour le moment.

Partie mécanique

Pour ce qui est de la partie méca, nous avons imprimé une pièce durant le week end (l'impression précédente ayant planté). Il s'agit de l'arrière du bus. Après 11 heures d'impressions nous avons la pièce correctement réalisée. Il a fallu la retravailler un peu car elle contenait de nombreux support-plateau, et ainsi il y avait beaucoup de bavures lorsqu'on hôtait ces derniers. Après avoir poli un peu le tout et gratté les imperfecctions, nous avons, nous espérons, la pièce finale pour le bout du bus. De plus, le PLA transparent pourrait nous donner un rendu très sympathique si nous couplons cette transparence avec un néon à l'intérieur du bus ! Il faudrait donc pour le bien, imprimer les autres pièces dans la même matière de PLA. Si ce n'est pas le cas il faudra sûrement donner un coup de peinture ou de bombe dessus, afin d'homogénéiser le tout.

Encore faut-il imprimer les autres pièces ! Pour se faire nous avons réservé la Dagoma du fabricarium jeudi soir (et ainsi la nuit complète) ainsi que samedi midi (et ainsi tout le week end également) En espérant que cela sera suffisant pour imprimer la suite des pièces. Nous aimerions ainsi disposer d'ici lundi du toit ainsi que de l'avant du bus. Nous pourrions donc consacrer notre dernière semaine à l'impression des deux faces latérales, moins épaisses et donc plus rapides à imprimer.

Semaine 6 (11-15 Février)

Au début de la sixième semaine, nous avons enfin reçu la caméra tant attendue ! Nous sommes donc débloqués et pouvons continuer d'avancer.

Partie informatique

Le placement de la caméra n'étant pas encore décidé, nous avons commencé la semaine comme nous avions fini la précédente, en écrivant des petits scripts de pré-traitement. En particulier, nous avons réalisé un script permettant d'inverser les images verticalement ou horizontalement, qui pourra s'avérer utile pour l'entraînement, soit pour doubler la taille du jeu d'entraînement soit pour harmoniser le sens des images entre le simulateur et les images réelles.

Le jeudi de cette semaine, le grand jour est enfin arrivé : nous avons conduit la voiture. Nous avons ainsi récolté énormément de données, qu'il faut maintenant pré-traiter avant de les donner à apprendre au réseau. Nous avons récolté environ 15 000 images, ce qui est une quantité tout à fait raisonnable et plus que nous l'espérions. Cependant, notre conduite a été loin d'être parfaite et le jeu de données contient beaucoup de déchet. La première étape devra donc être une vérification et validation manuelle de la totalité du jeu de données, ce qui sera prendra beaucoup de temps. En outre, il est possible que les micro-ajustements que nous avons faits pendant la conduite perturbent l'apprentissage, surtout que nous allions assez lentement et nos commandes ne seraient peut-être pas appropriées à une conduite à plus haute vitesse. Nous allons donc essayer d'utiliser ces données de façon brute, mais il est probable que nous devions tout étiqueter manuellement.

Préventivement, nous avons écrit un script permettant de tracer une ligne sur une image et de la convertir en une commande. Ce dernier pourra nous permettre de faire l'étiquetage assez rapidement, d'autant que nous n'avons pas besoin d'autant de données. La plupart des projets IronCar utilisent en effet des jeux de données de moins de 4000 échantillons, sachant que la mise en miroir nous permet déjà de doubler la taille de notre jeu. Nous pourrons donc nous contenter des images de meilleure qualité.

Le vendredi, nous nous sommes séparés les tâches de façon à explorer les deux possibilités évoquées plus haut. L'un d'entre nous a étiqueté manuellement certaines données (environ 3800 échantillons), tandis que l'autre a entrepris de valider manuellement les 15 000 et quelques échantillons totaux. En milieu de journée, nous avons eu le premier jeu de données étiqueté manuellement, et nous l'avons augmenté à l'aide de nos scripts de pré-traitement. En appliquant un effet de miroir vertical, puis en ajoutant des variations d'exposition, contraste et niveau de bruit, nous avons multiplié la taille du jeu de données par 8. Cela nous a permis de le diviser en un jeu d'entraînement de 25364 enregistrements et un jeu de validation de 5108 enregistrements. Nous avons lancé un premier entraînement...et les résultats ont été extrêmement impressionnants. Pour une métrique à +/-5, la précision est d'environ 90%, mais en passant à +/-8, elle augmente jusqu'à 98.7%, un résultat que nous n'avions jamais obtenu avec les données du simulateur. Par ailleurs, les valeurs aberrantes (> +/-20) sont tout simplement absentes, ce qui signifie que le réseau se trompe très peu sur l'interprétation des images.

Partie électronique

Partie mécanique

logo polytech et écriture modélisés

Nous expliquerons cette partie mécanique avec plus en détails dans le wiki de la semaine prochaine, les deux semaines étant dans la continuité l'une de l'autre.

Semaine 7 (18-23 Février) (Semaine de vacances)

Partie électronique

La semaine de vacances fut consacrée à la réalisation intégrale de la carrosserie de la voiture. En effet, nous avons profité du fait que le fabrication était presque désert (de part la période d'interruption scolaire) pour nous atteler à la tâche de réalisation de la coque du bolide. La première partie à été focalisé sur la suite et la fin de l'impression des pièces, ainsi qu’à la découpe dans du plexiglas, de ce qui nous servirait de vitre de fenêtres, par souci du détail et du réalisme, et également parce que ça nous amuse de découper au laser.

carrosserie totale
mise en peinture de la carrosserie


Une fois toute les pièces imprimées et ou découpées, encore fallait il les assembler. Pour cela, nous avons opté pour la bonne vieille colle extra forte à prise immédiate pour ce qui est de l'assemblage des différentes pièces de la coque. Le résultats d'impression n’étant pas parfait, certaines pieces étaient légèrement voûtées et ainsi, certaines faces censés être superposables ne l'étaient pas parfaitement. Nous avons alors renforcés les collages bancales avec des chutes de bois collé au pistolet à colle à l’intérieur de la carrosserie. Ce n'est pas très propre mais cette face intérieur n’étant pas destinée à être exposé au regard, cela ne pose pas de problèmes particuliers. Aussi, par souci du détails , nous avons pris l'initiative de corriger certaines imperfections avec de la patafix… on fait ce qu'on peux avec ce qu'on a comme on dit !

Une fois la carrosserie assemblée, nous lui avons donné un peu de vie en unifiant le tout d'un somptueux jaune canarie laqué ( vous l'avez ?! LOL), couleur originale légendaire des bus de ramassage scolaire dans le pays de l'oncle Sam. Le résultat des différents couche de peinture n'est pas parfait mais il donne tout de même un petit effet a ne pas piquer de cannetons (promis on arrête avec les blagues cette fois) !

fixation rudimentaire pour aimanter la carrosserie


Les carreaux des fenêtres sont un doux mélange d’encadrement, de collage, de fixation via patafix, etc… le tout ne bougez plus, c'est l'essentiel !

Enfin pour que la coque soit correctement décorée à l'effigie de l'école, nous avons modélisé et imprimé en bleu (le même que celui du réseau polytech), les lettres de P,O,L,Y,T,E,C et H. N'ayant pas les bonnes lettres pour écrire « vive la raclette », nous avons donc orné le bus de « POLYTECH ». Nous tenons à préciser que l’idée originale était de mettre des autocollants « Polytech Lille », de part et d'autres de la voiture pour simuler un sponsoring type « 4L Trophy » mais ces autocollants ont été jugés comme non adéquat par notre binôme (comprendre « moches ») Le logo de Polytech a également était désigné et Imprimer, mais il sera quand a lui positionné à l'avant du véhicule, servant ainsi de tuteur et de protection pare-choc à la caméra. Ce qui nous amène vers la fixation de cette fameuse caméra (on appréciera tout le talent des deux auteurs pour rendre les transitions de ce wiki aussi fluides et agréables). Alors, autant être honnêtes, c'est du bricolage ! « on penche encore un peu, un peu plus… oui voila, inclinaison parfaite » -> on badigeone de patafix pour que ça tienne et ça ira.


Une fois cette douce carrosserie assemblée, il fallait encore la joindre au reste de la voiture ! Nous avons donc utilisé un système d'aimant assez rudimentaire mais fonctionnel !

Semaine 8 (25 Février - 2 Mars)

Cette semaine étant consacrée aux passages des soutenances à partir du Mercredi, nous l'avons consacrée à la rédaction du rapport final ainsi qu'à la mise à jour du wiki.

Nous avons également préparé notre passage à l'oral pour la présentation.


Aussi avons nous construit une nouvelle piste pour entraîner notre voiture !

piste d'entraînement accompagné de son pilote exceptionnel
piste d'entraînement numéro 4, vue aérienne

Résultats et conclusion

Le prototype final est ainsi satisfaisant. Il est robuste, stable et propre.

De plus il est capable de s’orienter seul et de suivre la piste de manière autonome grâce à son entraînement. L’orientation des roues est en adéquation avec la courbure de la piste et la voiture cherche à rester réellement sur le centre de la piste. Toutefois, il est vrai que parfois, la voiture sort de piste sans que nous en sachions exactement la raison. Nous avons par exemple remarqué que les virages à 90◦ avaient tendance à poser des problèmes. Il faudra donc essayer d’améliorer l’entraînement avant la participation à la compétition IRONCAR.


Ce projet nous a permis de mettre en application et de nous familiariser avec certaines notions d’intelligence artificielle étudiées lors de semestres à l’étranger. Le machine Learning est un domaine qui nécessite beaucoup d’intuition, et cette intuition s’acquiert grâce à l’expérience. Ce projet nous permettra donc d’être plus performants sur d’éventuels travaux futurs. Il nous a également permis de consolider nos connaissances en informatique, en modélisation et en réalisation mécanique. Nous avons dû concevoir un système alliant chacun de ces domaines pour fonctionner en harmonie, et mettre en commun nos compétences pour optimiser notre efficacité. Nous savons que le projet sera probablement repris par d’autres groupes dans des années futures, et nous nous sommes efforcés de fournir un travail facile à reprendre et de communiquer avec les groupes en 4A et 3A. Nous espérons que notre travail servira de première brique aux futures victoires de Polytech Lille en compétitions IronCar. Enfin, nous avons pu, lors de ce PFE, mener intégralement un projet de ses fondements à sa présentation finale en passant par sa réalisation. Chacun de ces points est essentiel, puisque c’est ce que nous serons amenés à faire tout au long de notre carrière d’ingénieur.

Version Final de 4xCAR

Documents rendus

Rapport de projet : File:P44_IronCar.pdf

Lien du dépôt GitHub


Rapide Retour sur la course IRONCAR

Cette partie a été rédigée après la deadline de rendu des wikis, cependant nous trouvions essentiel de faire un rapide retour-bilan sur la course. La participation à cette course constituant l'étape finale de ce PFE, il parait judicieux d'en évoquer rapidement le déroulement.

Premièrement, comme nous nous en doutions, certaines règles pourtant écrite dans le réglement de l'ironcar avait était modifiées. Notamment la largeur des lignes blanches continues qui n'était plus que d'1 métre au lieu d'1m80, sans bande pointillée jaune au milieu. Les lignes étaient faites en scotch blanc, très fortement visibles. De plus le terrain était de sorte "tapis_moquette, avec différentes teintes (gris ou noir).

Les entraînements que nous avions donc fait n'était pas judicieux étant donné que les conditions avaient toutes de même beaucoup évolués. Aussi avons nous donc décidé de refaire un entraînement sur la piste de la compétition, et d'utiliser uniquement ce dataset (sans utilisé tous les entraînements que nous avions faits précédemment dans ce PFE). Les trois équipes participantes ont choisies de faire de même.

Un première essai fut décevant, la voiture "faisait le tour de la piste" en ignorant les virages serrés, en sortant donc de la piste, et en la réintégrant plus loin. Nous avons donc décidé de renflouer le dataset d'entraînements uniquement composés de virage serrés, pour "l'habituer" à cette particularité de parcours. Nous avions un jeu de donnée de environ 2500 images. Ce qui est peu, mais suffisant quand l'entraînement à lieu sur la même piste que la course. Une piste différente (avec des conditions de luminosité différentes et un parcours réordonné différemment) aurait sûrement donné des résultats bien moins convainquant. Notre voiture était en réalité sur-entrainée pour cette piste en particulier, mais le peu de temps disponibles pour habituer la voiture, ne nous permettait pas de faire autrement.

Aussi, il ne fallait réaliser que 2 tours au lieu de 3.


Finalement, (avec une certaine surprise, il faut l'admettre), notre voiture a finie première de la course, avec un premier tour en 46 secondes et un second en 45, avec seulement 3 sorties de pistes. Le fait de rajouter les entraînements des virages dans le dataset a été payant ! La voiture a fait une course plus qu'honorable pour une première participation à la course. Nous sommes satisfait du résultats obtenus et ceci est donc encourageant pour continuer à explorer le domaine de l'intelligence artificielle, que nous souhaitions découvrir concrètement, lors de la réalisation de ce PFE. Monsieur Vantroys était souriant après la prestation de la voiture, le contrat est rempli !


Nous avons donc transmis l'ensemble de nos travaux au binôme de 4A participant à d'éventuelles prochaines éditions de l'IRONCAR et leur souhaitons bonne chance dans l'élaboration de leur projet !

Participants à l'IRONCAR, le Samedi 16 Mars, à Polytech Lille