Scanner 3D NXT™

Mise à jour de la page : 3 juin 2009.
    
J.C. Tchang
Original Version
On Philo's Site
.

Je suis un auteur de pièces LDraw (Dixit Philo), et comme tel je me suis toujours intéressé à trouver de nouvelles façons de modéliser les pièces LEGO. Beaucoup de pièces ont une structure géométrique claire, et sont relativement faciles à créer, mais des pièces comme la grenouille représentée ci-dessus, n'ont pas de forme géométrique définie simple, et sont très difficiles à modéliser. J'ai joué avec l'idée d'un scanner 3D pendant quelques temps... La solution est venue avec les ensembles LEGO Technic de 2008, qui incluent une nouvelle pièce, l'actionneur linéaire. Cet élément convertit le mouvement de rotation d'un moteur, en mouvement linéaire. Associé avec l'encodeur NXT de haute précision, j'avais tous les éléments pour faire un scanner 3D, assez précis pour réaliser mon idée.

 

Description du dispositif

Ensemble des éléments, avec l'ordinateur portable récoltant les données.
Le scanner complet, montrant ses modules. Le module de palpage (rouge et jaune) déplace l'aiguille de palpage en arrière et en avant, aussi bien que de haut en bas. Lorsque la pointe de l'aiguille touche l'objet, la position du point de contact est enregistrée. Le module de maintient de l'objet (blanc et bleu) est capable de déplacer l'objet en arrière et en avant, et de le faire tourner. Tous les mouvements combinés permettent d'avoir un scanner aussi bien cartésien que cylindrique. L'assemblage (en noir) entre les deux modules permet d'assurer leur liaison.
Vue de côté du module de maintien. Le moteur arrière pilote un actionneur linéaire qui déplace le chariot porte-objet. Le moteur est directement accouplé avec l'actionneur pour minimiser le jeu des pignons. Le chariot porte un plateau tournant, actionné par un second moteur, par l'intermédiaire d'une vis sans fin sur la couronne dentée. Notez la présence de deux couronnes empilées, pour éviter un vacillement de l'ensemble causé par le jeu mécanique.
Vue de dessus du module de maintien. Bien que le scanner décrit ici utilise 4 moteurs, seulement 3 sont utilisés en même temps, suivant le style de scan. En conséquence, un seul NTX est exigé pour piloter le scanner.
Si vous décidez d'utiliser uniquement un scanner cartésien (mouvements X-Y-Z), alors l'ensemble plateau tournant avec le 4ème moteur peut être supprimé, et remplacé par un simple support. De toute façon, je n'ai pas écrit la partie logicielle pour le scanner à mouvement cylindrique !
Système plateau tournant vu de l'arrière.
L'objet est fixé sur le plateau tournant par tout moyen convenable de plate, connecteur, brique, etc...
Le module de palpage. Deux actionneurs linéaires sont utilisés ici, également pilotés directement par des moteurs NXT. Des axes glissant dans des trous de pièces Technic sont utilisés pour guider précisément les mouvements.
Vue de dessus, montrant le chariot de palpage. L'aiguille est la seule pièce non-LEGO. Elle est collée dans un trou foré dans un axe Technic de longueur 2, et doit être la plus pointue possible pour limiter le glissement sur l'objet. Attention à vos doigts !!!
Voici une vue grossie sur les pointes de palpage que j'ai crées pour ce projet. La version du bas utilise une épingle ordinaire. J'ai ensuite évolué vers la version du haut, meilleure, utilisant une aiguille de machine à coudre, plus rigide. Son acier, et sa forme à la base, la rend plus raide, rendant le système plus précis.
Détail du palpeur. L'aiguille est montée sur un axe, qui est maintenu en place par un élastique très souple. Lorsque l'aiguille touche l'objet, l'axe recule un petit peu, et des cylindres noir et blanc (Technic Pin Joiner Round 75535) se déplacent devant le capteur lumineux. Cela permet de détecter le contact avec une très petite force appliquée sur l'objet (et en conséquence l'objet n'est pas marqué par l'aiguille). Notez l'usage d'un câble de liaison Mindsensors Flexi-Cable pour connecter le capteur lumineux. Bien que raisonnablement rigide, l'ensemble chariot porte-aiguille fléchit lorsqu'un câble ordinaire plus raide est utilisé.
Cet assemblage est utilisé pour attacher les deux modules ensemble. Il peut être facilement modifié, pour s'adapter aux différentes tailles d'objets scannés.
Les modules configurés en position de scan cylindrique. Je n'ai cependant pas encore écrit le programme nécessaire pour ce type de configuration de scanner.
Scanner une pièce peut être très long (plusieurs heures). Pour soulager mes batteries, j'utilise mon adaptateur secteur NXT supply adapter. Bien sûr, vous pouvez également utiliser les batteries LEGO NXT Li-ion avec leur propre adaptateur.
Affectation des ports NTX

 

Vidéo

 

Questions diverses

Bien que le résultat soit plutôt convainquant, il reste quelques questions :

 

Construction du scanner

Pas (encore) d'instructions de construction, mais voici les fichiers MLCad complets incluant les pièces non officielles.

 

Programmes

Ce projet nécessite de remonter beaucoup de données au PC, beaucoup plus que la mémoire disponible dans un NXT. En conséquence, une connexion permanente est nécessaire. Comme je ne voulais pas écrire de code coté PC, je me suis tourné vers pbLua. Ce système communique avec le PC serveur à travers un port série virtuel, via une connexion USB ou Bluetooth. Obtenir les données du scanner est donc simple : NXT "imprime" (envoie) les coordonnées des points vers la console, et un programme d'émulation de terminal (j'ai utilisé TeraTerm et Putty) renvoie les données reçues dans un fichier. Vous pouvez également utiliser pbLua avec la récente introduction de "Xmodem" pour envoyer les données à l'ordinateur serveur.

Les données sont envoyées en utilisant le format de fichier 3D ASCII ".obj", consistant simplement en triplets de coordonnées 3D, précédés de la lettre v. Exemple : v -5.000000 -8.500000 24.041666. Après la fin du scan, utilisez un éditeur de texte pour nettoyer le fichier, en supprimant les messages de la console avant et après les données du scan. Sauvegarder le résultat dans un fichier ayant .obj comme extension.

 
Programme "Scan Setup". Envoyer ce programme dans la console pbLua, puis exécuter la fonction Setup(). Un menu est ensuite affiché sur l'écran NXT, suivez le pour paramétrer les trois limites du scan, et initialiser la sensibilité du capteur lumineux. A la fin du processus, toutes les fonctions inutiles sont supprimées de la mémoire, laissant la place à la fonction de scan.
Programme "ScanXY". Envoyer ce programme dans la console pbLua, puis lancez l'émulation du terminal pour rediriger les données, et ensuite exécutez la fonction ScanXY(dx, dy). dx et dy définissent la résolution du scan, exprimé en pas moteur : 96 pas = 0.4 mm = 1 LDU (unité LDraw). ScanXY(48,48) effectue un scan dans une grille de résolution de 0.2 mm.
Nota : "Scan Setup" DOIT avoir été exécuté avant de lancer le scan !

Naturellement ces programmes peuvent être installés dans une mémoire flash NXT (voir le tutoriel en anglais). Attention : Le programme "Scan Setup" est trop gros pour être chargé dans la mémoire NXT en une fois. Vous devez le faire en deux étapes (voir un exemple ici).

 

Reconstruction 3D

Après avoir scanné (palpé) tous les côtés de votre objet, il est nécessaire de transformer toutes ces longues listes de coordonnées en un joli modèle 3D virtuel. MeshLab (un outil développé avec le soutient de Epoch NOE) est un système extensible, portable, et ouvert (open source) pour le traitement et l'édition de maillages triangulaires non structurés. Voici ci-dessous un pas à pas du processus de reconstruction. Les copies d'écran et descriptions sont basées sur la version Alpha de MeshLab 1.2 (MeshLabSetup_v120ALPHA_2009_02_08). J'ai choisi cette version car elle supporte la version texte du format stl, nécessaire pour utiliser l'utilitaire de conversion LDraw stl2dat. Notez que je ne suis PAS un expert en 3D, et il peut y avoir des moyens plus faciles ou plus efficaces pour faire cela.

Ce fichier : frog.zip (917 ko) contient plusieurs exemples, à différentes étapes du processus.

Importez le fichier .obj dans MeshLab. Le fichier doit contenir uniquement des points, et MeshLab passe alors en mode affichage (cercle rouge).
Exemple : FrogSide.obj.
Nous ajoutons maintenant des triangles sur le squelette de points. Pour faire cela, nous appliquons un filtre de reconstruction : Filters > Remeshing, simplification and reconstruction > Ball Pivoting Surface Reconstruction. Les options par défaut donnent un bon résultat, il suffit donc de cliquer sur "Apply", et de fermer le fenêtre des filtres. Le maillage triangulaire n'est pas visualisé, sauf si vous choisissez le mode approprié "flat lines", entouré en rouge.
Nous allons maintenant nettoyer le maillage des parties inutiles, principalement le plan de base. Utilisez l'outil de sélection (entouré en rouge) sur les parties à enlever. En plus du plan de base, essayez d'enlever les zones ou la direction de l'aiguille de palpage était presque tangente avec la surface de l'objet (comme l'aiguille glisse dans ces zones, les coordonnées des points sont très imprécises). Vous pouvez utiliser la touche "Ctrl" pour ajouter une sélection, "Maj" (Shift) pour enlever une sélection, et la touche "Echap" (Esc) pour passer alternativement du mode sélection au mode orientation/navigation dans l'espace. Notez que la sélection opère sur tous les triangles sous le curseur, même les faces cachées sous une autre.
En appuyant sur la touche "Suppr" (Del) tous les triangles sélectionnés sont supprimés. Notez que j'ai intentionnellement laissé le dessus de la brique 1 x 1 sous la grenouille, pour aider à l'assemblage des divers éléments. Sauvegardez le résultat au format .ply (Exemple : FrogSide.ply). Procédez de la même façon avec tous les scans de la grenouille (FrogTop.obj, FrogFront.obj, FrogBack.obj) pour obtenir tous les maillages (FrogTop.ply, FrogFront.ply, FrogBack.ply). Notez que seule la moitié de la grenouille (elle est symétrique) a été scannée pour gagner du temps.
Nous allons maintenant aligner proprement toutes les parties scannées. Meshlab a des fonctions automatiques d'alignement, mais elles ne paraissent pas fonctionner correctement dans notre cas de figure, probablement parce qu'il y a un petit chevauchement entre les différents fichiers. Donc, je vous montrerai la méthode entièrement manuelle. J'ai préparé un fichier 3D de la brique 1 x 1 (convertie à partir de LDraw en utilisant 3dto3d). Il sera utilisé pour ancrer la grenouille dessus. Ouvrez le fichier de la brique (brick1.ply), puis le côté de la grenouille (FrogSide.ply) sur une nouvelle couche (Layer) avec : File > Open as new layer. Puisque les scans ont été faits suivant des directions cartésiennes, il est facile de tourner le côté de la grenouille par pas de 90° autour des axes principaux, pour obtenir la bonne orientation. Chargez le filtre "Apply Transform" avec : Filters > Normal, Curvature and Orientation > Apply Transform. Dans la boite de dialogue qui s'ouvre, cochez "Relative Transformation mode", "Rotate", fixez l'angle à 90° et choisissez l'axe de rotation (ici : Y).
Lorsque vous êtes satisfait du résultat, fermez la fenêtre "Apply Transform", puis effectuez vos transformations avec : Filters > Normal, Curvature and Orientation > Apply Transform > Freeze Current Matrix. Notez que "Apply Transform" a un bouton "Close and Freeze" qui ferait les deux opérations, mais c'est malaisé à utiliser en mode relatif, puisque nous appliquons plusieurs fois la transformation avant de figer la position.
Le côté de la grenouille est maintenant orienté correctement, mais pas à la bonne position. Alors que nous pourrions utiliser le mode déplacement de "Apply Transform", il est plus simple d'utiliser une méthode interactive, et donc nous allons utiliser l'outil d'alignement. Lancez l'outil d'alignement (icone A jaune de la barre d'outils), cliquez sur le côté de la grenouille dans la liste des couches (Layers list), puis sur le bouton "Manual Rough Glue".
Vous pouvez maintenant aligner le côté de la grenouille avec la brique. Utilisez la touche "Ctrl" + la souris pour déplacer le côté de la grenouille. Notez que si vous oubliez d'appuyer sur la touche Ctrl, vous faites tourner la couche, ce qui n'est pas désiré ici.
Vous pouvez presser la touche "Echap" pour changer de point de vue, et de nouveau sur "Echap" pour revenir en mode alignement. Lorsque vous avez fini d'aligner, cliquez sur le bouton "Store Transformation" de la fenêtre "Alignment", puis appliquez la transformation au maillage avec : Filters > Layers Management > Freeze Current Matrix. Sauvegardez le fichier (FrogSide-b.ply).
Maintenant, ajoutez les autres parties de la grenouille, un par un, et exécutez sur eux les mêmes étapes de rotation et déplacement (FrogBack.ply, FrogFront.ply, FrogTop.ply). N'oubliez pas de figer les matrices de transformations, et de sauvegarder chaque couche en cours de route (FrogBack-b.ply, FrogFront-b.ply, FrogTop-b.ply). Utilisez la boite de dialogue des couches (icone "stack of sheets") pour suivre où vous en êtes. Notez que vous pouvez sauvegarder uniquement une couche à la fois. La moitié de la grenouille est maintenant prête...
La brique est maintenant inutile. Sélectionnez la dans la boite de dialogue des couches, et cliquez sur le bouton "-". Vous pouvez maintenant fusionner toutes les couches en une seule avec : Filters > Layer management > Flatten visible layers. Puis, sauvegardez le résultat (frog-half.ply).
Maintenant nous avons besoin de l'autre moitié de la grenouille, créée par miroir. Appliquez une symétrie avec : Filters > Normal, Curvature and Orientation > Apply Transform. Une boite de dialogue s'ouvre, et cochez "Relative Transformation mode", "Scale" et fixez l'échelle en X à la valeur -1, puis cliquez sur le bouton "Close and Freeze". Le second côté de la grenouille est réalisé, mais il apparait sombre... C'est parce que l'opération de symétrie ne change pas le sens des facettes. Pour corriger cela, utilisez le filtre : Filters > Normal, Curvature and Orientation > Invert Faces Orientation. Puis, sauvegarder le résultat (frog-half-sym.ply).
Ré-ouvrez la première moitié de la grenouille dans une nouvelle couche, fusionnez le résultat avec : Filters > Layer management > Flatten visible layers, puis sélectionnez et supprimez le dessus scanné de la brique support. Assurez-vous d'utiliser le bouton "Delete faces and surrounding vertices" (icone entourée), Puis, sauvegarder le résultat (frog-raw.ply).
La grenouille encore à l'état brute, n'est pas faite d'un seul et simple maillage de triangles sur une surface "tendue". Il est nécessaire de créer une nouvelle forme à partir de la version brute, avec un algorithme de reconstruction, suivant la méthode de Poisson, en utilisant le filtre : Filters > Remeshing, simplification and reconstruction > Poisson reconstruction. Cela crée une nouvelle couche. Cachez la couche contenant la version brute en cliquant sur l'icone en forme d'œil dans la boite de dialogue "Layers", et admirez le résultat ! Comme vous pouvez le voir, cette reconstruction a aussi filtré le "bruit de scan" (arrondi les imprécisions de mesure). Fichier résultat : frog-final.ply. Comme nous avons un très bon utilitaire (stl2dat) qui convertit le format stéréo-lithographique (.stl), utilisé entre autres par SolidWorks, en format LDraw, nous sauverons notre résultat final comme frog-final.stl. Pensez à décocher "binary encoding" (encodage binaire), car stl2dat gère uniquement les fichiers encodés en mode texte.

Le fichier LDraw 33320.dat, que j'ai soumis au LDraw parts tracker a encore nécessité de :

  • Couper la pièce en 2 pour réduire la taille du fichier final (fichier s\33320s01.dat).
  • Découper le dessous pour obtenir une base plane.
  • Ajouter un trou de tenon dans la base.
  • Remplacer la bosse formant les yeux, trop arrondie, par un cône et une portion de sphère pour donner plus de caractère à la grenouille. Le pas de scan n'a pas été assez fin, pour saisir ces minuscules petits détails.
  •  

    Une autre pièce scannée, avec le rat 40234.
    La queue a été ajoutée manuellement.

     

    Droits et Copyright

    Cette méthode et son manuel d'utilisation a été écrit par (c) Philo (Philippe Hurbain).

    Vous pouvez le retrouver sur son site et sa page des utilitaires LDraw, et sur la version d'origine en anglais de cette page.

    Traduction et Adaptation : J.C. Tchang.