// --- Programme Arduino ---
// Auteur du Programme : Xavier HINAULT - Tous droits réservés - Licence GPL v3
// Programme écrit le : 02/2015 MAJ : 04/2015
// www.mon-club-elec.fr
// github du projet : https://github.com/sensor56/Simple-GCode-Decoder
// exemple d'utilisation : www.mon-club-elec.fr/openmakermachine
// initié d'après : https://www.marginallyclever.com/blog/2013/08/how-to-build-an-2-axis-arduino-cnc-gcode-interpreter/
// ------- Licence du code de ce programme -----
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// //////////////////// PRESENTATION DU PROGRAMME ////////////////////
// -------- Que fait ce programme ? ---------
/*
* Ce programme est un décodeur de GCode simplifié pour machine 3 axes de base
* /
// -------- Circuit à réaliser ---------
/*
* broches STEP des étages moteurs sur les broches STEP
* broches DIR des étages moteurs sur les broches DIR
* /
// /////////////////////////////// 1. Entête déclarative ///////////////////////
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles...
// --- Déclaration des constantes ---
// --- Inclusion des librairies ---
// --- Déclaration des constantes utiles ---
// --- Déclaration des constantes des broches E/S numériques ---
// --- Déclaration des constantes des broches analogiques ---
// --- Déclaration des variables globales ---
/*
int octetReception=0; // variable de stockage des valeurs reçues sur le port Série
long nombreReception=0; // variable de stockage du nombre reçu sur le port Série
long nombreReception0=0; // variable de stockage du dernier nombre reçu sur le port Série
String chaineReception=""; // déclare un objet String vide pour reception chaine
*/
#define VERSION (0.2)
//--- config générale ---
#define BAUD (115200) // debit de communication
#define MAX_BUF (64) // taille max du buffer de reception serie
#define VERBOSE 1 // pour messages
//--- vitesse de deplacement --- // en (mm/sec)
#define MAX_FEEDRATE (100.0) // vitesse maximale
#define MIN_FEEDRATE (0.1) // vitesse minimale
//-- params moteurs
#define X 0
#define Y 1
#define Z 2
#define STEPS_PER_TURN (200) // pas par tour du moteur
#define MICROSTEPS_MODE (16) // mode micropas utilisé
#define MM_PER_TURN 1.25 // mm par tour - fonction pas de vis - M6 : 1mm | M8 : 1.25mm
#define PULSE_US 5 // largeur du pulse moteur en µs
//-- params mouvements
#define X_STEPS_PER_MM (STEPS_PER_TURN*MICROSTEPS_MODE/MM_PER_TURN)
#define Y_STEPS_PER_MM (STEPS_PER_TURN*MICROSTEPS_MODE/MM_PER_TURN)
#define Z_STEPS_PER_MM (STEPS_PER_TURN*MICROSTEPS_MODE/MM_PER_TURN)
// limites mouvements en mm
#define X_MAX_POS 200
#define X_MIN_POS 0
#define Y_MAX_POS 200
#define Y_MIN_POS 0
#define Z_MAX_POS 200
#define Z_MIN_POS 0
// chaque moteur est controlé par
// > une broche de pulse : front montant déclenche pas suivant
// > une broche de dir : fixe le sens du moteur
//--- identifiant X,Y,Z pour indices tableaux
#define x (0)
#define y (1)
#define z (2)
//-- broches de pulse moteur
/*
const int X_STEP=2;
const int Y_STEP=3;
const int Z_STEP=4;
*/
int pin_STEP[3]={2,3,4}; // les broches de step des moteurs X,Y,Z
//-- broches de sens moteur
/*
const int X_DIR=5;
const int Y_DIR=6;
const int Z_DIR=7;
*/
int pin_DIR[3]={5,6,7}; // les broches de direction des moteurs X,Y,Z
//-- broche activation moteur
const int pin_ENABLE=8; // broche activation moteur
//-- broches fin de course
/*
const int X_END_STOP=8;
const int Y_END_STOP=9;
const int Z_END_STOP=10;
*/
int pin_ENDSTOP[3]={9,10,11}; // les broches de endstop des moteurs X,Y,Z
const int APPUI=LOW; // endstop actif sur niveau bas
//-- reception serie
char buffer[MAX_BUF]; // tableau de reception des caracteres
int sizeIn; // nombre de caracteres presents dans le buffer
//--- position
// variables de position courante
float px=0.0;
float py=0.0;
float pz=0.0;
float pxn, pyn, pzn; // variable nouvelle position courante
//-- vitesse
float fr=1.0; // memo feedrate en mm/sec - utilisée pour G01
float frmax=6.0; // feedrate utilisé pour G00
float currentfr=0; // le feedrate courant actif - different de fr pour initialisation possible
//long step_delay_ms;
long step_delay_us=0; // delai entre 2 pas
//-- parametrages fonctionnement
int mode=90; // mode absolu/relatif - 90 = absolu 92 = relatif - par défaut absolu
long line_number=0;
int lastCmd=-1; // Variable mémorise dernier commande G appelée
// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---
// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation //////////////////////////
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme
void setup() { // debut de la fonction setup()
// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---
// ------- Initialisation fonctionnalités utilisées -------
Serial.begin(115200); // initialise connexion série à 115200 bauds
delay(1000);
help(); // messages d'instruction
ready(); // fonction qui réinitialise contenu buffer
feedrate(1); // initialisation feedrate
// IMPORTANT : régler le terminal côté PC avec la même valeur de transmission
// ------- Broches en sorties numériques -------
// broches de pulse moteur
pinMode(pin_STEP[X], OUTPUT); // met broche en sortie
pinMode(pin_STEP[Y], OUTPUT); // met broche en sortie
pinMode(pin_STEP[Z], OUTPUT); // met broche en sortie
digitalWrite(pin_STEP[X], LOW); // met broche niveau BAS
digitalWrite(pin_STEP[Y], LOW); // met broche niveau BAS
digitalWrite(pin_STEP[Z], LOW); // met broche niveau BAS
// broches de dir moteur
pinMode(pin_DIR[X], OUTPUT); // met broche en sortie
pinMode(pin_DIR[Y], OUTPUT); // met broche en sortie
pinMode(pin_DIR[Z], OUTPUT); // met broche en sortie
digitalWrite(pin_DIR[X], LOW); // met broche niveau BAS
digitalWrite(pin_DIR[Y], LOW); // met broche niveau BAS
digitalWrite(pin_DIR[Z], LOW); // met broche niveau BAS
// broches de endstop
pinMode(pin_ENDSTOP[X], INPUT_PULLUP); // met broche en entrée avec rappel au + actif
pinMode(pin_ENDSTOP[Y], INPUT_PULLUP); // met broche en entrée avec rappel au + actif
pinMode(pin_ENDSTOP[Z], INPUT_PULLUP); // met broche en entrée avec rappel au + actif
/*
digitalWrite(pin_ENDSTOP[X], HIGH); // met broche avec rappel au + actif
digitalWrite(pin_ENDSTOP[Y], HIGH); // met broche avec rappel au + actif
digitalWrite(pin_ENDSTOP[Z], HIGH); // met broche avec rappel au + actif
*/
//---- broche activation moteur
pinMode(pin_ENABLE, OUTPUT); // broche en sortie
digitalWrite(pin_ENABLE, LOW); // activation par defaut moteur - ENABLE ACTIF SUR NIVEAU BAS ++
// ------- Broches en entrées numériques -------
// ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------
// ------- Initialisation des variables utilisées -------
} // fin de la fonction setup()
// ********************************************************************************
////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension
void loop(){ // debut de la fonction loop()
// --- ici instructions à exécuter par le programme principal ---
//---- code type réception chaine sur le port série ---
/*
while (Serial.available()>0) { // tant qu'un octet en réception
octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable
if (octetReception==10) { // si Octet reçu est le saut de ligne
Serial.println (chaineReception); // affiche la chaine recue
chaineReception=""; //RAZ le String de réception
break; // sort de la boucle while
}
else { // si le caractère reçu n'est pas un saut de ligne
chaineReception=chaineReception+char(octetReception); // ajoute le caratère au String
//Serial.print(char(octetReception)); // affiche la chaine recue
}
*/
// Gcode de la forme : G1 Z5 F5000 ;
// reception serie
while(Serial.available() > 0) { // tant qu'un caractere dans la file d'attente serie
char c=Serial.read(); // lecture du caractere suivant
//Serial.print(c); // affichage
if(sizeIn<MAX_BUF) buffer[sizeIn++]=c; // on le memorise dans le buffer tant que place
//if(buffer[sizeIn-1]==';') break; // on sort si dernier caractere recu=;
if (c==';') break; // equivalent car c est le dernier caractere recu -
// on analyse après...
if (Serial.available()==0) delay(5); // laisse temps éventuel nouveau caractere arriver
} // fin while octet réception
// si arrivee instruction GCode valide
//if(sizeIn>0 && buffer[sizeIn-1]==';') { // si caractere dans le buffer et dernier est un ;
if(sizeIn>0 && buffer[sizeIn-1]=='\n') { // si caractere dans le buffer et dernier est un \n
// lorsqu'un message GCode valide a été recu
buffer[sizeIn]=0; // ajoute un 0 à la fin du buffer pour traitement en chaine de caractere
//Serial.print(F("\r\n")); // affiche message
// if debug : Serial.println(buffer); // affiche message - traité comme une chaine
analyseChaine(); // analyse la commande
ready(); // reinitialise buffer
}// fin else
// --- commande personnalisée --- => a mettre dans analyse chaine..
else if (sizeIn>0 && buffer[0]=='$') { // sizeIn>0 et ready() necessaires
Serial.println("status()");
status();
ready(); // reinitialise buffer
} // else if
else if(sizeIn>0 ) { // sinon on vide le buffer reception
Serial.println(); // saut ligne
ready(); // reinitialise buffer
} // fin else if
/* // -- test des endstops --
// lecture des endstops
if (digitalRead(pin_ENDSTOP[X])==APPUI) {
Serial.println("Appui ENDSTOP X");
delay(100); // anti-rebond
} // fin si appui
if (digitalRead(pin_ENDSTOP[Y])==APPUI) {
Serial.println("Appui ENDSTOP Y");
delay(100); // anti-rebond
} // fin si appui
if (digitalRead(pin_ENDSTOP[Z])==APPUI) {
Serial.println("Appui ENDSTOP Z");
delay(100); // anti-rebond
} // fin si appui
*/
} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************
// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS ////////////////////
// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME ////////////////////
// message d'aide
void help() {
// Serial.print(F("--- Simple Gcode --- v"));
// Serial.println(VERSION);
// Serial.println(F("Par X.HINAULT - www.mon-club-elec.fr - GPLv3"));
// Serial.println(F("$ Statut interne "));
// Serial.println(F("Commandes:"));
// Serial.println(F("G00 [X(steps)] [Y(steps)] [F(feedrate)]; - linear move"));
// Serial.println(F("G01 [X(steps)] [Y(steps)] [F(feedrate)]; - linear move"));
// Serial.println(F("G04 P[seconds]; - delay"));
// Serial.println(F("G28 [X] [Y] [Z]; - home axis"));
// Serial.println(F("G90; - absolute mode"));
// Serial.println(F("G91; - relative mode"));
// Serial.println(F("G92 [X(steps)] [Y(steps)]; - change logical position"));
// Serial.println(F("M18; - disable motors"));
// Serial.println(F("M100; - this help message"));
// Serial.println(F("M114; - report position and feedrate"));
}
//---- message etat ----
void status() {
output("X steps/mm : ",X_STEPS_PER_MM);
output("Y steps/mm : ",Y_STEPS_PER_MM);
output("Z steps/mm : ",Z_STEPS_PER_MM);
output("Feedrate mm/s : ",currentfr);
output("step_delay_us : ", step_delay_us);
output("pos X :", px);
output("pos Y :", py);
output("pos Z :", pz);
}
//--- RAZ buffer reception
void ready() {
sizeIn=0; // RAZ nombre caracteres en reception
//Serial.flush(); // vide file d'attente
//Serial.print(F(">>>")); // signal ready to receive input
}
void analyseChaine() {
// Gcode de la forme : G1 Z5 F5000 ;
//float cmd=parsenumber('G',-1); // la fonction renvoie valeur passée = -1 si pas de changement
//Serial.println (cmd);
//------- code exit = ; initial -------
if (buffer[0]==';'){
sendOK() ;
return; // sort de la fonction
} // fin if ;
//------- decodage instruction G ------------
else if (buffer[0]==' ') analyseEspace(); // si espace en premier = on utilise la dernière commande
//------- decodage instruction G ------------
else if (buffer[0]=='G') analyseG();
//---------- decodage instructions M ---------------
else if (buffer[0]=='M') analyseM();
else sendOK();
} // fin analyse chaine
//--------- fonction d'analyse des chaines du buffer serie
// detecte les lettres suivies de valeur numerique dans la chaine
// Gcode de la forme : G1 Z5 F5000 ;
// la fonction parsenumber reçoit une valeur val qui restera inchangée si pas de valeur trouvée
float parsenumber(char code,float val) {
char *ptr=buffer; // recupere pointeur buffer reception
while(ptr && *ptr && ptr<buffer+sizeIn) {
if(*ptr==code) {
return atof(ptr+1); // conversion en float de ce qui suit la lettre
} // fin if
ptr=strchr(ptr,' ')+1; // recherche de caractere dans une chaine - +1 pour décaler... devient 0 si pas ? ici ' ' = fin de chaine
} // fin while
return val;
} // fin parsenumber
//----- analyse espace -----
void analyseEspace() { // si que X, Y Z précédé de espace, on se cale sur la dernière commande reçue
if (lastCmd==01) G01(), sendOK(); // si dernière commande est G01 - en prem's car le plus frequent
else if (lastCmd==00) G00(), sendOK(); // si dernière commande est G00
else sendOK();
} // fin analyse espace
//----- analyse chaine G -----
void analyseG() {
int cmd = parsenumber('G',-1);
switch(cmd) {
//---- code 0x ----
// G00 // Déplacement rapide - idem G01 en rapide
case 0:
G00();
lastCmd=00;
sendOK();
break;
// G01 : // mouvement linéaire vitesse standard
case 1: // move linear
G01();
lastCmd=01;
sendOK();
break;
// G04 : // pause
case 4:
Serial.println(F("G04"));
//pause(parsenumber('S',0) + parsenumber('P',0)*1000.0f);
float delai;
delai=parsenumber('P',0);
Serial.print("Pause "), Serial.print(delai), Serial.println(" sec.");
delay(delai*1000.0f);
sendOK();
break; //
//--- codes 1x --
case 17: // ..
Serial.println(F("G17"));
sendOK();
break;
//--- codes 2x --
case 20: // ..
Serial.println(F("G20"));
sendOK();
break;
case 28: // home axes
G28();
sendOK();
break;
//--- codes 5x --
case 54: // ..
Serial.println(F("G54"));
sendOK();
break;
//--- codes 9x --
// G90 : mode coordonnées absolues
case 90:
Serial.println(F("G90"));
mode=90;
sendOK();
break;
// G91 : mode coordonnées relatives
case 91:
Serial.println(F("G91"));
mode=91;
sendOK();
break; // relative mode
case 92: // fixe la position courante interne - pas de mouvement
G92();
//position( parsenumber('X',0),
//parsenumber('Y',0) );
sendOK();
break;
case 94: // ..
Serial.println(F("G94"));
sendOK();
break;
default:
sendOK();
break;
} // fin switch
} // fin analyse G
//------- analyse M --------
void analyseM() {
int cmd = parsenumber('M',-1);
switch(cmd) {
case 18: // arret moteurs
Serial.println(F("M18"));
//release();
sendOK();
break;
case 100:
Serial.println(F("M100"));
help();
sendOK();
break;
case 110:
Serial.println(F("M110"));
//line_number = parsenumber('N',line_number);
sendOK();
break;
case 114:
Serial.println(F("M114"));
where();
sendOK();
break;
default:
sendOK();
break;
} // fin switch
}// fin analyse M
//----- G00 ----
void G00(){
Serial.println(F("G00"));
feedrate(frmax);// on utilise le feedrate max
parseFXYZ(); // on fait comme G01 mais avec feedrate maxi
} // fin G00
//---- GO1 ---
void G01(){
Serial.println(F("G01"));
feedrate(fr);// on utilise le feedrate simple
parseFXYZ();
} // fin G01
//---- G28 ---
void G28(){
Serial.println(F("G28"));
feedrate(frmax);// on utilise le feedrate rapide
int test=0.0; // variable pour test
// -- axe X
test=parsenumber('X',-1); // nouvelle position X - on passe -1 en parametre - sera idem si pas present - note X seul idem X0
output("X :", test);
if (test!=-1) { // si X : on va chercher le endstop X
searchEndstop(X); // fonction de recherche endstop
px=0.0; // RAZ position X
} // fin if
// -- axe Y
test=parsenumber('Y',-1); // nouvelle position Y - on passe -1 en parametre - sera idem si pas present - note Y seul idem Y0
output("Y :", test);
if (test!=-1) { // si Y : on va chercher le endstop Y
searchEndstop(Y); // fonction de recherche endstop
py=0.0; // RAZ position Y
} // fin if
// -- axe Z
test=parsenumber('Z',-1); // nouvelle position Z - on passe -1 en parametre - sera idem si pas present - note Z seul idem Z0
output("Z :", test);
if (test!=-1) { // si X : on va chercher le endstop X
searchEndstop(Z); // fonction de recherche endstop
pz=0.0; // RAZ position X
} // fin if
} // fin G28
//---- G92 --- modifie valeurs absolues à 0 - quasi idem G28 sans recherche des endstops
void G92(){
Serial.println(F("G92"));
int test=0.0; // variable pour test
// -- axe X
test=parsenumber('X',-1); // nouvelle position X - on passe -1 en parametre - sera idem si pas present - note X seul idem X0
//output("X :", test);
if (test!=-1) px=0.0; // si X : RAZ position X
// -- axe Y
test=parsenumber('Y',-1); // nouvelle position Y - on passe -1 en parametre - sera idem si pas present - note Y seul idem Y0
//output("Y :", test);
if (test!=-1) py=0.0; // si Y : RAZ position Y
// -- axe Z
test=parsenumber('Z',-1); // nouvelle position Z - on passe -1 en parametre - sera idem si pas present - note Z seul idem Z0
//output("Z :", test);
if (test!=-1) pz=0.0; // si Z : RAZ position Z
} // fin G92
//--- fonction de recherche d'un endstop
void searchEndstop(int axisIn) {
int search=true;
while(search) {
onestep(axisIn,-1); // 1 pas en arriere
tick(); // delay de feedrate
if (digitalRead(pin_ENDSTOP[axisIn])==APPUI) { // on teste le endstop
//Serial.println("Appui ENDSTOP"); // debug
delay(80); // anti-rebond
search=false; // pour sortir du while
} // fin si appui
} // fin while
} // fin searchEndstop
//---- parse FXYZ ----
void parseFXYZ(){
//feedrate(parsenumber('F',fr)); // analyse valeur FXXX présent aussi dans l'instruction - fixe la vitesse
int newfr=parsenumber('F',-1); // extraction du feedrate - currentfr est passé en paramètre à parsenumber = valeur inchangée si pas de valeur renvoyée
if (newfr!=-1) {
feedrate(newfr); // prend en compte le nouveau feedrate --
fr=newfr; // mémorise nouveau fr
} // fin if
//output("feedrate : ", currentfr);
//line( parsenumber('X',(mode_abs?px:0)) + (mode_abs?0:px),parsenumber('Y',(mode_abs?py:0)) + (mode_abs?0:py) );
// condition ? valtrue : valfalse : si condition est vraie, valeur true sinon valeur false
// la ligne (mode_abs?px:0)) + (mode_abs?0:px) permet d'utiliser coord absolue ou relative = bien vu !
//-- mouvement absolus --
if (mode==90) { // mode absolu
pxn=parsenumber('X',px); // nouvelle position X - on passe px en parametre pour idem si pas present
//output("X :", pxn);
pyn=parsenumber('Y',py); // nouvelle position Y - on passe py en parametre pour idem si pas present
//output("Y :", pyn);
line(pxn, pyn); // mouvement linéaire en nouvelle position
pzn=parsenumber('Z',pz); // nouvelle position X - on passe px en parametre pour idem si pas present
//output("Z :", pzn);
outil(pzn); // mouvement outil
// memorisation nouvelles valeurs absolues (dans tous les cas)
px=pxn;
py=pyn;
pz=pzn;
} // fin if mode absolu
//-- mouvements relatifs --
else if (mode==91){
pxn=parsenumber('X',0); // nouvelle position X - on passe 0 en parametre pour idem si pas present
//output("X :", pxn);
pyn=parsenumber('Y',0); // nouvelle position Y - on passe 0 en parametre pour idem si pas present
//output("Y :", pyn);
line(px+pxn, py+pyn); // mouvement linéaire en nouvelle position relativement à la précédente
pzn=parsenumber('Z',0); // nouvelle position X - on passe 0 en parametre pour idem si pas present
//output("Z :", pzn);
outil(pz+pzn); // mouvement outil en nouvelle position relativement à la précédente
// memorisation nouvelles valeurs absolues (dans tous les cas)
px=px+pxn; // position courante + nouveau déplacement
py=py+pyn; // position courante + nouveau déplacement
pz=pz+pzn; // position courante + nouveau déplacement
//output("X :", px);
//output("Y :", py);
//output("Z :", pz);
} // fin si mode relatif
} // fin parseFXYZ
//============ fonctions d'affichage utiles ======================
// affiche message + valeur sur 1 ligne
void output(char *code,float val) {
Serial.print(code);
Serial.println(val);
} // fin output
// send ok
void sendOK() {
Serial.println(F("<ok>"));
} // sendOK
//============= fonctions de position ================
// affiche position courante
void where() {
output("X",px); // le x actuel
output("Y",py); // y actuel
output("Z",pz); // y actuel
output("F",fr); // le feedrate actuel
Serial.println((mode-90)?"REL":"ABS");// affiche mode ABS ou REL - mode 90 : ABS et 92 : REL
} // fin where
//============= fonctions de mouvements moteurs ===================
/**
* Set the feedrate (speed motors will move)
* @input nfr the new speed in steps/second
*/
// fonction qui modifie le feedrate
void feedrate(float nfr) {
if(currentfr==nfr) return; // same as last time? quit now.
// le feedrate s'exprime en mm par seconde
// ici on calcul le delay entre 2 pas en µs qui vaut donc :
// step_delay_us = 1 000 000 / total_steps_per_mm = 1 000 000 / fr * axe_steps_per_mm
if (nfr!=0){ // pour éviter division par zero si nfr=0
step_delay_us=1000000/(nfr*X_STEPS_PER_MM); // calcul delai entre 2 pas
//output("step_delay_us : ", step_delay_us);
} // fin if nfr!=0
/*
if(nfr>MAX_FEEDRATE || nfr<MIN_FEEDRATE) { // limitation feedrate
Serial.print(F("Le feedrate doit etre superieur a "));
Serial.print(MIN_FEEDRATE);
Serial.print(F("steps/s et inferieur a "));
Serial.print(MAX_FEEDRATE);
Serial.println(F("steps/s."));
return;
} // fin if
*/
// calcul du feedrate - ici en pas par minute
/*long us_per_min = 60 * 1000 * 1000;
long frmin = us_per_min / nfr;
step_delay_ms = frmin / 1000;
step_delay_us = frmin % 1000;
*/
currentfr=nfr;
} // fin feedrate
// mouvement en nouvelle position X,Y
void line(float newx,float newy) {
// calcul delta x et y
long dx=(newx-px)*X_STEPS_PER_MM;
long dy=(newy-py)*Y_STEPS_PER_MM;
// fixe sens moteur adequat
//int dirx=dx>0?1:-1;
//int diry=dy>0?-1:1; // because the motors are mounted in opposite directions
int dirx=dx>0?0:1; // 0 et 1 plutôt que -1 et 1
int diry=dy>0?0:1; // 0 et 1 plutôt que -1 et 1
// valeur absolue de delta x, y
dx=abs(dx);
dy=abs(dy);
// variables utiles
long i;
long over=0;
// debug
#ifdef VERBOSE
//Serial.println(F("Start XY>"));
#endif
// boucle de mouvement
if(dx>dy) {
for(i=0;i<dx;++i) {
onestep(X,dirx); // moteur X
over+=dy;
if(over>=dx) {
over-=dx;
onestep(Y,diry); // moteur Y
} // fin if
tick();
} // fin for
} // fin if
else { // si dy<dx
for(i=0;i<dy;++i) {
onestep(Y,diry);
over+=dx;
if(over>=dy) {
over-=dy;
onestep(X,dirx);
} // fin if
tick();
} // fin for
} // fin else
} // fin line
void outil(float newz) {
long dz=(newz-pz)*Z_STEPS_PER_MM;
int dirz=dz>0?0:1; // 0 et 1 plutôt que -1 et 1
// valeur absolue de delta z
dz=abs(dz);
// variables utiles
long i;
// debug
#ifdef VERBOSE
//Serial.println(F("Start Z>"));
#endif
// boucle de mouvement
for(i=0;i<dz;++i) {
onestep(Z,dirz); // moteur Z
tick();
} // fin for
} // fin outil
// fonction 1 pas moteur
void onestep(int motor,int direction) {
// motor =0 pour X, 1 pour Y et 2 pour Z
// fixe sens moteur
digitalWrite(pin_DIR[motor], direction); // sens du pas - direction vaut 0 ou 1
// genere pulse moteur
digitalWrite(pin_STEP[motor], HIGH); // pulse de pas
delayMicroseconds(PULSE_US);
digitalWrite(pin_STEP[motor],LOW); // fin pulse
//delayMicroseconds(step_delay_us-PULSE_US); // - pulse_us pour pas exactement tous les step_delay_us
// mis dans tick pour avoir tous les moteurs positionnés ensemble. Pause commune pour l'ensemble...
} // fin onestep
void tick() { // pause entre deux pulse moteur
delayMicroseconds(step_delay_us-PULSE_US); // - pulse_us pour pas exactement tous les step_delay_us
// en fait, on ne tient compte que d'un pulse moteur... mais il peut y en avoir plusieurs
} // fin tick.
//void pause(long ms) {
//delay(ms/1000);
//delayMicroseconds(ms%1000); // delayMicroseconds doesn't work for values > ~16k.
//}
void position(float npx,float npy) {
// fixe la position courante ...
px=npx;
py=npy;
} // fin position
// ////////////////////////// Fin du programme ////////////////////
// ////////////////////////// Mémo instructions ////////////////////
// ////////////////////////// Fin Mémo instructions ////////////////////