Rubriques:
|
Conception
Au commencement de ce projet je ne savais pas
exactement comment m'y prendre pour
actioner
une machine à partir d'un pc: quelle interface ? quels moteurs ?
quel soft ? ... après quelques recherches
sur
l'internet il semblait évident que le couple port
parallèle et moteur pas à pas s'imposait pour les raisons
suivantes:
- aspect "standard" du port // (présent sur
tout les pc).
- rapidité de programmation et de mise en
oeuvre de la commande des moteurs pas à pas.
- coût réduit
Comme
je le précise sur la page d'accueil, cette rubrique à
pour seul but d'expliquer de manière claire (du moins je
l'espère) les différents mécanismes qui permettent
une découpe numérique.
Les
spécifications
Principe de
base:
Pour découper
un
noyau d'aile en mousse on utilise un fil métallique de quelque
10eme de mm de diamètre, tendu et monté en
court-circuit sur une alimentation variable afin d'être
chauffé par effet Joule à une température
suffisante pour faire fondre le bloc de polystyrène.
Considerons
maintenant les
2 points du fil espacés de l'envergure de l'aile, l'un des
points
décrit le profil de l'emplanture, et dans le même temps
l'autre décrit le profil du saumon. Je souligne dans le
même
temps, car de ces 4 mots découlent la principale
difficulté
du projet.
Quand on a
décrit
l'intrados et l'extrados, on en ressort le noyau d'aile.
La méthode
manuelle consite à fabriquer des gabaris de découpe et de
faire glisser le fil sur ces gabaris
de manière à peu près synchrone.
Tous les
modélistes
connaissent les difficultés de mise en oeuvre: chaque nouveau
type
d'aile entraine la fabrication de nouveaux gabaris. Le respect
exact du profil passe par une qualité de gabaris et une
synchronisation de la découpe emplanture/saumon, qu'il est
très difficile d'obtenir manuellement.
La
machine CNC permet de s'affranchir de ces problèmes: les gabaris et les
déplacements sont assurés
par le couple logiciel + machine.
Le logiciel
assure la
découpe d'aile d'une envergure quelconque, possèdant une
flèche, une corde
variable
et un vrillage donné ( ceci dans la limite des dimensions
mécanique de la
machine).
Enfin, le
logiciel est compatible avec les formats des fichiers de
coordonnées de profils
les
plus courant (.dat) et permet la sauvegarde des fichiers
découpe
d'ailes.
Schématiquement
voici
à quoi j'ai aboutit:
Toutes les
questions que
vous vous posez suite à la lecture de ce schéma sont, je
l'espère,
dans les paragraphes qui suivent.
Solution
Technique
OS:
Linux
Plus la
peine de
vanter les mérites de ce système d'exploitation. Ouvert,
libre c'est une base de développement fantastique. Le logiciel a
été développé sur une
RedHat 7.2, et fonctionne aujourd'hui sur une Mandrake 9.2.
Interface
graphique: Tcl/Tk
Tcl/tk
est un langage
script pour application graphique que j'ai eu l'occasion de connaitre
de
par mes activités professionelles. Très puissant, facile
d'aprentissage, de nombreuses documentations et sources existent sur le
web.
Le role de
l'interface est
de passer des coordonnées des profils aux coordonnées de
découpe.
Les
coordonnées de
découpes sont les couples de vecteurs d'interpolation
linéaire u(x,y)
et v(x,y) qui décrivent les courbes des profils.
Ils sont ensuite
transmis
au driver de la carte interface machine les uns après les autres
pour décrire les mouvements complet de la machine.
Voici quelques
captures d'écran
de la version 1.1 du logiciel:
Fenêtre
Principale
Graph
du profil emplanture
Graph
du profil saumon
Les
coordonnées du profil emplanture
Interface
Matériel: Le Port parallèle
Présent
sur
tous les pc, il est très facilement programmable. Sous
Linux,
en langage C, on lit et on écrit directement les
états
des bits du port // par les commandes inb <lecture> et outb
<ecriture>.
Il faut par contre
autoriser
au préalable ces opérations par la commande ioperm.
Attention seul
le user
root peut faire un ioperm car c'est une opération
très
dangereuse, on imagine facilement ce qui se passerait si n'importe quel
user pouvait accéder directement aux d'entrées sorties du
pc.
Pour commencer,
il faut connnaitre
l'adresse de base du port // sur le PC, en géneral 0x378, mais
en
cas de doute vérifier dans le setup ou lancer les
commandes:
echo
> /dev/lp0
(puis crtl-c) (force la prise en compte du port // par le
système
)
et
cat
/proc/ioports
qui vous donne
la liste
des plages d'entrées sortie des périphériques:
....
0378-037a :
parport0
.....
cherchez la
ligne correspondant
au "parport0", et recuperez l'adresse, ici 378h.
Enfin il faut
connaitre
le mapping du port // :
En
résumé:
A l'adresse de
base nous
trouvons un port en écriture dont les 8 bits sont
accessibles
, à l'adresse de base+1 un port en lecture dont seulement 6 bits
sont accessibles et enfin à l'adresse de base +2 un port en
écriture
dont 4~5 ? bits sont accessibles.
Ceci est largement
suffisant
pour la commande de la machine.
Le petit plus:
Je fais
remarquer aux non-initiés,
que les commandes d'i/o ne permettent pas de commander ou de connaitre
l'état d'un seul bit d'un port, on y accède par octet.
Pour isoler un bit
en particulier,
il faut masquer les autres: le bit n, aura un masque
sera
égal à 2^n :
n bit=
76543210
2^0 = 00000001
2^1 = 00000010
2^2 = 00000100
Un exemple:
Lecture:
Supposont
qu'inb(adresse_base+1)
renvoie la valeur entiere 233 soit 11101001 en binaire
Pour
connaitre la valeur
du bit 3 on fait un ET logique entre l'état du port et
le
masque: 2^3 soit 00001000 en binaire.
11101001&&00001000
=00001000
L'opération
vaudra
0 si 0 Volt est appliqué à la broche 4 du port // (b3
à
0), et vaudra 2^3 si vous y appliquez 5 volts.
Ecriture:
Cette
fois il faut
lire le port pour connaitre sont état et donc la valeur de tous
les bits du port, et si ce n'est pas possible connaitre sont
état
préalable (c'est le dernier état appliqué par le
logiciel)
ETAT_PREV.
Mise à
1 d'un bit:
On applique
le masque du
bit n à ETAT_PREV et on ecrit ce nouvel état par outb(adresse_base,ETAT):
ETAT =
ETAT_PREV ||
2^n ( OU logique )
ex bit
4:
ETAT_PREV=10001010
n=4 =>
masque bit4=0x10
en hexa soit en binaire: 00010000
10001010 ||
0001000
= 10011010
et hop le bit
est à
1
Mise à 0
d'un bit:
si l'on veut
mettre le bit
n à 0 on prend le complément du masque (
opération
~ en c ) et l'on fait un ET logique:
ETAT
= ETAT_PREV
&& ~2^n (et logique )
ex bit 4:
ETAT_PREV=10111010
n=4 =>
masque bit4=0x10
en hexa
soit en
binaire: 00010000
son complement
vaut: 11101111
10111010
&&
11101111
= 10101010
et hop le bit
est à
0
Pour ceux qui
comme moi,
ne parlent pas l'hexabinarodécimal couramment, une calculatrice
de type scientifique est souhaitable.
Maintenant que
les opérations
de base sont décrites, on imagine toutes les possibliltés
qui s'offrent à nous.
La
programmation:
Les
header à
ne pas oublier:
#include
<unistd.h>
#include
<asm/io.h>
un define pour
l'adresse de
base:
#define
ADR_BASE
0x378
les fonctions de
base d'entree
/ sortie
int
out_port(int
adresse, int port, int val)
{
outb(val,adresse + port);
return(0);
}
int
in_port(int adresse,
int port)
{
int val;
val = inb(adresse + port);
return(val);
}
dans le main,
placer la commande
d'autorisation à l'init :
if
(ioperm(ADR_BASE,2,
1)) // => depuis l'adresse de base ADR_BASE sur 2
octets
, mettre à 1 ( autoriser), les accès i/o .
{
perror("ioperm");
exit(EXIT_FAILURE);
}
on peut alors
appeler les fonctions
out_port et in_port.
J'ai créer
un programme
de base io.c qui donne un bon
exemple de ce que l'on peut faire avec un port parallèle, vous
le
retrouverez dans la rubrique download.
Une étape
plus loin
a été de développer un
testeur de servo avec une interface tk qui s'appuie sur la RTC
(Real Time clock) tout comme le driver cnc.
Moteurs:
Pas à Pas
Au
début,
je pensais utiliser des servomoteurs, j'ai même developpé
une interface pour les piloter via le port // qui est resté au
stade
de testeur de servo.
Et puis je me suis vite rendu compte que je ne pourrai jamais asservir
correctement
ces moteurs en vitesse relative, point indispensable à la
réussite
du projet.
Je me suis donc
orienté
vers des moteurs pas à pas, très intéressant, bien
plus facile a commander qu'un servo
avec un pc. Par contre si un servo peut se commander avec 1 bit (en
modulation
de largeur de pulse) un moteur pas à pas nécessite au
minimum
2 bits (1 bit d'horloge et 1 bit de sens).
Quant à
l'asservissement
en vitesse relative, pas de problème il suffit d'envoyer les
tops
d'horloges "intelligement", le driver de la carte interface va se
charger
de ça grâce à l'algorithme
de Breseham.
Le
driver carte interface: langage c
Si
l'interface et
les calculs sont écrits en tcl/tk , il était impossible
d'écrire
la partie driver dans ce langage pour des questions évidentes de
rapidité d'éxecution.
Le driver pilotera
la carte
interface via le port parallèle: il reçoit les
coordonnées
des vecteurs à décrire et met en forme les signaux sur le
port // pour la commande des moteurs.
Dans un premier
temps le
driver a été développé en 2 parties:
Une partie client
et une
partie serveur auxquelles je dédiais respectivement les
tâches
1) d'algorithmie 2) de commande de la carte via le port //, ces 2
programmes
communiquant aux travers de fifos pour la "buffersation".
Tous ceci
fonctionnait très
bien (du moins sur le papier) mais dès les premiers tests de
découpe
je me suis rendu compte de ralentissement des moteurs au passage entre
chaque nouveau vecteur à cause de rides dans le
polystyrène
!!!
Explication: en
fait l'interface
graphique communiquait avec la partie cliente à chaque vecteur,
et cette fois sans "bufferisation" d'où une perte de performance
à chaque appel.
Puisque c'est
ainsi pourquoi
ne pas ré-écrire le driver ? Et tant qu'on y est pourquoi
ne pas utiliser des threads ?
L'idée a
donc
été de considérer ces programmes
précédant
comme 2 threads d'un même programme, qui communiqueraient cette
fois
non plus par fifo mais par un tableau à référence
circulaire à double index: un index pour l'écriture et
l'autre
pour la lecture obéïssants aux rêgles suivantes: la
lecture
ne dépasse jamais l'écriture et l'écriture ne
dépasse
pas l'indexe écriture. Tout ça modulo la taille du
tableau
of course.
thread
1: algorithme de bresenham
Une
première thread
est dédiée à la lecture de la FIFO in (messages en
provenance de l'interface) , elle y recoit les 2 vecteurs u(x,y)
v(x,y)
d'interpolation linéaire des courbes à décrire
avec
la machine.
Elle transforme
ensuite ces
vecteur en instructions élémentaires: "pas" et
"direction"
pour chacun des moteurs qu'elle transmets à un tableau
circulaire.
Pour ce faire
le programme repose sur l'algorithme de Bresenham.
Dans un plan
discret,
cet algorithme permet de trouver les points du système de
coordonnées
les plus proches des courbes (ou plus exactement des vecteurs
d'interpolation
linéaire)
Ce paragraphe s'appuie sur un article de Mme Marie-Renée
Josserand (Maatel) (ÉLECTRONIQUE - No. 38, Mai 1994),
j'ai
ensuite modifié l'algorithme pour
qu'il s'applique non pas à un vecteur mais à 2.
Graphe d'un
profil dans
le repère discret
Seuls les
points de croisement
sont accessibles.
Description
de l'algorithme
original pour 1 vecteur (2 moteurs)
Extrapolation
d'un
vecteur dans un repere discret:
Soit
u(A,B) un vecteur de ce repere ( A et B entier) ramené dans le
premier octan: A=abs(A), B=abs(B) , permutation A B si A<B)
Représentation
du vecteur U dans le repère discret
pour
decrire le vecteur dans ce systeme:
on
pose VAR=2B-A
Faire
A fois
Si
VAR < 0
VAR=VAR+2B
On
avance d'un pas suivant l'axe majeur
sinon
VAR=VAR+2B-2A
on
avance simultanément d'un pas suivant l'axe majeur
et
suivant l'axe mineur
fin
si
fin
faire
on
decrit aisement tout types de vecteurs en ayant memorisé les
opérations
effectuées
pour le ramener dans le premier cadran.
en
clair si A etait < B
on permute axe majeur mineur
si
A <
0
on recule suivant cet axe
si
B <
0
on recule suivant cet axe
Application de
l'algorithme
pour 2 vecteurs ( == 4 moteurs)
Dans
la suite
on considere u(A,B),v(C,D) vecteurs du repere discret
- les 2
vecteurs sont
ramenés dans le premier octan de la meme maniere
- de plus
si C > A
alors on permute les deux vecteurs.
pour
decrire les vecteurs
dans ce systeme:
on
pose
VAR_U=2B-A
on
pose
VAR_V=2D-C
on
pose
R = C/A
on
pose
JS=-1
DE I=1
a I<A I=I+1
(
Traitement
du 1 eme vecteur
)
( Traitement du 1 eme vecteur )
Si (
VAR_U < 0
)
VAR_U=VAR_U+2B
on
avance d'un pas
suivant l'axe majeur 1
sinon
VAR_U=VAR_U+2B-2A
on
avance simultanément
d'un pas suivant l'axe majeur 1 et suivant l'axe mineur 1
fin si
J=
entier ( R * I )
si ( J
different de
JS && J >= à 1 ) ( nouveau pas pour
le
2eme vecteur )
(
Traitement du 2
eme vecteur )
Si ( VAR_V
< 0 )
VAR_V=VAR_V+2D
on
avance d'un pas
suivant l'axe majeur 2
sinon
VAR_V=VAR_V+2D-2C
on
avance simultanément
d'un pas suivant l'axe majeur 2
et
suivant l'axe mineur
2
fin si
JS=J
(memorisation du pas effectue)
fin si
fin DE
Le vecteur v
est decrit au
fur et a mesure de la description de u: Ils sont décrits dans le
meme temps ( ceci permet de
s'affranchir
du casse tête qu'aurait été la synchronisation d'un
bras par rapport
à
l'autre).
De meme que pour
un vecteur
seul, on decrit aisement tout types de vecteurs en ayant
memorisé
les opérations effectuées pour les ramener dans le
premier
cadran.
pour u
& v
si
A etait
<
B
on permute axe majeur1 mineur1
si A
<
0
on recule suivant cet axe
si B
<
0
on recule suivant cet axe
si C
etait <
D
on permute axe majeur2 mineur2
si C
<
0
on recule suivant cet axe
si D
<
0
on recule suivant cet axe
nb: dans tout
ceci j'ai considéré
que les axes majeur1&2 mineur1&2 etaient echantillonnés
avec le meme pas ( sinon il faudrait introduire un facteur
d'echelle
dans le calcul J = entier ( R * I ) ce que je n'ai pas fait car toutes
mes mécaniques sont identiques)
Chaque
itération de
l'algorithme est transmise à la thread de commande du port
grâce
à un tableau circulaire.
Format du
message du tableau
: pas1:pas2:pas3:pas4:
ex:
-1:+0:+0:+1:
-1 pas
moteur 1
1
pas moteur
2
0
pas moteur
3
1
pas moteur
4
thread 2:
commande port
parallèle
C'est le thread
qui va réellement
attaquer le port parallèle ( par la commande outb). Il applique
un mot binaire,
suivant les
instructions
reçues dans le tableau circulaire, au rythme de ça propre
horloge (cadencée de manière très précise
par la RTC ) :
__ __ __
__
__ __
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
__| |__| |__| |__| |_____| |__| |__ pas
__
________________ sens
|
|
|____________________|
Mapping
port //
voie 1:
pas: pin 2 sens: pin 3
voie 2:
pas: pin 4 sens: pin 5
voie 3:
pas: pin 6 sens: pin 7
voie 4:
pas: pin 8 sens: pin 9
masse:
pin 22
thread 3:
commande de la chauffe
La modulation de température est
obtenue par
hachage de la
tension appliquée au fil: Pour
cela le soft fait varier le rapport
cyclique du
créneau appliqué à un MOSFET utilisé en
mode commutateur.
0% ___________
__ __
| | | |
66% _| |_| |_
__
__
| | |
50% _| |__|
________
|
100% _|
Hard:
Carte commande moteur
But:
transformer
les 8 bits d'entrée (horloge et sens des 4 moteurs fourni par la
port // ) en des signaux compatibles avec la commande des moteurs pas
à
pas. Je précise qu'il seront du type "unipolaire".
L'alimentation
sera assurée
par une alim. de PC.
Pour rendre
à César
ce qui lui appartient je précise que je suis parti d'un
existant: infos
, j'ai ensuite modifié le schéma pour mes besoins
J'ai
représenté
par la suite le schéma pour un moteur. Pour les trois autres je
vous laisse deviner.
- Le
schéma est des plus
simple: mise en forme des signaux via 2 transistor NPN ( passage de TTL
5v à 12 v ).
- Le bit
d'horloge et le bit
de sens attaquent un 4029 qui va transformer les signaux en
une séquence binaire sur 2 bits qui comptera ou
décomptera
suivant le cas.
- on relie
les 2
bits de sortie
du 4029 au 4028 qui "décodera" le mot binaire et
alimentera
une à une les bobines du moteur pas à pas.
- ces
signaux
transitent via un 2803
pour la puissance et sont ensuite relié au bornier.
schema de
l'électronique
de commande moteur pas à pas
Pas de
composant programmable,
tout est dans le soft.
Voici le
mapping utilisé
pour commander la carte depuis le soft:
et quelques
photos de la
carte que réalisée en wrapping:
on reconnait les
transistors,
les 3 CI par voie, et le bornier d'alimentation type pc.
Telle qu'elle
est faite,
la carte est passive. Je m'explique: pour obtenir un cadencement
à
une certaine vitesse, une rampe d'accelération ou de
descélération
c'est au PC et au soft qu'il faut le demander.
Mécanique:
La rustica
Pour la
réussite du projet, il fallait une
machine facile à construire, pas d'usinage compliqué, pas
de pièce introuvable en grande surface de bricolage, bref un
must.
vue arrière
de la machine démontée depuis l'oeil de la webcam
Decoupe:
Principe de Projection / Prolongation
Posons
le problème:
La machine a des dimensions fixes: tant en largeur qu'en hauteur pour
chaque
chariot mais aussi en empatement. Les 2 plans que décrivent les
points mobiles des chariots sont toujours à la même
distance: c'est
la largeur de la table sur le schema ( D ).
Or, ce que
l'on se
propose de faire, c'est de décrire le profil emplanture et le
profil
saumon de notre aile sur ces deux plans pour faire la découpe (
ici les plans rouge et vert ).
Dans ces
conditions, pour des ailes d'envergure différente de la largeur
de la machine (ici E ), nous n'obtiendrons une découpe correcte
que si les ailes sont à profil, corde, incidence et
épaisseur
constant ( autant dire très peu d'ailes) .
Dans tous les
autres cas
il faut "prolonger / projeter " le profil saumon sur le plan du chariot
de découpe.
On peut faire cela
en applicant
le théorème de Thalès, un rappel:
On applique
cela au triangle
orange de la figure suivante qui représente l'aile vue du dessus:
(X0n - N) / (X0n - M ) =
(X0n-X'1n) / (X0n-X1n)
= (X'1n-N) / (X1n-M)
d'où
X'1n-N = (X0n-N)
/ (X0n-M ) x (X1n-M) soit X'1n-N= D/E(X1n - X0n)
et X'1n
= D/E
(X1n - X0n ) - X0n
On pourrait
appliquer le
meme principe pour trouver l'ordonnée Y'1n du point de
prolongation.
En notation
vectorielle cela
donne: (en considérant les notation du schéma 3D du
dessus):
V'n= D/E (Un-Vn) + Un
Unvecteur
décrivant le nieme point du profil emplanture dans le plan Po
Vn vecteur
décrivant le nieme point du profil saumon dans le plan P1
D distance
entre les
2 plans de découpe
E envergure
de l'aile.
Quelques
exemples
pour une machine de 750 mm d'empatement:
Sont
représentés
sur les graphes suivants, les chemins empreintés par le fil de
la
machine pour la de découpe d'une aile à 30° de
flèche
avec 10° de vrillage négatif de 330 mm de corde
emplanture
et 130 mm de corde de saumon ( trait vert ) et le point de projection (
trait bleu).
-
trait rouge: cheminement
du fil dans le plan de l'emplanture ( 1er chariot )
- trait
vert: cheminement
du fil dans le plan du saumon
- trait
bleu: cheminement
du fil dans le plan du 2eme chariot
Envergure=550mm
D=750mm E=550mm
Même aile
mais avec une
Envergure=450mm
D=750mm E=550mm
On voit
clairement l'évolution
de la forme décrite par le 2eme chariot de la machine ( en bleu
) pour que le profil saumon ( en vert ) reste le meme quelque soit
l'envergure.
Crevasse de
découpe
Dernier
paramètre: le fil chaud a un
diamètre
de quelques 10ème de mm, il créé de plus une
crevasse de plusieurs dixièmes millimètres dans la mousse
en fonction de la chaleur dissipée.
L'épaisseur
de mousse
fondue au passage du fil est relative à la vitesse du fil, au
matériau
utilisé (type de mousse, densité), et bien sûr
à
la température du fil.
Dans le cas
d'un rectangle
voici ce qu'on obtient:
Le rectangle
voulu est en
pointillés rouges ( déplacement du fil ), le rectangle
obtenu
est de dimension inférieure et en tout état de cause non
conforme à l'attendu.
Il faut donc
implémenter
un facteur correctif pour que le fil
décrive,
non pas le contour de la forme, mais une trajectoire tangeantant la
forme
à 1/2 largeur de crevasse ( E ):
Le
schéma précédant
représente la trajectoire du fil et les points
d'échantillonnages.
Chaque point An
de coordonnées
(xAn,yAn) correspondant de la trajectoire échantillonnée
est remplacé par le point An" (xAn",yAn") tel que ( en
notation
vectorielle):
An"=An
- ( E . tg(alpha) . Un
)+ E . En
où:
Un vecteur
unitaire
// au segment [An-1,
An]
En vecteur
unitaire
_|_ au segment [An-1,
An]
Un+1 vecteur
unitaire
// au segment [An,
An+1]
En+1 vecteur
unitaire
_|_ au segment [An,
An+1]
alpha moitié
de l'angle formé par les deux vecteurs Un,Un+1
Nota: Comme on n'a
pas accès
directement à la valeur de l'angle Alpha on cherche tout
naturellement
à passer par celle de Beta grâce à un arccos ou un
arcsin et diviser par 2.
Or ce qui nous
intéresse
en fin de compte ce n'est pas alpha mais tg(alpha) alors pour
éviter
les accumulations d'erreurs de calcul; et optimiser un peu,
référons
nous aux formules de trigonométrie, voici celle utilisée
dans
le soft:
tg(beta/2)=sin(beta) /
(1+cos(beta) )
sin(beta) et
cos(beta) sont
obtenus par une simple division de la norme des vecteurs par chacune
de
leurs coordonnées d'où:
An"=An
- E . ( (sin(beta) / (1+cos(beta) ) ).Un
+ En )
Exemple de découpe
|