Breve guida su HAL · 1 Introduzione EMC2 contiene al suo interno un potente strumento chiamato HAL...
Transcript of Breve guida su HAL · 1 Introduzione EMC2 contiene al suo interno un potente strumento chiamato HAL...
Breve guida su HAL
Manfredi Leto
15 giugno 2007
Indice
1 Introduzione 2
2 Elementi di un sistema HAL 4
2.1 I componenti HAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 I Segnali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 I thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3 Gli strumenti per creare un sistema HAL 8
3.1 La riga di comando halcmd: . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2 I comandi HAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4 Prime prove pratiche 14
4.1 Esempio I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.2 Halmeter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.3 Halscope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4 Esempio II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5 HAL ed EMC2, perchè? 32
1
1 Introduzione
EMC2 contiene al suo interno un potente strumento chiamato HAL1, il proposito di
questa breve guida è quello di fornire le nozioni di base necessarie per poter cominciare
ad utilizzarlo, purtroppo non tutto potrà essere trattato in queste poche pagine e per
sfruttare a fondo le potenzialità di HAL sarà necessario un ulteriore approfondimento
fatto soprattutto di ricerca sul web ed esperienze personali.
Ovviamente le prime domande cui è necesario dare subito una risposta sono: cosa è
HAL? A che serve? in che modo è collegato ad EMC2?
Cominciando diciamo che il nome HAL è una sigla che sta per Hardware Abstrac-
tion Layer, letteralmente Piano di Astrazione dell'Hardware. Si immagini una macchi-
na utensile a controllo numerico, questa macchina sarà costituita sicuramente da una
parte meccanica, ma oltre questa vi saranno una certa quantità di componenti elettri-
ci/elettronici connessi tra loro in modo opportuno allo scopo di comandarla nel modo
desiderato. Questi componenti possono essere per esempio schede per il controllo del
movimento e per la generazione della traiettoria dell'utensile, interfacce di input/output,
generatori di segnali step/dir per comandare motori passo-passo, decodi�catori per i
segnali provenienti da eventuali encoder, PLC ecc.
Tutti questi componenti solitamente vengono visti da chi monta la macchina come
"scatole nere" ovvero, non si conosce e�ettivamente cosa avviene al loro interno, ma si
sa che queste "scatole" hanno dei connettori, alcuni di ingresso altri di uscita, tramite
i quali ricevono e generano segnali. Chi monta il sistema conosce invece quali segnali
devono entrare e quali escono dai connettori dei vari componenti e qual è la loro funzione,
e dunque li collega tra loro opportunamente per ottenere l'e�etto desiderato.
Poichè e�ettivamente EMC2 è a tutti gli e�etti un Controllo Numerico che risiede in
un PC, e poichè un PC, se opportunamente programmato e soprattutto se capace di
gestire operazioni in Real Time, può e�ettivamente eseguire al suo interno tutta una
serie di operazioni che normalmente vengono gestite da componenti hardware esterni
(come quelli elencati sopra) si è pensato bene di costruire uno strumento software
che permetta di utilizzare una serie di componenti hardware "virtuali" (per questo
"Hardware Abstraction") da poter interconnettere tra loro e con l'esterno.
1tutta la documentazione originale in inglese su HAL può essere scaricata in formato .pdf dal sitohttp://www.linuxcnc.org/docs/HAL_Documentation.pdf
2
In questo modo si sostituiscono tutta una serie di componenti reali rendendoli virtuali e
li si "sposta" in questo modo all'interno del computer (diventano "componenti HAL").
Altri componenti hardware rimangono invece esterni e reali e la loro connessione con
quelli virtuali all'interno del PC avviene materialmente attraverso porte di comuni-
cazione come per esempio la porta parallela, che sono gestite da appositi componenti
HAL che altro non sono che dei driver. Le porte sono e�ettivamente il ponte tra l'esterno
e l'interno del PC (e viceversa) e per questo sono dei componenti che esistono sia come
reali che come virtuali. Chiariamo con un esempio: si immagini la porta parallela del
PC, essa è reale, ha dei pin �sici a cui sono connessi altri componenti tramite cavi. Ma
nel nostro caso esisterà anche una porta parallela "virtuale" in HAL costituita dal driv-
er (chiamato hal_parport) che in e�etti crea una serie di pin virtuali che corrispondono
esattamente ai pin �sici della porta. In questo modo un segnale che entra dall'ester-
no passa, grazie al driver che lo legge, dal pin �sico della parallela al pin virtuale del
driver hal_parport e diventa in questo modo utilizzabile da tutti gli altri componenti
virtuali in HAL. E' logico che al momento tutto questo potrà risultare poco chiaro, ma
andando avanti nella lettura e soprattutto provando di persona si capirà esattamente
come funziona il sistema.
Per riassumere con poche parole, HAL è uno strumento che serve a creare un equivalente
"virtuale" di un sistema Hardware reale. Ciò che nel sistema hardware per esempio viene
fatto da un transistor, può essere fatto in HAL da un componente corrispondente.
Nella sezione seguente analizzeremo nel dettaglio da quali elementi è costituito un
sistema HAL.
3
2 Elementi di un sistema HAL
2.1 I componenti HAL
Prima di ogni cosa è bene dire che un componente HAL può essere di due tipi: Re-
al Time o Userspace. Componenti Real Time hanno funzioni (sarà chiarito in seguito
il signi�cato preciso di funzione di un componente) che vengono eseguite ciclicamente
ad intervalli di tempo pre�ssati e precisi, i componenti Userspace sono dei semplici
programmi che si interfacciano con altri componenti HAL, ma non in Real Time, bensì
si comportano come tutte le altre applicazioni.
Un componente HAL, sia Real Time che Userspace ha dei pin e dei parametri, solo i
componenti Real Time hanno delle funzioni.
pin è l'equivalente di un connettore in un componente hardware reale. Attraverso i
pin noi possiamo mandare e ricevere dei segnali, i pin vengono usati quindi per
interconnettere i componenti tra loro, essi possono essere di ingresso (IN) o di
uscita (OUT).
parametri i componenti hardware reali hanno spesso potenziometri, interruttori ecc.
che servono per esempio a variare determinati valori di tensione, corrente, re-
sistenza ecc. in modo da determinare un cambiamento nel funzionamento stesso
del componente. Questi valori non sono connessi ad altri componenti (potrebbero
esserlo, ma è bene distinguerli dai pin in quanto la loro funzione rimane quella di
"regolazione"). In perfetta analogia un componente HAL ha dei parametri che
possono essere impostati dall'utente (o anche da un altro componente) e che ne
regolano il funzionamento. La frequenza di un generatore di sinusoidi per esempio
è un parametro. Anche i parametri possono essere di ingresso o di uscita, i primi
possono essere cambiati dall'utente (come per esempio un potenziometro in un
componente reale), gli altri non possono essere modi�cati dall'utente, ma possono
essere letti per monitorare l'andamento dei segnali interni.
Sia i pin che i parametri hanno un tipo assegnato. Essi possono assumere valori solo
del tipo previsto e possono essere collegati a pin, parametri e segnali dello stesso tipo.
I tipi disponibili sono:
• BIT: valori 0 o 1, o FALSE e TRUE (vero o falso).
4
• FLOAT: valore a virgola mobile a 32 bit
• U32: intero senza segno a 32 bit che può assumere valori da 0 a +4294967295
• S32: intero con segno a 32 bit che può assumere valori da -2147483648 a +2147483647
funzioni per le funzioni è un po' più di�cile fare un analogia con i componenti hard-
ware reali perchè in realtà un'analogia stretta non esiste. Si immagini un sistema
elettronico estremamente semplice: un diodo LED con in serie una resistenza.
Quando ai due capi di questo sistema è applicata una di�erenza di potenziale
nel giusto verso, il LED si accende. Il punto sta nel fatto che il LED reagisce in
maniera immediata e soprattutto "automatica" a seconda di ciò che viene appli-
cato ai terminali. La reazione è dettata dalla costituzione �sica del componente
(LED più resistenza). Si immagini quindi di creare un componente HAL che
riproduce più o meno lo schema visto sopra. Tale componente potrebbe avere
per esempio due pin di ingresso di tipo BIT, i quali dunque possono assumere i
valori 0 o 1, che corrisponderebbero ai terminali dello schema reale. Si avrebbe
poi un unico pin di uscita, sempre di tipo BIT. Tale pin rappresenterebbe la luce
del LED (1 acceso, 0 spento). Noi vogliamo che questo componente HAL dia 1 in
uscita (LED acceso) solo quando il primo pin in ingresso vale 1 e il secondo vale 0
(giusto verso della d.d.p. applicata ai terminali). In tutti gli altri casi (11, 01, 00)
l'uscita dovrà essere 0. Questa volta il punto è: come fa l'uscita del componente
virtuale a reagire a ciò che avviene all'ingresso? Di certo il caso è molto diver-
so da quello del componente �sico. Siamo di fronte a un componente software,
quindi l'unica cosa che può legare l'uscita ai due ingressi è una "funzione" (si
tratterà esattamente di una funzione scritta in C), nel nostro caso la funzione
sarà costituita da una serie di "if" ed "else" che analizzando i valori in ingres-
so determineranno il corrispondente valore in uscita. Il problema fondamentale
adesso è: quando eseguiamo questa funzione? Qui entra in gioco il Real Time. Se
noi vogliamo che il comportamento di questo componente sia quanto più possibile
simile a quello reale, la reazione deve essere pressochè immediata. A�nchè ciò
avvenga facciamo eseguire la funzione ciclicamante ad intervalli di tempo pre�s-
sati molto brevi, per esempio ogni millisecondo, in questo modo ad ogni ciclo la
funzione legge i valori in ingresso e aggiorna quello in uscita. Tanto più breve è il
periodo del ciclo tanto più veloce sarà la reazione. Un componente HAL può avere
5
diverse funzioni che eseguono tipi di operazioni diverse, per esempio, il compo-
nente hal_parport, driver della porta parallela ha due funzioni, una per leggere lo
stato dei pin �sici della porta e aggiornare di conseguenza i pin virtuali corrispon-
denti (read) e un'altra per aggiornare lo stato dei pin �sici della parallela in base
ai valori assunti da quelli virtuali (write). Le funzioni possono essere con sup-
porto per operazioni con numeri a virgola mobile o no. Molti componenti hanno
funzioni che eseguono alcune operazioni che devono essere ripetute ad intervalli
molto brevi (per esempio 50000 nanosecondi, ovvero 50 milionesimi di secondo),
queste funzioni generalmente sono sempli�cate al massimo e non fanno operazioni
con numeri con la virgola in modo da poter essere eseguite alla velocità richiesta
anche su PC non velocissimi. Le funzioni così descritte sono presenti ovviamente
solo nei componenti HAL Real Time. I componenti Userspace avranno le loro
funzioni eseguite come in ogni altro programma usando i loop le condizioni ecc.
ma non in cicli con periodo pre�ssato. La parte più interessante riguardo ai com-
ponenti HAL è che se si conosce un po' di linguaggio C è possibile non limitarsi
all'utilizzo di quelli già disponibili (che sono comunque molti), ma se ne possono
costruire di nuovi (adesso in modo veramente semplice grazie all'aggiunta di un
programma chiamato Comp) che eseguano esattamente le operazioni di cui si ha
bisogno. E' un po' come dire che chi conosce l'elettronica può costruirsi da solo
un circuito funzionante che esegue determinate operazioni e non solo utilizzare
ciò che si trova nei negozi.
2.2 I Segnali
I segnali in HAL sono esattamente l'equivalente dei cavi di collegamento in un sistema
hardware reale. Un segnale può essere collegato ad uno o più pin (ma anche parametri)
di un componente e andare ad uno o più pin di un altro, in questo modo i pin dei
componenti sono collegati tra loro e questi ultimi possono scambiarsi dati uno con
l'altro.
I segnali hanno gli stessi tipi dei pin e dei parametri, ovvero BIT, FLOAT, U32, S32. Un
segnale può collegare parametri o pin solo se del suo stesso tipo. E' possibile connettere
e disconnettere i segnali con appositi comandi, anche mentre il sistema sta funzionando.
6
2.3 I thread
I thread sono i "cicli" visti prima cui vengono collegate le funzioni Real Time. Ad ogni
ciclo è associato un periodo in nanosecondi che è l'intervallo di tempo che passa tra
l'esecuzione di un ciclo ed il successivo. Ad un thread possono essere collegate molte
funzioni la cui esecuzione viene ripetuta ad ogni periodo. Ogni thread ha un suo nome
che lo identi�ca in modo univoco. I thread possono avere supporto per funzioni con
numeri con virgola o no. Se si hanno delle funzioni la cui esecuzione va ripetuta molto
velocemente e che non necessitano di operazioni con numeri con virgola, allora si creerà
un thread con un periodo molto piccolo e senza supporto per tali operazioni.
7
3 Gli strumenti per creare un sistema HAL
3.1 La riga di comando halcmd:
Tutte le operazioni che riguardano HAL vengono eseguite dal terminale di Linux e,
nello speci�co, da un'apposita riga di comando chimata halcmd (è in fase di sviluppo
un'interfaccia gra�ca per HAL, ma purtroppo non è ancora disponibile).
Si apra una �nestra del terminale e si digitino i seguenti comandi:
$ /etc/init.d/realtime start
$ halcmd -kf
La prima riga fa partire il Real Time senza cui HAL non può funzionare, e la seconda
passa alla riga di comando halcmd. Per uscire da halcmd, la procedura corretta è:
halcmd: unload all
halcmd: exit
$ /etc/init.d/realtime stop
Unload all serve ad eliminare tutti i componenti che si erano caricati, exit esce dalla
riga di comando halcmd e in�ne la terza riga ferma il Real Time.
Esiste uno script (halrun) per lanciare halcmd con un solo comando ma crea esso crea
spesso problemi quindi è meglio usare la procedura descritta sopra.
Dalla riga di comando halcmd si possono eseguire tutti i comandi HAL che descriviamo
di seguito. Non sono molti e soprattutto sono abbastanza intuitivi.
3.2 I comandi HAL
Qui di seguito sono elencati i principali comandi HAL, probabilmente non sono tutti,
ma sicuramente questi sono i più usati e con questi è possibile costruire un sistema HAL
perfettamente funzionante.
8
loadrt serve a caricare un componente HAL Real Time. E' seguito dal nome del
componente e spesso da un altra istruzione che indica o il numero di compo-
nenti uguali da caricare, o opzioni che riguardano il componente stesso. Queste
opzioni sono speci�che per ogni componente ed è quindi opportuno consultare
la documentazione riguardante il componente per sapere con esattezza cosa va
scritto.
Esempi:
halcmd: loadrt encoder num_chan=3
carica 3 componenti "encoder"
halcmd: loadrt hal_parport cfg="0x0378"
carica il driver per la porta parallela che si trova all'indirizzo "0x0378"
unloadrt serve a eliminare un componente HAL Real Time. E' seguito dal nome del
componente da eliminare. Se seguito da "all" elimina tutti i componenti Real
Time caricati.
Esempio:
halcmd: unloadrt encoder
loadusr serve a caricare un componente HAL userspace. E' seguito dal nome del
componente da caricare e spesso può essere seguito da altre istruzioni speci�che
per ogni componente.
Esempio:
halcmd: loadusr hal_joystick -d /dev/input/js0 -p joypad
carica il componente hal_joystick con riferimento alla periferica in /dev/input/js0
e mette il pre�sso "joypad" a tutti i pin creati dal componente.
unloadusr stessa cosa di unloadrt, ma speci�co per i componenti userspace.
newsig crea un nuovo segnale. E' seguito dal nome che si vuole dare al segnale e dal
tipo.
9
Esempio:
halcmd: newsig accendi-mandrino BIT
crea un nuovo segnale di tipo BIT con il nome "accendi-mandrino".
setp assegna a un pin o ad un parametro un valore speci�co. E' seguito dal nome del
pin/parametro e dal valore da assegnare. Se il pin o il parametro sono collegati
ad un segnale, allora non è possibile speci�carne il valore.
Esempio:
halcmd: setp pwmgen.0.pwm-freq 1000
imposta il valore del parametro pwmgen.0.pwm-freq a 1000
linksp, linkpp, linkps sono tre comandi che servono a eseguire i collegamenti tra i
componenti. le ultime due lettere aiutano a comprendere la funzione del comando.
linksp sta per "link signal-to-pin/parameter" e serve a collegare un segnale ad un
pin o un parametro, linkpp sta per "link pin-to-pin" e serve a collegare due pin
tra loro senza bisogno di un segnale, linkps sta per "link pin-to-signal" e serve a
collegare un pin ad un segnale. Sono seguiti da ciò che rappresentano le due lettere
�nali, linksp sarà seguito per esempio dai nomi del segnale e del pin. Spesso si
possono usare (solo per chiarezza, non è obbligatorio) i simboli => o <= tra i
due nomi per evidenziare la direzione del �usso dei dati.
Esempi:
halcmd: linksp spindle-on parport.0.pin-01-out
collega il segnale spindle-on al pin parport.0.pin-01-out
halcmd: linkpp motion.spindle-speed-out => pwmgen.0.value
collega il pin motion.spindle-speed-out al pin pwmgen.0.value, => evidenzia
che il primo è un pin OUT e il secondo è un pin IN, quindi i dati viaggiano
dal primo al secondo.
halcmd: linkps pwmgen.0.pwm-freq <= pwm-frequency
10
collega il parametro pwmgen.0.pwm-freq al segnale pwm-freqeuncy, <=
evidenzia che il parametro è un ingresso.
net è un comando che da solo crea un segnale e con questo segnale collega due o più
pin. E' seguito dal nome del segnale e dal nome dei pin da collegare con esso.
Esempio:
halcmd: net spindle-on motion.spindle-on parport.0.pin-01-out
crea il segnale spindle-on e collega con questo i pin motion.spindle-on e
parport.0.pin-01-out
unlinkp serve a dsconnettere un pin o un parametro da un segnale o da un altro pin.
E' seguito dal nome del pin da disconnettere.
Esempio:
halcmd: unlinkp motion.spindle-on
disconnette il pin motion.spindle-on da tutti i segnali ad esso collegati.
loadrt threads è il comando che serve a creare i threads necessari per il funzionamento
del sistema. In futuro probabilmente esisterà un comando dedicato del genere
"newthread" ma per adesso si usa praticamente il comando loadrt per caricare
un componente chiamato "threads" che non fa altro che creare i nuovi threads.
E' seguito nell'ordine da: name1=, fp1=, period1=, name2=, fp2=, period2=,
name3=...e così via �no a che non si siano creati tutti i threads desiderati: name
indica il nome, fp può essere o 0 o 1 ed è il supporto per operazioni con numeri
con la virgola, period è il periodo del thread.
Esempi:
halcmd: loadrt threads name1=esempio fp1=1 period1=1000000
crea un thread chiamato "esempio", con supporto per le operazioni con nu-
meri con la virgola e con periodo pari a 1000000 di nanosecondi (1/1000 di
secondo).
11
halcmd: loadrt threads name1=esempio_veloce fp1=0 period1=50000
name2=esempio_lento fp2=1 period2=1000000
crea due threads, il primo con nome "esempio_veloce" , senza supporto per
le operazioni con numeri con virgola e con periodo di 50000 nanosecondi,
il secondo con nome "esempio_lento" con supporto per le operazioni con
numeri con la virgola e con periodo pari a 1000000 di nanosecondi.
addf è il comando che serve a collegare la funzione Real Time di un componente ad un
thread. E' seguito dal nome della funzione e dal nome del thread cui quest'ultima
va collegata.
Esempio:
halcmd: addf encoder.update-counters esempio_veloce
collega la funzione encoder.update-counters del componente encoder al thread
"esempio_veloce".
show è il comando più semplice per analizzare un po' il sistema che si stà costruendo.
Serve a visualizzare nella �nestra del terminale un elenco di elementi del sistema
HAL in uso. Show può essere seguito da:
• comp mostra tutti i componenti
• pin mostra tutti i pin
• param mostra tutti i parametri
• sig mostra tutti i segnali
• funct mostra tutte le funzioni
• thread mostra tutti i threads
save è il comando che serve per salvare il sistema HAL creato. E' seguito dalla dicitura
"all" e dal nome del �le in cui vogliamo venga salvata la con�gurazione. Save salva
in un �le tutti i comandi che servono a ricreare il sistema in uso. Questo comando
crea un �le "razionale", nel senso che non salva tutti i comandi che si sono scritti
12
per creare il sistema, ma salva solo quelli che servono e�ettivamente ad arrivare
alla con�gurazione �nale. Se per esempio si connette un pin ad un segnale, poi
lo si disconnette, poi lo si riconnette ad un altro pin ecc., nel �le salvato sarà
presente un solo comando per ricreare la condizione �nale.
Esempio:
halcmd: save all prova.hal
Per poter caricare ciò che si è salvato in modo da avere il sistema esattamente
come lo si era creato la volta precedente, basterà digitare dal terminale:
$ /etc/init.d/realtime start
$ halcmd -f prova.hal
La prima riga ovviamente solo se il Real Time non sta già funzionando,
mentre la seconda non fa altro che lanciare la riga di comando halcmd ed
eseguire tutti i comandi contenuti nel �le prova.hal.
13
4 Prime prove pratiche
A questo punto si può �nalmente cominciare a fare qualche prova pratica per capire a
fondo il funzionamento di HAL. Gli esempi riportati di seguito sono più o meno quelli
che sono presenti nei tutorial del manuale originale su HAL in inglese.
4.1 Esempio I
Si apra una �nestra terminale e si avvii la riga di comando halcmd:
$ /etc/init.d/realtime start
$ halcmd -kf
Si carichi il modulo Real Time "siggen":
halcmd: loadrt siggen
Siggen è un modulo che serve per la generazione di segnali. Si provi ad usare il comando
show per vedere cosa si ha a disposizione:
halcmd: show comp
Loaded HAL Components:
ID Type Name PID State
00003 RT siggen ready
00002 User halcmd5181 5181 ready
show comp mostra i componenti caricati, si può vedere il componente siggen appena
caricato che è di tipo Real Time (Type RT), si vede anche il componente halcmd5181
di tipo userspace (Type User) perchè la riga di comando halcmd è essa stessa un com-
ponente HAL. Siggen ha ID (un numero che identi�ca univocamente il componente)
pari a 3. Si provi ora a visualizzare i pin:
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
14
03 float IN 1 siggen.0.amplitude
03 float OUT 0 siggen.0.cosine
03 float IN 1 siggen.0.frequency
03 float IN 0 siggen.0.offset
03 float OUT 0 siggen.0.sawtooth
03 float OUT 0 siggen.0.sine
03 float OUT 0 siggen.0.square
03 float OUT 0 siggen.0.triangle
Il componente siggen che si è caricato ha 8 pin, tutti di tipo "�oat" ovvero numero
a virgola mobile. Alcuni sono di ingresso, altri di uscita (Dir IN o OUT). I pin di
uscita sono tutti i segnali che il componente può generare (seno, coseno, dente di sega,
quadro, triangolare), i pin di ingresso sono i valori dell'ampiezza dei segnali (amplitude),
della frequenza (frequency) e dello scostamento dell'origine (o�set). "Value" mostra il
valore che ha un pin nel momento in cui si lancia il comando "show pin". La colonna
"Owner" mostra invece a quale componente appartengono i pin, si ricordi che l'ID del
componente siggen era 3.
Si noti come sono strutturati i nomi dei pin. E' importante capirlo perchè è una tipologia
standard che si ritroverà sempre. Il nome del pin è diviso generalmente in 3 parti (però
esistono anche con due sole parti) separate da punti. La prima parte identi�ca il nome
del componente cui appartiene il pin, la seconda parte è un numero, esso cambia se ci
sono più componenti uguali. Se per esempio avessimo due componenti siggen invece di
uno, i pin del secondo sarebbero del tipo siggen.1.xxxxx invece di siggen.0.xxxxx (alcuni
componenti non possono essere caricati in numero maggiore di uno, questi sono quelli
che hanno solo due parti nel nome). La terza parte è lì per indicare in modo quanto
più possibile chiaro a cosa il pin si riferisce nel dato componente.
Si osservino adesso i parametri:
halcmd: show param
Parameters:
Owner Type Dir Value Name
03 s32 RO 0 siggen.0.update.time
03 s32 RW 0 siggen.0.update.tmax
15
Il componente siggen ha soltanto due parametri che tralaltro hanno dei valori standard
che è meglio non modi�care. Sono entrambi interi con segno (Type s32), uno è del tipo
che può essere esclusivamente letto dall'operatore (Dir RO "Read Only"), l'altro invece
può essere sia letto che scritto (Dir RW "Read & Write"). Per i nomi valgono le stesse
regole illustrate per i pin.
Si provi in�ne a visualizzare le funzioni del componente siggen:
halcmd: show funct
Exported Functions:
Owner CodeAddr Arg FP Users Name
03 d0a98120 d0d72130 YES 0 siggen.0.update
c'è una sola funzione, con supporto per operazioni con numeri con virgola (FP YES,
FP sta per Float Point) che serve ad aggiornare il valore del segnale.
Per poter cominciare a vedere qualcosa di funzionante si deve creare un thread:
halcmd: loadrt threads name1=esempio fp1=1 period1=1000000
Così si crea un thread chiamato "esempio" con supporto per operazioni con numeri a
virgola mobile (l'unica funzione presente lo richiede) e con periodo pari a 1000000 di
nanosecondi (1/1000 di secondo).
Per veri�care che l'operazione sia andata a buon �ne, si usi sempre il comando show:
halcmd: show thread
Realtime Threads:
Period FP Name (Time, Max-Time)
999849 YES esempio ( 0, 0 )
Si vede il thread appena creato, il periodo non è proprio 1000000 ma è approssimato al
valore più vicino e�ettivamente ottenibile dalla CPU.
Come ultima cosa, a�nchè il sistema possa fare qualcosa si deve collegare l'unica
funzione presente al thread creato:
halcmd: addf siggen.0.update esempio
16
Sempre per veri�care che tutto sia dome desiderato, si usi sempre il comando show per
i threads come prima:
halcmd: show thread
Realtime Threads:
Period FP Name (Time, Max-Time)
999849 YES esempio ( 0, 0 )
1 siggen.0.update
Come si vede il risultato del comando è simile a quello precedente, ma questa volta
dopo il thread viene visualizzata la funzione ad esso collegata.
Finalmente si può far partire il sistema:
halcmd: start
il sistema in questo momento sta funzionando...come fare a capirlo? Si provi a visual-
izzare i pin con show:
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
03 float IN 1 siggen.0.amplitude
03 float OUT 0.08210425 siggen.0.cosine
03 float IN 1 siggen.0.frequency
03 float IN 0 siggen.0.offset
03 float OUT -0.5241643 siggen.0.sawtooth
03 float OUT 0.9971199 siggen.0.sine
03 float OUT -1 siggen.0.square
03 float OUT 0.0483287 siggen.0.triangle
come si vede i valori dei pin in uscita sono cambiati, e se si ripete tante volte questo
comando, si vedrà che i valori sono sempre diversi, questo signi�ca che il sistema è
e�ettivamente in funzione.
17
Ovviamente questo è troppo poco, HAL mette a disposizione dell'operatore due impor-
tanti strumenti per testare i propri sistemi che sono: halmeter e halscope. Entrambi
sono componenti HAL Userspace.
Prima di spiegare come usarli, si provi a salvare il sistema:
halcmd: stop
halcmd: save all esempio.hal
la prima riga ferma il funzionamento del sistema, la seconda salva tutto nel �le esem-
pio.hal, se si apre questo �le si troverà:
# components
loadrt siggen
# signals
# nets
# parameter values
setp siggen.0.update.tmax 938
# realtime thread/function links
addf siggen.0.update esempio
che è la lista di comandi che serve per ottenere un sistema come quello creato prece-
dentemente. Le righe precedute da # sono commenti e vengono ignorate, in questo �le
esse rappresentano le sezioni del �le hal. Signals e net sono vuote perchè e�ettivamente
questo sistema non ha segnali o collegamenti. La sezione paramter values presenta una
riga che è l'assegnazione di un valore standard ad un parametro, questa viene inclusa
anche se questo valore non era stato e�ettivamente assegnato.
Il sistema potrà essere ricaricato in ogni momento usando:
$ /etc/init.d/realtime start
$ halcmd -f esempio.hal
18
4.2 Halmeter
Potremmo dire che halmeter è l'equivalente in hal di ciò che è un voltmetro o in generale
un multimetro in un sistema reale.
Prima di ogni cosa si faccia ripartire il sistema se era stato fermato:
halcmd: start
Per caricare un halmeter si usa:
halcmd: loadusr halmeter
Vi si apre una piccola �nestra con due pulsanti.
si clicchi su select e si aprirà un'altra �nestra con tre tabs: pins, signals e parameters:
Cliccando su ognuna si vedrà l'elenco degli elementi disponibili, signals ovviamente non
mostra niente perchè nel sistema attuale non ci sono segnali. Si vada nella tab pins e si
19
selezioni per esempio il pin siggen.0.cosine. Cliccando su Ok, la �nestra di selezione si
chiude e halmeter mostrerà in modo continuo i valori del pin scelto (cliccando su apply
invece di ok si possono visualizzare in modo diretto in halmeter i valori dei vari pin):
In questo momento si vede come variano i valori di una cosinusoide con ampiezza 1 e
con freqeunza 1 Hz.
Si provi per esempio a cambiare il valore dell'ampiezza:
halcmd: setp siggen.0.amplitude 10
Il comando dovrebbe avere e�etto immediato e si dovrebbe essere in grado di vederlo
in halmeter perchè i valori adesso vanno da -10 a 10. Si riporti l'ampiezza a 1:
halcmd: setp siggen.0.amplitude 1
La �nestra di halmeter è stata pensata così piccola appositamente, in questo modo
è infatti possibile caricarne tante e visualizzare così molti pin, segnali e parametri.
Questo è senz'altro utile quando si creano sistemi complessi in cui è necessario tenere
sotto controllo tanti fattori per capire se tutto funziona correttamente. Per caricare un
altro halmeter basta scrivere di nuovo:
halcmd: loadusr halmeter
Per esempio di seguito si vedono sei halmeter quattro dei quali visualizzano i valori di
quattro pin diversi, mentre due visualizzano due parametri (costanti):
20
Per uscire da un halmeter basterà cliccare su Exit.
4.3 Halscope
Halscope è l'equivalente virtuale di un oscilloscopio. Esso va ovviamente molto più in là
del semplice halmeter, esattamente come un oscilloscopio è molto di più di un semplice
multimetro.
Per caricare halscope si usa:
halcmd: loadusr halscope
Si apre una �nestra che chiede di speci�care alcuni parametri:
Si selezioni l'unico thread "esempio". Sopra viene mostrato che il periodo di campiona-
mento è quello del thread selezionato (1000 microsecondi ovvero 1000000 di nanosecon-
di), mentre la frequenza di campionamento è ovviamente 1 kHz (1000 volte al secondo).
Halscope ha una memoria limitata per registrare un certo numero di campionamenti
e quindi visualizzarli. Nella parte inferiore della �nestra si può scegliere il numero di
21
campionamenti da registrare, in base a questo varia il numero di canali che è possibile
monitorare. Se serve un solo canale si può scegliere il massimo numero di campiona-
menti, se serve più di un canale oppure si vuole aggiornare in modo più frequente il
video di halscope allora si potrà scegliere un numero inferiore di campionamenti. Si
selezionino 4047 campionamenti (quattro canali) e si clicchi su Ok. Si apre la �nestra
di halscope che ovviamente non mostra ancora nulla:
Si deve ora decidere cosa vedere, cliccando sul numero 1 in basso a sinistra, si apre una
�nestra di selezione:
Si scelga ad esempio "cosine", e si ripeta lo stesso con i canali 2 e 3, selezionando per
esempio "sawtooth" e "square".
22
In alto a destra in "Run Mode", si clicchi su "Normal", e accanto in "Trigger" si clicchi
su "Force" due volte. si dovrebbe �nalmente cominciare a vedere la prima sequenza
campionata:
Si notano i tre segnali, la cosinusoide, l'onda a dente di sega e l'onda quadra. Quando
si clicca sui numeri nella striscia in basso, si seleziona un canale, si provi ad esempio a
selezionare 1. Le due barre di scorrimento a destra in "vertical" servono a ingrandire
verticalmente e a spostare verticalmente. si potrenno regolare i 3 canali in modo da
visualizzarli meglio come nella �gura seguente:
23
In alto in �Horizontal� c'è praticamente la stessa cosa per l'orizzontale.
Se si vuole registrare una nuova sequenza si clicchi nuovamente su "Force". Se invece
si desidera registrare sequenze in modo continuo si clicchi su "Auto".
Questo è più o meno tutto quello che c'è da dire su halscope. Chi ha usato almeno
una volta nella vita un vero oscilloscopio probabilmente si troverà abbastanza a proprio
agio.
4.4 Esempio II
Il primo esempio riportato è molto utile per cominciare a prendere la mano con la riga
di comando halcmd, ma in e�etti non fa molto, è un sistema con un unico compo-
nente, mentre lo spirito di HAL è quello di creare sistemi complessi con più componenti
interconnessi tra loro.
In quest'esempio si useranno due componenti: siggen (già usato precedentemente) e
freqgen.
Freqgen è un componente che genera i segnali step/dir per muovere un motore passo-
passo a partire da una velocità o da una frequenza. Esiste anche un altro componente
"stepgen" che fa lo stesso però a partire dal valore di una posizione comandata, ma
per quest'esempio è più conveniente usare il primo (mentre e�ettivamente non lo è se
si vuole muovere veramente un motore passo-passo che muove una macchina utensile).
In primo luogo è necessario cominciare con un sistema completamente pulito (se avete
appena terminato l'esempio precedente vari componenti saranno ancora caricati), allora
si procede nel modo seguente:
halcmd: unload all
halcmd: exit
$ /etc/init.d/realtime stop
$ /etc/init.d/realtime start
halcmd -kf
Si carichino i moduli che servono:
halcmd: loadrt siggen
halcmd: loadrt freqgen step_type=0,0
24
La seconda riga carica due componenti freqgen del tipo 0 (una descrizione dettagliata
del modulo si trova nel manuale originale).
Usando show pin si osservano al solito tutti i pin disponibili:
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
04 s32 OUT 0 freqgen.0.counts
04 bit OUT FALSE freqgen.0.dir
04 float OUT 0 freqgen.0.position-fb
04 bit OUT FALSE freqgen.0.step
04 float IN 0 freqgen.0.velocity
04 s32 OUT 0 freqgen.1.counts
04 bit OUT FALSE freqgen.1.dir
04 float OUT 0 freqgen.1.position-fb
04 bit OUT FALSE freqgen.1.step
04 float IN 0 freqgen.1.velocity
03 float IN 1 siggen.0.amplitude
03 float OUT 0 siggen.0.cosine
03 float IN 1 siggen.0.frequency
03 float IN 0 siggen.0.offset
03 float OUT 0 siggen.0.sawtooth
03 float OUT 0 siggen.0.sine
03 float OUT 0 siggen.0.square
03 float OUT 0 siggen.0.triangle
Si immagini che le uscite Step e Dir di ognuno dei due moduli freqgen siano connesse ad
un motore passo-passo e che questi motori comandino gli assi X ed Y di una fresatrice a
controllo numerico. Praticamente si potranno far girare questi motori (e quindi muovere
gli assi X e Y) comandando la frequenza degli step oppure la velocità di rotazione. Si
immagini dunque di voler muovere la tavola lungo una circonferenza, le velocità X e Y
in questo caso hanno l'andamento rispettivamente delle funzioni coseno e seno.
Ma è già nel sistema un componente, siggen, capace di generare questi segnali, quindi
non resterà altro che collegarli in modo opportuno.
Si creino due nuovi segnali per le velocità X e Y:
25
halcmd: newsig X_Vel float
halcmd: newsig Y_Vel float
Adesso si colleghino questi due segnali ai pin di ingresso per la velocità dei due freqgen:
halcmd: linksp X_Vel freqgen.0.velocity
halcmd: linksp Y_Vel freqgen.1.velocity
Ed in�ne si colleghino i due segnali alle uscite coseno e seno di siggen:
halcmd: linksp X_Vel siggen.0.cosine
halcmd: linksp Y_Vel siggen.0.sine
Adesso si usi show pin nuovamente e si noti come la simbologia con ==> e <== aiuti
a capire i collegamenti tra pin e segnali:
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
04 s32 OUT 0 freqgen.0.counts
04 bit OUT FALSE freqgen.0.dir
04 float OUT 0 freqgen.0.position-fb
04 bit OUT FALSE freqgen.0.step
04 float IN 0 freqgen.0.velocity <== X_Vel
04 s32 OUT 0 freqgen.1.counts
04 bit OUT FALSE freqgen.1.dir
04 float OUT 0 freqgen.1.position-fb
04 bit OUT FALSE freqgen.1.step
04 float IN 0 freqgen.1.velocity <== Y_Vel
03 float IN 1 siggen.0.amplitude
03 float OUT 0 siggen.0.cosine ==> X_Vel
03 float IN 1 siggen.0.frequency
03 float IN 0 siggen.0.offset
03 float OUT 0 siggen.0.sawtooth
03 float OUT 0 siggen.0.sine ==> Y_Vel
26
03 float OUT 0 siggen.0.square
03 float OUT 0 siggen.0.triangle
halcmd: show sig
Signals:
Type Value Name
float 0 X_Vel
==> freqgen.0.velocity
<== siggen.0.cosine
float 0 Y_Vel
==> freqgen.1.velocity
<== siggen.0.sine
Si visualizzino adesso le funzioni dei vari componenti presenti nel sistema:
halcmd: show funct
Exported Functions:
Owner CodeAddr Arg FP Users Name
04 d0aad690 d0d720dc YES 0 freqgen.capture-position
04 d0aad270 d0d720dc NO 0 freqgen.make-pulses
04 d0aad4c0 d0d720dc YES 0 freqgen.update-freq
03 d0a98120 d0d720b4 YES 0 siggen.0.update
Ci sono quattro funzioni, la prima non verrà utilizzata perchè serve a catturare il
valore della posizione data da un eventuale encoder. L'ultima è già nota dall'esempio
precedente. La seconda è la funzione che genera gli impulsi Step/Dir, non ha bisogno
di operazioni con numeri con virgola mobile e deve essere ripetuta con una frequenza
molto elevata. La terza è la funzione che aggiorna la frequenza (o la velocità) in ingresso
del componente freqgen, questa necessita di operazioni con virgola mobile e può essere
eseguita meno velocemente.
Per questo motivo sarà necessario creare due thread diversi:
halcmd: loadrt threads name1=veloce fp1=0 period1=50000 name2=lento
fp2=1 period2=1000000
27
Adesso si potrenno collegare ai threads creati le funzioni in modo opportuno:
halcmd: addf freqgen.make-pulses veloce
halcmd: addf freqgen.update-freq lento
halcmd: addf siggen.0.update lento
Show thread mostrerà il risultato dei collegamenti:
halcmd: show thread
Realtime Threads:
Period FP Name (Time, Max-Time)
988960 YES lento ( 0, 0 )
1 freqgen.update-freq
2 siggen.0.update
49448 NO veloce ( 0, 0 )
1 freqgen.make-pulses
Si osservino in�ne i parametri a disposizione:
halcmd: show param
Parameters:
Owner Type Dir Value Name
04 u32 RW 00000001 freqgen.0.dirhold
04 u32 RW 00000001 freqgen.0.dirsetup
04 float RO -788.9156 freqgen.0.frequency
04 float RW 0 freqgen.0.maxaccel
04 float RW 10111.63 freqgen.0.maxfreq
04 float RW 1 freqgen.0.position-scale
04 s32 RO -4678 freqgen.0.rawcounts
04 u32 RW 00000001 freqgen.0.steplen
04 u32 RW 00000001 freqgen.0.stepspace
04 float RW 1 freqgen.0.velocity-scale
04 u32 RW 00000001 freqgen.1.dirhold
04 u32 RW 00000001 freqgen.1.dirsetup
04 float RO -614.5015 freqgen.1.frequency
28
04 float RW 0 freqgen.1.maxaccel
04 float RW 10111.63 freqgen.1.maxfreq
04 float RW 1 freqgen.1.position-scale
04 s32 RO 2052 freqgen.1.rawcounts
04 u32 RW 00000001 freqgen.1.steplen
04 u32 RW 00000001 freqgen.1.stepspace
04 float RW 1 freqgen.1.velocity-scale
04 s32 RO 0 freqgen.capture-position.time
04 s32 RW 0 freqgen.capture-position.tmax
04 s32 RO 502 freqgen.make-pulses.time
04 s32 RW 6497 freqgen.make-pulses.tmax
04 s32 RO 669 freqgen.update-freq.time
04 s32 RW 6884 freqgen.update-freq.tmax
08 s32 RO 766 scope.sample.time
08 s32 RW 6902 scope.sample.tmax
03 s32 RO 479 siggen.0.update.time
03 s32 RW 6604 siggen.0.update.tmax
Di tutti questi quello che potrebbe interessare è velocity-scale, perchè immaginando
di avere a che fare con una macchina reale, bisognerebbe aggiustare la scala a�nchè
il valore di velocità comandato da stepgen sia e�ettivamente quello della tavola della
macchina, per far questo si deve tener conto delle particolare caratteristiche di quest'ul-
tima come passo delle viti, step a giro dei motori, riduzioni meccaniche ed eventuale
comando in microstep.
Immaginando per ora che la scala sia corretta, si faccia partire il sistema:
halcmd: start
Per poter vedere qualcosa conviene usare halscope, una volta caricato quest'ultimo, si
scelga come periodo di campionamento quello corrispondente al thread più veloce (50
microsecondi) e come lunghezza di registrazione 2023 campioni. Si imposti il canale 1
e il canale 2 sui pin freqgen.0.step e freqgen.1.step (gli step per X e Y). Si cambino i
valori della frequenza di siggen e della scala della velocità nei freqgen come segue:
29
halcmd: setp siggen.0.frequency 0.1
halcmd: setp freqgen.0.velocity-scale 1000
halcmd: setp freqgen.1.velocity-scale 1000
A questo punto si selezioni "Normal" in "Run Mode" in alto a destra e "Auto" in
"Trigger� in�ne si clicchi su "Force".
Si dovrebbe cominciare a veder scorrere i segnali step per gli assi X e Y che servono ad
eseguire un cerchio. Chi ha visto lavorare una macchina CN almeno una volta potrà
associare facilmente questa visualizzazione al rumore tipico fatto dai motori passo-
passo durante l'esecuzione di una traiettoria circolare. Aggiustando un po' lo zoom e
la posizione si potranno vedere in maniera più chiara i segnali come nella schermata
seguente:
Come si vede quando la frequenza degli impulsi Step è massima per X, diventa minima
per Y e viceversa, il che è ovvio visto che l'andamento è quello delle funzioni seno e
coseno.
Dopo aver svolto questi due esempi il funzionamento di HAL dovrebbe essere molto più
chiaro. Ovviamente per poter usare tutti i componenti disponibili bisognerebbe studiarli
uno per uno, e per alcuni non esiste neanche una documentazione documentazione
dettagliata2 .
2Una lista e una descrizione dei componenti disponibili può essere trovata all'indirizzo:http://linuxcnc.org/docs/2.1/html/hal/rtcomps/index.html
30
Il modo migliore per imparare a fondo ad usare HAL rimane comunque, come per ogni
cosa, l'esperienza. Usandolo per quello per cui è stato pensato in poco tempo si sarà in
grado di sfruttarlo a fondo.
31
5 HAL ed EMC2, perchè?
Probabilmente ci si sarà domandati: "perchè HAL ed EMC2 viaggiano assieme?
Per farsi una prima idea, si avvii EMC2, poi in una �nestra terminale si digiti:
$ halcmd -kf
halcmd: show pin
(non è necessario avviare il Real Time perchè è già avviato da EMC2). Come si vede
viene visualizzata una lista di molti pin. Si provi anche con show comp, show sig, show
funct ecc. è evidente che c'è un sistema HAL molto complesso già caricato.
Questo sistema HAL è lo "scheletro" di EMC2, quest'ultimo infatti usa dei compo-
nenti HAL (principalmente motmod e stepgen) per trasformare i movimenti comandati
dall'inteprete del G-Code in movimenti reali della macchina.
Il componente (si tratta in realtà di un modulo, ovvero un oggetto che da solo cari-
ca più componenti HAL) motmod equivale a un controllore del movimento hardware,
praticamente interagisce con EMC2, che genera le successive posizioni dell'utensile ad
intervalli di tempo molto stretti, e le riporta a vari pin HAL, il componente stepgen
poi trasforma queste posizioni in segnali per comandare i motori passo-passo (per es-
empio Step/Dir). Il tutto comunica con l'esterno mediante driver, per esempio il driver
hal_parport per la porta parallela.
Modi�cando il sistema HAL di base, è possibile adattare la con�gurazione di EMC2
per comandare virtualmente qualsiasi tipo di macchina secondo le proprie esigenze,
si può per esempio cambiare il componente stepgen con un componente per generare
segnali pwm e un componente per decodi�care il segnale di posizione proveniente da un
encoder, questi due componenti insieme ad un componente PID per il controllo dello
scostamento tra posizione comandata e posizione reale possono comandare un sistema
basato su servomotori invece che su motori passo-passo. Senca considerare la possibilità
di creare componenti ad hoc per ogni esigenza. Tutto questo soltanto modi�cando una
con�gurazione "software" e quindi senza nessuna spesa per nuovi componenti hardware.
Si possono programmare cinematiche diverse per il sistema e quindi pilotare sistemi
complessi come bracci di robot, esapodi ecc., macchine con assi "gantry" (un asse
mosso da due motori contemporaneamente).
32
Il sistema HAL che EMC2 ha caricato è il risultato dell'esecuzione di una serie di
comandi indicati in appositi �le .hal de�niti nel �le di con�gurazione .ini. Aprendo
questo �le vi si troverà infatti una sezione HAL, per esempio per la con�gurazione
stepper standard si legge:
[HAL]
HALFILE = core_stepper.hal
HALFILE = standard_pinout.hal
I �le core_stepper.hal e my_pinout.hal contengono tutti i comandi HAL per arrivare
al sistema che si è visto prima usando il comando show da halcmd. Aprendoli si
potrà vedere quali componenti vengono caricati, come sono connessi tra loro ecc. I
�le vengono caricati nella sequenza indicata e ovviamente quello che è stato fatto nel
precedente rimane valido anche nel successivo. Se il modulo stepgen è stato caricato
nel primo �le, tutti i pin, i parametri di questo potranno essere usati dai comandi nel
secondo �le, se si erano creati dei segnali nel primo �le questi potranno essere usati nel
secondo e così via.
Il primo �le core_stepper.hal è quello che crea tutto il sistema che trasforma i movimenti
(posizioni comandate) in segnali Step/Dir per i motori.
Il secondo �le standard_pinout.hal si occupa invece soltanto della gestione della co-
municazione con l'esterno, carica il driver della porta parallela hal_parport e manda i
segnali richiesti dall'elettronica di controllo ai pin opportuni della porta.
E' possibile ovviamente creare i propri �le .hal e farli lanciare all'avvio di EMC2 in
modo da avere il sistema con�gurato a proprio piacimento. Le possibilità di personaliz-
zazione sono innumerevoli, soprattutto utilizzando HAL in combinazione con altri utili
strumenti come pyVCP (che consente di creare pannelli di comando virtuali), Comp
(che permette facilmente di creare nuovi componenti Real Time) e la programmazione
in genere, esistono infatti librerie apposite per C e Python che permettono di creare
programmi (componenti Userspace) che possano interagire facilmente con sistemi HAL
(ovvero che possano creare nuovi componenti, nuovi pin, modi�care i valori di questi
ecc.)
33