/***************************
gerber.ccp
pour carte Arduino Mega2560
pilote deux (ou trois) moteurs pas-a-pas d'une photoflasheuse + diode laser
liaison USB au PC
par Silicium628
logiciel Libre Open Source
****************************/
/****************************
PRINCIPE DE LA MESURE DE POSITION
les moteurs pas-à-pas utilisés pour les déplacement en X et Y sont de modèles 200 pas/tour (1.8 deg/ pas)
moteur1.steps_par_tour = 200;
moteur1.tours_par_mm = 2; // pas-de-vis 0.5mm (pour un diamètre M3)
moteur1.impuls_par_step = 2; // de par la configuration de la carte "EasyDriver"
calcul du nb d'impulsions par 1/100mm :
2 imp/pas * 200 pas/T * 2 T/mm = 800 imp/mm
800 imp/mm = 8 impulsions /centième de mm
Ce nombre 8 est un chiffre rond, un entier, ce qui va nous simplifier la vie !
si nous utilisons des "long" (long int = 32 bits = 4 octets, soit -2 147 483 648 à 2 147 483 647) pour compter ces impulsions
nous pourrons controler les déplacements sur une distance de +/-2 147 483 647 / 800 = 2684354 mm = 2684 m = +/-2.7 km... ça devrait le faire !!
remarque1 : l'utilisation de uint16_t (16 bits) = +/-32768 ne permettrait des déplacements que sur 32768/800 = +/-40mm ce qui n'est pas suffisant, la machine
est prévue pour graver des circuits de 100*100mm
remarque2 : des uint24_t (3 octets soit +/- 20m) conviendraient, mais c'est typiquement le truc à ne pas faire pour des tas de raisons (alignement sur avr 8 bits)
qui provoquent la chute prématurée des cheveux.
*****************************/
// #include "WProgram.h"
// #include <avr/power.h>
#include <Arduino.h>
#include <avr/delay.h>
#include <HardwareSerial.h>
#include "../lib/step_motor6.cpp" // lib perso
#define bit_LED_rouge 0b00100000; // sur PORTA
#define bit_LED_verte 0b01000000; // sur PORTA
#define bit_buzzer 0b10000000; // sur PORTA
//#define bit_LED_blanche1 0b01000000; // sur PORTC - sert de stroboscope moteur1 (pour contrôle visuel de la position angulaire du moteur)
//#define bit_LED_blanche2 0b10000000; // sur PORTC - sert de stroboscope moteur2 (pour contrôle visuel de la position angulaire du moteur)
#define bit_LASER 0b01000000; // sur PORTL
#define bit_pointage_LASER 0b10000000; // sur PORTL - allume la diode laser avec une très faible intensité pour faire un pointage visuel
String version = "23.4";
String inputString = ""; // a string to hold incoming data
String data_in ="";
// String outputString = "";
boolean stringComplete = false; // whether the string is complete
char inChar;
/**
struct aperture
{
char forme; // = 'R' ou 'C'
uint16_t x;
uint16_t y; // peut eventuellement etre utilisé aussi dans le cas d'un cercle pour définir une éllipse...
}
cette structure est utilisée par le soft en Qt4. Ici on va faire autrement, avec un tableau...
**/
struct aperture
{
uint16_t x;
uint16_t y;
char type;
};
aperture apertures[40];
//uint16_t apertures[40][3]; // apertures[i][0] -> x ; apertures[i][1] -> y; (x et y ne sont pas des positions mais des dimensions); apertures[i][2] -> 'R' ou 'C'
uint8_t num_aperture;
long ax, ay; // pour les dimensions des apertures; ce type "long" est rendu nécessire pour l'emploi d'un passage de paramètre par adresse dans la fonction "decode_xy_A()"
char type_ap;
uint8_t digits_ap[2];
Step_Motor moteur1; // moteur X (déplacements de la table)
Step_Motor moteur2; // moteur Y (déplacements sur la potence)
//Step_Motor moteur3; // = Z (déplacements verticaux de la plume (stylo ou focalisation du laser)) -> remplacé par un servo
uint8_t etat_laser; // eteint=0 ; allumé=1;
uint8_t blocage_laser=1;
uint8_t simulation;
uint8_t n_octet;
uint8_t etat_FC_x1, etat_FC_x2, etat_FC_y1, etat_FC_y2, etat_FC_z1;
uint8_t fdc_envoi_fait =0;
uint16_t cpt1=0;
uint16_t compteur1;
uint16_t compteur2;
uint16_t periode1;
uint16_t periode2;
float fpx; // facteur periode x
float fpy; // facteur periode y
uint16_t ocr3a_min; // pour moteur1
uint16_t ocr3a_depart; // pour moteur1
uint16_t ocr4a_min; // pour moteur2
uint16_t ocr4a_depart; // pour moteur2
uint16_t base_ocr; // sera décrémenté par l'INT pour accélérer les 2 moteurs
uint16_t base_ocr_depart; // determine la vitesse de rotation à la mise en rotation. La vitesse augmentera ensuite
uint16_t base_ocr_min; // determine la vitesse max de rotation permise, voir les fonctions "ISR(TIMER3_COMPA_vect)" et "ISR(TIMER4_COMPA_vect)"
uint16_t base_ocr_min2; // determine la vitesse max de rotation permise lors des "goto zero" et "goto safe pos"
uint8_t pas_mot1_demande; // drapeau permettant de déplacer le traitement de interruptions moteur dans vers la boucle principale, afin d'éviter les collisions d'interruption.
uint8_t pas_mot2_demande;
uint8_t mm_par_s;
uint8_t mm_par_s_max;
/*************************************************
rappel1 :
vis au pas de 0.5mm -> 2 tours /mm
2 imp/pas * 200 pas/tour * 2 tours/mm = 800 imp/mm
800 imp/mm = 8 impulsions /centième de mm
**************************************************
rappel2 :
long = entier signé codé sur 32 bits = 4 octets
**************************************************/
long x0, y0; // position actuelle en nb/impulsions moteur (plus exactement impulsions vers EasyDriver). (8 impulsions = 1/100 mm)
//long x1, y1; // position à atteindre en nb/impulsions moteur (plus exactement impulsions vers EasyDriver). (8 impulsions = 1/100 mm)
long d_impuls_x, d_impuls_y; // distances à parcourir en nb d'impulsions
/*
Mémorisation numérique du tracé pour contôle sans tracé physique:
la fréquence max envoyée aux cartes EasyDriver en vitesse rapide est = 2500Hz
Si l'on veut mémoriser toutes les positions parcourues, chaque position étant définie par 2 x 4 octets = 8 octets,
il faut 2500*8 = 20 000 octets/s (=160 kbits/s) (on voit déjà que la transmission à 115200 bauds ne suffit pas si l'on veut envoyer le résultat au PC en temps réel)
si on veut mémoriser 1/2h de tracé, il faut 20 kB/s * 1800s = 36MB. -> la RAM du Mega2560 = 8kB soit 4500 fois moins !!! juste de quoi mémoriser 0,4s de tracé.
utiliser un processeur ARM ? un Raspberry Pi2 quad core ?
J'envisage une acquisition externe par un second ATmega connecté sur les sorties des signaux, qui mémoriserait dans une SDcard.
*/
long diff_x;
long diff_y;
int16_t erreur_X = 0; // en nb d'impulsions. Peut varier entre -200 et +200 (pour 0 à 360° d'angle moteur). Doit être = 0 si pas d'erreur.
int16_t erreur_Y = 0; // en nb d'impulsions. Peut varier entre -200 et +200 (pour 0 à 360° d'angle moteur). Doit être = 0 si pas d'erreur.
uint8_t largeur_plume = 5;
uint8_t digits_X[4];
uint8_t digits_Y[4];
uint8_t n;
uint16_t nb_operations = 0;
uint8_t goto_en_cours_xy = 0; // dans le plan horizontal
uint8_t goto_en_cours_z = 0; // concerne la hauteur de la plume
uint8_t raz_demande = 0;
uint8_t acceleration_permise = 0;
char msg_ret_gto[3]; // permet à la fonction goto d'envoyer plusieurs types de message en retour vers le PC, suivant la nature de son appel
int16_t table_sinus[1024];
int8_t data_valide = 0;
void init_ports (void) // ports perso
// 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
{
PORTA = 0b00000000;
DDRA = 0b11111111; // affichage LCD (ecran Nokia 5110) sur bits 0..4 + LEDS + Buzzer
PORTB = 0b00000000;
DDRB = 0b11111111; // PB4 = OC2A = sortie PWM du Timer2 utilisé pour piloter la luminosité du laser
PORTC = 0b00000000;
DDRC = 0b11111111; // PC0 et PC1 -> enables des moteurs ; PC6 et PC7 -> LEDS blanches stroboscopiques
PORTD = 0b00000000;
DDRD = 0b11111100; // PD0 = entrée (=INT0) ; PD1 = entrée (=INT1)
PORTG = 0b00000000;
DDRG = 0b11111111;
PORTK= 0b00000000; // ne PAS activer les R de Pull Up (tirage à VCC) sinon risque de ne pas detecter le rayon IR
DDRK = 0b11100000; // entré des fin de course
PORTL= 0b00000000;
DDRL = 0b11111111; // commandes des 2 moteurs (X, Y), de la diode laser et sortie PWM pour servomoteur(PL4)
}
/**
Info pour le Timer2 (8bits) : (Pb : on utilise ici les timers 3 et 4 (16 bits) )
20.4.2 (page:172 du datasheet ATmega2560)
Clear Timer on Compare Match (CTC) Mode
In Clear Timer on Compare or CTC mode (WGM22:0 = 2), the OCR2A Register is used to manipulate the counter
resolution. In CTC mode the counter is cleared to zero when the counter value (TCNT2) matches the OCR2A. The
OCR2A defines the top value for the counter, hence also its resolution. This mode allows greater control of the
compare match output frequency
**/
/**
Pour les timers 16 bits(3 et 4...) voir le tableau p:145
Il faut mettre le bit WGMn2 à 1
Pb: où est ce bit ???
panique à bord...
Voir le grand tableau "Register Summary" p:399
ce qui permet de le localiser dans le registre TCCRnB - voir page 156
**/
/**
void int_EXT_setup()
{
// voir 15. External Interrupts p:109
// EICRA |= 0b00001010; // bits[1,0] = 10 -> int0 sur front descendant; bits[3,2] = 10 -> int1 sur front descendant; - p: 110
// EICRA |= 0b00000101; // bits[1,0] = 10 -> int0 ; bits[3,2] = 10 -> int1 ; Any edge of INTn generates asynchronously an interrupt request - p: 110
EICRA |= 0b00001111; //The rising edge of INTn generates asynchronously an interrupt request
//je choisis "Any edge of INTn generates asynchronously an interrupt request" pour éviter de déclencher sur le mauvais sur rebonds.
EIMSK |= 0b00000011; // bit[0]=1 -> INT0 enable ; bit[1]=1 -> INT1 enable - parag 15.2.3 EIMSK - p:111
}
**/
void timer2_setup()
{
// génère un signal PWM (luminosité du laser) - sortie sur PB4 (OC2A)
cli();
//mode Fast PWM - voir p:184
// WGM2 [2,1,0] = 011
// WGM2[1,0] sont les bits [1,0] du registre TCCR2A - voir p:182
/**
Il faut mettre le bit WGM22 à 0
Pb: où est ce bit ??? panique à bord...
Voir le grand tableau "Register Summary" p:401
ce qui permet de le localiser dans le registre TCCR2B et nous renvoie à la page 185
WGM22 est donc le bit 3 du registre TCC2B
* */
// COM2A[1,0] = 1,0 - voir p:183 non inverting mode
// COM2A[1,0] sont les bits [7,6] de TCCR2A - p:401 et p:182
// sortie du signal sur pin OC2A ( pin PB4 = pin 23 du Mega2560)
TCCR2A |= 0b10000011;
TCCR2B = 0b11110010; // bit WGM22=1 et prescaler = 1/8 voir Table 20-9. (Clock Select Bit Description) p:185
OCR2A = 50;
sei();
}
void timer3_setup()
// Pour générer les pas du moteur1 (axe X = déplacements de la table)
{
cli();
TIMSK3 = 0b00000010; // Bit 1 – OCIE3A: Timer/Counter1, Output Compare A Match Interrupt Enable - p:161
TCCR3A = 0b00000000; // p:154
TCCR3B = 0b00001010; // prescaler = 1/8 - CTC mode - p:156 et tableau p:157
OCR3A = ocr3a_depart; // compare match register - valeur la plus faible possible afin d'augmenter la fréquence primaire
sei();
}
void timer4_setup()
{
// Pour générer les pas du moteur2 ((axe Y = déplacements ddu laser sur le portique)
cli();
TIMSK4 = 0b00000010; // Bit 1 – OCIE4A: Timer/Counter3, Output Compare A Match Interrupt Enable
TCCR4A = 0b00000000; // p:154
TCCR4B = 0b00001010; // prescaler = 1/8 - CTC mode - p:156 et tableau p:157
OCR4A = ocr4a_depart; // compare match register - valeur la plus faible possible afin d'augmenter la fréquence primaire
sei();
}
void timer5_setup()
{
//pour piloter le servomoteur (type micro servo C141 Graupner) (hauteur du laser = réglage de la focalisation -> largeur du trait)
// génère un signal PWM - sortie sur PL4 (OC5B)
// mode15 = fast PWM - WGM[3,2,1,0] = 1111 - voir p:145
// WGM[1,0] sont les bits [1,0] de TCCR5A - p:154
// WGM[3,2] sont les bits [4,3] de TCCR5B - p:156
cli();
TIMSK5 = 0b00000000; // p:162
// TCCR5A = (TCCR5A & 0xCC) | _BV(COM5B1) | _BV(WGM10); // fast PWM 8-bit, sortie sur pin OC5b
//mode7 = Fasr PWM, 10 bits -> WGM[2,1,0] = 111
TCCR5A = 0b00100011;
// bits[5,4] = COM5B[1,0] = compare output mode = 10 select-> canal B (sortie sur pin OC5b) - p:144, 146, 154, 155
// bits[1,0] = WGM[1,0] = 11 -> Clear OCnA/OCnB/OCnC on compare match, set OCnA/OCnB/OCnC at BOTTOM (non-inverting mode) - p:154 et p:155 - et tableau des modes p:145
TCCR5B = 0b00001100; // prescaler = 1/256 - tableau p:157
// bit[4,3] = WGM[3,2]
// bit[2,1,0] = CS[2,1,3] (clock selection)
TCCR5C = 0;
OCR5B = 140; // largeur impulsion min=50 ; max=145 -> [0,8ms..2,4ms]
sei();
}
void beep()
{
uint8_t n;
for (n=0; n<255; n++)
{
PORTA ^= bit_buzzer;
_delay_us(300);
}
}
void beep2()
{
uint8_t n;
for (n=0; n<255; n++)
{
PORTA ^= bit_buzzer;
_delay_us(200);
}
}
void clic()
{
uint8_t n;
for (n=0; n<10; n++)
{
PORTA ^= bit_buzzer;
_delay_us(50);
}
}
void n_beep(uint8_t n)
{
uint8_t i;
for (i=0; i<n; i++)
{
beep2();
_delay_ms(200);
}
}
void laser_on()
{
if (blocage_laser == 0)
{
PORTL |= bit_LASER;
etat_laser=1;
}
}
void laser_off()
{
PORTL &= ~bit_LASER;
etat_laser=0;
}
void laser_bloque()
{
laser_off();
etat_laser=0;
blocage_laser=1;
}
void laser_debloque()
{
laser_off();
etat_laser=0;
blocage_laser=0;
}
void laser_set_lum(uint8_t lum)
{
OCR2A = lum;
}
void laser_set_Z(uint16_t z)
{
OCR5B = z;
}
uint16_t calcul_rapide_periode_x(uint16_t base)
{
float px;
px = 1000.0 * (float)base * fpx;
if (px > 0xFFFF) {px = 0xFFFF;}
return (int) px;
}
uint16_t calcul_rapide_periode_y(uint16_t base)
{
float py;
py = 1000.0 * (float)base * fpy;
if (py > 0xFFFF) {py = 0xFFFF;}
return (int) py;
}
/**
ISR(INT0_vect )
{
// interruption externe déclenchée par le disque à fente sur l'axe moteur X + opto-switch
PORTA ^= bit_LED_verte;
if(moteur1.get_sens() == 0) { erreur_X = 226 - moteur1.position_impuls % 400; } else { erreur_X = 189 - moteur1.position_impuls % 400; } // 18 = largeur fente...
}
**/
/**
ISR(INT1_vect )
{
// interruption externe déclenchée par le disque à fente sur l'axe moteur Y + opto-switch
PORTA ^= bit_LED_verte;
if(moteur2.get_sens() == 0) { erreur_Y = 211 - moteur2.position_impuls % 400; } else { erreur_Y = 198 - moteur2.position_impuls % 400; } // 18 = largeur fente...
}
**/
/**
Le code exécuté par la RA1 du flag 'pas_mot1_demande' sera executé dans la boucle principale et/ou dans les boucles des goto_xy, mais pas dans l'interruption elle-même
ceci afin d'éviter les problèmes de collision d'interruption
Ces interruptions (qui codent des 'cli durant leur exécution' interdisant l'autre int) peuvent ainsi rendre la main le plus rapidement possible
voir les fonctions 'pas_mot1' et 'pas_mot2'
**/
ISR(TIMER3_COMPA_vect) // MOTEUR 1
{
if (moteur1.get_marche() == 1) { pas_mot1_demande +=1; }
}
ISR(TIMER4_COMPA_vect) // MOTEUR 2
{
if (moteur2.get_marche() == 1) { pas_mot2_demande +=1; }
}
/*
ISR(TIMER5_COMPA_vect)
{
}
*/
int calcul_periode_deplacement(long x1_i, long y1_i, long x2_i, long y2_i)
{
float dx, dy, dx2, dy2, v0, px, py, dt; // vx, vy,
v0=1;
if (x2_i >= x1_i) { dx=x2_i-x1_i; moteur1.set_sens(0); } else { dx=x1_i-x2_i; moteur1.set_sens(1); }
if (y2_i >= y1_i) { dy=y2_i-y1_i; moteur2.set_sens(0); } else { dy=y1_i-y2_i; moteur2.set_sens(1); }
if ( (x2_i == x1_i) && (y2_i == y1_i) ) // les points sont confondus, le ds est nul
{
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
return(1); // pour éviter les divisions par zéro plus bas
}
dx2=dx*dx; // dx²
dy2=dy*dy; // dy²
dt = (sqrt(dx2+dy2))/v0;
//vx= dx/dt;
//vy= dy/dt;
px = 600000.0 * ((float) mm_par_s_max / (float) moteur1.impuls_par_mm) * dt/dx; // 400000.0
py = 600000.0 * ((float) mm_par_s_max / (float) moteur2.impuls_par_mm) * dt/dy; // 400000.0
if (px > 0xFFFF) {px = 0xFFFF;}
if (py > 0xFFFF) {py = 0xFFFF;}
OCR3A = (int) px;
OCR4A = (int) py;
return(0);
}
void envoi_FDC()
{
Serial.println("FIN DE COURSE");
}
int lecture_fins_de_course_xy() // xy, et pas z
{
// lecture de l'etat des capteurs (optiques) de fin de course et activations des blocages logiciels correspondants
etat_FC_x1 = PINK & moteur1.bit_finCourse1; if (etat_FC_x1 != 0) { moteur1.set_stop_sens1(1); } else { moteur1.set_stop_sens1(0); }
etat_FC_x2 = PINK & moteur1.bit_finCourse2; if (etat_FC_x2 != 0) { moteur1.set_stop_sens2(1); } else { moteur1.set_stop_sens2(0); }
etat_FC_y1 = PINK & moteur2.bit_finCourse1; if (etat_FC_y1 != 0) { moteur2.set_stop_sens1(1); } else { moteur2.set_stop_sens1(0); }
etat_FC_y2 = PINK & moteur2.bit_finCourse2; if (etat_FC_y2 != 0) { moteur2.set_stop_sens2(1); } else { moteur2.set_stop_sens2(0); }
//etat_FC_z1 = PINK & moteur3.bit_finCourse1; if (etat_FC_z1 != 0) { moteur3.set_stop_sens2(1); } else { moteur3.set_stop_sens2(0); }
//if ((etat_FC_x1 != 0)||(etat_FC_x2 != 0)||(etat_FC_y1 != 0)||(etat_FC_y2 != 0)||(etat_FC_z1 != 0))
if ((etat_FC_x1 != 0)||(etat_FC_x2 != 0)||(etat_FC_y1 != 0)||(etat_FC_y2 != 0))
{
if ( ((PORTA & 32) == 0) && (fdc_envoi_fait == 0) )
{
envoi_FDC();
fdc_envoi_fait = 1;
} // si la led était éteinte, on signale le changement d'état au soft Qt4 ;
// REMARQUE on lit l'état d'un port conf en sortie, ce qui est tout à fait possible, on lit ce qu'on y a écrit précédemment...
PORTA |= bit_LED_rouge;
return 1;
}
else
{
PORTA &= ~bit_LED_rouge;
fdc_envoi_fait == 0;
}
return 0;
}
void pas_mot1()
{
// la fréquence max du signal envoyé à la carte EasyDriver (lors d'un goto_origine par exemple) est de 2500Hz.
if (acceleration_permise ==1)
{
if (OCR3A > ocr3a_min)
{
compteur1++;
compteur1=0;
OCR3A -=1;
}
}
cli();
moteur1.step();
sei();
//if ((goto_en_cours_xy == 1) && ( moteur1.get_compteur_impuls() >= d_impuls_x )) {moteur1.set_marche(0); } // ARRET
//if (moteur1.position_impuls % 400 == 0 ) {PORTC |= bit_LED_blanche1; } else {PORTC &= ~bit_LED_blanche1; }
}
void pas_mot2()
{
if (acceleration_permise ==1)
{
if (OCR4A > ocr4a_min)
{
compteur2++;
compteur2=0;
OCR4A -=1;
}
}
cli();
moteur2.step();
sei();
//if ((goto_en_cours_xy == 1) && ( moteur2.get_compteur_impuls() >= d_impuls_y )) {moteur2.set_marche(0); }
//if (moteur2.position_impuls % 400 == 0 ) {PORTC |= bit_LED_blanche2; } else {PORTC &= ~bit_LED_blanche2; }
}
void envoi_PRET(long xi, long yi)
{
// ATTENTION : cette fonction envoi le signal qui déclenche en retour l'envoi de la commande suivante par le prog Qt4.
// Donc ne pas l'appeler inconsidérement ! en particulier pas avant que l'éxécution de la commande en cours soit terminée.
// en particulier pas dans une sous-fonction de la commande en cours (comme "laser_set_lum" par exemple)
unsigned char r ;
// char msg_position[20]="0123456789012345678"; // 19 car max pour un string20
char msg_position[20]="X+0000Y+0000 PRET "; // 19 car max pour un string20
char signe_x, signe_y;
int i, fdc;
long valeur;
fdc = lecture_fins_de_course_xy();
msg_position[0]='X';
if (xi >=0) {valeur = xi/8; signe_x ='+';} else {valeur = -xi/8; signe_x ='-';}
msg_position[1]=signe_x;
for (i=0; i<4; i++)
{
r=48 + valeur % 10; // modulo (reste de la division)
valeur /= 10; // quotient
msg_position[5-i]=r;
}
msg_position[7]='Y';
if (yi >=0) {valeur = yi/8; signe_y ='+';} else {valeur = -yi/8; signe_y ='-';}
msg_position[7]=signe_y;
for (i=0; i<4; i++)
{
r=48 + valeur % 10; // modulo (reste de la division)
valeur /= 10; // quotient
msg_position[11-i]=r;
}
if (fdc == 1)
{
msg_position[11]=' '; msg_position[13]='F'; msg_position[14]='I'; msg_position[15]='N'; msg_position[16]='C' ; msg_position[17]=' ';
// c.à.d : envoi "X+0000Y+0000 FINC " (= fin de course)
}
clic();
nb_operations ++;
_delay_ms(100);
Serial.println("-");
_delay_ms(100);
Serial.println(msg_position);
}
void envoi_diff_xy()
{
unsigned char r ;
// char msg_erreur[20]="0123456789012345678"; // 19 car max pour un string20
char msg_diff[20]="difX= 000 difY= 000"; // 19 car max pour un string20
char signe_x, signe_y;
int i;
uint16_t valeurX, valeurY;
valeurX = abs(diff_x);
if (diff_x >=0) {valeurX = diff_x; signe_x ='+';} else {valeurX = -diff_x; signe_x ='-';}
msg_diff[5]=signe_x;
for (i=0; i<3; i++)
{
r=48 + valeurX % 10; // modulo (reste de la division)
valeurX /= 10; // quotient
msg_diff[8-i]=r;
}
valeurY = abs(diff_y);
if (diff_y >=0) {valeurY = diff_y; signe_y ='+';} else {valeurY = -diff_y; signe_y ='-';}
msg_diff[15]=signe_y;
for (i=0; i<3; i++)
{
r=48 + valeurY % 10; // modulo (reste de la division)
valeurY /= 10; // quotient
msg_diff[18-i]=r;
}
_delay_ms(50);
Serial.println(msg_diff);
}
void envoi_pos()
{
unsigned char r ;
// char msg_erreur[20]="0123456789012345678"; // 19 car max pour un string20
char msg_pos[20]="-------------------"; // 19 car max pour un string20
int i;
long valeurX, valeurY;
valeurX = moteur1.position_impuls;
for (i=0; i<10; i++)
{
r=48 + valeurX % 10; // modulo (reste de la division)
valeurX /= 10; // quotient
msg_pos[10-i]=r;
}
/*
valeurY = moteur2.position_impuls;
for (i=0; i<3; i++)
{
r=48 + valeurY % 10; // modulo (reste de la division)
valeurY /= 10; // quotient
msg_pos[18-i]=r;
}
*/
_delay_ms(50);
Serial.println(msg_pos);
}
void test_fin_goto(long xi, long yi)
{
//uint8_t n;
// teste si la destination est atteinte, si oui stoppe le ou les moteurs.
// la valeur du "msg_ret_gto" déterminera plus précisément le comportement de cette fonction
// if ((goto_en_cours_xy == 1) && ( moteur1.get_compteur_impuls() >= d_impuls_x )) {moteur1.set_marche(0); }
// if ((goto_en_cours_xy == 1) && ( moteur2.get_compteur_impuls() >= d_impuls_y )) {moteur2.set_marche(0); }
if (moteur1.get_sens() == 0) { if (moteur1.position_impuls >= xi) { moteur1.set_marche(0); } }
else { if (moteur1.position_impuls <= xi) { moteur1.set_marche(0); } }
if (moteur2.get_sens() == 0) { if (moteur2.position_impuls >= yi) { moteur2.set_marche(0); } }
else { if (moteur2.position_impuls <= yi) { moteur2.set_marche(0); } }
if ((goto_en_cours_xy == 1) && (moteur1.get_marche() == 0) && (moteur2.get_marche() == 0) )
{ // FIN DU GOTO si LES DEUX coordonnées x ET y sont atteintes.
goto_en_cours_xy = 0;
laser_off();
//POUR TEST ***********************************************************
// envoi_pos(); // test ok, les coordonnées sont bonne, pourtant il manque des impulsion lors de déplacements doubles (les 2 mot en marche) vers l'origine
//**********************************************************************
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
if (raz_demande)
{
moteur1.RAZ_pos();
moteur2.RAZ_pos();
x0=0; y0=0;
raz_demande = 0;
}
//----------------------------------------------------------------------
if ( (msg_ret_gto[0]=='T') && (msg_ret_gto[1]=='S') && (msg_ret_gto[2]=='G') ) // fin du tracé de segment
{
laser_off();
_delay_ms(10); // frein (immobilisation le courant est maintenu sans impulsions)
moteur1.disable(); // stop courant
moteur2.disable();
envoi_PRET(x0, y0);
}
//----------------------------------------------------------------------
if (msg_ret_gto[0]=='L') // fin du tracé demandé en local
{
_delay_ms(10); // frein (immobilisation, le courant est maintenu sans impulsions)
moteur1.disable(); // stop courant
moteur2.disable();
}
//----------------------------------------------------------------------
if (msg_ret_gto[0]=='S') // fin du tracé de segment sans delai de freinage (pour tracer les nombreux segments des pastilles rondes)
{
;
}
//----------------------------------------------------------------------
if ( (msg_ret_gto[0]=='-') && (msg_ret_gto[1]=='X') && (msg_ret_gto[2]=='Y') )
{
_delay_ms(5);
envoi_PRET(x0, y0);
} // fin du goto plume levée
//----------------------------------------------------------------------
if ( (msg_ret_gto[0]=='Z') && (msg_ret_gto[1]=='0') && (msg_ret_gto[2]=='0') ) // fin du goto ZERO (origine XY)
{
laser_off();
n_beep(3);
moteur1.disable(); // stop courant
moteur2.disable();
envoi_PRET(x0, y0);
}
//----------------------------------------------------------------------
if (msg_ret_gto[0]=='P') // fin du tracé d'une pastille
{
laser_off();
_delay_ms(20); // frein (immobilisation le courant est maintenu sans impulsions)
moteur1.disable(); // stop courant
moteur2.disable();
envoi_PRET(x0, y0);
}
}
}
void goto_xy(long xi, long yi)
{
if (simulation == 1)
{
_delay_ms(50);
return;
}
acceleration_permise = 0;
int r = calcul_periode_deplacement(x0, y0, xi, yi); // fixe également le sens de rotation
// remarque :labs est la version pour les entiers "long" de abs.
// d_impuls_x = labs(xi-x0); // longueur du segment en x. Non signé. servira à détecter la fin du trajet. précis à 1 impulsion près, soit (1/100mm)/8
// d_impuls_y = labs(yi-y0); // longueur du segment en y. Non signé. servira à détecter la fin du trajet.
// moteur1.RAZ_compteur_impuls(); // servira à mesurer la distance parcourue exactement à une impulsion près.
// moteur2.RAZ_compteur_impuls();
moteur1.enable();
moteur2.enable();
moteur1.set_marche(1);
moteur2.set_marche(1);
goto_en_cours_xy = 1;
while (goto_en_cours_xy == 1)
{
lecture_fins_de_course_xy();
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; _delay_us(1);} // rotation de 1 pas du moteur1 (x)
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; _delay_us(1);} // rotation de 1 pas du moteur2 (y)
test_fin_goto(xi, yi); // le goto s'arretera lorsque position_impuls == (xi, yi)
}
}
void X_plus_mm(long valeur)
{
long n, n_max;
n_max = moteur1.impuls_par_mm * valeur;
moteur1.set_sens(0);
moteur1.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur1.step();
_delay_us(1200);
}
moteur1.disable();
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
envoi_PRET(x0, y0);
}
void X_moins_mm(long valeur)
{
long n, n_max;
n_max = moteur1.impuls_par_mm * valeur;
moteur1.set_sens(1);
moteur1.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur1.step();
_delay_us(1200);
}
moteur1.disable();
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
envoi_PRET(x0, y0);
}
void rotX_n_pas(long valeur)
{
long n, n_max;
n_max = valeur;
moteur1.set_sens(1);
moteur1.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur1.step();
_delay_us(1200);
}
moteur1.disable();
}
void rotY_n_pas(long valeur)
{
long n, n_max;
n_max = valeur;
moteur2.set_sens(0);
moteur2.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur2.step();
_delay_us(1800);
}
moteur2.disable();
}
void Y_plus_mm(uint8_t valeur)
{
uint16_t n, n_max;
n_max = moteur2.impuls_par_mm * valeur;
moteur2.set_sens(0);
moteur2.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur2.step();
_delay_us(1200);
}
moteur2.disable();
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
_delay_ms(50);
envoi_PRET(x0, y0);
}
void Y_moins_mm(uint8_t valeur)
{
uint16_t n, n_max;
n_max = moteur2.impuls_par_mm * valeur;
moteur2.set_sens(1);
moteur2.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur2.step();
_delay_us(1200);
}
moteur2.disable();
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
_delay_ms(50);
envoi_PRET(x0, y0);
}
void envoi_nombre(uint16_t valeur) // valeur = 0..9999
{
// char msg_nbr[20]="0123456789012345678"; // 19 car max pour un string20
char msg_nbr[20]=" "; // 19 car max pour un string20
uint8_t i, r;
for (i=0; i<4; i++)
{
r=48 + valeur % 10; // modulo (reste de la division)
valeur /= 10; // quotient
msg_nbr[5-i]=r;
}
_delay_ms(50);
Serial.println(msg_nbr);
}
/**
void envoi_texte(char *txt, int lg) // txt = 19 caract max
{
// char msg_nbr[20]="0123456789012345678"; // 19 car max pour un string20
char msg_txt[20]=" "; // 19 car max pour un string20
uint8_t i;
for (i=0; i<=lg; i++)
{
msg_txt[i]=txt[i];
}
Serial.println(msg_txt);
_delay_ms(300);
}
**/
void ajout_aperture(uint8_t num, char type)
{
if (num < 40)
{
apertures[num].x = ax;
apertures[num].y = ay;
apertures[num].type = type; // "C" ou "R" ou "O"
}
envoi_PRET(x0, y0);
}
void RAZ_POS()
{
moteur1.RAZ_pos();
moteur2.RAZ_pos();
x0=0;
y0=0;
}
void STOP()
{
laser_off();
moteur1.set_marche(0);
moteur2.set_marche(0);
moteur1.disable(); // stop courant
moteur2.disable();
//PORTA &= ~bit_LED_verte;
goto_en_cours_xy = 0; // le cas échéant...
envoi_PRET(x0, y0);
}
void rotation_2k_pi()
{
// fait tourner les axes pour les orienter toujours à 2k pi près (pour test visuel de dérives éventuelles de positions)
// rappel : 2pi radians = 1 tour = 400 pas.
long n0;
long n, n_max;
n0 = moteur1.position_impuls;
n_max = 400 - (n0 % 400); // modulo (reste de la division)
moteur1.set_sens(0);
moteur1.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur1.step();
_delay_us(2000);
}
moteur1.disable();
n0 = moteur2.position_impuls;
n_max = 400- (n0 % 400); // modulo (reste de la division)
moteur2.set_sens(0);
moteur2.enable();
for (n=0; n<n_max; n++)
{
lecture_fins_de_course_xy();
moteur2.step();
_delay_us(2000);
}
moteur2.disable();
beep();
x0 = moteur1.position_impuls;
y0 = moteur2.position_impuls;
_delay_ms(500); // temps d'observation visuelle.
}
//GHA0195YA0600
//SXA0572YA0381XB1143YB0381D27
void decode_xy_A(long *x, long *y) // retourne des valeurs numériques (en 1/100mm) de la partie numerique qui suit le "XA" et le "YA" dans le message recu
{
for (n=0; n<4; n++)
{
digits_X[n]=data_in[n+3]-48;
digits_Y[n]=data_in[n+9]-48;
}
*x =(long) 8 * ((long)digits_X[3]+(long)10*digits_X[2]+(long)100*digits_X[1]+(long)1000*digits_X[0]); // 8 -> parceque 8 imps /100eme de mm
*y =(long) 8 * ((long)digits_Y[3]+(long)10*digits_Y[2]+(long)100*digits_Y[1]+(long)1000*digits_Y[0]);
}
//SXA0572YA0381XB1143YB0381D27
void decode_xy_B(long *x, long *y) // retourne des valeurs numériques (en nb impulsions) de la partie numerique qui suit le "XB" et le "YB"
{
for (n=0; n<4; n++)
{
digits_X[n]=data_in[n+15]-48;
digits_Y[n]=data_in[n+21]-48;
}
*x = (long) 8 * (digits_X[3]+(long)10*digits_X[2]+(long)100*digits_X[1]+(long)1000*digits_X[0]);
*y = (long) 8 * (digits_Y[3]+(long)10*digits_Y[2]+(long)100*digits_Y[1]+(long)1000*digits_Y[0]);
}
//XN000000
//LA000000
void decode_6_digits(long *x) // retourne des valeurs numériques [0..1E6] de la partie numérique qui débute à la position 2
{
uint8_t digits[6];
for (n=0; n<6; n++)
{
digits[n]=data_in[n+2]-48;
}
*x = digits[5]+(long)10*digits[4]+(long)100*digits[3]+(long)1000*digits[2]+(long)10000*digits[1]+(long)100000*digits[0];
}
uint8_t decode_num_aperture()
{
/*
* Les formats de reception et d'utilisation des apertures sont volontairement similaires :
MXA1234YA1234XB0000YB0000D12R
PXA2149YA0411XB0000YB0000D13
*/
uint8_t num_ap;
for (n=0; n<2; n++)
{
digits_ap[n]= data_in[n+26]-48;
}
num_ap = digits_ap[1]+10*digits_ap[0];
return num_ap;
}
void tracer_segment() // trace le segment
{
uint16_t d; // largeur x en 1/100mm
float z1, lum1;
long xi, yi;
if (simulation == 1)
{
_delay_ms(50);
envoi_PRET(0,0);
return;
}
decode_xy_A(&xi, &yi); // coorgonnées du début du segment
d = (apertures[num_aperture].x) /8; // largeur x en 1/100mm le /8 because dimensions memorisées en nb de pas moteur. voir la fonction decode_xy_A() (1/100mm = 8 pas)
/**
z = [50..145] . attention z=50 -> presque au contact
LARGEUR DES PISTES :
z = 80 -> ultrafines (avec lum = 20) pour d=0
z = 145 -> 2mm (avec lum = 200) pour d >= 200 (2mm)
**/
z1 = 80.0 + (float)d * 65.0/200.0;
if (z1>145.0) {z1 = 145.0;}
laser_set_Z((uint16_t)z1);
/**
lum = [0..250]
voir le fichier "platine_laser.ods"
-pistes ultra-fines -> lum = 20 ou moins (5) dans le cas de pastilles cms proches (circuits intégrés smd)
-pistes largeur mx (2mm) -> lum = 250 (à voir)
**/
lum1 = 20.0 + (z1-80.0) * 3.53; // 3.53 = dy/dx = (250-20)/(145-80) = 230/65;
if (lum1 < 20.0){lum1 = 20.0;}
if (lum1 > 250.0) {lum1 = 250.0;}
laser_set_lum((uint16_t)lum1);
laser_off();
msg_ret_gto[0]='L'; // demandé en local
goto_xy(xi, yi); // GOTO au début du segment
while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // attend la fin du premier déplacement plume levée vers l'origine du segment
decode_xy_B(&xi, &yi); // coordonnées de l'extrémité du segment
msg_ret_gto[0]='T'; msg_ret_gto[1]='S'; msg_ret_gto[2]='G';
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // trace le segment
laser_off();
}
void tracer_pastille_ronde(uint16_t rayon) // rayon en nb d'implulsions
{
// par segments de droite juxtaposés
long centre_x, centre_y;
long xi, yi;
float rayon_i; // rayon des cercles concentriques qui constitueront la pastille. rayon_i sera diminué à chaque tour.
float largeur_trait, rt;
float x, y;
uint16_t n, i;
int8_t stop;
_delay_ms(50);
Serial.println("ronde");
if (simulation == 1)
{
_delay_ms(50);
envoi_PRET(0,0);
return;
}
largeur_trait = 8 * 15.0; // "8*" because 8 pas/mm
rayon_i = rayon;
// rt = (8*25) + largeur_trait; // rayon du trou; "8*" because 8 pas/mm
// rt = 400; // trous trops grands
rt = 300; // rayon du TROU
if (rayon < 100 ) {rt=0;} // ne pas percer les très petites pastilles qui sont des raccordements de pistes
laser_set_Z(80);
laser_set_lum(10); // 40
centre_x = x0;
centre_y = y0;
n = 0;
stop = 0;
while ((n<12) && (stop == 0))
{
//d= n * largeur_trait;
//if (d > (ax/1.5) || d > (ay/1.5))
if ( (rt>0) && (rayon_i < rt)) { stop=1; }
else
{
for (i=0; i<=180; i++) // tracé d'un cercle_i constitué par 180 minuscules segments
{
x = rayon_i * cos(2.0 * M_PI * i / 180.0);
y = rayon_i * sin(2.0 * M_PI * i / 180.0);
xi = centre_x + (long) round(x);
yi = centre_y + (long) round(y);
msg_ret_gto[0]='S'; // demandé en local et sans frein
if (i>=1) {laser_on();} // le premier déplacement, lui, du centre vers la circonférence, n'a pas été tracé
goto_xy(xi, yi); // trace la pastille - ce goto est effectué par les INT des timers 3 et 4. Il est terminé par le "test_fin_goto"
while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
}
rayon_i -= largeur_trait;
if (rayon_i < 0) {stop=1; }
}
n++;
}
xi = centre_x;
yi = centre_y;
//affleure_plume();
laser_off();
msg_ret_gto[0]='P';
goto_xy(xi, yi); // retour au centre, non tracé
}
void tracer_pastille_rectangulaire(uint16_t ax_i, uint16_t ay_i)
{
// ax_i et ay_i sont les dimensions de la pastille
long centre_x, centre_y;
long xi, yi;
float x, y;
float largeur_trait, d; // epaisseur du trait
int8_t n;
_delay_ms(50);
Serial.println("rectangulaire");
if (simulation == 1)
{
_delay_ms(50);
envoi_PRET(0,0);
return;
}
laser_set_Z(80);
laser_set_lum(5); // 40
largeur_trait = 8.0 * 7.5;
ax_i -= largeur_trait; // pour retrécir le rectangle extérieur de la largeur du trait
ay_i -= largeur_trait; // pour retrécir le rectangle extérieur
centre_x = x0;
centre_y = y0;
msg_ret_gto[0]='L'; // demandé en local
// ici on se trouve au centre de la pastille
// on va se rendre à un coin, plume levée, sans tracer.
xi = centre_x -ax_i;
yi = centre_y -ay_i;
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
// ici on se trouve au premier coin, on commence le tracé
n=0; // au départ n=0 ne retrécit pas la pastille de la largeur du trait, mais cela a été fait ci-dessus au préalable.
while (n<12)
{
d= n * largeur_trait;
if ((d < ax_i) && (d < ay_i))
{
xi = centre_x +ax_i -d;
yi = centre_y -ay_i +d;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x +ax_i -d;
yi = centre_y +ay_i -d;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x -ax_i +d;
yi = centre_y +ay_i -d;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x -ax_i +d;
yi = centre_y -ay_i +d;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
}
n++;
}
//affleure_plume();
laser_off();
xi = centre_x;
yi = centre_y;
msg_ret_gto[0]='P';
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // retour au centre
}
void tracer_carre()
{
long centre_x, centre_y;
long xi, yi;
long x, y, c;
c = 8 * 200.0;
centre_x = x0;
centre_y = y0;
msg_ret_gto[0]='L'; // demandé en local
// ici on se trouve au centre du carré
// on va se rendre à un coin, plume levée, sans tracer.
xi = centre_x -c;
yi = centre_y -c;
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
// ici on se trouve au premier coin, on commence le tracé
xi = centre_x +c;
yi = centre_y -c;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x +c;
yi = centre_y +c;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x -c;
yi = centre_y +c;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
xi = centre_x -c;
yi = centre_y -c;
laser_on();
goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
//affleure_plume();
laser_off();
xi = centre_x;
yi = centre_y;
msg_ret_gto[0]='P';
goto_xy(xi, yi); // retour au centre
}
void recupere_data()
{
String cs_recu = "";
String cs_calc = "";
uint16_t CS_a, CS_b;
int p1 = inputString.indexOf("TRNS:"); // ce string "TRANSMIS:" a été rajouté pour fiabiliser le dialogue USB
int p2 = inputString.indexOf("-CS=["); // ce string "-CS="" précède le checksum ajouté à la fin de la ligne
int p3 = inputString.indexOf("]");
if ((p1>-1) && (p2>-1))
{
int lg= inputString.length();
data_in = inputString.substring(p1+5, p2);
cs_recu = inputString.substring(p2+5, p3);
_delay_ms(50);
Serial.print("CS extrait = " + cs_recu);
CS_a = cs_recu.toInt();
//calcul du checksum de la ligne telle qu'elle est reçue
uint8_t taille = data_in.length();
int8_t n, v;
uint16_t somme = 0;
for (n=0; n<taille; n++)
{
v=data_in[n];
somme += v;
}
CS_b = somme;
cs_calc = String(CS_b);
//_delay_ms(50);
Serial.print(" - CS recalcul = " + cs_calc);
if (CS_b == CS_a)
{
data_valide = 1;
Serial.println(" -> Ok");
}
else
{
data_valide = 0;
n_beep(5);
_delay_ms(50);
Serial.println(" erreur checksum !");
}
// uint16_t cs = qChecksum(qPrintable(data_in), data_in.length()); //checksum
inputString="";
}
}
void X_plus()
{
char inChar2;
acceleration_permise = 1;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
moteur1.enable();
moteur1.set_sens(0);
moteur1.set_marche(1);
uint8_t sortir = 0;
lecture_fins_de_course_xy();
while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
{
lecture_fins_de_course_xy();
while( Serial.available() && ( stringComplete == 0) )
{
inChar2 = (char)Serial.read(); inputString += inChar2;
if (inChar2 == '\n') { stringComplete = 1; }
}
if (stringComplete == 1)
{
recupere_data();
if (data_in[0] == 'A')
{
Serial.println("STOP2");
sortir =1;
}
inputString = "";
stringComplete = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
moteur1.disable();
envoi_PRET(x0, y0);
}
void X_moins()
{
char inChar2;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
acceleration_permise = 1;
moteur1.set_sens(1);
moteur1.enable();
moteur1.set_marche(1);
uint8_t sortir = 0;
lecture_fins_de_course_xy();
while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
{
lecture_fins_de_course_xy();
while( Serial.available() && ( stringComplete == 0) )
{
inChar2 = (char)Serial.read();
inputString += inChar2;
if (inChar2 == '\n') { stringComplete = 1; }
}
if (stringComplete == 1)
{
recupere_data();
if (data_in[0] == 'A')
{
Serial.println("STOP2");
sortir =1;
}
inputString = "";
stringComplete = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
moteur1.set_marche(0);
moteur1.disable();
envoi_PRET(x0, y0);
}
void Y_plus()
{
char inChar2;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
acceleration_permise = 1;
moteur2.set_sens(0);
periode2=36;
moteur2.enable();
moteur2.set_marche(1);
uint8_t sortir = 0;
lecture_fins_de_course_xy();
while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
{
lecture_fins_de_course_xy();
while( Serial.available() && ( stringComplete == 0) )
{
inChar2 = (char)Serial.read();
inputString += inChar2;
if (inChar2 == '\n') { stringComplete = 1; }
}
if (stringComplete == 1)
{
recupere_data();
if (data_in[0] == 'A')
{
Serial.println("STOP2");
sortir =1;
}
inputString = "";
stringComplete = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
moteur2.set_marche(0);
moteur2.disable();
envoi_PRET(x0, y0);
}
int Y_moins()
{
char inChar2;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
acceleration_permise = 1;
moteur2.set_sens(1);
periode2=36;
moteur2.enable();
moteur2.set_marche(1);
uint8_t sortir = 0;
lecture_fins_de_course_xy();
while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
{
lecture_fins_de_course_xy();
while( Serial.available() && ( stringComplete == 0) )
{
inChar2 = (char)Serial.read();
inputString += inChar2;
if (inChar2 == '\n') { stringComplete = 1; }
}
if (stringComplete == 1)
{
recupere_data();
if (data_in[0] == 'A')
{
Serial.println("STOP2"); sortir =1;
}
inputString = "";
stringComplete = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
moteur1.set_marche(0);
moteur2.disable();
envoi_PRET(x0, y0);
}
int goto_Safe_POS()
{
char inChar2;
String inputString2 = "";
uint8_t stringComplete2 = 0;
// déplacement en vitesse rapide jusqu'aux arrêts fin de course, puis positionnement précis
laser_off();
laser_set_Z(140); // position haute
acceleration_permise = 1;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
moteur1.enable();
moteur1.set_sens(0);
moteur1.set_marche(1);
moteur2.enable();
moteur2.set_sens(0);
moteur2.set_marche(1);
uint8_t sortir = 0;
lecture_fins_de_course_xy();
while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
{
lecture_fins_de_course_xy();
stringComplete2 = 0;
while( Serial.available() && ( stringComplete2 == 0) )
{
inChar2 = (char)Serial.read();
inputString2 += inChar2;
if (inChar2 == '\n')
{
stringComplete2 = 1;
}
}
if (stringComplete2 == 1)
{
int p = inputString2.indexOf("TRNS:");
if (p>-1)
{
data_valide = 1;
int lg= inputString.length();
data_in = inputString2.substring(p+5, lg-1);
inputString2="";
}
if (data_in[0] == 'A')
{
Serial.println("STOP2");
sortir =1;
}
inputString2 = "";
stringComplete2 = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
moteur1.disable();
moteur2.disable();
envoi_PRET(x0, y0);
return(0);
}
int goto_ZERO(long xi, long yi) // goto vers zéro mécanique (définit par les fin de course) + valeur de la marge envoyée par le PC
{
char inChar2;
String inputString2 = "";
uint8_t stringComplete2 = 0;
//----------------------------------------------------------------------
// déplacement en vitesse rapide jusqu'aux arrêts fin de course, puis positionnement précis
laser_off();
laser_set_Z(140); // position haute
acceleration_permise = 1;
OCR3A = ocr3a_depart;
OCR4A = ocr4a_depart;
moteur1.enable();
moteur1.set_sens(1);
moteur1.set_marche(1);
moteur2.enable();
moteur2.set_sens(1);
moteur2.set_marche(1);
uint8_t sortir3 = 0;
lecture_fins_de_course_xy();
stringComplete2 = 0;
while ( ((etat_FC_x1 == 0) || (etat_FC_y1 == 0) ) && (sortir3==0) )
{
lecture_fins_de_course_xy();
stringComplete2 = 0;
while( Serial.available() && ( stringComplete2 == 0) )
{
inChar2 = (char)Serial.read();
inputString2 += inChar2;
if (inChar2 == '\n')
{
stringComplete2 = 1;
}
}
if (stringComplete2 == 1)
{
int p = inputString2.indexOf("TRNS:");
if (p>-1)
{
data_valide = 1;
int lg= inputString.length();
data_in = inputString2.substring(p+5, lg-1);
inputString2="";
}
if (data_in[0] == 'A')
{
Serial.println("STOP3");
sortir3 =1;
}
inputString2 = "";
stringComplete2 = 0;
}
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
if (sortir3 == 1)
{
moteur1.disable();
moteur2.disable();
envoi_PRET(x0, y0);
return 1;
}
_delay_ms(50);
Serial.println("goto pt origine dessin");
RAZ_POS(); // ICI : REFERENCE ABSOLUE DES POSITIONS PROVISOIRE (pour pouvoir rejoindre le pt de départ du tracé (valeur de marge envoyée par la commande))
// goto vers valeur envoyée par la commande
acceleration_permise = 0;
base_ocr = 500;
calcul_periode_deplacement(0, 0, 100, 100);
msg_ret_gto[0]='Z'; msg_ret_gto[1]='0'; msg_ret_gto[2]='0';
goto_xy(xi, yi);
while (goto_en_cours_xy == 1)
{
lecture_fins_de_course_xy();
test_fin_goto(xi, yi);
if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
}
_delay_ms(50);
moteur1.disable();
moteur2.disable();
_delay_ms(50);
Serial.println("RAZ coordonnees XY");
RAZ_POS(); // ICI : REFERENCE ABSOLUE DES POSITIONS DEFINITIVE
envoi_PRET(x0, y0);
return(0);
}
void test()
{
//tracer_pastille_ronde(8*75);
/* goto_xy(800* 10, 800* 10);
goto_xy(800* 3, 800* 5);
goto_xy(800* 7, 800* 2);
goto_xy(800* 12, 800* 4);
goto_xy(800* 20, 800* 20);
goto_xy(800* 5, 800* 8);
goto_xy(800* 1, 800* 6);
goto_xy(800* 4, 800* 17);
goto_xy(800* 2, 800* 7);
goto_xy(800* 6, 800* 14);
*/
/*
goto_xy(800*1, 1*800);
goto_xy(800*1, 5*800);
goto_xy(800*8, 5*800);
goto_xy(800*8, 2*800);
goto_xy(800*10, 2*800);
goto_xy(800*10, 3*800);
goto_xy(800*7, 3*800);
goto_xy(800*7, 4*800);
goto_xy(800*3, 4*800);
goto_xy(800*3, 1*800);
goto_xy(800*5, 1*800);
goto_xy(800*1, 6*800);
goto_xy(800*5, 6*800);
goto_xy(800*5, 4*800);
goto_xy(800*5, 3*800);
tracer_pastille_ronde(400);
*/
/*
uint8_t n;
goto_xy(800*1, 1*800);
for (n=1; n<=10; n++)
{
goto_xy(800*1, 5*800);
goto_xy(800*6, 5*800);
goto_xy(800*6, 1*800);
goto_xy(800*1, 1*800);
}
*/
Serial.println("Essai de transmission d'un message long");
}
void envoi_liste_apertures()
// vers le PC, pour test
// rappel : apertures[i][0] -> x ; apertures[i][1] -> y; (x et y ne sont pas des positions mais des dimensions); apertures[i][2] -> 'R' ou 'C'
{
uint16_t x, y, type;
uint8_t i, r, valeur;
// char msg_position[20]="0123456789012345678"; // 19 car max pour un string20
char msg_aperture[20]="APERTURE 00 = X "; // 19 car max pour un string20
Serial.println("Liste APERTURES:");
for (n=0; n<40; n++)
{
x = apertures[n].x;
y = apertures[n].y;
type = apertures[n].type; // "C" ou "R" ou "O" (en principe!))
valeur = n;
for (i=0; i<2; i++)
{
r=48 + valeur % 10; // modulo (reste de la division)
valeur /= 10; // quotient
msg_aperture[10-i]=r;
}
msg_aperture[14]=type;
_delay_ms(50);
Serial.println(msg_aperture);
}
}
void setup()
{
// CLKPR = 0b10000000;
// CLKPR = 0b00000000;
init_ports();
laser_off();
simulation=0;
// int_EXT_setup(); // desable (inutile depuis que les moteurs ne "glissent" plus )
timer2_setup();
timer3_setup();
timer4_setup();
timer5_setup();
// init_table_sinus(); <- ***************************** A VOIR !!! *************************
// lcd_init(); // voir l'attribution des bits dans le ficher LCD_5110-b28b.h - Note: j'ai supprimé l'affichage LCD.
// ==== Le port est défini dans le step_motor4.h ========
moteur1.bit_ENABLE = 0b00000001; // X
moteur2.bit_ENABLE = 0b00000010; // Y
// ==== Le port est défini dans le step_motor4.h ========
moteur1.bit_finCourse1 = 0b00000001; // X
moteur1.bit_finCourse2 = 0b00000010; // X
moteur2.bit_finCourse1 = 0b00000100; // Y
moteur2.bit_finCourse2 = 0b00001000; // Y
// ==== Le port est défini dans le step_motor4.h ========
moteur1.bit_DIR = 0b00000001; // X
moteur1.bit_STEP = 0b00000010; // X
moteur2.bit_DIR = 0b00000100; // Y
moteur2.bit_STEP = 0b00001000; // Y
// =====================================================
mm_par_s_max = 2; // par défaut
mm_par_s = mm_par_s_max;
moteur1.steps_par_tour = 200;
moteur1.tours_par_mm = 2; // pas-de-vis 0.5mm (pour un diamètre M3)
moteur1.impuls_par_step = 2; // de par la configuration de la carte "EasyDriver"
moteur2.steps_par_tour = 200;
moteur2.tours_par_mm = 2;
moteur2.impuls_par_step = 2;
ocr3a_min = 800; // pour moteur1 800
ocr3a_depart = 2000; // pour moteur1 1300
ocr4a_min = 800; // pour moteur2 800
ocr4a_depart = 2000; // pour moteur2 2000
base_ocr_depart = 3000; // 3000 determine la vitesse de rotation (basse) appliquée lors de la mise en rotation
base_ocr_min = 500; // determine la vitesse max de rotation permise, voir les fonctions "ISR(TIMER3_COMPA_vect)" et "ISR(TIMER4_COMPA_vect)"
base_ocr_min2 = 300; // determine la vitesse max de rotation permise lors des "goto zero" et "goto safe pos"
moteur1.init(); // calcule les autres paramètres...
moteur2.init(); // calcule les autres paramètres...
n_octet=0;
Serial.begin(38400); // 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200
uint16_t x2, y2, p1, p2;
x0=0;
y0=0;
x2=100;
y2=100;
calcul_periode_deplacement(x0, y0, x2, y2);
moteur1.RAZ_pos();
moteur2.RAZ_pos();
for (int i=0; i<40; i++) { apertures[i].type = 'x'; }
//apertures[23][2] = 'R'; // pour test
sei();
laser_off();
laser_set_lum(40);
laser_set_Z(145);
_delay_ms(50);
Serial.println("hello");
_delay_ms(50);
Serial.println("CNC version " + version);
_delay_ms(50);
Serial.println("Bonjour");
_delay_ms(50);
Serial.println("Mega2560 INIT");
_delay_ms(50);
beep();
_delay_ms(50);
beep();
Serial.println("USB ok");
envoi_PRET(x0, y0);
}
void loop() // BOUCLE PRINCIPALE
{
// ne pas inclure de tempo dans cette boucle principale sous peine de perdre la précision des positions de fin de goto, et donc la précision de position de la plume !
long xil, yil;
lecture_fins_de_course_xy();
// test_fin_goto(); // stope le cas échéant le goto en cours
cpt1++;
if (cpt1 >= 1000)
{
PORTA ^= bit_LED_verte;
cpt1=0;
}
if (goto_en_cours_xy == 0)
{
uint8_t n;
stringComplete = false;
while(stringComplete == false)
{
if (Serial.available())
{
inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {stringComplete = true; }
}
}
data_valide = 0;
if (stringComplete = true)
{
_delay_ms(50);
Serial.println("recu: "+inputString);
_delay_ms(1);
recupere_data();
}
if (data_valide == 1) // lorsque les checksums sont égaux...
{
// decodage du message reçu par USB
//--------------------------------------------------------------------------------------------------------------------------------------------------------
if (data_in[0] == 'A') // STOP
{
_delay_ms(50);
Serial.println("STOP");
STOP();
data_in="";
stringComplete = false;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'T') // TESTS
{
if (data_in[1] == 'E')
{
test();
data_in="";
stringComplete = false;
}
if (data_in[1] == 'A') // envoyer liste liste apertures
{
envoi_liste_apertures();
data_in="";
stringComplete = false;
}
if (data_in[1] == 'I') // mode simulation
{
simulation=1;
_delay_ms(50);
Serial.println("MODE SIMULATION");
data_in="";
stringComplete = false;
}
if (data_in[1] == 'N') // stop du mode simulation
{
_delay_ms(50);
Serial.println("FIN SIMULATION");
simulation=0;
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'Z') // LASER ON/OFF
{
if (data_in[1] == '1') // allume LASER
{
laser_on();
data_in="";
stringComplete = false;
}
if (data_in[1] == '0') // éteint LASER
{
laser_off();
data_in="";
stringComplete = false;
}
if (data_in[1] == 'B') // BLOCAGE LASER
{
laser_bloque();
_delay_ms(50);
Serial.println("Blocage laser");
data_in="";
stringComplete = false;
}
if (data_in[1] == 'D') // DEBLOCAGE LASER
{
laser_debloque();
data_in="";
stringComplete = false;
}
}
else if (data_in[0] == 'L')
{
if (data_in[1] == 'U') // intensité luminosité laser
{
long LU;
decode_6_digits(&LU);
laser_set_lum((uint8_t)LU);
data_in="";
stringComplete = false;
}
if (data_in[1] == 'Z') // Hauteur du laser
{
long LZ;
decode_6_digits(&LZ);
laser_set_Z((uint16_t)LZ); // remarque: le timer5 est configuré en mode "fast PWM 10 bits"
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'X') // déplacements en X
{
_delay_ms(50);
Serial.println("DEPLACEMENT MANUEL");
moteur1.set_marche(0);
if (data_in[1] == 'P') // X Plus
{
_delay_ms(50);
Serial.println("X+");
data_in="";
stringComplete = false;
X_plus();
}
if (data_in[1] == 'M') // X Moins
{
_delay_ms(50);
Serial.println("X-");
data_in="";
stringComplete = false;
X_moins();
}
if (data_in[1] == 'N') // rotation de N pas du moteur X (pour tester des moteurs)
{
_delay_ms(50);
Serial.println("XN");
long P;
decode_6_digits(&P);
rotX_n_pas(P);
data_in="";
stringComplete = false;
}
if (data_in[1] == '1') {Serial.println("X+1"); X_plus_mm(1); data_in="";}
if (data_in[1] == '2') {Serial.println("X+10"); X_plus_mm(10); data_in=""; }
if (data_in[1] == '3') {Serial.println("X-1"); X_moins_mm(1); data_in="";}
if (data_in[1] == '4') {Serial.println("X-10"); X_moins_mm(10); data_in="";}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'Y') // déplacement en Y
{
_delay_ms(50);
Serial.println("DEPLACEMENT MANUEL");
moteur2.set_marche(0);
if (data_in[1] == 'P') // Y Plus
{
_delay_ms(50);
Serial.println("Y+");
data_in="";
stringComplete = false;
Y_plus();
}
if (data_in[1] == 'M') // Y Moins
{
_delay_ms(50);
Serial.println("Y-");
data_in="";
stringComplete = false;
Y_moins();
}
if (data_in[1] == 'N') // rotation de N pas du moteur Y (pour tester des moteurs)
{
_delay_ms(50);
Serial.println("YN");
long P;
decode_6_digits(&P);
rotY_n_pas(P);
data_in="";
stringComplete = false;
}
if (data_in[1] == '1') {Serial.println("Y+1"); Y_plus_mm(1); data_in="";}
if (data_in[1] == '2') {Serial.println("Y+10"); Y_plus_mm(10); data_in=""; }
if (data_in[1] == '3') {Serial.println("Y-1"); Y_moins_mm(1); data_in="";}
if (data_in[1] == '4') {Serial.println("Y-10"); Y_moins_mm(10); data_in="";}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'P') // TRACER PASTILLE à partir d'une ligne de commande reçue
{
_delay_ms(50);
Serial.println("TRACE pastille");
if (data_in[1] == 'X') // en x,y
{
laser_off();
type_ap = apertures[num_aperture].type; // -> 'R'(rectangulaire) ou 'C'(circulaire) ou 'O'(ovale)
_delay_ms(50);
Serial.println(" de type ");
Serial.println(type_ap);
decode_xy_A(&xil, &yil);
num_aperture = decode_num_aperture();
ax = (apertures[num_aperture].x /2); // dimension x (rayon = diam/2) - épaisseur de la trace
if (ax > largeur_plume) {ax -= largeur_plume;} else {ax = 0;}
ay = (apertures[num_aperture].y /2);
if (ay > largeur_plume) {ay -= largeur_plume;} else {ay = 0;}
msg_ret_gto[0]='R'; msg_ret_gto[1]=' '; msg_ret_gto[2]=' ';
goto_xy(xil, yil); // goto vers l'emplacement de la pastille à tracer
while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }
if ((type_ap == 'R') || (type_ap == 'O')) { tracer_pastille_rectangulaire(ax, ay); } // les pastilles ovales seront tracées rectangulaires...
// todo : écrire une fonction qui trace une pastille ovale
else if (type_ap == 'C') { tracer_pastille_ronde(ax);}
else
{
_delay_ms(50);
Serial.println(type_ap + " inconnue");
}
data_in="";
stringComplete = false;
}
if (data_in[1] == '1') // PASTILLE rectangulaire là où on se trouve
{
_delay_ms(50);
Serial.println("PST ici");
tracer_pastille_rectangulaire(8*200, 8*200); // 8 (impls/100eme de mm) x 200 (100eme de mm); -> 1600 impulsions
stringComplete = false;
data_in="";
}
if (data_in[1] == 'R') // PASTILLE ronde là où on se trouve
{
Serial.println("PST ici");
decode_xy_A(&ax, &ay);
tracer_pastille_ronde(8 * ax/2); // le diametre est transmis par le PC, on va tracer le rayon.
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'R')
{
if (data_in[1] == 'P')
{
_delay_ms(50);
Serial.println("RAZ POS");
RAZ_POS();
data_in="";
stringComplete = false;
}
if (data_in[1] == 'K')
{
_delay_ms(50);
Serial.println("Rot 2kPi");
rotation_2k_pi();
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'S') // TRACER SEGMENT
{
_delay_ms(50);
Serial.println("TRACE segment");
if (data_in[1] == 'X')
{
num_aperture = decode_num_aperture();
tracer_segment();
data_in="";
stringComplete = false;
}
if (data_in[1] == '1') // segment là où on se trouve
{
Serial.println("SEG ici");
xil=x0 + (8 * 1000); // 10.00 mm
yil=y0;
msg_ret_gto[0]='S'; msg_ret_gto[1]='1';
laser_on();
goto_xy(xil, yil); // trace le segment
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'C')
{
if (data_in[1] == '1')
{
_delay_ms(50);
Serial.println("carre ici");
tracer_carre();
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'H') // TRACER mire pour la mise au point
{
Serial.println("TRACE MIRE");
if (data_in[1] == '1')
{
for (n=0; n<3; n++)
{
Y_plus_mm(5);
moteur1.RAZ_pos();
moteur2.RAZ_pos();
x0=0;
y0=0;
xil=8*(x0+1000); // 10.00 mm
yil=8*(y0);
laser_on();
goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
tracer_pastille_rectangulaire(8*200, 8*200);
xil=8*(x0+1000); // 10.00 mm
yil=8*y0;
laser_on();
goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
tracer_pastille_ronde(8*200);
xil=8*(x0+1000); // 10.00 mm
yil=8*y0;
laser_on();
goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
tracer_pastille_ronde(8*200);
xil=8*(x0-3000); // 30.00 mm
yil=8*y0;
laser_off();
goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
}
data_in="";
stringComplete = false;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
else if (data_in[0] == 'G') // GOTO ( DEPLACEMENT laser éteint / plume levée)
{
laser_off();
if (data_in[1] == 'X')
{
_delay_ms(50);
Serial.println("GOTO");
decode_xy_A(&xil, &yil);
msg_ret_gto[0]='-'; msg_ret_gto[1]='X'; msg_ret_gto[2]='Y';
OCR3A = 1000; // pour moteur1
OCR4A = 1500; // pour moteur2
goto_xy(xil, yil);
data_in="";
stringComplete = false;
}
if (data_in[1] == 'S')
{
_delay_ms(50);
Serial.println("goto SAFE POS");
goto_Safe_POS();
data_in="";
stringComplete = false;
}
if (data_in[1] == 'H')
{
_delay_ms(50);
Serial.println("GOTO ZERO XYZ");
decode_xy_A(&xil, &yil);
goto_ZERO(xil, yil);
data_in="";
stringComplete = false;
}
}
// -------------------- AJOUT APERTURES à la liste -----------------------------------------------------------------------------------------------
else if (data_in[0] == 'M')
{
laser_off();
//PORTA &= ~bit_LED_verte;
beep2();
_delay_ms(50);
Serial.println("ajout APERTURE ");
_delay_ms(50);
if (data_in[1] == 'X')
{
decode_xy_A(&ax, &ay); // attention : ici il ne s'agit pas de la position de l'objet mais de ses dimensions (qui sont codées de la même façon au même endroit dans la ligne)
type_ap = data_in[28]; // "C" ou "R" ou "O"
if (type_ap == 'C') {n_beep(1);}
else if (type_ap == 'R') {n_beep(1);}
else if (type_ap == 'O') {n_beep(1);}
else {n_beep(5);}
num_aperture = decode_num_aperture();
ajout_aperture(num_aperture, type_ap);
data_in="";
stringComplete = false;
}
data_in="";
}
else
{
_delay_ms(50);
Serial.println("non interpretable ");
}
}
// ---------------------------------------------------------------------------------------------------------------------------------------------------
//x0 = moteur1.position_impuls;
//y0 = moteur2.position_impuls;
}
else
{ // ICI goto en cours -> procédures au ralenti pour minimiser les ressources nécessaires afin de laisser le max pour la détection de position de fin de goto
}
}