CNC DVD : avancement du 11 Février 2013

La présentation initiale de ce projet est disponible ici, avec des photos.

Voici ce qui s’est passé cette semaine:

  • J’ai reçu les composants L293 commandés sur ebay, merci au vendeur nanopunk.
  • J’ai beaucoup cherché et réfléchi sur le coté logiciel de l’affaire.
  • J’ai ensuite commencé à programmer le firmware de la machine, qui reçoit les instructions du PC et pilote les moteurs de la machine.

Le coté logiciel

Coté conception, il semble que je vais travailler avec Inkscape, le fameux logiciel libre de dessin vectoriel. Il est capable de produire des dessins vectoriels constitués de courbes, de lignes complexes, et dispose de nombreuses aides à la conception.

Le pilotage de la machine elle même se veut relativement compatible avec les autres projets de CNC, et il utilisera donc le fameux format “G-code” (RS274)  qui sert aussi de base aux fichiers GERBER bien connus dans le domaine de l’électronique. Dans ce format, la machine est connectée par un port série au PC, et reçoit des commandes ASCII composées de lignes de texte. On peut donc ainsi écrire un programme dans un fichier texte, puis l’envoyer à la machine.

Un plugin inkscape est disponible pour faire ces conversions: Gcodetools. Il est disponible librement, dispose d’un forum de suivi et d’un développement actif. Quelques essais m’ont convaincu de ses capacités, il est capable de piloter une graveuse XY avec déplacement de la broche selon Z, ce qui permet de graver des “montagnes” et de découper des pièces selon deux dimensions.

Ma machine n’utilisera pas une broche rotative mais un laser. Cela signifie que je n’ai pas à me préoccuper des variations de l’axe Z, mais seulement d’allumer et d’éteindre le laser au bon moment. Un essai rapide m’a convaincu que je n’avais pas tout à fait bien compris: En effet, le fichier gcode généré par le plugin démarre la broche au début de son fichier résultat et ne l’arrête qu’à la fin, et elle n’est jamais interrompue. Ceci est dû au fait que les phases de coupure et de déplacement sans coupure sont liées à la valeur de l’axe Z… La surface supérieure de la pièce à graver est considérée comme le plan de référence Z=0, les déplacements sans coupure se font tous avec un Z positif, et les déplacements qui coupent se font en pilotant la machine dans les Z négatifs. Je dois donc piloter mon laser selon la valeur de Z! Voici ce que j’ai décidé:

  • M3 (démarrage de la broche) allumera le laser à son courant minimum;
  • M5 (arrêt de la broche) éteindra le laser;
  • Les valeurs négatives de Z passeront le laser à sa puissance maximum (coupure);
  • Les valeurs positives de Z passeront le laser à sa puissance minimum (déplacement visible).

Pilotage de la machine

Le pilotage de la machine se fera donc grâce à des commandes au format G-code, interprétées par un firmware. J’aurais pu choisir le logiciel LinuxCNC (anciennement EMC2), qui interprète lui même le G-code et pilote des moteur/capteurs par port parallèle, mais cette solution est encombrante, nécessite un PC linux (ou un raspberry pi) et des extensions temps réel, et n’est pas facilement utilisable avec un ordinateur portable sans port parallèle.
J’ai commencé à développer une carte électronique capable d’interpréter le G-code. Je me suis basé sur un PIC18F4685 de Microchip, car ce microcontrôleur dispose de 32 entrées/sorties, 3,5k de RAM et surtout de 96k de flash, ce qui permet d’écrire un programme confortable. Ce PIC va piloter:

  • deux moteurs pas à pas via des circuits L293D (pins A1,A2,B1,B2,enable)
  • 4 capteurs fin de course (2 par axe) switchés à la masse, avec pull-up et condensateur de debounce
  • 1 sortie PWM pour piloter le laser
  • un port série pour la communication avec le PC

Il reste encore beaucoup d’E/S disponibles, si je veux ajouter un moteur d’axe Z (par exemple, pour contrôler la focalisation du laser) ou pour un afficher LCD. Je ne bufferise pas les commandes, mais je les exécute dès leur réception. Quand elles sont terminées le firmware retourne la chaine “ok”, ou “!!” suivi d’une description en cas d’erreur. Le code ok peut également être suivi d’informations supplémentaires pour les commandes d’état.

L293 chips
des circuits L293
cnc_ctl board
La carte cnc_ctl
board in place
La carte en situation

Le G-code

Détaillons un peu ce qu’est le G-code.

Une commande G-code est composée d’un groupe de définitions de variables composée d’une lettre suivie d’un nombre. Chaque lettre représente une “variable” définissant l’état souhaité de la machine.

  • La lettre G signale une commande générale de la machine (la plupart du temps, un déplacement).
  • La lettre M signale une commande accessoire (changement de paramètres, activation de l’arrosage/ventilateur, démarrage/arrêt de la broche, retour d’infos, etc).
  • Les lettre X,Y,Z signalent les valeurs de déplacement à effectuer. Dans des machines plus complexes, on a d’autres axes, par exemple U,V,W, et A,B,C.
  • F est le feedrate, la vitesse de déplacement, utilisée avec certaines commandes
  • P et S signalent divers paramètres
  • N est le numéro de la ligne, utilisable en cas d’erreur pour demander au PC de renvoyer une ligne.

En général une commande doit absolument contenir un M ou un G, mais pas les deux en même temps. En tout cas, c’est un besoin pour mon contrôleur, même si j’ai déjà vu des exemples de commandes plus complexes.

Les principales commandes de déplacement  sont G0 et G1.

G0 est un déplacement rapide utilisé quand l’outil est inactif. On doit spécifier les coordonnées X et Y de la destination souhaitée en millimètres. La machine pilote les axes dans la direction souhaitée pour atteindre la destination le plus rapidement possible. Il est possible qu’un axe termine son déplacement avant l’autre.

G1 est un déplacement linéaire synchronisé, à vitesse contrôlée. On spécifie également les coordonnées de la destination, et le firmware pilote les moteurs pour que les deux axes arrivent à destination au même moment en respectant la vitesse linéaire programmée. Pour que G1 fonctionne, il faut indiquer sur la même ligne ou avant un “feedrate” (variable F), c’est à dire une vitesse de déplacement. Note: le firmware des machines Reprap interpole aussi le feedrate pour que les extrusions soient plus régulières, alors que ce n’est pas le cas de mon programme, au moins pour l’instant.

Les coordonnées indiquées pour la destination peuvent être absolues (dans ce cas elles indiquent les véritables coordonnées du point souhaité) ou relatives (décalages par rapport au point de départ). Ceci est spécifié par les commandes G90 et G91, qui n’ont pas besoin de paramètres. Les unités indiquées pour les valeur d’axes peuvent être en millimètres (G21) ou en pouces (G20).

Il est utile de pouvoir caler les axes sur leur point de départ, représenté par la valeur zéro. Pour cela la commande G28 pilote les axes rapidement vers les fins de courses, tant que ceux ci ne sont pas enclenchés. Ensuite les axes sont légèrement reculés, puis remis au contact des fins de course à vitesse lente. C’est la procédure de “homing”, ou positionnement à l’origine.

Il existe des commandes (G2 et G3) pour faire des arcs sans avoir à définir des facettes rectilignes. Ces commandes prennent les coordonnées du centre (paramètres I et J) en plus des coordonnées du point d’arrivée, et tracent un arc de cercle dans le sens des aiguilles d’une montre (G2) ou inverse (G3). Ces commandes sont assez complexes et pour l’instant je ne m’en occuperai pas, mais je les implémenterai à terme.

Les commandes M utiles sont les suivantes:

  • M115 affiche la version du firmware (ok cnc_ctl 1.0 http://www.openmakersdaily.org)
  • M114 affiche la position actuelle (ok C: X:— Y:—)
  • M3 démarre le laser à la puissance minimale (c’est la valeur de Z pour les commandes G1 qui changera sa puissance)
  • M5 arrête le laser
  • M2 et M30 arrêtent la machine et réinitialisent tous les paramètres par défaut

Normalement les commandes G acceptent aussi des commentaires (entre parenthèses) mais pour le moment je ne les gère pas. Ce sera pour plus tard!

Voici un exemple de programme dessinant un carré de 10 mm de coté à 20mm de l’origine:

G90 (mode absolu)
G21 (unités en mm)
G28 (se mettre à l'origine)
M3 (allumer le laser) 
G0 X20 Y20 (se déplacer au premier coin) 
G1 Z-1 (commencer a graver) 
G1 F60 X30 (se déplacer au point X=30 à 60mm/minute=1mm/sec - Y reste à 20) 
G1 Y30 (se déplacer au point Y=30 (même vitesse, même abscisse) 
G1 X20 Y30 (se déplacer au point X=20,Y=30, la variable Y30 n'a aucun effet) 
G1 Y20 (revenir au point de départ) 
G1 Z1 (laser faible puissance) 
G28 (revenir a l'origine) 
M5 (éteindre le laser) 
M2 (arrêt machine et reinitialisation paramètres)

En mode relatif, on écrirait:

G91 (mode relatif)
G21 (unités en mm)
G28 (se mettre à l'origine)
M3 (allumer le laser)
G0 X20 Y20 (se déplacer au premier coin)
G1 Z-1 (commencer a graver)
G1 F60 X10 (se déplacer au point X=30 à 60mm/minute=1mm/sec - Y reste à 20)
G1 Y10 (se déplacer au point Y=30 (même vitesse, même abscisse)
G1 X-10 Y0 (se déplacer au point X=20,Y=30, la variable Y30 n'a aucun effet)
G1 Y-10 (revenir au point de départ)
G1 Z2 (laser faible puissance)
G28 (revenir a l'origine)
M5 (éteindre le laser)
M2 (arrêt machine et reinitialisation paramètres)

Détails d’implémentation

Le logiciel est écrit en C, et compilé à l’aide de SDCC et de gputils, deux projets libres. J’édite le code avec Code::Blocks. Le code PIC généré par SDCC est bien moins efficace que celui du compilateur Microchip, mais ce compilateur a le mérite d’être disponible plus facilement. Le PIC choisi a suffisamment de mémoire pour tolérer un code sous-optimal 😉

Les moteurs de DVD sont apparemment des modèles 20 pas par tour, je peux donc obtenir une résolution de 40 pas par tour en mode demi-pas. La vis en laiton a un pas de 3mm, ce qui me donne une résolution de 3/40=75 microns. Plus tard, je testerai un driver microstep pour augmenter encore cette résolution. Un millimètre représente donc 13,3333 pas, ce qui n’est pas réalisable de manière exacte. Pour cette raison je ne vais pas gérer les positions internes en millimètres, mais en pas. La position courante et finale de chaque axe est représentée en pas, ce qui me permet de travailler avec des nombres entiers représentant des positions exactes. La position reportée par M114 est recalculée en unités réelles (mm ou inch) à partir des positions courantes en pas.

Le parseur de G-code fonctionne en analysant les chaines de caractères reçues à la recherche du format suivant:
-un nombre quelconque de caractères non-variables
-un caractère de variable (FGMIJPXYZ)
-jusqu’a 15 caractères numériques
-optionnellement, un point suivi d’autres caractères numériques définissant la partie fractionnaire du nombre (seules les 4 premières décimales sont converties).
Chaque variable reconnue est stockée dans un élément de tableau indiquant:

  • la partie entière du nombre (prenant éventuellement en compte les chiffres après la virgule)
  • le diviseur (puissance de 10) permettant de calculer les chiffres après la virgule
  • un flag indiquant si la variable a été définie sur la ligne

De cette manière, X13 stocke (13;1) dans la variable, et 12.345 stocke (12345;1000). On a donc une représentation décimale exacte des nombres non entiers.
On peut donc stocker des nombres de -214748.3648 à + 214748.3648 ce qui permet de représenter 400 mètres de long avec une résolution de 0.1 micron!

Une fois la ligne parsée, on vérifie que G ou M a été défini, puis on exécute les actions correspondant à la commande souhaitée.

Pour gérer les déplacements, j’utilise une machine à état dans la boucle principale du commande, qui s’exécute à chaque fois qu’une commande complète a été traitée:

  • Quand il n’y a rien à faire, on est dans l’état MODE_IDLE. On attend simplement que d’autres caractères soient entrées, et quand un retour chariout est reçu, on parse cette commande.
  • Quand on a parsé correctement une commande G0, on passe dans l’état MODE_LIN_FAST. dans ce mode, la position courante est comparée à la position cible, et on pilote les moteurs dans le bon sens, à leur vitesse maximum, tant que la position courante est différente de cette position cible. Pour le moment les moteurs ne sont pas vraiment actionnés, mais j’affiche un commentaire. Quand le nombre de pas requis est réalisé, on affiche OK et on attend d’autres commandes.
  • Quand on a parsé une commande G1, on passe à l’état MODE_LIN_RATE. On calcule la vitesse nécessaire sur chaque axe en fonction des parcours à réaliser et de la vitesse linéaire souhaitée. On en déduit le délai entre chaque pas, puis on se comporte comme le mode LIN_FAST jusqu’à ce que la destination soit atteinte, mais on attend un délai particulier entre chaque pas.
  • Quand on a parsé une commande G28, on passe à l’état MODE_HOMING_START. Dans ce mode, on fait tourner chaque moteur à grande vitesse jusqu’à ce qu’on touche les contacteurs de fin de course. Quand c’est fait, on passe en mode MODE_HOMING_RETRACT qui fait tourner les axes à faible vitesse jusqu’au relâchement des contacteurs. On passe ensuite en MODE_HOMING_FINAL qui reprend le contact avec les fins de course à vitesse réduite. Ensuite on affiche le OK et on passe en MODE_IDLE.

Voici un exemple d’exécution de quelques commandes G0 qui montre les déplacement prévus, et le fait qu’un axe se termine avant l’autre si on leur demande des déplacements différents:

M114
ok C: X:0 Y:0
G0 X0.5 Y1
// frac!
// f_nlen=01
// div=10
// mult=0
// total=5
// crt_x=1 crt_y=1
// crt_x=2 crt_y=2
// crt_x=3 crt_y=3
// crt_x=4 crt_y=4
// crt_x=5 crt_y=5
// crt_x=6 crt_y=6
// crt_x=6 crt_y=7
// crt_x=6 crt_y=8
// crt_x=6 crt_y=9
// crt_x=6 crt_y=10
// crt_x=6 crt_y=11
// crt_x=6 crt_y=12
// crt_x=6 crt_y=13
// tgt_x=6 tgt_y=13
ok
M114
ok C: X:6 Y:13
G0 X0
// crt_x=5 crt_y=13
// crt_x=4 crt_y=13
// crt_x=3 crt_y=13
// crt_x=2 crt_y=13
// crt_x=1 crt_y=13
// crt_x=0 crt_y=13
// tgt_x=0 tgt_y=13
ok
M114
ok C: X:0 Y:13
G0 Y0
// crt_x=0 crt_y=12
// crt_x=0 crt_y=11
// crt_x=0 crt_y=10
// crt_x=0 crt_y=9
// crt_x=0 crt_y=8
// crt_x=0 crt_y=7
// crt_x=0 crt_y=6
// crt_x=0 crt_y=5
// crt_x=0 crt_y=4
// crt_x=0 crt_y=3
// crt_x=0 crt_y=2
// crt_x=0 crt_y=1
// crt_x=0 crt_y=0
// tgt_x=0 tgt_y=0
ok
M114
ok C: X:0 Y:0

On voit que pour le moment, M114 indique la position courante en nombre de pas et non en millimètres 🙂

cnc_dvd 1.0 sur putty
Exemple de communication sur PuTTY

A venir

Je vais maintenant repasser en mode “électronique” pour terminer le pilotage des moteurs. Il me faut câbler les circuits L293, les moteurs, et les contacts de fin de course. Cela me permettra de tester les commandes de déplacement et de retour à l’origine.

 

La présentation initiale de ce projet est disponible ici, avec des photos.