Progettazione e realizzazione di un regolatore PID su architettura ...

193
Capitolo 1 - Abstract 1 Capitolo 1 Abstract

Transcript of Progettazione e realizzazione di un regolatore PID su architettura ...

Page 1: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 1 - Abstract

1

Capitolo 1

Abstract

Page 2: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 1 - Abstract

2

Il presente capitolo ha lo scopo di fornire al lettore una visione d’insieme del progetto discusso in questa tesi.

1. IL PROGETTO

In primo luogo si vuole palesare quanto segue:

il progetto consiste nella progettazione, realizzazione e collaudo

di un regolatore PID digitale su piattaforma RCX.

Per comprendere appieno questa asserzione, è necessario introdurre i tre elementi-

cardine attorno ai quali ruota l’intera attività di sviluppo:

CONTROLLO

PID

La realizzazione di un regolatore industriale

richiede competenze specifiche, quali:

- principi, concetti e teorie che stanno alla

base del controllo modulante;

- caratteristiche della legge di controllo

PID;

- problematiche legate alla realizzazione di

un PID digitale.

Controllo PID

RCX BrickOS

Page 3: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 1 - Abstract

3

RCX

L’RCX è un dispositivo costituito, internamente,

da un microcontrollore Hitachi corredato da una

memoria RAM; si interfaccia verso l’esterno

attraverso tre porte d’ingresso e tre d’uscita,

quattro pulsanti e un piccolo display LCD da

cinque cifre. Infine, è dotato di una porta ad

infrarossi che rende possibile la comunicazione

con un qualunque PC.

BRICKOS

BrickOS può essere considerato, allo stesso

tempo, come:

- un sistema operativo per l’RCX, che

permette di gestire a basso livello tutte le

risorse offerte da questo dispositivo;

- un ambiente di sviluppo che offre al

programmatore un insieme minimo di

funzionalità (API) su cui impostare

l’attività di implementazione del software.

Gli unici linguaggi di programmazione

supportati sono C/C++.

Ora che sono noti gli “attori” del progetto, è possibile scendere ad un livello di

dettaglio più basso, sostenendo quanto segue: l’obiettivo finale consiste nel realizzare

un’applicazione che, una volta scaricata sull’RCX, “trasformi” tale dispositivo in un

regolatore PID completamente autonomo; pertanto il software deve:

- essere in grado di leggere le informazioni provenienti dai sensori (porte

d’ingresso), eseguire l’algoritmo PID ed inviare il nuovo valore del controllo agli

attuatori (porte d’uscita);

- offrire un’interfaccia operatore (basata sull’uso del display LCD e dei pulsanti)

per consentire la visualizzazione/modifica dei parametri di sistema.

Infine, deve essere possibile gestire o un singolo regolatore o più regolatori in cascata.

Page 4: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 1 - Abstract

4

2. ORGANIZZAZIONE DEL TESTO

Prima di entrare nel vivo della trattazione, si ritiene utile delineare la struttura logica

del testo, costituita da una successione di aree tematiche, a ciascuna delle quali possono

corrispondere uno o più capitoli.

2.1. Cenni teorici sul controllo PID

Sezione dedicata all’esposizione dei principi e concetti che stanno alla base del

controllo modulante; introduce gli elementi essenziali della legge di controllo PID,

soffermandosi sugli aspetti più interessanti per il progetto in questione:

- realizzazione digitale di un regolatore;

- conversione A/D e D/A;

- modulazione PWM.

2.2. Ambiente operativo

Parte rivolta alla presentazione degli strumenti di lavoro, hardware e software, su cui

si basa lo sviluppo del regolatore industriale; in particolare:

- si descrivono le caratteristiche principali dell’RCX e dei dispositivi fisici di cui è

dotato, con particolare riferimento a:

! microcontrollore Hitachi H8/3292;

! memoria RAM;

! ingressi analogici e convertitore A/D (multiplexaggio);

! uscite PWM.

- si introducono gli elementi essenziali del sistema operativo BrickOS:

! BrickOS come punto di contatto tra hardware e software;

! Descrizione del “kernel” del S.O.;

! Gestione delle periferiche (motori, sensori, display lcd e pulsanti).

2.3. Descrizione del progetto

A questo punto il lettore avrà, a propria disposizione, un pacchetto informativo tale

Page 5: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 1 - Abstract

5

da poter affrontare, senza alcuna incertezza, le sezioni dedicate al vero e proprio

sviluppo dell’applicazione di controllo.

Il testo riflette completamente l’organizzazione del processo di sviluppo, basato sul

modello di vita a cascata; a ciascuna delle fasi seguenti è dedicato un intero capitolo:

- analisi e specifica dei requisiti: descrizione del funzionamento del prodotto da

realizzare e individuazione delle caratteristiche fondamentali del sistema;

- progettazione: studio delle soluzioni tecniche più opportune (in relazione alle

competenze dei relatori) per il raggiungimento degli obiettivi stabiliti nella fase

precedente;

- programmazione: discussione e motivazione delle principali scelte

implementative concernenti strutture dati, procedure di elaborazione e

modularizzazione;

- integrazione e test di sistema: integrazione dei moduli realizzati e verifica dei

meccanismi di interazione fra essi. Esecuzione dei test sull’applicazione

completa.

Page 6: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

6

Capitolo 2

Controllo PID

Page 7: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

7

In questo capitolo si presenteranno i regolatori industriali che attuano leggi di controllo PID rivolgendo particolare attenzione alla loro realizzazione digitale.

1. INTRODUZIONE

Un sistema di controllo industriale ha, come scopo primario, quello di migliorare sia

l’affidabilità nel funzionamento dell’impianto che le prestazioni del processo produttivo

(in termini di rendimento e/o quantità di prodotto).

Attualmente la scena è dominata dai regolatori a microprocessore, il cui successo è

dovuto a fattori quali l’elevato potenziale di elaborazione, la precisione e la stabilità

(invarianza) nel tempo; si tratta di prodotti con caratteristiche relativamente standard,

basilari nella regolazione e nell’automazione dei processi continui.

Il capitolo inizia con la presentazione della legge di controllo PID nella sua forma

più semplice per poi affrontare l’esposizione degli accorgimenti implementativi

comunemente adottati nella pratica industriale. Infine, si approda alla stesura di uno

pseudo-codice che modellizza il regolatore sottoforma di funzione (nell’accezione

informatica del termine).

E’ opportuno precisare che la locuzione “regolatore PID” può essere causa di

qualche ambiguità, essendo usata per indicare, da una lato, una legge di controllo

diffusamente utilizzata nel mondo industriale e, dall’altro, un prodotto elettronico che

implementa tale legge (spesso arricchita con una serie di funzionalità aggiuntive).

Nel seguito si adotterà la seguente simbologia:

v(t) indica un generico segnale tempo-continuo

V(s) indica la trasformata di Laplace del segnale v(t)

v*(t) indica un generico segnale tempo-discreto

V*(z) indica la trasformata Zeta del segnale v*(t)

Page 8: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

8

2. LEGGE DI CONTROLLO PID

In questo paragrafo e nei successivi si farà essenzialmente riferimento allo schema

classico di controllo in retroazione, rappresentato dalla figura seguente:

Legenda

y°(t) Segnale di riferimento (Set-Point) w(t) Variabile controllata (o di processo) y(t) Misura della variabile controllata e(t) Errore u(t) Variabile di controllo d(t) Disturbo di carico n(t) Rumore di misura PID Regolatore PID P(s) Funzione di trasferimento del processo

La legge di controllo PID è costituita dalla combinazione di tre azioni elementari di

controllo: azione proporzionale, azione integrale, azione derivativa.

2.1. Azione proporzionale

L’azione proporzionale lega algebricamente l’ingresso e(t) e l’uscita u(t) secondo

una costante di proporzionalità Kp detta guadagno proporzionale:

)()( teKtu p ⋅=

Essa dipende dal solo valore attuale, istantaneo dell’errore.

Con un regolatore puramente proporzionale, a regime, con ingressi costanti, l’errore

Page 9: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

9

di regolazione in generale non si annulla ma assume valori dipendenti dagli ingressi

stessi.

Tale azione è caratterizzata da un’elevata reattività all’errore; pertanto, dà il suo

contributo maggiore nelle fasi iniziali del transitorio, mentre perde efficacia a transitorio

esaurito.

2.2. Azione integrale

E’ particolarmente importante nelle applicazioni in quanto assicura un errore nullo a

regime per variazioni a scalino (o valori costanti) del set-point YSP e del disturbo d.

Si ha:

∫= dtteTKtu

I

P )()(

L’integratore non tiene conto del solo valore attuale, istantaneo dell’errore, bensì

anche del suo passato; se, ad esempio, l’errore fosse costante, la variabile di controllo

continuerebbe ad aumentare linearmente.

L’azione integrale è scarsamente reattiva, pertanto non da un contributo significativo

nelle fasi iniziali del transitorio, ma governa in maniera predominante il modo in cui il

sistema va a regime.

2.3. Azione derivativa

Serve a far dipendere il controllo dal futuro dell’errore, cioè dalla direzione in cui

esso si muove e dalla velocità con cui varia.

Si ha:

)()( tedtdTKtu DP=

Il parametro TD dà la misura di quanto lontano nel futuro si spinge la predizione. Tale

azione presenta un’elevata reattività e risulta efficace se TD non è troppo grande rispetto

alle dinamiche temporali dell’errore.

Si osservi la figura seguente:

Page 10: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

10

Nel caso A, la predizione è buona, ovvero TD è correttamente dimensionato; nel caso B,

invece, TD è troppo grande rispetto alle dinamica dell’errore (vedi [1]).

Si intuisce, quindi, che l’azione derivativa, essendo caratterizzata da un’elevata

reattività, apporta un sostanziale ed utile contributo nelle sole fasi iniziali dei transitori.

Il problema principale è dovuto al fatto che amplifica anche gli eventuali rumori di

misura sulla variabile controllata; per questo motivo è necessario utilizzarla con estrema

cautela, in modo tale che non determini eccessive sollecitazioni agli organi attuatori o

inconvenienti al processo.

Ulteriori informazioni sull’azione derivativa possono essere trovate in [1] e [2].

3. ACCORGIMENTI IMPLEMENTATIVI

I regolatori industriali, nella totalità dei casi, implementano una legge di controllo

PID sensibilmente differente da quella ideale esposta nel precedente paragrafo. Tali

accorgimenti sono stati introdotti in risposta a varie esigenze: realizzabilità, flessibilità,

interazioni fra regolatori che compongono sistemi di controllo complessi, e così via. Di

seguito verranno presentati i più comuni accorgimenti implementativi; nel paragrafo

successivo si affronterà la loro realizzazione digitale.

3.1. Derivatore reale

Come introdotto in precedenza, l’azione derivativa deve essere utilizzata con estrema

cautela in quanto, derivando anche le componenti dei segnali ad alte frequenze, può

Page 11: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

11

causare un’eccessiva sollecitazione degli organi attuatori. Pertanto, essa viene associata

ad un filtro passa-basso che ne limita il guadagno ad alta frequenza; il filtro, del primo

ordine, è caratterizzato dalla seguente funzione di trasferimento:

NsTsH

D+=

11)(

con N che, orientativamente, assume valori compresi fra 5 e 10. L’azione derivativa

filtrata amplifica, al più, di NK P .

3.2. Forma standard ISA

L’implementazione delle legge di controllo nei regolatori commerciali, spesso,

assume la seguente forma (si è omesso, per semplicità, d’indicare la dipendenza dalla

variabile complessa s):

( )

+++−= YcY

NsTsTE

sTYbYKU SP

D

D

ISPP /1

1

I coefficienti b e c assumono, di regola, valori compresi fra 0 e 1. Un PID in forma

standard ISA permette di elaborare in modo indipendente le risposte al set-point e al

disturbo di carico (vedi [2]). Si consideri:

+

++== cNsT

sTsT

bKYUG

D

D

IP

SPff /1

1

+

++==NsT

sTsT

KYUG

D

D

IPfb /1

11

Il sistema di controllo può essere descritto dal seguente schema a blocchi:

Page 12: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

12

I parametri KP, TI e TD, oltre a N, intervengono nell’anello di retroazione e

consentono di aggiustarne la stabilità e la dinamica, e quindi la risposta al disturbo di

carico; i parametri b e c consentono di intervenire sulla risposta di Y a YSP.

Questa struttura del regolatore si dice “a due gradi di libertà”, intendendo con questo

che i cammini del segnale da yo ad u e da y ad u sono diversi; è possibile, pertanto,

separare i problemi relativi al grado di stabilità e alla reiezione dei disturbi da quelli

relativi all’inseguimento del set-point.

3.2.1. Risposta al Set-Point

Osservando lo schema di riferimento presentato all’inizio di questo capitolo, risulta

evidente che la variabile di controllo (u) risente subito della variazione del set-point (yo),

infatti i due segnali sono separati dalla sola dinamica del PID. A meno che la risposta

del processo sia praticamente istantanea, a fronte di una variazione a scalino del

riferimento l’azione proporzionale subisce una brusca variazione a scalino che andrà a

riflettersi sulla variabile di controllo.

Il peso sul set-point nell’azione proporzionale (parametro b nella forma standard

ISA) viene introdotto proprio per ovviare a questo inconveniente; la possibilità di

limitare gli sbalzi del controllo risulta particolarmente utile, ad esempio, negli anelli

interni dei controlli in cascata, nei quali il set-point non è imposto direttamente da un

operatore, ma fornito dal regolatore esterno. Nel caso in cui b sia diverso da 1, a regime

l’azione proporzionale non sarà nulla; comunque, non influenza le fasi avanzate del

transitorio poiché in esse prevale nettamente l’azione integrale. E’ bene notare come al

crescere di b la risposta al set-point diventi più pronta ma con possibilità di

sovraelongazione; scegliendo b nell’intervallo 0-1 si può trovare un buon compromesso

tra velocità di risposta e sovraelongazione: contenere la sovraelongazione nella risposta

al set-point senza penalizzare la banda del sistema retroazionato.

Un altro possibile accorgimento implementativo riguarda l’introduzione del peso sul

set-point nell’azione derivativa (corrispondente al parametro c nella forma standard

ISA); anche in questo caso l’obiettivo è quello di evitare che il controllo subisca sbalzi

troppo bruschi a fronte di variazioni repentine dell’errore. Il peso c ha influenza solo

negli istanti in cui yo varia (quando è costante la sua derivata è nulla); ne consegue che c

Page 13: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

13

gioca un ruolo fondamentale, ad esempio, negli anelli interni dei controlli in cascata, il

cui set-point può variare di continuo.

Ulteriori informazioni possono essere trovate in [1].

3.2.2. Risposta al Disturbo di Carico

Si consideri lo schema di controllo di riferimento. A meno che la risposta del

processo non sia praticamente istantanea, un disturbo di carico a scalino non provoca

una variazione a scalino dell’errore, infatti la variabile di controllo dipende dal disturbo

di carico tramite la dinamica sia del processo che del PID (vedi [1]). Pertanto, nessuna

delle azioni di controllo subisce sbalzi bruschi. Il problema, in questo caso, è

determinato dal fatto che il regolatore inizia a reagire solo dopo che il processo ha

subito gli effetti del disturbo, ovvero solo quando tali effetti hanno prodotto variazioni

rilevabili dell’uscita y. Alla luce delle ultime considerazioni, si giustifica, almeno

intuitivamente, il fatto che l’inseguimento del set-point e la reiezione dei disturbi di

carico siano due problemi di controllo palesemente differenti.

3.3. Wind-up dell’integratore

Nella maggior parte delle applicazioni, la variabile di controllo di un anello di

regolazione è limitata superiormente e inferiormente. Se il sistema è ben progettato, essa

assume valori abbastanza lontani dai limiti di saturazione, ma può capitare che li

raggiunga in occasione di variazioni rilevanti del set-point o del disturbo di carico.

Quando la variabile di controllo è in saturazione, il processo evolve con ingresso

costante, come se fosse in anello aperto; anche il regolatore si trova ad evolvere in

anello aperto, infatti viene a mancare l’effetto della retroazione tra la sua uscita e

l’errore. Poiché l’integratore è un sistema dinamico non asintoticamente stabile, in

queste condizioni può allontanarsi di molto dal campo di valori utili per il controllo; se

ciò accade, occorre tempo, dopo che l’errore è tornato a valori tali da non richiedere più

la saturazione della variabile di controllo, prima che l’integratore, e con esso l’uscita del

regolatore, ritorni a valori utili per il controllo. La situazione descritta è illustrata nella

figura seguente (tratta da [1]), che riporta il transitorio della risposta ad una variazione a

scalino del set-point:

Page 14: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

14

t1 t2 t3 t4 t5

Note:

- all’istante t1, l’operatore modifica il set-point.

- All’istante t2, il controllo effettivo satura, la variabile controllata assume un andamento costante

e l’errore si ferma ad un valore non nullo; il controllo calcolato, pertanto, continua a crescere.

- All’istante t3, l’operatore si accorge del problema e modifica di nuovo il set-point.

- All’istante t4, l’errore cambia segno ed il controllo calcolato inizia a scendere; il controllo

effettivo, comunque, non si muove finché quello calcolato non esce dalla saturazione.

- All’istante t5, il controllo calcolato torna nel range di valori utili.

Riassumendo, il grafico evidenzia un blocco dell’azione di controllo e un pessimo transitorio della

variabile controllata.

Un modo semplice e diffusamente utilizzato per evitare il wind-up è quello di

arrestare l’integrazione quando interviene la saturazione.

Per catene di regolazione complesse, a più livelli gerarchici o con anelli annidati, la

saturazione di un attuatore o di un regolatore comporta di arrestare l’integrazione in tutti

i regolatori della struttura a monte.

3.4. Commutazione manuale/automatico

Gli operatori di un impianto hanno la facoltà di mettere in qualsiasi momento un

anello di regolazione in manuale o di comandarne il passaggio in automatico. Nel primo

Page 15: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

15

caso la variabile di controllo sarà governata direttamente dall’operatore, mentre nel

secondo caso essa sarà calcolata dal regolatore. Le commutazioni devono avvenire

senza brusche variazioni della variabile di controllo, per evitare transitori indesiderati e

danni agli attuatori.

Al passaggio da automatico a manuale, il controllo (ovvero l’uscita del regolatore

durante il funzionamento in automatico) si deve fermare al valore corrente e l’operatore

può comandare la variabile di controllo impostandone le variazioni

(incrementa/decrementa).

Al passaggio da manuale ad automatico il controllo, invece, deve muoversi a partire

dal valore corrente e verso quello richiesto dal regolatore affinché la variabile

controllata tenda al set-point senza salti.

Molti regolatori dispongono di un ingresso logico, detto forzamento in manuale, che

può causare una commutazione automatico/manuale anche in assenza di una diretta

richiesta dell’operatore; si può pensare, ad esempio, al caso del controllo in cascata: se il

regolatore interno va in manuale, sia l’anello interno che quello esterno risultano aperti;

sarà, pertanto, necessario che il regolatore esterno sia forzato in manuale in modo da

evitare una situazione di inconsistenza.

E’ importante sottolineare che, in una logica di controllo, i comandi locali (impartiti

dagli operatori tramite pannelli posti vicino all’impianto) devono sempre prevalere su

quelli remoti (provenienti da altri regolatori, dal sistema di supervisione, ... posti in zone

differenti da quella in cui è situato l’impianto); di conseguenza, se un operatore mette in

manuale un regolatore, i livelli superiori del controllo devono essere informati della

situazione affinché possano intraprendere opportune azioni di controllo, le quali non

dovranno mai prevaricare i comandi impartiti localmente dagli operatori.

Riassumendo:

- Se localmente si impone il manuale, l’ingresso di forzamento in manuale non ha

effetto;

- Se localmente il regolatore è in automatico, l’ingresso di forzamento in manuale

è attivo e la modalità di funzionamento sarà determinata dalle necessità del resto

del sistema di controllo.

Page 16: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

16

4. REALIZZAZIONE DIGITALE

In questo paragrafo si affronta il problema della realizzazione fisica di un PID

tramite una funzione (nell’accezione informatica del termine) che riceve i valori del set-

point e della variabile controllata e produce il valore della variabile di controllo. Il

tempo che intercorre tra un’esecuzione di questa funzione e la successiva è costante e si

sceglie in sede di sintesi del regolatore stesso; questo ulteriore parametro prende il nome

di “tempo di campionamento” (nel seguito indicato con TS). Esso determina la

granularità del controllo, ovvero la cadenza temporale con cui il regolatore fa variare il

controllo.

4.1. Equivalente Discreto del PID

Per realizzare le azioni di un PID con un sistema di elaborazione digitale, è

necessario ottenerne equivalenti discreti. Il problema della discretizzazione consiste,

data una funzione di trasferimento a tempo continuo e dato un tempo di

campionamento, nel determinare i parametri di una funzione di trasferimento a tempo

discreto che ne approssimi abbastanza bene il comportamento (vedi [1]).

La discretizzazione può essere compiuta secondo vari metodi. Alcuni consistono

nell’applicazione di formule di calcolo numerico: la discretizzazione in avanti ( o

formula esplicita di Eulero), la discretizzazione all’indietro (o formula implicita di

Eulero), il metodo del trapezio (o di Tustin).

Un altro metodo, che fornisce l’equivalente discreto di un sistema dinamico lineare, è

quello dello Zero Order Hold (ZOH), che fornisce il valore esatto dell’uscita agli istanti

di campionamento, nell’ipotesi in cui l’ingresso sia costante nel periodo di

campionamento.

Di seguito si riporta, con riferimento alla forma standard ISA descritta in precedenza,

la discretizzazione del PID reale (nel caso a derivazione d’uscita, ovvero 0=c )

secondo la formula esplicita di Eulero:

Azione Proporzionale

( ))()()()( *** kykbyKkPKsP oPP −=⇔=

Page 17: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

17

Azione Integrale

( ))()()1()()( **** kykyT

TKkIkIsTKsI o

I

SP

I

P −+−=⇔=

Si noti che per il calcolo al primo istante di campionamento è necessario conoscere

)0(*I . La discretizzazione mette in particolare evidenza il problema del wind-up;

infatti, se la variabile controllata satura senza riuscire a raggiungere il set-point e

l’errore si ferma ad un valore costante, si ha che l’equivalente discreto dell’azione

integrale tende a crescere indefinitamente a meno che non si prendano opportuni

provvedimenti.

Azione Derivativa

( ))1()()1()(1

)( **** −−+

−−+

=⇔+

= kykyNTT

NTKkDNTT

TkDNsT

TsKsDSD

DP

SD

D

D

DP

Si noti che per il calcolo al primo istante di campionamento è necessario conoscere

)0(*D e )0(*y .

L’equivalente discreto del PID, pertanto, sarà dato dalla somma degli equivalenti

delle tre azioni:

)()()()( **** kDkIkPkU ++=

4.1.1. Scelta della frequenza di campionamento

La scelta della frequenza di campionamento deve scaturire da un buon compromesso

tra esigenze diverse e, talvolta, contrapposte. Considerazioni relative al costo del

sistema spingono a scegliere un valore basso, affinché la potenza di calcolo necessaria

per eseguire gli algoritmi di controllo sia minima, e i convertitori A/D e D/A più

economici. L’analisi delle prestazioni del sistema di controllo impone, però, un limite

inferiore assoluto; difatti, il processo di sintesi del regolatore pone in essere un insieme

di requisiti dai quali non è possibile prescindere:

- la capacità del controllo di inseguire efficacemente il riferimento, esprimibile sia

in termini di banda passante, che di tempo di salita o di assestamento della

risposta ad una variazione a scalino;

Page 18: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

18

- la capacità di compensare efficacemente i disturbi agenti sul processo;

- la capacità di filtrare adeguatamente i rumori associati ai segnali provenienti dai

sensori.

Si consideri l’inseguimento del riferimento. La condizione che il sistema di controllo

in anello chiuso debba inseguire il riferimento fino alla banda passante π

ω2

CCf =

impone un limite inferiore assoluto alla frequenza di campionamento: per il teorema di

Shannon essa deve essere almeno doppia di Cf . Allo stesso risultato si giunge se si

considera di dover acquisire senza perdita d’informazione le componenti di y in banda

passante. Il limite imposto dal teorema del campionamento è, tuttavia, teorico e non

adeguato alle applicazioni di controllo; in letteratura esistono varie indicazioni di

massima che permettono di individuare la frequenza di campionamento ottimale per il

singolo problema in esame.

Per quanto concerne la compensazione dei disturbi, il periodo di campionamento

rappresenta il valore limite del ritardo di reazione di un sistema di controllo digitale a un

disturbo di carico agente sul processo; pertanto, si tratta di un parametro critico ai fini

della prontezza con cui il controllo reagisce al disturbo.

Ulteriori informazioni sono disponibili in [2].

4.1.2. PID Posizionale e PID Incrementale

La legge di controllo PID può essere espressa in due modi:

- Posizionale, in cui si calcola direttamente, ad ogni passo di campionamento, il

nuovo valore del controllo;

- Incrementale, in cui si calcola, ad ogni passo di campionamento, la variazione del

controllo che, sommata al valore precedente, determina il nuovo valore del

controllo.

La forma incrementale è molto utilizzata nella pratica in quanto semplifica

notevolmente l’implementazione di funzionalità complementari alla mera legge di

controllo (anti-windup, tracking di un segnale, commutazione manuale/automatico,

logiche di blocco, etc… ) nel software che rappresenta l’equivalente discreto del PID.

Risulta immediato esprimere un PID in forma incrementale a partire dalla

Page 19: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

19

discretizzazione sopra operata (vedi [1]).

Sia:

)1()()( *** −−=∆ kvkvkv

la variazione del generico segnale a tempo discreto )(* kv . Sulla base di questa

definizione è possibile formulare le tre azioni del regolatore nel modo seguente:

( )( )

( ))1()()1()(

)()()(

)()()(

****

***

***

−∆−∆+

−−∆+

=∆

−=∆

∆−∆=∆

kykyNTT

KNTkDNTT

TkD

kykyT

TKkI

kykybKkP

SD

D

SD

D

o

I

SP

oP

Si può osservare come le variazioni delle azioni proporzionale e integrale non

dipendano dai loro valori passati, mentre ciò si verifica nel caso dell’azione derivativa.

4.2. Pseudo-codice di un regolatore PID

L’algoritmo per il calcolo dell’equivalente discreto del PID, si compone

essenzialmente di due parti, sempre presenti in un sistema di controllo in tempo reale:

- l’inizializzazione, eseguita una sola volta all’accensione del regolatore;

- il codice ricorsivo, eseguito ad ogni periodo di campionamento; questa parte

presenta criticità rispetto ai tempi di calcolo e all’affidabilità di funzionamento,

per cui deve essere codificato e verificato con particolare cura. Al suo interno si

possono individuare quattro sezioni ben distinte:

! acquisizione degli ingressi e conversione A/D (y e ySP);

! calcolo della variabile di controllo (u);

! scrittura dell’uscita;

! aggiornamento dello stato.

Il codice ricorsivo può essere più o meno complesso, a seconda delle funzionalità

ausiliarie che si decide di implementare; la precedente trattazione teorica conduce alla

codifica dei seguenti servizi, realizzata considerando il PID nella sua forma

incrementale:

- anti-windup: l’implementazione proposta mantiene entro i limiti di saturazione

non solo l’azione integrale, ma tutta l’azione di controllo, il che, ai fini pratici,

Page 20: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

20

non comporta alcuna sostanziale differenza (si ricorda, infatti, che il wind-up è

un fenomeno che interessa solo ed esclusivamente l’integratore). Il frammento di

codice (tratto da [1]) corrispondente è il seguente:

...

/* A questo punto si dispone:

- della variazione del controllo (DeltaCS)

- del valore precedente del controllo (CSold)

- dei limiti di saturazione (CSmax e CSmin) */

CSnew = CSold + DeltaCS;

if (CSnew >= CSmax) CSnew = CSmax;

if (CSnew <= CSmin) CSnew = CSmin;

CSold = CS new;

/* Segue l’attuazione del nuovo controllo CSnew */

...

- logiche di blocco: questa sezione di codice permette di gestire logiche di

controllo che scaturiscono dall’interconnessione di più regolatori; consideriamo,

ad esempio, il caso di due anelli annidati: si può ragionevolmente sostenere che,

quando il regolatore dell’anello interno (Ri) è in saturazione, si deve permettere a

quello dell’anello esterno (Re) di modificare la sua uscita soltanto nella direzione

che fa uscire Ri dalla saturazione. A tale scopo, i regolatori industriali sono dotati

di due uscite booleane (solitamente dette HIsat e LOsat) preposte a segnalare con

un livello logico alto, rispettivamente, le saturazioni superiore e inferiore.

Dispongono, inoltre, di due ingressi booleani (di solito individuati con F+ e F-)

che, se posti a livello logico alto, impediscono all’uscita del regolatore di

crescere o decrescere, rispettivamente. Una possibile implementazione (proposta

da [1]) è la seguente:

...

/* Fplus e Fminus sono i due ingressi

di blocco, HIsat e LOsat i segnali

di saturazione */

if ((DeltaCS>0 && Fplus==TRUE)||(DeltaCS<0 && Fminus==TRUE))

DeltaCS = 0;

CSnew = CSold + DeltaCS;

if (HIsat = (CSnew >= CSmax)) CSnew = CSmax;

Page 21: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

21

if (LOsat = (CSnew <= CSmin)) CSnew = CSmin;

CSold = CSnew;

...

- commutazioni A/M e M/A bumpless: una volta definite le modalità di

comportamento del regolatore a fronte di tali commutazioni, la traduzione in

codice è pressoché immediata (vedi [1]):

...

/* Verifica dello stato del comando A/M locale e del forzamento remoto */

if ((ComandoAMlocale==AUTO)||(ComandoAMremoto==AUTO)

/* Il regolatore è in modalità Automatica */

/* Codice per il calcolo di DeltaCS */

/* Gestione logiche di blocco */

/* Aggiornamento del controllo in automatico */

else

/* Il regolatore è in modalità Manuale */

/* Verifica dello stato dei comandi locali d'incremento e decremento; IncrementoUnitarioCS è un parametro del regolatore */

if (ComandoIncrementoCS == TRUE) CSnew = CSold + IncrementoUnitarioCS;

if (ComandoDecrementoCS == TRUE) CSnew = CSold - IncrementoUnitarioCS;

/* Gestione dell'antiwindup (indipendentemente dalla modalità di funzionamento) ed eventuale segnalazione della saturazione */

if (HIsat = (CSnew >= CSmax)) CSnew = CSmax;

if (LOsat = (CSnew <= CSmin)) CSnew = CSmin;

/* Aggiornamento dello stato finale */

CSold = CSnew;

...

Di seguito si riporta il codice completo che costituisce la realizzazione digitale di un

PID in forma incrementale, con ovvio significato dei simboli:

Page 22: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

22

void PID()

deltaSP = SPnew – SPold;

deltaPV = PVnew – Pvold;

/* Verifica dello stato del comando A/M locale e del forzamento remoto */

if ((ComandoAMlocale==AUTO)||(ComandoAMremoto==AUTO)

/* Il regolatore è in modalità Automatica */

/* Calcolo di DeltaCS */

deltaP = K*(b*deltaSP-deltaPV);

deltaI = K*Ts/Ti*(SPnew-PVnew);

Dnew=(Td*Dold+K*N*Td*(c*deltaSP-deltaPV))/(Td+N*Ts);

deltaD = Dnew-Dold;

deltaCS = deltaP+deltaI+deltaD;

/* Gestione delle logiche di blocco */

if ((DeltaCS>0 && Fplus==TRUE)||(DeltaCS<0 && Fminus==TRUE))

DeltaCS = 0;

/* Aggiornamento del controllo in automatico */

CSnew = CSold + DeltaCS;

else

/* Il regolatore è in modalità Manuale */

/* Verifica dello stato dei comandi locali d'incremento e decremento */

if (ComandoIncrementoCS==TRUE) CSnew = CSold + IncrementoUnitarioCS;

if (ComandoDecrementoCS==TRUE) CSnew = CSold - IncrementoUnitarioCS;

/* Gestione dell'antiwindup */

if (HIsat=(CSnew>=CSmax)) CSnew = CSmax;

if (LOsat=(CSnew<=CSmin)) CSnew = CSmin;

/* Aggiornamento dello stato finale */

CSold = CSnew;

Page 23: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 2 - Controllo PID

23

SPold = SPnew;

PVold = PVnew;

Dold = Dnew;

/* Attuazione del nuovo controllo CSnew */

Page 24: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

24

Capitolo 3

Strumenti di lavoro

Page 25: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

25

In questo capitolo si presenta il dispositivo fisico ed il relativo sistema operativo che costituiscono il supporto del prodotto oggetto di questa tesi.

1. INTRODUZIONE

Il capitolo prende le mosse fornendo una definizione dell’RCX attraverso una

descrizione generale della sua architettura: si passano in rassegna i principali elementi,

cercando di non porre enfasi su tecnicismi hardware, ma di fornire informazioni utili a

formare un’idea di massima del funzionamento e delle potenzialità in esso racchiuse.

Sulla base di questa introduzione, si espongono le caratteristiche fondamentali del

sistema operativo impiegato in questo progetto: BrickOS. Anzitutto, s’introduce il

“kernel”, indicandone l’organizzazione, i principi di funzionamento e le tecniche

adottate per implementare le tipiche funzionalità presenti in un sistema operativo.

Successivamente, si discutono le modalità di interazione a basso livello fra hardware e

software. L’obiettivo principale è quello di comprendere come vengono eseguiti gli

applicativi utente e come essi possono sfruttare le potenzialità dell’RCX.

Si procede affrontando la gestione delle periferiche (display LCD, pulsanti, motori e

sensori); dopo una breve illustrazione dell’hardware, si indica come il S.O. gestisce tali

dispositivi, ponendo particolare attenzione all’interfaccia utente. Non viene presentata

una descrizione completa delle API di BrickOS, in quanto non è obiettivo di questo

capitolo fornire una guida alla programmazione.

Si riportano, infine, alcune considerazioni sul connubio RCX-BrickOS e si discute il

ruolo che il progetto trattato in questa tesi assume all’interno della “comunità BrickOS”.

2. RCX

L’RCX è un dispositivo costituito internamente da un microcontrollore corredato da

una memoria di tipo ROM ed una di tipo RAM, che si interfaccia verso l’esterno

attraverso tre porte d’ingresso e tre d’uscita, quattro pulsanti, una porta a infrarossi e un

piccolo display LCD. Può essere alimentato sia tramite batterie, sia attraverso la rete

elettrica per mezzo di un trasformatore, che, sul secondario, genera una tensione

Page 26: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

26

continua a 10V.

Tutte le informazioni riguardanti l’hardware dell’RCX sono tratte da [8] e [11].

2.1. CPU

L'RCX utilizza il microprocessore Hitachi H8/3292 a 16 MHz, esteso con 32K di

memoria RAM esterna, alla quale si accede attraverso indirizzi da 16 bit. Il chip dispone

di 16 registri (R0L, R0H,..., R7L, R7H) da 8 bit ciascuno, che la CPU può anche gestire

come 8 registri (R1,…R7) da 16 bit per effettuare indirizzamenti. Sono presenti anche

due registri di controllo: un program counter (PC) da 16 bit e un condition code register

(CCR) da 8 bit. Il registro R7 viene utilizzato come stack pointer (SP). Ciascuna

operazione sullo stack avviene attraverso words di 2 byte.

Nel microcontrollore Hitachi H8/3292 sono presenti alcuni sottosistemi on-chip tra i

quali: un timer a 16 bit, un convertitore A/D (DAC) e porte I/O. Il timer è utilizzato per

generare gli interrupts che guidano il sistema operativo, mentre il convertitore A/D

serve per campionare e convertire i segnali analogici provenienti dai sensori collegati

alle porte d’ingresso dell’RCX.

2.2. ROM & firmware

La CPU dispone di una memoria ROM da 16K contenete software fornito dal

produttore, ovvero un driver che va in esecuzione quando l'RCX viene acceso.

Sostanzialmente tale driver è composto da routines per la gestione a basso livello

dell'RCX e dei suoi sottosistemi. Tra esse è presente anche un gestore degli interrupts, il

quale reagisce ad una chiamata puntando a stabilite locazioni nella memoria RAM, nelle

quali è possibile inserire dei comandi per la personalizzazione della risposta agli eventi.

Il driver nella ROM è responsabile anche dell'attivazione del firmware, che viene

caricato nella memoria RAM al momento dell’accensione. Quando si scarica BrickOS,

il firmware viene rimpiazzato da una immagine del kernel. BrickOS sfrutta solo alcune

delle funzioni presenti nella ROM: refreshing del display, procedure di on/off e sound

playing.

Page 27: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

27

2.3. RAM esterna

La RAM esterna è indirizzata attraverso il range d’indirizzi che vanno da 0x8000

fino a 0xFFFF; tuttavia parte di questi indirizzi è riservata al Memory Mapped I/O, al

display LCD ed al Memory Mapped Motor Control. Lo spazio libero è suddiviso in una

“parte bassa” riservata al kernel (in cui viene memorizzata l'immagine del kernel di

BrickOS che occupa 16K) e una “parte alta” dedicata ai programmi utente. Oltre alla

RAM esterna, l’RCX non possiede nessun altro dispositivo di memoria, per cui non è

necessario alcun filesystem.

2.4. Porte d’ingresso

L’RCX dispone di tre porte d’ingresso analogiche, alle quali è possibile collegare

alcuni sensori (di luce, di contatto, di rotazione,…). Ciascuna porta è collegata al

convertitore A/D da 10 bit ad approssimazioni successive, il quale può accedere fino ad

8 canali d'ingresso analogici (AN0, AN1,..., AN7).

Il convertitore dispone di quattro registri dati (ADDRA,.....,ADDRD) da 16 bit

ciascuno, che sono mappati in memoria in corrispondenza degli indirizzi che vanno da

0xFFE0 sino a 0xFFE7. Tali registri sono di sola lettura e sono suddivisi in una parte

alta e una bassa. Su di essi vengono posti i risultati della conversione di un massimo di

4 canali d'ingresso (uno per ogni porta più uno per il livello di carica delle batterie).

Oltre a questi, vi è il registro a 8 bit ADCSR, il quale serve per controllare lo stato

del convertitore. Questo registro è sia leggibile che scrivibile, al fine di poter dare il

comando di start al convertitore e di rilevare il termine di una conversione. Quando la

conversione di un segnale analogico è finita viene invocato un interrupt (ADI).

2.5. Porte d’uscita

L’RCX dispone di tre porte d’uscita, alle quali è possibile collegare i motori forniti

dal produttore.

L’unico tipo di segnale che può essere generato su queste porte è di tipo PWM (Pulse

Width Modulation). Questo è tipicamente un segnale ad onda quadra, in cui il periodo e

l’ampiezza sono mantenuti costanti, mentre la durata degli impulsi varia a seconda

Page 28: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

28

dell’informazione associata.

Il segnale PWM generato in uscita dall’RCX si discosta in parte dalla definizione

classica sopra citata. Infatti, al fine di ottimizzare il controllo operato sui motori, il

segnale applicato alle porte d’uscita mantiene costante il duty cycle, ma può variare in

frequenza. L’ampiezza dell’impulso è costante e pari a 10V.

La frequenza degli impulsi viene impostata attraverso una word da 8 bit, così da

ottenere 256 possibili diversi valori di frequenza. In corrispondenza del valore 0 il

motore resta fermo, mentre a 255 corrisponde la massima potenza erogabile al motore.

Sfortunatamente, non vi è una relazione di linearità fra l’impostazione della frequenza

(potenza erogata) e la velocità di rotazione, la quale dipende, inoltre, dal carico

applicato.

Infine, si può verificare molto facilmente che, applicando a due motori diversi lo

stesso segnale (stessa impostazione di frequenza), questi non girano esattamente alla

stessa velocità.

3. BRICKOS

BrickOS è un sistema operativo embedded per Lego Mindstorms RCX, proposto

come alternativa al firmware fornito dal produttore; si tratta di un progetto “open

source” rilasciato sotto licenza «Mozilla».

In estrema sintesi, si può sostenere che le principali caratteristiche siano: priority-

based preemptive multitasking, semafori POSIX, caricamento dinamico dei programmi

utente, gestione dinamica della memoria e IR networking. BrickOS fornisce delle API

per lo sviluppo di programmi utente in linguaggio C/C++; esse prevedono l’impiego di

un cross-compilatore gcc (derivato dall’omonimo compilatore di Linux). Pertanto, è

possibile sviluppare applicativi per BrickOS sia attraverso un approccio procedurale, sia

attraverso la tecnologia ad oggetti. In pratica, l’utente scrive e compila le proprie

applicazioni su personal computer e, in un secondo tempo, scarica il codice compilato

sull’RCX attraverso un trasmettitore IR.

Le caratteristiche tecniche di BrickOS sono trattate, in modo approfondito, in [6].

Page 29: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

29

3.1. Il kernel di BrickOS

Il kernel di BrickOS è un blocco monolitico, in quanto l'intera sorgente viene

compilata in un’unica immagine binaria. Le interfacce per i programmi utente sono rese

disponibili in uno script linker dinamico.

L’attivazione del kernel avviene quando dalla ROM viene chiamata la funzione

kmain. Il kernel può lavorare sia in multitasking o in singletasking.

Durante l'inizializzazione del kernel vengono creati 3 tasks. Il primo, detto idle, è un

“task fantasma” con priorità minima, che viene eseguito quando nessun altro task è

attivo e ha il compito di "mettere a riposo" la CPU facendole eseguire l'istruzione sleep.

Gli altri due tasks, grazie ai quali è possibile eseguire il caricamento dinamico dei

programmi, sono chiamati packet-consumer e key-handler e vengono eseguiti con

priorità massima.

In breve, si può sostenere che il packet-consumer gestisce l'attività della porta IR,

mentre il key-handler si occupa della gestione dei pulsanti dell'RCX.

In seguito, viene attivato il task manager, il quale porta in esecuzione i tre tasks sopra

citati. Nuovi processi possono essere attivati scaricando ed eseguendo i programmi

utente.

3.1.1. Temporizzazioni

BrickOS è guidato da interrupts generati dal timer a 16 bit, il quale è configurato per

produrre un interrupt ogni millisecondo.

Gli interrupts vengono gestiti da una routine della ROM, la quale chiama la funzione

systime-handler (definita in kernel/systime.c). Tale funzione interroga in sequenza tutti i

vari sottosistemi dell’RCX, invocando, per ciascuno di essi, il relativo gestore. In

pratica, BrickOS utilizza la tecnica del polling per comunicare con le varie parti

dell'hardware.

L'ultima attività, svolta al termine di un giro di polling, è il controllo del timeslice

(20ms per default) del task in esecuzione, in modo da controllare se è scaduto il tempo a

sua disposizione. In caso affermativo viene chiamata la funzione tm-switcher che

eseguirà in cooperazione con lo scheduler un cambio di contesto della CPU.

Page 30: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

30

3.1.2. Gestione dei Tasks

Con il termine “task manager” si intende l'insieme di funzioni, implementate in

kernel/tm.c, che si occupano della gestione dei tasks e dei loro risultati. Pertanto, non si

tratta di un processo separato o di un thread.

Ciascun programma in BrickOS è costituito da un'immagine binaria memorizzata

nella RAM; una volta entrato in esecuzione ha, come minimo, un processo attivo, ma

può crearne di nuovi grazie alla funzione execi. I processi creati per mezzo di questa

funzione condividono lo spazio di memoria del programma che li ha generati.

Il task manager implementa una politica priorità-based di tipo preemptive (vedi [8]);

a ciascun processo è associato un descrittore (di tipo pdata_t) che contiene informazioni

di stato ed informazioni necessarie per lo swithing dei tasks (livello di priorità, stack

pointer, ....).

Un processo si può trovare in cinque differenti stati (vedi [5]):

- Dead: il processo ha terminato la sua esecuzione ed il suo stack è stato

deallocato.

- Zombie: il processo ha terminato la sua esecuzione ma il suo stack non è stato

ancora liberato.

- Waiting: il processo non occupa la CPU ed è in attesa di un evento.

- Sleeping: il processo non occupa la CPU ma è pronto per essere eseguito.

- Running: il processo è in esecuzione.

Le informazioni di stato sono gestite dallo scheduler, il quale si occupa anche di

liberare la parte di stack occupata da un processo una volta che questo viene terminato.

L'esecuzione di un task può essere sospesa e posta in attesa di un evento a seguito

della chiamata alla procedura wait_event, i cui parametri permettono di specificare la

funzione di risveglio che deve essere invocata ogniqualvolta si debbano valutare le

condizioni di riattivazione. Il controllo della condizione di risveglio di un processo

viene eseguito ogni volta che lo scheduler, mentre è alla ricerca di un nuovo task da

eseguire, incontra un processo nello stato waiting. Se la funzione di risveglio ritorna un

valore non nullo, significa che la condizione di attesa non è più soddisfatta, così il

processo sospeso passa dallo stato waiting a quello sleeping.

Il problema di questa tecnica è che la condizione di attesa viene controllata solo

Page 31: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

31

quando il sistema deve schedulare un nuovo processo. Così, può accadere che un

processo in attesa di un evento esterno resti a lungo bloccato se la sua condizione di

risveglio, una volta verificata, ritorni falsa prima che venga controllata nuovamente.

3.1.2.1. Linking dinamico dei programmi utente

Nelle prime versioni di BrickOS i programmi utente dovevano essere collegati

staticamente al kernel; pertanto, le applicazioni ed il kernel erano contenuti in un’unica

immagine binaria. Questo imponeva la ricompilazione dell’intero kernel ogni volta che

si apportavano modifiche ad un programma.

A partire dalla versione 0.2.4 è stata introdotta la possibilità di eseguire un

caricamento dinamico delle applicazioni utente, mediante il quale risulta possibile

caricare sino a 8 programmi utente nella memoria RAM. Le applicazioni sono

compilate su PC (con il compilatore gcc sopraccitato) in un formato rilocabile con

estensione .lx.

Il linker dinamico, chiamato dll, permette di eseguire il download delle applicazioni

utente (trasferimento da PC a RCX) e provvede, in automatico, alle operazioni di

linking con il kernel.

La directory boot (presente su PC) contiene due files: legOS.srec e legOS.lds; il

primo rappresenta l'immagine del kernel, mentre il secondo è uno script generato

durante la compilazione del kernel. Tale script ha la funzione di associare a ciascuna

funzione di libreria del kernel un indirizzo relativo di memoria. Quando si richiede la

compilazione di un programma utente, legOS.lds viene utilizzato nella fase di linking

per creare il file .lx. Il link finale agli indirizzi di memoria assoluti avviene durante il

download del programma utente sull'RCX. Al termine del download, il programma è

pronto per essere eseguito.

Le informazioni riguardanti tutti gli applicativi residenti sull’RCX sono contenute in

un array composto da 8 variabili di tipo program_t. Questa struttura contiene

informazioni riguardanti indirizzi e dimensioni dei vari segmenti di cui si compongono i

programmi. Inoltre, sono riportate informazioni relative alla dimensione dello stack, alla

priorità associata, al conteggio dei bytes scaricati (necessari per individuare errori

durante il download).

Per eseguire un applicativo sull’RCX, è sufficiente selezionarlo, premendo il

Page 32: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

32

pulsante “prgm”, e, infine, premere il pulante “run”. A questo punto viene creato un

nuovo task per mezzo della chiamata alla funzione execi.

3.1.2.2. La funzione execi

Come detto in precedenza, questa funzione viene utilizzata per creare nuovi task che

condividono lo stesso spazio degli indirizzi del programma che li ha generati.

Richiede i seguenti parametri:

- un puntatore alla funzione che costituisce il corpo del nuovo task;

- il numero di argomenti richiesti da tale funzione;

- l’elenco dei parametri attuali con cui invocarla;

- il livello di priorità;

- la dimensione dello stack.

Execi cerca di inserire una nuova variabile di tipo pdata_t nella coda delle priorità

(vedere paragrafo successivo) e di allocare memoria per lo stack del task.

Il nuovo processo viene inserito nella struttura dei task nello stato sleeping, come se

la sua esecuzione fosse stata sospesa dallo scheduler; quando viene creato lo

stackframe, come primo valore viene inserito l'indirizzo della funzione exit, la quale ha

il compito di liberare la memoria allocata al task. In questo modo si garantisce che

ciascun task esegua, come ultima istruzione, un’invocazione alla suddetta funzione.

3.1.2.3. La struttura organizzativa dei task

A ciascun task (processo) è associata una priorità, la quale può assumere 20

differenti valori: 1 è la priorità minima, mentre 20 è quella massima. I processi sono

organizzati in una struttura composta da una lista ordinata, detta catena delle priorità.

A ciascun livello è della catena collegata una lista bidirezionale, i cui elementi sono di

tipo pdata_t. In pratica, tutti i processi che si trovano nella stessa lista hanno lo stesso

valore di priorità. Se ad un livello di priorità non è collegata alcuna lista (non c’è nessun

task con quel valore di priorità), allora il livello viene eliminato al fine di rendere più

efficiente la struttura.

L’accesso alla struttura avviene in mutua esclusione per mezzo di un semaforo;

operando in questo modo si garantisce, tra l’altro, che nessun nuovo task possa essere

inserito se lo scheduler sta selezionando un nuovo processo da eseguire.

Page 33: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

33

La figura seguente schematizza la catena delle priorità:

Un nuovo task viene inserito nella struttura dalla funzione execi, la quale percorre la

catena dall'alto verso il basso: se esiste già una lista relativa al livello di priorità in cui

deve essere inserito il processo, allora esso viene collocato in fondo; in caso contrario,

si crea un nuovo anello nella catena delle priorità al quale si collega l’oggetto pdata_t

relativo al task da inserire.

3.1.2.4. Lo scheduler

L’alternanza in esecuzione dei processi è gestita dallo scheduler, il quale adotta uno

schema di tipo “round-robin” con priorità (vedi [7]). Il timeslice garantito a ciascun

processo è di 20ms.

Quando scade il quanto di tempo a disposizione di un processo o quando il processo

volontariamente libera la CPU, lo scheduler viene invocato per stabilire quale processo

deve essere eseguito nel prossimo timeslice. Per fare ciò, si esegue una “trywait” sul

semaforo che gestisce la coda dei task; se questo risulta bloccato (un altro task sta

aggiornando la struttura) il task manager attende che la risorsa ritorni disponibile.

Altrimenti, lo scheduler occupa il semaforo (che da questo istante risulterà bloccato per

PREVIOUS PRIORITY = 20 NEXT

Packet Consumer

Key Handler

PREVIOUS PRIORITY = 10 NEXT

PREVIOUS PRIORITY = 1 NEXT

User Task 1 User Task 2 User Task 3

Idle Task

Page 34: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

34

gli altri processi) ed esamina lo stato del processo corrente. Se questo si trova nello

stato zombie dealloca la sua memoria e lo rimuove dalla struttura dei tasks. Nel caso in

cui sia l'ultimo processo in quel livello di priorità, allora viene eliminato dalla catena

anche l’anello ad esso corrispondente.

A questo punto, viene eseguita una scansione della struttura dei tasks al fine di

individuare un processo da portare in esecuzione.

Partendo dal livello di priorità più alto, si scandisce la coda dei tasks: se il processo

esaminato si trova nello stato sleeping; allora è pronto per essere attivato e quindi viene

schedulato per l'esecuzione impostando il suo stato a running. Lo scheduler a questo

punto abbandona il semaforo e salva lo stack pointer del nuovo task.

Se, invece, il processo considerato è nello stato waiting, la sua funzione di risveglio

viene valutata: nel caso in cui ritorni un valore non nullo il processo passa allo stato

running e lo scheduler procede come sopra descritto; in caso contrario si passa al

processo successivo oppure ai processi del livello di priorità inferiore.

Questa operazione procede tra i vari livelli di priorità finchè non viene individuato un

processo adatto per entrare in esecuzione. Nel caso estremo, in cui non vi sia alcun

processo pronto per l’esecuzione, la CPU verrà occupata dal task idle.

L'impiego simultaneo di semafori e di scheduling con priorità introduce il problema

dell'inversione di priorità, ovvero quella particolare situazione in cui un processo a

bassa priorità (task A) ne blocca un altro con priorità più alta (task B) poiché detiene

una o più risorse ad esso necessarie; per questo motivo, il task B, pur avendo diritto di

prelazione sul task A, non può procedere nella propria esecuzione. Per informazioni più

approfondite sul problema dell’inversione di priorità è possibile consultare [12].

3.1.3. Gestione della memoria

BrickOS alloca la memoria in maniera sequenziale, a partire dalla prima locazione

libera. Non esiste alcun supporto per una gestione più avanzata della memoria; essa,

infatti, è una risorsa scarsa ed un gestore più complesso comporterebbe solo un

overhead anziché reali benefici. Il gestore della memoria è costituito dall’insieme di

funzioni definite in kernel/mm.c.

Si è visto in precedenza che la memoria RAM è suddivisa in due parti: una dedicata

Page 35: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

35

al kernel ed una ai programmi utente. Il codice del kernel e i suoi dati statici sono

allocati nella parte inferiore a partire dall'indirizzo 0x8000 sino all'indirizzo mm_start

(variabile globale di sistema).

Il Memory Management ha la responsabilità dello spazio di memoria compreso fra

mm_start e l'indirizzo 0xFFFF, il quale risulta organizzato in blocchi formati da una

intestazione di 4 byte (header) e da un campo dati (data field) a dimensione variabile.

I primi 2 byte dell'header contengono l'identifficatore del processo (process ID) al

quale il blocco è allocato. Se il blocco non è allocato il valore di questo campo è pari a

MM_FREE (impostato a 0 per default). Gli ultimi 2 byte dell'intestazione contengono la

dimensione del campo dati che la segue.

Un puntatore alla variabile globale mm_first_free è usato per indirizzare il primo

blocco di memoria libera. L'unità di memoria adottata internamente dal gestore della

memoria è una word di 2 byte.

L’accesso in mutua esclusione alla memoria avviene attraverso un apposito semaforo

(mm_semaphore).

3.1.3.1. Allocazione della memoria

I processi del kernel e quelli dei programmi utente possono allocare zone di memoria

chiamando la funzione malloc, la quale, per prima cosa, aspetta che il semaforo

mm_semaphore sia libero. Una volta garantito l'accesso alla regione critica, malloc

inizia a sondare la memoria a partire dall'indirizzo mm_first_free, finché non trova un

blocco di memoria libero avente dimensioni adeguate. Nel caso in cui raggiunga la fine

della memoria, restituisce il valore null. Se malloc ha successo ritorna un puntatore al

campo dati del blocco di memoria allocato.

3.1.3.2. Deallocazione della memoria

La deallocazione dinamica della memoria è attuata dalla funzione free, la quale non

fa altro che indicare come liberi i blocchi designati. Solo gli indirizzi non nulli verranno

considerati in questa operazione. Al termine dell'esecuzione viene aggiornato il

puntatore mm_first_free.

Quando un processo conclude la propria esecuzione deve liberare la memoria che

aveva allocato dinamicamente. Come detto in precedenza, al termine dell'esecuzione di

Page 36: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

36

un task viene chiamata la funzione exit, che, a sua volta, invoca la funzione mm_reaper.

Quest'ultima esegue una scansione di tutti i blocchi di memoria, marcando come liberi

(MM_FREE) tutti i blocchi appartenenti al processo che termina l'esecuzione.

E’ importante evidenziare il fatto che lo stack non appartiene al processo che lo

utilizza, bensì al suo processo padre; pertanto, non viene deallocato da mm_reaper.

Nel caso in cui il processo che termina sia indicato come processo del kernel, allora i

blocchi di memoria ad esso relativi non vengono deallocati.

I segmenti (testo e dati) che compongono le applicazioni utente sono allocati dal task

packet_consumer, il quale è indicato come processo del kernel; in pratica, quando un

programma termina la sua esecuzione, giustamente, non viene rimosso.

Questo schema di gestione della memoria non fornisce alcuna forma di protezione:

tutti i processi possono scrivere in qualsiasi parte della RAM. Inoltre, gli applicativi

possono allocare dinamicamente la memoria, perciò è possibile che i programmi vadano

a scrivere oltre i limiti dello spazio di memoria ad essi assegnato (run out of memory).

Per queste ragioni, i programmatori devono gestire con particolare cura le operazioni di

allocazione/deallocazione dinamica, in modo da evitare il crash del sistema.

3.1.4. Comunicazioni Interprocessuali

BrickOS fornisce i semafori come unico meccanismo di sincronizzazione tra i vari

processi in esecuzione parallela. Non esistono primitive per lo scambio di messaggi fra

processi; ad ogni modo, i task creati da uno stesso programma condividono il medesimo

spazio di memoria, pertanto è possibile sfruttare tale caratteristica per realizzare scambi

informativi.

E’ bene sottolineare, però, che il kernel non fornisce alcun supporto per lo scambio

di dati fra processi generati da programmi diversi.

3.1.4.1. Semafori

BrickOS fornisce semafori che implementano la classica definizione fornita da

Dijkstra (vedi [4]). In sostanza, si tratta di semafori a conteggio, i quali aggiungono,

alle usuali operazioni wait e post, una chiamata non bloccante (trywait) ed una

operazione per la lettura del valore del semaforo (getvalue).

L'operazione wait è realizzata dalla funzione wait_event, la quale pone il processo

Page 37: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

37

nello stato sleeping e definisce una funzione di risveglio, sem_event_wait, che testa il

valore del semaforo.

Se più processi sono bloccati su uno stesso semaforo che riceve un post, allora il

primo processo ad essere risvegliato sarà quello con priorità più alta. Nel caso ci siano

più processi con la stessa priorità, sarà l’ordine di arrivo a stabilire quale task avrà

accesso alla risorsa protetta.

3.1.5. IR Networking

Un’esposizione completa delle caratteristiche del protocollo di rete esula dagli scopi

di questa trattazione; di seguito vengono riportate solo alcune informazioni a carattere

introduttivo sull’argomento. Per ulteriori informazioni vedi [7].

LNP è il protocollo di rete per BrickOS ed è utilizzato dai programmi utente per

comunicare attraverso la porta IR dell’RCX. A partire dalla versione 0.2.4 possono

essere usati due tipi di pacchetti LNP: il primo, detto “integrity racket”, non contiene

informazioni sull'indirizzamento ed è utilizzato per comunicazioni broadcasting; il

secondo, detto “addressing racket”, aggiunge, rispetto al precedente, informazioni

relative all'indirizzamento, riportando l'indirizzo del mittente e quello del destinatario.

L'addressing packet fornisce un servizio simile all'UDP, ovvero non garantisce la

certezza d'arrivo dei pacchetti, ma è di tipo «error-free».

3.2. Gestione delle periferiche

BrickOS fornisce un insieme di primitive per l'interfacciamento con i principali

dispositivi di cui è corredato l’RCX: display LCD, pulsanti, motori e sensori.

La gestione delle periferiche è ampiamente discussa in [7].

3.2.1. Motori

I motori di Lego Mindstorms devono essere collegati ad una delle tre possibili porte

di uscita (indicate con lettere minuscole: a, b, c); è possibile collegare e pilotare fino a

tre motori contemporaneamente. Essi sono controllati con la tecnica del memory

mapped I/O.

Page 38: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

38

In BrickOS lo stato di un motore è descritto da due elementi: direzione e velocità;

l'impostazione della direzione determina il comportamento del motore quando questo

riceve un impulso elettrico.

I comandi vengono forniti per mezzo di una combinazione del valore di due bit:

Azione Bit Comando BrickOS

Avanti 01 Fwd

Indietro 10 Rev

Stop 00 Off

Frena 11 Brake

La differenza sostanziale fra le modalità brake (11) ed off (00) consiste nel fatto che

la prima blocca la rotazione, mentre la seconda non oppone alcuna resistenza al moto.

Per controllare la potenza applicata al motore, si utilizza una variabile da 8 bit, detta

speed; il nome di questa variabile può creare confusione, infatti, a parità di potenza

erogata, la velocità di rotazione dipende dal carico applicato all’albero.

I motori, identificati attraverso il nome delle porte di output a cui sono collegati,

vengono gestiti per mezzo delle funzioni incluse nella libreria dmotor.h (dove x sta per

a, b o c):

- motor_X_dir(enum MotorDirection): permette di impostare la direzione. Riceve,

come unico parametro, uno dei seguenti valori predefiniti: off, fwd, rev e brake.

- motor_X_speed(int speed): permette di impostare la potenza erogata. Riceve un

solo parametro di tipo intero, con un valore compreso tra MIN_SPEED e

MAX_SPEED (pari a 0 e 255 rispettivamente).

Queste funzioni sono state create per agevolare l’utilizzo dei motori.

3.2.2. Sensori

Alle porte d’ingresso dell’RCX è possibile collegare i vari sensori che Lego

Mindstorms fornisce: sensori di luce, di contatto e di rotazione. In corrispondenza delle

misure che effettuano, i sensori generano dei segnali analogici con valori di tensione

Page 39: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

39

compresi tra 0 e 5 V. Tali segnali vengono convertiti in digitale ed il risultato scritto in

appositi registri dati.

E’ possibile accedere direttamente a questi valori utilizzando la macro SENSOR_X

(dove X sta per 1,2 o 3 a seconda della porta cui è collegato il sensore) definita in

dsensor.h. La macro non fa altro che accedere alle sequenze di valori binari

continuamente fornite dal convertitore D/A e convertirle in valori di tipo intero. Poiché

il convertitore ha una risoluzione di 10 bit, SENSOR_X potrà assumere solo valori

compresi tra 0 e 1023.

Questa modalità di lettura dei sensori, detta “raw-mode”, è la più semplice e

generale possibile.

In aggiunta ad essa, per ogni tipo di sensore esiste una specifica macro, sviluppata

tenendo conto delle caratteristiche fisiche del sensore e dei valori che esso fornisce. Per

i sensori di contatto si utilizza TOUCH_X, per quelli di luce LIGHT_X e per quelli di

rotazione ROTATION_X.

3.2.2.1. Sensori di luce

I sensori di luce sono gestiti dalle librerie kernel/dsensor.c e dsensor.h. Questi

dispositivi consentono di operare la distinzione chiaro/scuro. In altre parole permettono

di distinguere fra aree di diversa luminosità, di individuare un oggetto scuro su sfondo

chiaro o di seguire una linea (pista) scura tracciata lungo un piano chiaro.

La lettura di tali sensori è gestita in modo sufficientemente accurato da poter

distinguere fra differenti colori. Questo utilizzo prevede, però, che l’utente eserciti uno

stretto controllo sulle condizioni di luce ed esegua degli esperimenti (campionamenti)

per determinare valori consistenti ed utilizzabili in relazione alle condizioni esterne ed

alle potenzialità del sensore.

I sensori di luce presentano due diverse modalità operative: attiva e passiva, che

possono essere selezionate per mezzo delle funzioni ds_active(&SENSOR_X) e

ds_passive(&SENSOR_X). In esse il parametro SENSOR_X (dove X sta per 1,2 o 3)

consente di specificare la porta, a cui è collegato il sensore. Per default i sensori si

trovano in modalità passiva.

Ovviamente a seconda della modalità il sensore offre delle prestazioni differenti e la

scelta di una o dell’altra dipende dal tipo di lettura/misura che si intende operare.

Page 40: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

40

Fisicamente, i sensori sono costituiti da due parti: il sensore di luce vero e proprio ed

una piccola sorgente di luce.

In modalità attiva il sensore viene alimentato, così il piccolo “led” montato sul

sensore emette una luce rossa. Questa modalità risulta conveniente nei casi in cui si

voglia distinguere fra chiaro e scuro, o, comunque, individuare oggetti che determinano

una forte differenza nella riflessione della luce rispetto allo sfondo in cui sono

“immersi”. E’ necessario che il sensore sia ragionevolmente vicino alla superficie da

campionare: 10cm circa; solo in questo caso, infatti, la luce emessa amplificherà la

differenza di riflessione.

In modalità attiva i valori ottenuti in raw-mode (attraverso la macro SENSOR_X)

appartengono al range di valori compresi, approssimativamente, tra 50 e 300, mentre i

valori forniti dalla macro LIGHT_X appartengono al range 0-100.

La modalità passiva, invece, è da preferirsi nel caso in cui la finalità sia quella di

analizzare l’ambiente circostante (ad esempio individuare un punto bianco su una parete

ad una certa distanza). In tale situazione, l’eventuale attivazione dell’emettitore interno

potrebbe interferire nella misura e, pertanto, deve essere inibita. In questa impostazione

i valori di LIGHT_X coincidono con i valori grezzi di SENSOR_X e risultano essere

compresi, in modo approssimato, tra 60 e 280/300.

In generale, si può osservare una maggiore stabilità delle letture effettuate in

modalità attiva, ma va ricordato che il sensore non è lineare e che i valori forniti

risultano sensibilmente influenzati da una molteplicità di fattori: utilizzo di batterie o

dell’alimentazione di rete, stato di carica delle batterie, condizioni ambientali esterne.

3.2.2.2. Sensori di rotazione

Attraverso il sensore di rotazione è possibile rilevare l’angolo di rotazione percorso

da un albero. Può lavorare solo in modalità attiva e presenta una sensibilità (valore

minimo letto) pari a 1/16 di un giro completo (22,5°).

I sensori di rotazione hanno un proprio gestore specifico: ds_rotation incluso nelle

librerie kernel/dsensor.c e dsensor.h

Per effettuare delle misurazioni corrette è necessario, anzitutto, rendere attivo il

sensore attraverso la funzione ds_active(&SENSOR_X); successivamente si invoca la

funzione ds_rotation_set(&SENSOR_X, int i), la quale imposta il valore attualmente

Page 41: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

41

campionato come punto di partenza. Se questa funzione non viene invocata, la posizione

attuale del sensore viene inizializzata con il valore 0.

A questo punto si può dare l’avvio all’operazione di misura attraverso la funzione

ds_rotation_on(&SENSOR_X); da questo istante in poi, il valore della posizione

istantanea, cui si accede attraverso la macro ROTATION_X, viene incrementato (o

decrementato) di una unità in corrispondenza di una rotazione pari ad 1/16 di giro in una

direzione (o in quella opposta).

Per terminare la misura è sufficiente invocare ds_rotation_off(&SENSOR_X).

3.2.2.3. Sensori di contatto

Come i sensori di luce, anche questi dispositivi sono gestiti dalle librerie

kernel/dsensor.c e dsensor.h.

Fisicamente possono essere considerati come degli “switch”; per conoscere il loro

stato attuale, si utilizza la macro TOUCH_X, la quale assume il valore 1 quando il

sensore rileva un contatto (pulsante premuto), mentre ha valore 0 quando non vi è

contatto. Per tali sensori è prevista la sola modalità passiva.

3.2.3. Display LCD

Il display di cui è munito l’RCX dispone di cinque cifre a 8 segmenti (uno è per il

punto) e di un elevato numero di simboli, così come schematizzato nella figura

seguente:

Il display viene controllato dalle funzioni definite nelle librerie conio.h e dlcd.h ed è

gestito per mezzo di interrupts temporizzati.

La funzione lcd_refresh_next_byte viene chiamata ogni 6ms (vedi [8]); poiché i dati

da visualizzare sono rappresentati da 9 bytes, l’aggiornamento completo si realizza ogni

54 ms (corrispondente a 18-19 operazioni di refresh al secondo). Questi dati sono

Page 42: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

42

contenuti in due array: il primo, display_memory, contiene ciò che deve essere

visualizzato; il secondo, lcd_shadow, contiene ciò è appena stato visualizzato.

L’array lcd_shadow è impiegato per controllare se è necessario eseguire il refresh;

tale operazione viene eseguita solo sui bytes modificati, individuati dalla differenza tra

il contenuto di display_memory e quello di lcd_shadow.

Un programma utente può forzare l’aggiornamento del display utilizzando la

funzione lcd_refresh, la quale visualizza tutti i 9 bytes contenuti in display_memory.

Per un elenco completo delle funzioni di gestione del display consultare [7].

3.2.4. Pulsanti

I pulsanti disponibili sull’RCX sono quattro: “on/off”, “run”, “view” e “prgm”. Il

modulo del sistema operativo incaricato della loro gestione è dkey_handler; l’insieme

delle funzioni che ne fanno parte sono raccolte nelle librerie dkey.h e dbutton.h.

I pulsanti sono gestiti con una tecnica antirimbalzo; ciò significa che, a seguito di una

pressione, lo stato del bottone verrà testato di nuovo solo dopo che sarà trascorso un

certo lasso di tempo. In questo modo, si evita di leggere una singola pressione più volte.

Il tempo di attesa fra una lettura di stato e la successiva è impostato, di default, a 100ms.

A ciascuno dei quattro pulsanti è associato un bit che ne identifica lo stato

(premuto/non premuto); i valori dei quattro bit così ottenuti sono invertiti ed utilizzati

per creare una maschera. La variabile dkey_multi memorizza l'ultima maschera di bit

utilizzata e la variabile dkey mantiene l'attuale maschera.

Se dkey_multi e dkey hanno lo stesso valore (non sono stati premuti pulsanti), allora

dkey non viene aggiornata. Altrimenti, si rilevano le differenze tra le due al fine di

identificare quali bottoni sono stati premuti o rilasciati. In seguito, entrambe le variabili

vengono aggiornate con il valore dell’attuale maschera di bit ed il tempo di attesa viene

riportato a 100ms.

L’ interfaccia utente per la gestione dei pulsanti è rappresentata principalmente dalla

funzione getchar, la quale attende finché viene premuto un pulsante e ritorna

l’identificativo del pulsante premuto: KEY_ONOFF, KEY_RUN, KEY_VIEW,

KEY_PRGM o KEY_ANY.

Page 43: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 3 - Strumenti di lavoro

43

3.3. Osservazioni

Rispetto al firmware fornito dal produttore, BrickOS espande notevolmente le

potenzialità dell’RCX, rendendolo un potente strumento didattico a livello accademico.

Per capire la differenza, basti pensare che il software originale di Lego Mindstorms

pone un limite al numero massimo di variabili utilizzabili (non più di 16!), mentre

BrickOS limita le applicazioni utente solo in relazione allo spazio di memoria

disponibile (32KB). In estrema sintesi, si può affermare che BrickOS offre un approccio

profondamente innovativo all’RCX; purtroppo, ciò va a discapito della semplicità di

utilizzo, in quanto si richiede all’utente la conoscenza del linguaggio di

programmazione C/C++ e la familiarità con strumenti teorici informatici non del tutto

banali: programmazione concorrente, sincronizzazione fra processi, accesso in mutua

esclusione a risorse condivise e concetti fondamentali che stanno alla base di un sistema

operativo. La sola operazione di “messa in opera” di BrickOS costituisce una notevole

barriera d’ingresso. Essa, infatti, avviene tramite una procedura piuttosto lunga che

prevede alcune competenze specifiche (ad esempio: personalizzazione e adattamento

delle procedure di compilazione). Inoltre, un utente Windows può accedere a BrickOS

solo tramite un emulatore dell’ambiente Linux (Cygwin).

Si ricorda, infine, che BrickOS è un prodotto software a livello “artigianale” (con

riferimento al significato che l’ingegneria del software attribuisce a tale definizione),

cioè un applicativo realizzato e mantenuto da persone che ne sono anche i primi

utilizzatori e che per tanto, plasmano il software per rispondere alle proprie esigenze.

La combinazione di BrickOS e RCX consente di realizzare, in modo relativamente

semplice, dei modelli utili per affrontare problemi e tematiche interdisciplinari che

spaziano dall’automazione all’informatica pura.

BrickOS, come già detto, è un prodotto open-source, che trova nell’ambiente

accademico la principale fonte di evoluzione ed applicazione. Le aree che

maggiormente costituiscono oggetto di ricerca sono lo sviluppo del protocollo di rete

(LNP) e la realizzazione di nuove funzionalità del sistema operativo, oltre che la

manutenzione di quelle già esistenti.

In questo contesto, il progetto trattato in questa tesi si prefigge di portare

nell’ambiente BrickOS un nuovo argomento: il controllo modulante.

Page 44: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

44

Capitolo 4

Analisi e specifica dei requisiti

Page 45: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

45

In questo capitolo si discuteranno i contenuti della prima fase di sviluppo: analisi e

specifica dei requisiti.

1. INTRODUZIONE

Il software viene sviluppato da un suo processo produttivo, definito ciclo di vita del

software, la cui struttura può avere una forte influenza sulla qualità del prodotto finale.

L’obiettivo ultimo è quello di trovare una soluzione di compromesso che sviluppi il

“miglior prodotto” non valutato in termini astratti e assoluti, ma in relazione alle risorse

e nel rispetto dei vincoli prestabiliti.

Nel corso della trattazione, spesso, si giustificherà la scelta di una soluzione

(progettuale o implementativa) a partire da un ventaglio di possibili alternative, alla luce

delle caratteristiche qualitative che si vogliono conferire al software. Si ritiene, pertanto,

opportuno distinguere i fattori di qualità in due categorie:

- Qualità esterne: percepibili da un osservatore esterno che esamina il prodotto

come se fosse una “scatola nera”; costituiscono l’interesse primario del

progettista. Affidabilità, correttezza, robustezza e sicurezza spiccano certamente

per importanza, soprattutto nel campo delle applicazioni di controllo industriale.

- Qualità interne: possono essere osservate solo esaminando la struttura interna del

prodotto, come se questo fosse una scatola trasparente. Tale prospettiva, pone in

primo piano caratteristiche quali verificabilità, manutenibilità, riusabilità e

comprensibilità.

Usando la terminologia tipica del software, si può affermare che le qualità interne

implementano (nel senso che sono un modo per realizzare) le qualità esterne. Entrambe

costituiscono sia una linea guida nella definizione degli obiettivi di qualità, sia uno

strumento di valutazione del prodotto sviluppato.

2. UN MODELLO PER IL PROCESSO DI SVILUPPO

La scelta di un modello su cui plasmare la soluzione ad un problema è, senza ombra

Page 46: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

46

di dubbio, una delle fasi più critiche dell’intera attività progettuale. Non è possibile

affermare che un modello sia meglio di un altro in termini assoluti, ma la valutazione

dipende da caso a caso ed, in particolare, da un attento esame dei rischi che le diverse

alternative presentano.

Se il rischio fondamentale è dato dall’affidabilità dell’applicazione, mentre i requisiti

sono estremamente stabili e ben noti, allora il modello più ragionevole è il classico

modello a cascata, con rigorosi controlli per il passaggio da una fase all’altra. Se,

invece, i rischi primari stanno nell’instabilità e nell’incertezza dei requisiti, allora è bene

pianificare un processo iterativo basato su un modello a spirale. L’applicazione oggetto

di questo elaborato si pone a livello intermedio rispetto a questi due poli, in quanto

richiede elevati livelli di affidabilità, ma presenta anche forti connotazioni evolutive.

Questo giustifica la scelta progettuale di utilizzare il modello a spirale come meta-

modello per il quello a cascata; in altre parole: l’intero processo di sviluppo

dell’applicazione (basato sul modello a spirale) viene suddiviso in una serie di sotto-

processi (conformati al modello a cascata), ciascuno dei quali determina un’evoluzione

dell’applicazione stessa.

Prima di affrontare in modo specifico le varie fasi di progetto, si discutono

brevemente le peculiarità dei due modelli sopraccitati.

2.1. Modello a Spirale

Tale modello, come dice direttamente il nome ed evidenzia chiaramente la figura, è

essenzialmente di tipo ciclico; ogni ciclo è composto da quattro passi logici:

Fase I Fase II

Fase III Fase IV

Page 47: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

47

- Fase I: determinazione di obiettivi, alternative e vincoli;

- Fase II: valutazione delle alternative; identificazione e risoluzione dei rischi;

- Fase III: sviluppo e verifica del prossimo livello del prodotto;

- Fase IV: pianificazione della fase successiva.

Il raggio della spirale rappresenta il costo accumulato durante lo svolgimento del

progetto; il ciclo si ripete sino ad esaurimento delle risorse a disposizione.

Per ulteriori informazioni vedi [5].

2.2. Modello a Cascata

Prevede che l’attività di sviluppo passi attraverso una serie di fasi poste in cascata, in

cui ciascuna di esse riceve ingressi dalla fase precedente e produce uscite (semilavorati)

che saranno, a loro volta, ingressi per quella successiva. Non sono previsti ritorni a fasi

già svolte (ricicli); essi sono addirittura visti come fattori di disturbo in quanto rendono

il processo difficilmente controllabile e gestibile.

In realtà il processo è costituito da un flusso continuo e la scomposizione in fasi è

semplicemente un’astrazione di comodo: le fasi sono importanti al fine di concentrare

l’attenzione, di volta in volta, su certe problematiche piuttosto che su altre; inoltre, in

questo modo è possibile controllare la progressione dello svolgimento del progetto.

Sulla base delle considerazioni precedenti, il processo di sviluppo risulta costituito

dalle seguenti fasi:

- Studio di Fattibilità: viene fatta una valutazione preliminare dei costi e dei

benefici dell’applicazione, con l’obiettivo primario di stabilire, per il progetto in

questione, quali siano le possibili alternative, le scelte più ragionevoli e le risorse

necessarie per l’attuazione del progetto. Tutto ciò sfocia nella definizione

preliminare del problema, delle possibili strategie risolutive nonché dei costi,

tempi e modalità di sviluppo ad esse relativi. In questa fase potrebbe risultare

molto utile valutare i punti di forza e di debolezza di eventuali prodotti simili già

esistenti.

- Analisi e Specifica dei Requisiti: viene svolta un’analisi completa dei problemi

dell’utente e della sua realtà applicativa al fine di poter specificare le

caratteristiche di qualità che il prodotto dovrà soddisfare. E’ importante, in questa

Page 48: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

48

fase, concentrarsi solo sulle funzionalità da offrire e non su aspetti

implementativi; in questo modo si evita di confondere i due livelli di astrazione:

quello esterno, di interesse dell’utente e quello interno di interesse del progettista.

E’ possibile utilizzare linguaggi quali l’UML per la stesura dei semilavorati in

uscita da questa fase.

- Progettazione: si definisce come i requisiti specificati possano essere raggiunti

attraverso un’opportuna architettura software (scomposizione in moduli e loro

funzionalità, relazione fra i vari moduli,…). Si può affermare che tale fase

costituisce una formalizzazione degli obiettivi del codice.

- Programmazione e Test di Unità: i diversi moduli vengono realizzati con il

linguaggio di programmazione scelto e sottoposti a test per verificare la loro

correttezza ed adeguatezza rispetto alle specifiche di progetto. Con l’avvento di

linguaggi di programmazione di livello sempre più alto, la distinzione fra

progettazione e programmazione diventa sempre più sfumata, in quanto entrambe

vengono realizzate con il medesimo strumento; concettualmente, però,

rimangono sempre distinte in quanto la prima ha lo scopo di identificare i

“mattoni logici” (visti come black-box di cui sono invisibili i dettagli) che

vengono aggregati per formare il sistema complessivo, mentre la seconda

definisce la struttura interna di tali “mattoni”.

- Integrazione e Test di Sistema: ha lo scopo di integrare i diversi moduli che sono

realizzati e testati al fine di produrre il sistema completo e collaudato.

- Manutenzione: affinché un software possa facilmente evolvere è necessario che si

possa modificare in modo semplice e affidabile. Il processo a cascata è

intrinsecamente ostile ad una gestione ordinata e pianificata della manutenzione

in quanto non prevede i ritorni; l’esperienza insegna che tali ritorni esistono e

l’impreparazione a gestirli viene pagata duramente.

Il modello a cascata è trattato approfonditamente in [5].

3. ANALISI E SPECIFICA DEI REQUISITI

Questa fase è sicuramente la più critica in quanto il successo del processo di sviluppo

Page 49: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

49

dipende, in ultima analisi, dalla misura in cui sono state colte le reali esigenze

dell’utente finale. L’attività è di tipo esplorativo: la realtà analizzata viene

progressivamente compresa e pertanto il livello di precisione e di dettaglio cresce in

maniera incrementale. L’obiettivo è quello di definire le caratteristiche di qualità del

prodotto e, in particolare, le proprietà funzionali.

Non esiste un unico strumento (linguaggio di specifica) per la descrizione analitica

dei requisiti che vada bene sempre e comunque: si tratta di scegliere in base al tipo di

applicazione che si deve sviluppare. Le applicazioni di controllo (regolazioni di

processo) elaborano insiemi di dati semplici (come, ad esempio, valori reali provenienti

dai sensori) applicando ad essi procedure di elevata complessità. Tale complessità

risiede nel modo in cui il controllo fluisce tra le diverse attività che si sincronizzano e

cooperano all’interno del sistema. Nel seguito, si utilizzerà il linguaggio naturale come

strumento espositivo di base, ricorrendo ad opportuni formalismi sono nel caso in cui

esso tenda ad essere impreciso, ambiguo o ridondante.

3.1. Realizzazione di un PID digitale

Il progetto consiste, essenzialmente, nel costruire ex-novo un PID digitale che possa

essere impiegato in situazioni di interesse pratico. Questa prospettiva pone in primo

piano la necessità di progettare un software che metta a disposizione le principali

funzioni di un regolatore industriale a microprocessore, ovvero:

- funzioni di controllo

- interfaccia verso il processo

- interfaccia operatore

L’applicativo deve rispettare vincoli e limiti imposti dall’hardware (RCX) su cui

deve essere eseguito; una volta scaricato sul dispositivo fisico, inoltre, deve poter

evolvere in completa autonomia, senza alcun supporto esterno (comunicazioni con PC,

etc…).

Nel caso si debba gestire una logica di controllo che prevede l’utilizzo di più PID

opportunamente interconnessi (controllo in cascata), la struttura del sistema può essere

definita solo staticamente; questo comporta che, una volta avvenuto il download

dell’applicazione sull’RCX, non è più possibile modificare le connessioni logiche fra i

Page 50: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

50

PID. E’, però, possibile apportare modifiche ai parametri caratteristici di ciascun

regolatore.

3.1.1. Funzioni di controllo

Il software deve garantire un controllo efficace del processo in esame ed operare in

modo tale che la variabile controllata segua con prontezza e precisione il riferimento

imposto dall’operatore, compatibilmente con la dinamica e con le caratteristiche del

processo stesso. E’ richiesta l’implementazione di una serie di funzionalità ausiliarie,

quali:

- anti-windup;

- logiche di blocco;

- commutazioni automatico/manuale (e manuale/automatico) bumpless;

Infine, è necessario garantire che la frequenza di campionamento determinata in fase

di sintesi del regolatore sia sempre rispettata durante l’esecuzione dell’applicazione, a

patto che essa si mantenga all’interno di un range di valori ammissibili (da determinare

effettuando adeguate “prove di carico”).

3.1.2. Interfaccia verso il processo

Il sistema deve essere in grado di interagire con il mondo esterno per mezzo delle

porte di ingresso e uscita messe a disposizione dall’RCX.

3.1.2.1. Input

Il software deve fornire opportune funzionalità per l’acquisizione e l’elaborazione

delle informazioni provenienti dai sensori, agendo in maniera differente a seconda del

tipo di sensore e della modalità in cui esso opera (attiva/passiva). Si deve valutare la

possibilità di utilizzare un motore come dinamo tachimetrica per effettuare letture di

velocità.

3.1.2.2. Output

Le uscite del microcontrollore possono essere pilotate unicamente con un segnale di

tipo PWM; da questo punto di vista, l’unico requisito, peraltro insito in BrickOS,

riguarda la possibilità di gestire la potenza in uscita in un range 0-255 (dove 0

Page 51: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

51

rappresenta la potenza minima, mentre 255 quella massima).

3.1.3. Interfaccia operatore

Il compito dell’interfaccia operatore è, fondamentalmente, quello di permettere

all’utente del sistema di controllo di impostare e/o visualizzare il valore dei parametri

che caratterizzano il regolatore digitale; dal punto di vista hardware, questa interazione

si realizza per mezzo di un semplice display e di un insieme minimo di pulsanti.

3.1.3.1. Display

Il display montato sul microcontrollore è in grado di visualizzare un massimo di

cinque cifre più il punto decimale. La modifica dei parametri numerici si effettua

agendo su ogni singola cifra che compone il valore stesso e modificando

opportunamente la posizione del punto decimale.

Non è possibile gestire, allo stato attuale, valori interi o frazionari costituiti da più di

cinque cifre.

3.1.3.2. Pulsanti fisici e pulsanti logici

L’RCX è equipaggiato di quattro pulsanti fisici, ma solo due di essi (ovvero View e

Program) possono essere utilizzati nelle applicazioni. Pertanto, si introduce il concetto

di “pulsante logico”, inteso come pulsante simulato per mezzo di opportune sequenze

temporizzate delle pressioni dei tasti fisici. A partire dai due pulsanti fisici (da questo

punto in poi identificati con KEY_1 e KEY_2), è possibile realizzare cinque pulsanti

logici, corrispondenti ad altrettanti eventi, definiti nel modo seguente:

- KEY_1 premuto e rilasciato (nel seguito identificato con KEY_1_short);

- KEY_1 premuto a lungo (nel seguito identificato con KEY_1_long);

- KEY_2 premuto e rilasciato (nel seguito identificato con KEY_2_short);

- KEY_2 premuto a lungo (nel seguito identificato con KEY_2_long);

- Pressione combinata di KEY_1 e KEY_2 (nel seguito identificato con KEY_1_2).

Una pressione “lunga” è caratterizzata da una durata almeno pari a 2 secondi.

3.1.3.3. Regole generali

Per aumentare la comprensibilità e la chiarezza delle specifiche, è utile presentare

Page 52: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

52

alcune regole di validità generale.

Funzionalità dei tasti logici

- KEY_1_short assume, a seconda del contesto in cui viene impiegato, due

possibili funzioni:

! funzione di scrolling, ovvero di selezione ciclica degli elementi appartenenti

ad un insieme finito e ben determinato (ad esempio: scorrimento di menù,

etc…);

! funzione di incremento del valore di un parametro incrementale o di una

singola cifra.

- KEY_2_short assume, tendenzialmente, la funzione di annullamento delle

modifiche relative ad un singolo parametro oppure alla totalità dei parametri di

un regolatore;

- KEY_2_long ha un comportamento analogo a KEY_2_short ma, anziché

annullare, permette di confermare le modifiche apportate.

- KEY_1_2 assume la sola funzione di decremento del valore di un parametro

incrementale.

Criteri di conferma delle modifiche

Quando l’utente accede alla modalità di modifica del valore di un qualsiasi

parametro, prima di poter effettuare altre operazioni deve necessariamente confermare

(o annullare) le variazioni apportate a quel parametro (si parla di “conferma di primo

livello”); solo in questo modo può uscire dalla modalità di modifica.

Le variabili che si riferiscono all’anello di controllo richiedono solo la conferma di

primo livello, nel senso che essa è sufficiente affinché le modifiche possano diventare

attive.

Le variabili che caratterizzano il singolo regolatore, invece, richiedono un ulteriore

livello di conferma (si parla di “conferma di secondo livello”); esiste un’apposita voce

di menù che permette di abilitare in modo definitivo tutte le modifiche apportate e che

viene visualizzata solo nel caso in cui uno o più parametri abbiano subito modifiche. Da

ciò si evince che la conferma di secondo livello è un’operazione atomica che coinvolge

contemporaneamente tutti i parametri del regolatore scelto.

Page 53: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

53

Alla luce delle considerazioni appena fatte, si passa a definire il comportamento

desiderato dell’interfaccia operatore.

3.1.3.4. Menù PID

Nel caso in cui la logica di controllo, definita staticamente, preveda l’utilizzo di più

PID, l’utente deve disporre di un menù attraverso il quale selezionare un qualsiasi

regolatore del sistema per modificare e/o visualizzare i parametri ad esso relativi. Tale

menù viene nascosto se la struttura di controllo è costituita da un unico anello di

regolazione.

Eventi

Quando il menù è attivo:

- KEY_1_short determina uno scorrimento verso il basso del menù; quando si

raggiunge l’ultimo PID della lista, si riparte dall’inizio. I nomi dei regolatori

rispettano il seguente formato: PID X (con ,...1,0=X ); il regolatore identificato

con “PID 0” è quello più interno del sistema.

- KEY_2_short permette di entrare nel menù di visualizzazione/modifica dei

parametri per il PID attualmente selezionato.

3.1.3.5. Menù parametri

Relativamente a ciascun regolatore, devono essere visualizzabili (ma non sempre

modificabili) i seguenti parametri:

Parametro Modificabile Guadagno (Kp) sempre

Tempo integrale (TI) sempre

Tempo derivativo (TD) sempre

Rapporto tra TD e la costante del derivatore reale (N) sempre

Peso sul segnale di riferimento nell’azione proporzionale (b) sempre

Peso sul segnale di riferimento nell’azione derivativa (c) sempre

Valore massimo del controllo (CSmax) sempre

Valore minimo del controllo (CSmin) sempre

Passo di incremento della variabile di controllo (deltaCSman) sempre

Para

met

ri de

l PID

Tempo di campionamento (TS) sempre

Page 54: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

54

Segnale di riferimento (SP) sempre

Variabile controllata (PV) mai

Variabile di controllo (CS) solo in modalità

MANUALE Para

met

ri de

ll’an

ello

Modalità di funzionamento (AUTO/MAN) sempre

Eventi:

- KEY_1_short, come nel caso precedente, determina uno scorrimento ciclico delle

voci di menù; per ciascuna di esse la visualizzazione viene gestita in due tempi:

prima viene mostrato il nome associato alla voce e, dopo pochi secondi, il suo

valore.

- KEY_2_short permette di modificare il valore del parametro corrente, sempre se

tale operazione è consentita in riferimento allo stato del PID; ad esempio, la

variabile di controllo può essere modificata solo quando il regolatore funziona in

modalità manuale.

3.1.3.6. Modifica parametri PID

E’ possibile distinguere i parametri caratterizzanti ciascun PID in:

- Valori numerici: possono assumere infiniti valori appartenenti all’insieme dei

numeri reali (nell’accezione matematica del termine); è possibile modificarli

impostando direttamente il nuovo valore (agendo sulle singole cifre che li

compongono);

- Valori incrementali: sono valori numerici ai quali è possibile apportare modifiche

solo attraverso una sequenza di incrementi o decrementi di passo prestabilito; non

consentono una modifica diretta.

- Valori lessicali: possono assumere un numero finito di valori, definiti a priori dal

progettista.

La modifica di un parametro avviene secondo modalità differenti, in funzione del

tipo di valore che si sta considerando.

Valore Numerico

Quando l’utente entra nel contesto di modifica di una voce numerica, la prima delle

cinque cifre (a partire dalla sinistra del display) che la compongono inizia a

Page 55: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

55

lampeggiare, indicando che è possibile modificarne il valore; a questo punto

KEY_1_short permette di impostare il valore (compreso fra 0 e 9) da applicare alla cifra,

mentre KEY_2_short permette di selezionare la cifra successiva.

Nella situazione in cui stia lampeggiando la quinta cifra, KEY_2_short determina il

lampeggiamento del punto decimale; in questo contesto, KEY_1_short permette di

posizionarlo correttamente.

Nella situazione in cui stia lampeggiando il punto decimale, KEY_2_short determina

il lampeggiamento di tutte le cifre e del punto decimale.

In questo contesto:

- KEY_2_short permette di annullare le eventuali modifiche apportate al valore

numerico;

- KEY_2_long permette, invece, di confermare le modifiche.

In entrambi i casi si ritorna al menù dei parametri; solo nel secondo caso viene attivato,

nella parte alta del display, un simbolo che segnala la presenza di modifiche per le quali

l’utente non ha ancora espresso la conferma definitiva.

Possibili esempi di voci numeriche sono dati da parametri quali guadagno, tempo

integrale, tempo derivativo, etc…

Valore Incrementale

La procedura di modifica è molto simile a quella prevista nel caso di valore

numerico; la differenza sostanziale è determinata dal fatto che non si può impostare

direttamente il valore di ciascuna cifra e la posizione del punto decimale, ma esse

diventano conseguenza della serie di incrementi o decrementi applicati. L’applicazione

prevede due soli valori di questo tipo: set-point incrementale e variabile di controllo (nel

caso in cui sia modificabile); il primo prevede un incremento unitario, mentre il passo di

incremento del secondo può essere impostato dall’utente (parametro deltaCS del

regolatore).

In questo ambito:

- KEY_1_short determina un incremento;

- KEY_1_2 determina un decremento;

- KEY_2_short annulla la modifica;

- KEY_2_long conferma la modifica.

Page 56: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

56

Valore Lessicale

Una volta espressa, da parte dell’utente, la volontà di modificare una voce lessicale, è

possibile procedere nel seguente modo:

- KEY_1_short permette di visualizzare in modo sequenziale la lista dei valori

ammissibili fra i quali scegliere il nuovo valore da applicare;

- KEY_2_short determina un annullamento, mentre KEY_2_long determina una

conferma della modifica appena apportata.

Un esempio di voce lessicale è dato dalla modalità di funzionamento, la quale può

assumere solamente due valori: automatico o manuale (in futuro sarà resa disponibile

una terza voce, tuning, riferita alla possibilità di effettuare un’autotaratura del

regolatore)

3.1.3.7. Gestione variabile di controllo

Se il regolatore corrente evolve in modalità automatica, deve essere inibita la

possibilità di modificare direttamente la variabile di controllo; l’unica operazione

consentita è la visualizzazione del valore.

Se il regolatore è posto in modalità manuale, il sistema consente di modificare il

valore della variabile di controllo operando in base alla procedura descritta nel caso di

valore incrementale; l’utente ha facoltà, in qualsiasi momento, di modificare il passo di

incremento (deltaCS).

3.1.3.8. Gestione del set-point

Il segnale di riferimento viene gestito sia come valore numerico che come valore

incrementale, cosicché sia possibile imporre direttamente nuovi valori o apportare

variazioni a scalino; per raggiungere questo obiettivo, si utilizzano due differenti voci di

menù (SP e SPi) che vanno ad agire, secondo modalità differenti, sulla medesima

variabile.

3.1.3.9. Conferma o annullamento delle modifiche

Come osservato in precedenza, le modifiche ai parametri che descrivono l’anello di

controllo, vengono applicate nell’istante stesso in cui l’utente dà la conferma di primo

livello.

Page 57: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 4 - Analisi e specifica dei requisiti

57

Per quanto riguarda i parametri descrittivi del singolo regolatore, invece, è necessario

un secondo livello di conferma; infatti, nel caso sia stato modificato almeno un

parametro, come ultimo elemento del menù viene visualizzata la voce di conferma, in

corrispondenza della quale:

- KEY_2_short: determina l’accesso alla funzione di conferma globale delle

modifiche. In questa situazione:

! KEY_2_short comporta l’annullamento di tutte le modifiche e l’eventuale

ritorno al menù PID;

! KEY_2_long comporta la conferma di tutte le modifiche e l’eventuale

ritorno al menù PID. Solo a fronte di questa seconda conferma, le modifiche

effettuate diventeranno operative a tutti gli effetti.

In entrambi i casi viene disattivato il simbolo che indica la presenza di

modifiche non ancora confermate.

- KEY_1_short: determina il ritorno alla prima voce del menù parametri per il

regolatore selezionato.

Nel caso in cui non sia stata apportata alcuna modifica ed il sistema sia composto da più

regolatori, in luogo della voce di conferma viene visualizzata la voce EXIT che consente

di tornare al menù PID. Sempre nel caso in cui non siano state apportate modifiche, ma

il sistema sia costituito da un singolo anello di controllo nessuna delle due voci

sopraccitate viene visualizzata.

Page 58: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

58

Capitolo 5

Progettazione

Page 59: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

59

In questo capitolo si affronta la seconda fase dell’attività di sviluppo: progettazione del sistema; si riportano le metodologie di lavoro applicate ed i risultati ottenuti.

1. INTRODUZIONE

Il capitolo si propone di descrivere la delicata fase di progettazione dell’applicativo,

non tanto come resoconto delle varie fasi in cui essa si articola, ma cercando

d’individuare le principali decisioni che si sono dovute affrontare e che maggiormente

caratterizzano il risultato finale. Seguendo la sequenza logica dell’attività progettuale, si

può notare come il livello di dettaglio dell’analisi aumenti man mano che si procede,

rivelando una logica di tipo top-down. Per ciascuna scelta operata, si cercherà di

riportare il ragionamento e le basi teoriche da cui è scaturita, sottolineando la necessità

di raggiungere un compromesso tra vari fattori quali: conoscenze degli autori, strumenti

a disposizione, necessità pratiche,… .

Infine, si vuole sottolineare che le descrizioni delle strutture dati riportate, non

vogliono anticipare alcun aspetto implementativo, ma, semplicemente, fornire

un’introduzione che aiuti a comprenderne la logica e l’utilità.

2. MODULARIZZAZIONE

Per modularizzazione si intende, in questa fase della realizzazione del progetto,

quell’attività che nasce dall’esigenza di scomporre un’entità complessa in varie

sottoparti al fine di poter circoscrivere le problematiche da affrontare in un ambito

ristretto, senza, però, perdere la visione d’insieme del progetto (vedi [3] e [5]).

L’obiettivo di questo strumento progettuale è l’identificazione di macroaree del

progetto, tra loro indipendenti, la cui unione deve portare alla costituzione del prodotto

finale. La suddivisione introdotta, però, non deve generare ulteriori vincoli oltre a quelli

già esistenti, né tantomeno deve essere fonte di complicazioni nelle fasi successive.

Per operare una buona modularizzazione è necessario procedere seguendo, in ordine,

le seguenti fasi:

Page 60: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

60

- Analisi del prodotto: è molto importante comprendere a fondo il tipo di prodotto

da realizzare ed in relazione a ciò valutare i requisiti e le specifiche richieste.

- Scelta del criterio di modularizzazione: è necessario porre particolare attenzione

alla scelta del criterio in base al quale operare la modularizzazione; tale scelta

deve essere operata sulla base delle valutazioni scaturite dalla fase precedente.

- Individuazione dei moduli: applicando il criterio scelto, si passa alla

scomposizione modulare del sistema.

Le dimensioni del progetto in questione sono tali da giustificare la scomposizione in

moduli al fine di implementare al meglio le caratteristiche funzionali e di ottenere una

più semplice ed ordinata gestione del processo di produzione (con riferimento al

significato che l’ingegneria del software attribuisce a questo termine).

2.1. Applicazione dei concetti di modularizzazione

In questo paragrafo, si ripercorrono le fasi d’implementazione della

modularizzazione contestualizzate nell’ambito del progetto da sviluppare.

Analisi del prodotto

A seguito di un’analisi operata sul tipo di prodotto da realizzare, si possono

individuare due principali aspetti caratterizzanti.

In primo luogo si tratta di produrre un regolatore PID, ovvero un software che

implementa un controllo modulante, la cui principale caratteristica sta nel fatto che deve

trattare delle strutture dati semplici, sulle quali eseguire un’elaborazione relativamente

complessa, anche se fortemente standardizzata. Inoltre, questo tipo di software deve

soddisfare precisi vincoli temporali e requisiti di robustezza

In secondo luogo il prodotto deve essere eseguito sull’RCX, quindi, ci si trova di

fronte alla necessità di dover realizzare un’applicazione “embedded”.

Una ulteriore valutazione, più approfondita, porta ad individuare nel prodotto due

macrofunzioni: il regolatore vero e proprio e l’interfaccia utente.

Scelta del criterio di modularizzazione

Alla luce di tutte le precedenti considerazioni, nel processo di sviluppo si è proceduto

considerando la modularizzazione da due differenti punti di vista: come strumento di

Page 61: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

61

organizzazione del progetto e come risposta alla necessità di produrre codice embedded.

Individuazione dei moduli

La visione prospettica così maturata ha portato a strutturare il sistema in tre moduli

distinti: esecuzione del PID, gestione degli eventi e visualizzazione dei dati.

Come è facile intuire, il modulo denominato “esecuzione del PID” racchiude in sé il

regolatore vero e proprio, ovvero il “nocciolo” dell’intero sistema; esso ricopre per

intero la macrofunzione relativa al controllo modulante.

L’altra macrofunzione (interfaccia utente) è ottenuta attraverso azioni coordinate sui

pulsanti e sul display; risulta, così, naturale individuare due moduli con distinte aree di

competenza sull’hardware. Il modulo denominato “gestione degli eventi” si occupa del

controllo dei pulsanti, attraverso i quali l’operatore può intervenire sui parametri e sulle

modalità di funzionamento del regolatore, mentre la presentazione di tali dati sul display

LCD avviene per mezzo delle funzionalità raccolte nell’area “visualizzazione dati”.

3. STRUTTURE DATI

La comunicazione tra i moduli individuati deve avvenire necessariamente attraverso

delle opportune strutture dati. Iniziando l’analisi dall’esecuzione del PID, si individua,

in questa macroarea, l’algoritmo del regolatore PID come il principale elemento

implementativo. Essendo questo fortemente standardizzato, è possibile stilare una lista

di parametri necessari alla taratura del regolatore, a cui si fa corrispondere la struttura

PIDPARAMS. La seguente tabella riporta i parametri principali che andranno a far

parte della struttura:

Parametro Tipo Descrizione

K Reale Guadagno (azione proporzionale)

TI Reale Tempo integrale

TD Reale Tempo Derivativo

N Reale Filtro sull’azione derivativa

Page 62: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

62

b Reale Peso sul set-point per l’azione proporzionale

c Reale Peso sul set-point per l’azione derivativa

Ts Reale Tempo di campionamento

CSmax Reale Limite superiore di saturazione della variabile di controllo

CSmin Reale Limite inferiore di saturazione della variabile di controllo

deltaCS Reale Passo d’incremento/decremento della variabile di controllo in

modalità manuale

L’informazione contenuta nella struttura precedente viene completata per mezzo di

una serie di variabili che descrivono il contesto di esecuzione del PID; esse vengono

raccolte nella struttura PIDLOOPDATA, di seguito tratteggiata:

Variabile Tipo Descrizione

SP Reale Valore del set-point

SPold Reale Valore del set-point al precedente passo di campionamento

PV Reale Valore del process value

PVold Reale Valore del process value al precedente passo di campionamento

CS Reale Valore del control signal (uscita del regolatore)

CSold Reale Valore precedente del control signal

Dold Reale Valore precedente dell’azione derivativa

MAN Booleano Indica la modalità di lavoro ( TRUE = manuale)

MANinc Booleano Se TRUE indica che CS è stata incrementata manualmente

MANdec Booleano Se TRUE indica che CS è stata decrementata manualmente

HIsat Booleano Se TRUE indica che è stato raggiunta la saturazione superiore

LOsat Booleano Se TRUE indica che è stato raggiunta la saturazione inferiore

Page 63: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

63

Noinc Booleano Se TRUE impedisce alla variabile CS di aumentare

Nodec Booleano Se TRUE impedisce alla variabile CS di diminuire

ForceMAN Booleano Se TRUE il PID viene forzato in modalità manuale

Per quanto riguarda l’interfaccia utente, si intende realizzarla in modo tale che

all’attivazione del sistema consenta all’operatore, nel caso sia presente più di un

regolatore, di selezionare un PID sul quale intervenire. Altrimenti, viene

automaticamente selezionato l’unico PID presente. In corrispondenza del regolatore

selezionato deve comparire il relativo menù, il quale è composto da una serie di voci a

cui si associano i parametri utili alla regolazione, le variabili del PID (Set-Point,

Control-Signal, Process-Value,…) e l’impostazione della modalità di lavoro (manuale /

automatico). Alcune voci possono essere modificate dall’operatore (ad esempio tutti i

parametri del regolatore), mentre altre possono solo essere lette (ad esempio il valore

della variabile Process-Value). Altre ancora, infine, possono essere modificate solo in

certe situazioni; questo è il caso della variabile Control-Signal, il cui valore può essere

modificato solo se il PID si trova in modalità manuale. Tranne nel caso

dell’impostazione del Set-Point e del Control-Signal (in modalità manuale), le

modifiche apportate non hanno effetto immediato sul controllo. Per renderle operative si

introduce alla fine del menu la voce “conferma”.

Per realizzare l’interfaccia utente, si individuano due strutture dati a due livelli logici

sovrapposti. A più basso livello, si pone la struttura denominata DISPLAY, la cui

funzione è quella di mappare in memoria il display fisico dell’RCX. Pertanto, in tale

struttura saranno presenti almeno i campi riportati nella seguente tabella:

Variabile Tipo Descrizione

Cifra_1 Carattere Prima cifra a sinistra del display

Cifra_2 Carattere Cifra del display

Cifra_3 Carattere Cifra del display

Cifra_4 Carattere Cifra del display

Page 64: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

64

Cifra_5 Carattere Ultima cifra a destra del display

Posizione punto Enumerazione Indica la posizione del punto decimale

Modifica Booleano Se TRUE si accende il simbolo di modifica

Nel livello logico superiore si pone la struttura che modellizza la voce di menù,

denominata VOCE_MENU.

Variabile Tipo Descrizione

Nome Stringa Etichetta del parametro da visualizzare

Valore Reale Valore numerico del parametro da visualizzare

Modificabile Booleano Se TRUE il parametro può essere modificato dall’utente

Con questa scelta è possibile costruire il menu di un PID come collezione delle

necessarie voci di menù.

3.1. Logica di funzionamento

Una volta introdotte le strutture dati, si vuole ora definire la logica con cui gestirle.

Le strutture relative ai dati del PID, oltre al loro impiego primario nell’algoritmo di

regolazione, sono utilizzate dall’interfaccia utente al fine di rendere disponibili i dati

all’operatore, sia per consultazioni che per impostazioni. Per quanto riguarda

PIDLOOPDATA, è necessario che sui dati in essa contenuti sia l’utente che il regolatore

abbiano un accesso diretto attraverso un’unica istanza. Per quanto riguarda

PIDPARAMS, tale soluzione, che può comportare dei rischi, non è necessaria. Pertanto,

per ragioni di sicurezza, di tale struttura si intende rendere disponibili due variabili:

PIDrun e PIDedit. La prima contiene i parametri utilizzati direttamente dal regolatore,

mentre la seconda viene utilizzata dall’interfaccia utente per le modifiche. Quest’ultime

avranno, dapprima, effetto solo sulla variabile PIDedit e, all’atto della conferma finale,

entreranno in elaborazione copiando i valori di PIDedit in PIDrun. In questo modo si

può garantire una maggiore sicurezza, consentendo all’operatore di eseguire delle

Page 65: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

65

modifiche e di poter, eventualmente, ritornare sui propri passi prima della conferma,

annullando le operazioni compiute.

4. ARCHITETTURA DELL’APPLICAZIONE

A questo punto dell’attività progettuale, si intende concretizzare le decisioni prese

nelle fasi precedenti sintetizzandole nella definizione dell’architettura del sistema.

Tenendo in considerazione le caratteristiche del supporto informatico a disposizione,

nella fattispecie BrickOS corredato dalle API per la programmazione in C/C++, si

giunge alla soluzione di organizzare l’applicativo come somma di più processi da

eseguire in pseudoparallelismo; sfruttando, quindi, il supporto fornito da BrickOS per il

multi-threading. Pertanto, si stabilisce di far corrispondere a ciascun modulo individuato

nella fase di modularizzazione un diverso processo di elaborazione indipendente.

Questa impostazione richiede necessariamente la definizione di appositi meccanismi

per la protezione dei dati. Di fronte agli inevitabili problemi di concorrenza che il multi-

threading introduce, si decide di sfruttare il supporto fornito dal sistema operativo. Così,

l’accesso in mutua esclusione alle strutture dati sarà garantito attraverso l’impiego di

semafori.

Si ritiene che questa soluzione possa contribuire ad implementare al meglio i

requisiti previsti, sia in termini di robustezza che di scalabilità. La struttura, così

progettata, presenta buone caratteristiche di flessibilità, mostrando pochi ostacoli ad

eventuali sviluppi futuri sia in termini di estensione delle funzionalità, che in termini di

riutilizzo dei singoli componenti, essendo essi fortemente indipendenti gli uni dagli

altri.

5. GESTIONE DEGLI EVENTI

Affinché la trattazione di questo argomento risulti il più possibile completa ed

esaustiva, si ritiene opportuno sintetizzare alcuni concetti e considerazioni

precedentemente sviluppati.

Page 66: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

66

La necessità di disporre di un’interfaccia operatore basata su criteri di usabilità ed

ergonomicità ha portato alla definizione dei pulsanti logici come astrazione dei due

pulsanti fisici effettivamente disponibili; da questo punto in poi, si farà riferimento solo

ed esclusivamente ai pulsanti logici, riferendosi ad essi semplicemente con il termine di

pulsanti (o bottoni).

L’applicazione deve permettere all’utente-operatore di visualizzare e modificare i

parametri di ciascuno dei PID che compongono il sistema di controllo. Le operazioni di

modifica avvengono secondo modalità differenti, in funzione del tipo di parametro. Da

questo punto di vista, è facile comprendere l’importanza del display come “strumento

guida” dell’interazione utente-controllore: in base allo stato del display, l’utente agisce

sui pulsanti resi disponibili dall’interfaccia e si aspetta che il sistema reagisca

esattamente nel modo previsto. Pertanto, è corretto sostenere che ad ogni evento

(pressione di un pulsante) l’interfaccia deve rispondere intraprendendo opportune azioni

(inclusa l’azione fittizia, corrispondente all’assenza di reazione).

Il sistema è in grado di rilevare cinque eventi, corrispondenti alla pressione dei

cinque tasti messi a disposizione dall’interfaccia operatore.

Queste prime osservazioni sono già sufficienti a giustificare la necessità di un

meccanismo che consenta di gestire gli eventi in modo flessibile e robusto. In altre

parole:

- nessun evento deve essere “perso”: il sistema deve garantire in ogni istante il

rilevamento fisico di tutti gli eventi.

- Un evento è considerato come un’entità “non durevole”: una volta consumata

non è possibile disporne nuovamente; per preservare la correttezza

dell’applicazione e la coerenza dei dati è necessario che ad un evento corrisponda

una ed una sola reazione.

- Il legame fra un evento e la corrispondente azione di risposta deve essere

dinamico, ovvero modificabile in base alle necessità. Infatti, uno stesso evento

rilevato in frangenti differenti può assumere significati profondamente differenti;

pertanto, le corrispondenti azioni di risposta dovranno essere conseguentemente

differenziate.

- Deve sempre essere possibile scegliere quali eventi rilevare. Infatti, può accadere

che, in un particolare frangente, un determinato evento non abbia alcun

Page 67: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

67

significato e, quindi, non debba comportare modifiche ai dati.

- In tutte le situazioni in cui un evento è di interesse per l’applicazione, è

necessario che ad esso sia associata un’azione (o un insieme di azioni) da

intraprendere in risposta all’evento stesso.

Questa serie di valutazioni costituisce una base informativa su cui impostare le

successive scelte progettuali.

5.1. Progettazione del gestore degli eventi

Il gestore degli eventi viene concepito come un blocco scomponibile in due entità

strettamente correlate ed interdipendenti:

- il rilevatore degli eventi;

- il registratore degli eventi.

Il concetto di base è semplice: si risponde ad un evento solo se si è dichiarato

esplicitamente di volerlo gestire.

Un meccanismo di questo tipo permette di raggiungere gli obiettivi di robustezza e

flessibilità di cui si è parlato in precedenza; inoltre, gode di una qualità molto

importante: la scalabilità. Nel seguito dell’esposizione risulteranno evidenti le ragioni di

tale affermazione.

5.1.1. Il rilevatore degli eventi

Sostanzialmente si tratta di un processo “demone”, ovvero sempre attivo, il cui

compito è quello di “mettersi in ascolto” di tutti gli eventi, indipendentemente dallo

stato del microcontrollore. Si può pensare ad esso come ad un elemento di confine tra il

mondo esterno e l’applicazione di controllo.

5.1.2. Il registratore degli eventi

In più occasioni, si è detto che:

- tutti gli eventi devono essere fisicamente rilevati;

- in un particolare frangente, non tutti gli eventi fisicamente rilevabili hanno

necessariamente un significato ai fini della corretta elaborazione dei dati.

Page 68: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

68

Pertanto, emerge la necessità di separare la fase di rilevamento da quella di reazione; il

registratore degli eventi assume proprio questa funzione.

Registrare un evento significa creare un legame fra esso e un’opportuna azione di

risposta costituita da una serie di operazioni da eseguire. Chiaramente, valgono le

seguenti regole:

- in ciascun istante temporale, ad un evento può essere associata una sola azione di

risposta;

- durante l’esecuzione dell’applicazione azioni differenti possono essere registrate

su uno stesso evento (ovviamente in istanti di tempo diversi);

- una stessa azione non può essere registrata contemporaneamente su due eventi

differenti.

Per preservare la coerenza e la correttezza dei dati, in alcune situazioni particolari (di

breve durata) sarà necessario disabilitare la risposta agli eventi, per fare in modo che il

sistema risulti insensibile a ciò che accade nel mondo esterno, salvo poi ripristinare gli

opportuni legami con le azioni di reazione. Ovviamente, tale servizio deve essere fornito

dal gestore degli eventi.

6. GESTIONE DEI CONTESTI

Anzitutto introduciamo il concetto di contesto, così come esso viene inteso nella

progettazione del software. Un contesto può essere definito come un legame univoco fra

uno stato del display e l’insieme degli eventi che per esso hanno significato; le azioni di

risposta associate a ciascun evento costituiscono parte integrante e caratterizzante del

contesto.

I contesti sono tra loro mutuamente esclusivi, nel senso che, ad ogni istante, di tempo

deve essere attivo uno ed un solo contesto (coerente con lo stato del display); inoltre,

l’applicazione di un contesto determina automaticamente la rimozione del contesto

precedente che, comunque, può essere nuovamente applicato in base alle future

necessità.

La combinazione data da gestione dinamica degli eventi e gestione dei contesti

permette di conferire al progetto dell’interfaccia operatore importanti proprietà di

Page 69: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

69

affidabilità, robustezza e, soprattutto, scalabilità.

6.1. Operare con i contesti

La creazione di un contesto può essere schematizzata in tre passi:

- Passo 1: anzitutto, è necessario stabilire quali eventi devono essere rilevati per

una corretta gestione del contesto (si ricorda che gli eventi fisicamente rilevabili

sono i cinque citati nella fase di analisi e specifica dei requisiti).

- Passo 2: per ciascuno degli eventi selezionati al passo precedente è necessario

definire un’opportuna azione di risposta, la quale può essere costituita da un

insieme di operazioni “elementari”; sostanzialmente ciascuna azione di risposta

verrà modellizzata come una funzione (intesa nel senso informatico del termine).

- Passo 3: si definisce una funzione che permetta di registrare, in modo atomico, le

azioni di risposta sui relativi eventi. A questo punto la struttura del singolo

contesto è completa.

Al momento opportuno sarà possibile applicare il contesto semplicemente richiamando

la funzione definita al passo 3.

6.2. Individuazione dei contesti

Rielaborando i requisiti dell’applicazione che sono stati presentati in precedenza, è

possibile individuare un primo insieme di contesti su cui basare l’attività di

implementazione. In questa fase non è possibile identificare tutti i contesti che

troveranno collocazione nella versione finale del software; alcuni di essi, infatti,

nasceranno da mere esigenze implementative e, pertanto, non sono prevedibili (né

giustificabili!) a livello di progetto.

Relativamente a ciascun contesto, viene di seguito riportata una breve descrizione

atta a qualificarlo, unita all’indicazione degli eventi per esso significativi (onde evitare

confusione, si precisa che per “selezione di un parametro” si intende l’operazione per

mezzo della quale l’utente vuole accedere alla modifica del parametro attualmente

visualizzato sul display. KEY_2_short è l’evento associato.)

Page 70: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

70

Nome Contesto Descrizione

Menù Selezione

PID

Attivazione

Viene applicato all’avvio del sistema ed ogni volta che si esce dal

menù parametri di uno dei regolatori.

Funzioni

Se la struttura di controllo si compone di più regolatori, è necessario

visualizzare e gestire il menù dei PID, offrendo funzionalità di:

- scorrimento del menù (→KEY_1_short);

- selezione del regolatore attualmente visualizzato sul display

(→KEY_2_long).

Nel caso in cui vi sia un solo regolatore, si applica automaticamente

il contesto di gestione del menù parametri PID.

Menù

Parametri PID

Attivazione

Viene applicato automaticamente all’avvio del sistema solo nel caso

di singolo regolatore. Inoltre, la sua attivazione è prevista quando:

- si seleziona un PID dal precedente menù, oppure

- si esce dal contesto di modifica di un generico parametro (sia

nel caso di conferma che di annullamento delle modifiche).

Funzioni

Per gestire correttamente il menù dei parametri è necessario disporre

di:

- scorrimento del menù (→KEY_1_short);

- selezione del parametro attualmente visualizzato sul display

(→KEY_2_short). A seconda del tipo di parametro e della

modalità di funzionamento del regolatore, la selezione di un

parametro determina l’applicazione di un particolare contesto

(modifica voce numerica, modifica voce incrementale,

modifica voce lessicale, visualizzazione variabile controllata).

Modifica

Valore

Lessicale

Attivazione

Applicabile solo a partire dal menù dei parametri, nel caso in cui il

parametro attualmente visualizzato (e selezionato dall’utente) sia una

Page 71: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

71

voce lessicale (ad esempio: modalità di funzionamento del

regolatore).

Funzioni

Una volta selezionata una voce lessicale deve essere possibile:

- far scorrere l’elenco dei possibili valori per quella voce

(→KEY_1_short);

- annullare l’eventuale modifica apportata (→KEY_2_short);

- confermare la modifica apportata (→KEY_2_long);

Negli ultimi due casi si torna al menù parametri del regolatore.

Modifica

Valore

Numerico

Attivazione

Applicabile solo a partire dal menù dei parametri, nel caso in cui il

parametro attualmente visualizzato (e selezionato dall’utente) sia una

voce numerica (ad esempio: guadagno, tempo integrale, tempo

derivativo).

Funzioni

Nel caso in cui l’utente decida di modificare una voce numerica

(seguendo la procedura già descritta) si vuole che:

- sia possibile selezionare (→KEY_2_short) singolarmente

ciascuna delle cinque cifre ed il punto decimale affinché sia

possibile modificarne (→KEY_1_short), rispettivamente, il

valore e la posizione;

- sia possibile annullare o confermare le modifiche apportate al

parametro.

Risulta evidente il fatto che le operazioni di annullamento o conferma

richiederanno un’ulteriore contesto affinché possano essere gestite in

modo efficace, ma ciò esula dalle competenze della progettazione per

ricadere nel dominio dell’implementazione; pertanto, si rimanda al

capitolo successivo la gestione di questo tipo di problematiche.

Modifica

Valore

Incrementale

Attivazione

Applicabile solo a partire dal menù dei parametri, nel caso in cui il

parametro attualmente visualizzato (e selezionato dall’utente) sia una

Page 72: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

72

voce incrementale (ad esempio: set-point incrementale).

Funzioni

Le uniche operazioni di modifica eseguibili su una voce incrementale

sono:

- incremento (→KEY_1_short) o decremento (→KEY_1_2) del

valore, in base al passo prestabilito;

- annullamento (→KEY_2_short) o conferma (→KEY_2_long)

delle modifiche.

Chiaramente, il passo di incremento/decremento è una caratteristica

del singolo parametro e, in genere, sarà diverso da caso a caso;

l’imposizione del passo corretto è, ancora una volta, un dettaglio

implementativo.

Evoluzione

Variabile

Controllata

Attivazione

Applicabile solo a partire dal menù dei parametri, solo quando il

parametro attualmente visualizzato e selezionato corrisponde alla

variabile controllata.

Funzioni

Si tratta di un contesto molto semplice giustificato dalla necessità di

visualizzare l’evoluzione temporale dell’uscita del processo da

controllare. L’unica funzione messa a disposizione è quella di uscita

dal contesto (→KEY_2_long).

Conferma o

Annullamento

Attivazione

Nel caso in cui siano state apportate modiche ai parametri del

regolatore selezionato, come ultimo elemento del menù dei parametri

viene visualizzata la voce di conferma; quando essa viene selezionata

dall’utente, si applica il presente contesto.

Funzioni

Permette di realizzare la “conferma di secondo livello” di cui si è già

parlato; da ciò si evince che le uniche funzioni disponibili sono la

conferma (→KEY_2_long) o l’annullamento (→KEY_2_short) di

tutte le modifiche apportate.

Page 73: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 5 - Progettazione

73

Di seguito viene riportato un diagramma che fornisce la versione progettuale della

struttura dei contesti (le frecce sono rappresentative degli eventi che determinano il

passaggio da un contesto all’altro):

MENU’ SELEZIONE PID

MENU’ PARAMETRI PID

MODIFICA VOCE NUMERICA

MODIFICA VOCE LESSICALE

MODIFICA VOCE INCREMENTALE

EVOLUZIONE VARIABILE

CONTROLLATA

CONFERMA O ANNULLAMENTO

Page 74: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

74

Capitolo 6

Implementazione

Page 75: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

75

In questo capitolo si discute l’implementazione, basata sul linguaggio C, delle specifiche progettuali.

1. INTRODUZIONE

Nella fase di programmazione i singoli moduli vengono realizzati nel linguaggio

scelto e, successivamente, sottoposti a test per verificare la loro adeguatezza rispetto alla

specifica di progetto. I moduli devono poi essere integrati, al fine di produrre il sistema

completo e collaudato.

In questo capitolo si discute l’intera attività implementativa, ponendo l’accento su

tutti quegli aspetti che caratterizzano e qualificano il progetto in esame. Dal punto di

vista dell’organizzazione del testo, si ripercorre lo schema adottato nella disamina della

fase progettuale. Tutti gli aspetti relativi alla sincronizzazione dei thread sono trattati

nella parte finale, in quanto richiedono una buona conoscenza del codice da parte del

lettore.

Il capitolo successivo affronterà, invece, tutte le problematiche relative al test di

unità, all’integrazione ed al test di sistema.

Prima di procedere, è necessario precisare quanto segue:

- quando si parlerà di “funzioni”, si farà riferimento all’accezione informatica del

termine, salvo diversa indicazione;

- i termini “task”, “thread” e “processo” sono considerati sinonimi.

2. ACCORGIMENTI IMPLEMENTATIVI

La fase d’implementazione è preceduta da un’analisi di carattere generale sul

software da realizzare; l’obiettivo di tale analisi è quello di individuare quali

problematiche possono affliggere il prodotto, al fine di impostare delle linee guida per

l’attività d’implementazione che garantiscano di porsi al riparo da tali difficoltà.

Di fronte alla necessità di realizzare codice embedded ci si scontra con una serie di

problematiche legate all’interazione con l’hardware attraverso il sistema operativo. Già

in fase di progettazione si sono ipotizzate difficoltà legate a questa caratteristica;

Page 76: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

76

pertanto, nella suddivisione in moduli del progetto (vedi Capitolo 2) si sono adottati

degli accorgimenti volti a semplificare la fase d’implementazione. A questo punto del

progetto, è necessario affrontare la questione definendo metodologie di lavoro e di

organizzazione del codice volte a minimizzare le fonti di errore e le perdite di tempo.

La soluzione più semplice, e presumibilmente la più ovvia, consiste nell’organizzare

il codice in due parti distinte:

- la parte detta “kernel”, completamente indipendente dall’RCX, che esegue una

pura elaborazione dei dati. Può essere considerata come una sorta di scatola nera

che mette ha disposizione degli ingressi e delle uscite per interagire con

l’ambiente esterno;

- la seconda parte realizza l’interazione tra il kernel e il mondo esterno attraverso

l’RCX. Si occupa di rilevare gli input (pressione dei bottoni, lettura dei sensori),

di comunicare gli output (scrittura uscite, visualizzazione dei dati sul display) e di

fornire le corrette temporizzazioni.

Questa soluzione offre una buona risposta al seguente problema di carattere pratico:

ciascun programma che va eseguito sull’RCX deve essere redatto e compilato su PC e,

in seguito, scaricato sul dispositivo. Tale procedura, oltre ad essere lenta, non consente

alcuna forma di “debugging”, rendendo, così, estremamente lenta e complessa l’attività

implementativa di un codice non banale.

Con la suddivisione sopra descritta è possibile procedere ad implementare e testare il

“kernel” interamente su PC, utilizzando tutti gli strumenti messi a disposizione dai

moderni ambienti di sviluppo. Inoltre, relegando tutte le operazioni di interazione con

l’hardware in un ambito circoscritto, consente di individuare più facilmente e

velocemente i problemi che sorgono, rendendo più efficiente e sicura l’attività di

sviluppo del codice.

Per applicare al meglio questa scelta, è necessario operare una corretta suddivisione

delle funzionalità, individuando per ciascuna di esse l’area di appartenenza: “kernel” o

parte di interazione con l’RCX. Pertanto, ciascuno dei tre moduli in cui si è suddiviso il

progetto risulta composto da una sezione d’interazione con l’RCX e da una totalmente

indipendente da esso, come di seguito riportato:

Page 77: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

77

Modulo Funzionalità del Kernel Funzionalità di

interazione

Esecuzione del PID Algoritmo PID

- Lettura ingessi

- Scrittura uscite

- Temporizzazione

Gestione degli eventi Gestione di contesti

- Rilevazione degli

eventi (pressioni

dei pulsanti)

Visualizzazione dei dati Organizzazione interna dei dati - Scrittura sul

display dell’RCX

3. ESECUZIONE DEL PID

L’esecuzione dell’algoritmo di regolazione è sicuramente l’attività principale che il

sistema è chiamato a svolgere; oltre all’algoritmo vero e proprio, questa attività

comprende una serie di funzioni e funzionalità di corredo, indispensabili sia ai fini della

messa in opera che del funzionamento del regolatore. Tra queste, a titolo d’esempio, si

cita il controllo del rispetto della frequenza di campionamento, la lettura degli ingressi e

la scrittura delle uscite.

Nel precedente capitolo è stata definita, in maniera generale, l’architettura dell’intera

applicazione; in particolare si è giunti alla conclusione di associare al modulo

“esecuzione del PID” un processo di elaborazione indipendente. A questo punto, è bene

entrare in maniera più approfondita nel merito di questa scelta. Di fronte alle necessità

d’implementare un sistema in grado di gestire più di un anello di regolazione e di

soddisfare specifici vincoli, legati all’esecuzione di un singolo algoritmo, si è giunti alla

soluzione di associare un thread a ciascun regolatore presente nel sistema. Ciò consente

una realizzazione modulare ed altamente scalabile del sistema, per mezzo della quale

sarà sufficiente lanciare in esecuzione tanti thread quanti sono gli anelli nel sistema,

avendo cura di operare le corrette interconnessioni fra ingressi e uscite dei regolatori e

di realizzare un corretto interfacciamento verso il processo.

Page 78: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

78

Nel seguito del paragrafo si affronteranno alcuni aspetti caratteristici

dell’implementazione dell’algoritmo di regolazione, per poi passare alla descrizione del

thread d’esecuzione, definendo anche alcune funzioni ausiliarie alla pura regolazione.

3.1. Contesto d’esecuzione del regolatore

Prima di procedere con la descrizione delle funzioni realizzate, è utile conoscere il

contesto di esecuzione del PID, il quale, in buona sostanza, è costituito dalle variabili

globali utilizzate dalla funzione di regolazione. Ad ogni regolatore presente nel sistema

sono associate:

− una variabile di tipo PIDLOOPDATA chiamata PIDloop;

− due variabili di tipo PIDPARAMS chiamate PIDa e PIDb, alle quali si accede solo

attraverso una coppia di puntatori: PIDrun e PIDedit.

Dovendo gestire più di un regolatore, tali variabili sono raggruppate in vettori la cui

dimensione è stabilita staticamente dalla costante NUMBER_OF_PIDs; pertanto, nel

sistema sono definiti i seguenti array:

PIDPARAMS PIDa[NUMBER_OF_PIDs], PIDb[NUMBER_OF_PIDs],

*PIDedit[NUMBER_OF_PIDs], *PIDrun[NUMBER_OF_PIDs];

PIDLOOPDATA PIDloop[NUMBER_OF_PIDs];

Più precisamente, durante l’esecuzione, il PID i-esimo utilizza solo la variabile

PIDloop[i] e il puntatore PIDrun[i]. L’altro puntatore che gli è associato (PIDedit[i])

viene utilizzato per consentire all’utente la modifica dei parametri. Le modifiche

apportate ai parametri, a seguito della conferma di primo livello (vedi Capitolo 5),

vengono registrate nella variabile puntata da PIDedit[i]. A questo punto, attraverso la

conferma di secondo livello, l’utente può decidere di renderle operative oppure di

annullarle. Nel caso di conferma, viene invocata la funzione switchPIDData, di seguito

descritta, mentre in caso di annullamento non si fa altro che copiare il contenuto della

variabile puntata da PIDrun[i] in quella puntata da PIDedit[i].

3.1.1.1. Cambio del contesto di esecuzione

La funzione switchPIDData(int indexPID) si occupa di cambiare il contesto

d’esecuzione del regolatore; ciò consiste semplicemente nello scambio reciproco di

Page 79: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

79

indirizzi fra PIDrun[indexPID] e PIDedit[indexPID].

Per prima cosa, la funzione disabilita gli eventi invocando la funzione

disableEvents(); il sistema, a questo punto, non risponde più alla pressione dei pulsanti.

Il passo successivo consiste nel verificare lo stato della variabile

PIDloop[indexPID].IamRunning:

− se TRUE, significa che il cambio di contesto non è abilitato, e, pertanto, la funzione

si pone in attesa dell’abilitazione;

− se FALSE, il cambio di contesto è abilitato e la funzione può procedere con lo

scambio degli indirizzi, tale operazione avviene attraverso un puntatore d’appoggio

(PIDPARAMS *buffer).

Infine, viene spento il simbolo di modifica sul display (display.change = FALSE) e

gli eventi vengono ripristinati (setContextPID()).

Nei paragrafi successivi viene trattata la gestione della sicurezza nel cambio di

contesto attraverso la descrizione del meccanismo che ne controlla l’abilitazione per

mezzo del variabile PIDloop[i].IAmRunning.

3.2. Algoritmo di regolazione

Questo algoritmo è già stato discusso approfonditamente nel Capitolo 2, nel quale,

tra l’altro, si fornisce un’implementazione in pseudo-codice. In questo paragrafo si

vogliono affrontare solo alcuni aspetti caratterizzanti, utili a contestualizzare la funzione

di regolazione con il resto del progetto.

L’algoritmo si compone essenzialmente di due parti: l’inizializzazione, eseguita una

sola volta all’avvio del regolatore, e il codice ricorsivo, eseguito ad ogni passo di

campionamento. Si è deciso d’implementare queste due parti attraverso funzioni

distinte: setUpPid, per quanto riguarda l’inizializzazione, e PID per quanto concerne il

codice ricorsivo.

3.2.1. Funzione di inizializzazione

La funzione setUpPID(), per prima cosa, inizializza tutti i puntatori necessari, il cui

numero dipende da quanti regolatori sono presenti nel sistema. Questa fase avviene

attraverso il seguente frammento di codice:

Page 80: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

80

for (i=0;i<NUMBER_OF_PIDs;i++)

PIDrun[i]=&PIDa[i];

PIDedit[i]=&PIDb[i];

Non ha alcuna importanza quale dei due puntatori è associato alla variabile PIDa[i] o

alla PIDb[i], i due, infatti, continueranno a scambiarsi la variabile puntata a seguito di

ogni conferma di secondo livello.

La fase successiva consiste nell’inizializzazione del contesto d’esecuzione: per

ciascun regolatore si assegnano i valori di partenza alle variabili PIDa[i], PIDb[i] e

PIDloop[i]. A titolo d’esempio, di seguito si riporta il frammento di codice in cui viene

inizializzato il contesto del regolatore individuato dall’indice 0:

PIDa[0].K = PIDb[0].K = 1.00;

PIDa[0].Ti = PIDb[0].Ti = 0.30;

PIDa[0].Td = PIDb[0].Td = 0.00;

PIDa[0].N = PIDb[0].N = 5.00;

PIDa[0].b = PIDb[0].b = 0.50;

PIDa[0].c = PIDb[0].c = 0.00;

PIDa[0].Ts = PIDb[0].Ts = 0.01;

PIDa[0].CSmax = PIDb[0].CSmax = 100.00;

PIDa[0].CSmin = PIDb[0].CSmin = 0.00;

PIDa[0].deltaCSMAN = PIDb[0].deltaCSMAN = 0.50;

PIDloop[0].SP = PIDloop[0].SPold = 0.00;

PIDloop[0].PV = PIDloop[0].PVold = 0.00;

PIDloop[0].CS = PIDloop[0].CSold = 0.00;

PIDloop[0].Dold = 0.00;

PIDloop[0].MAN = FALSE;

PIDloop[0].MANinc = FALSE;

PIDloop[0].MANdec = FALSE;

PIDloop[0].HIsat = FALSE;

PIDloop[0].LOsat = FALSE;

PIDloop[0].NoInc = FALSE;

PIDloop[0].NoDec = FALSE;

PIDloop[0].ForceMAN = FALSE;

PIDloop[0].IAmRunning = FALSE;

Page 81: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

81

Come si può vedere, per ovvi motivi di coerenza dei dati, le variabili PIDa e PIDb sono

inizializzate con gli stessi valori.

3.2.2. Funzione di regolazione

La funzione PID(PIDPARAMS* R, PIDLOOPDATA* L) implementa l’algoritmo di

regolazione vero e proprio, al quale sono aggiunte funzioni ausiliarie quali anti wind-up,

logiche di blocco e commutazioni A/M e M/A bumpless.

Per realizzare tale algoritmo, si definiscono le seguenti variabili locali di tipo REAL:

deltaSP, deltaPV, deltaP, deltaI, D, deltaD, deltaCS. Per quanto riguarda

l’implementazione, in questa fase non si è fatto altro che tradurre in linguaggio C

l’algoritmo in pseudo-codice presentato nel capitolo 2.

Anzitutto, la funzione rileva le variazioni del set-point e del process-value:

deltaSP = L->SP - L->SPold;

deltaPV = L->PV - L->PVold;

In seguito viene rilevata la modalità di lavoro (manuale o automatico), controllando

l’impostazione dell’operatore e l’eventuale forzatura in manuale attraverso la seguente

condizione:

!L->MAN && !L->ForceMAN

Se il sistema si trova in automatico, vengono calcolate deltaP, deltaI, D, deltaD e

deltaCS (per l’esplicitazione dei calcoli si rimanda al Capitolo 2). Dopo di che si passa

alla gestione delle logiche di blocco, la quale si riassume nella seguente riga di comando

che chiude il segmento di codice eseguito esclusivamente per il controllo in automatico:

if ((deltaCS>0 && L->NoInc) || (deltaCS<0 && L->NoDec)) deltaCS=0;

Se, invece, il regolatore lavora in modalità manuale, per prima cosa la funzione pone

a zero il valore delle variabili locali deltaCS e D, poi passa alla verifica dello stato dei

comandi locali d’incremento e di decremento, aggiornando di conseguenza deltaCS:

if(L->MANinc && !L->MANdec) //incremento

deltaCS = R->deltaCSMAN;

L->MANinc = FALSE;

if(L->MANdec && !L->MANinc) //decremento

Page 82: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

82

deltaCS = -R->deltaCSMAN;

L->MANdec = FALSE;

Questi due blocchi chiudono la sezione dedicata puramente al controllo in modalità

manuale.

Ora, indipendentemente dalla modalità di lavoro, la funzione calcola il nuovo valore

del controllo: L->CS = L->CSold+deltaCS e su tale valore applica l’azione di controllo

che impedisce il wind-up:

if(L->CS > R->CSmax)

L->CS=R->CSmax;

if(L->CS < R->CSmin)

L->CS=R->Csmin ;

La funzione conclude la sua attività aggiornando lo stato finale del regolatore:

L->CSold = L->CS;

L->SPold = L->SP;

L->PVold = L->PV;

L->Dold = D;

L->HIsat = (L->CS==R->CSmax);

L->LOsat = (L->CS==R->CSmin);

3.3. Thread d’esecuzione del PID

Nel thread executePID sono eseguite sequenzialmente tutte le attività necessarie alla

regolazione: lettura degli ingressi, esecuzione della funzione PID e scrittura delle uscite.

A fianco di queste tre operazioni fondamentali è realizzato un controllo, che consiste

nella verifica del passo di esecuzione, il cui fine è quello di far rispettare la frequenza di

campionamento. Inoltre, viene applicata una protezione ai parametri del controllo, che

inibisce il cambio di contesto durante l’esecuzione dell’algoritmo di regolazione; a tale

scopo, nella struttura dati PIDLOOPDATA è stato introdotto un campo di tipo booleano

denominato IAmRunning.

Si passa ora a descrivere l’implementazione del thread, nella quale, per semplicità, si

fa riferimento al primo regolatore PID della struttura, quello individuato dall’indice 0.

Dopo l’inizializzazione di alcune variabili locali, si entra nel ciclo che viene posto in

esecuzione parallela agli altri processi. In esso, per prima cosa, si inibisce il cambio

Page 83: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

83

PIDedit → PIDrun settando a TRUE la variabile PIDloop[0].IamRunning. Una volta

protetto il contesto di esecuzione, si rileva l’istante di inizio ciclo attraverso la seguente

riga di codice: time_cycle = sys_time; in essa l’istante di tempo attuale, fornito da

BrickOS attraverso la variabile sys_time, viene memorizzato nel time-marker

time_cycle.

Il passo successivo consiste nella lettura degli ingressi: il valore letto dal sensore, che

misura la variabile controllata, viene scritto nella variabile Process Value:

PIDloop[0].PV. La macro da utilizzare per accedere alla misura fornita dal sensore

dipende dal tipo di sensore utilizzato; per i dettagli implementativi che riguardano

questa fase si rimanda il lettore al paragrafo ‘Interfacciamento verso il processo’.

Una volta letti gli ingressi si esegue l’elaborazione, ciò avviene semplicemente

attraverso la chiamata alla funzione di regolazione: PID(PIDrun[0],&PIDloop[0]).

Al termine di questa procedura, il nuovo valore del controllo viene scritto sull’uscita.

Anche per quanto riguarda i dettagli implementativi della scrittura sulle uscite, si fa

riferimento al paragrafo ‘Interfacciamento verso il Processo’. In questa fase, si può solo

introdurre che il motore è l’unico dispositivo attuatore per ora disponibile; pertanto la

scrittura delle uscite deve avvenire obbligatoriamente attraverso la funzione offerta da

BrickOS: motor_x_speed(int speed).

Dopo che il valore in uscita è stato scritto (l’attuale ciclo di elaborazione è concluso),

si riporta il livello logico della variabile PIDloop[0].IamRunning a FALSE. In questo

modo si rende possibile un eventuale cambio di contesto, che ora può avvenire in

sicurezza, senza che sia fonte d’inconsistenza dei dati.

L’ultimo passo del ciclo è la temporizzazione del PID, in cui si verifica che il passo

di campionamento sia rispettato. La verifica avviene attraverso la seguente riga di

codice: wait_event(&checkSampleTime,time_cycle). Con questo comando il thread

executePID viene posto in attesa che il tempo di campionamento sia trascorso. Per far

questo si utilizza come funzione di risveglio checkSampleTime, la cui implementazione

è la seguente:

wakeup_t checkSampleTime(wakeup_t data)

return ((sys_time - data) >= PIDrun[0]->Ts*1000);

A questa funzione viene passato come parametro il time-marker time-cycle acquisito

Page 84: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

84

all’inizio del ciclo. Seguendo la tecnica già descritta, dalla differenza fra l’istante di

tempo attuale e quello d’inizio ciclo, si misura la durata del loop fino ad ora. Se il tempo

trascorso è inferiore al Sample-time (PIDrun[0]->Ts*1000), il thread viene sospeso

sino a che il passo di campionamento non sia terminato. Solo quando il tempo trascorso

è maggiore o uguale al periodo di campionamento, il thread viene risvegliato ed il ciclo

riprende dall’inizio. La figura seguente schematizza l’andamento temporale della

variabile IAmRunning:

PID 0

Ts 0

IAmRunning = TRUE

Ts 1

PID 1

PIDloop[0].IAmRunning

PIDloop[1].IAmRunning

Questo meccanismo di temporizzazione non fornisce alcuna protezione di fronte ad

un’elaborazione che impiega un tempo superiore al Sample-time. Sarà compito

dell’utente impostare correttamente la durata di Ts, avendo cura di scegliere un valore

che il sistema sia in grado di rispettare.

3.4. Interfacciamento verso il processo

Per controllare un processo è necessario poter agire, in modo coordinato, sulle

attività elementari che lo compongono, al fine di modularne le uscite e di garantire le

condizioni fisiche di svolgimento più opportune. Pertanto, per il controllo automatico di

un processo, oltre ad un’unità di elaborazione, che calcoli con continuità le condizioni

di controllo, sono necessari dei dispositivi di misura (sensori) che rilevino con

continuità le condizioni di funzionamento e dei dispositivi d’attuazione (attuatori) che

consentano alle azioni di controllo di agire fisicamente sul processo. E’ necessario,

inoltre, un sistema di comunicazione tra l’unità di controllo e i dispositivi di misura e

Page 85: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

85

attuazione. L’interfaccia verso il processo risulta quindi essere formata da due catene di

dispositivi fisici e componenti software: una che si occupa dell’acquisizione delle

misure e l’altra dell’attuazione dell’azione di controllo.

Con riferimento ad un’unità di elaborazione digitale, in linea di massima nella catena

di acquisizione si possono individuare in sequenza i seguenti elementi (vedi [2]):

sensore, condizionamento del segnale, convertitore analogico/digitale (DAC) e ingresso

dell’unità di calcolo. Di seguito è riportato lo schema a blocchi che descrive la catena

d’acquisizione.

La catena d’attuazione, seguendo la direzione che va dal controllore verso il

processo, è costituita in linea di principio dai seguenti elementi: convertitore analogico

digitale, uscite di controllo e attuatore. La figura di seguito schematizza la sequenza dei

dispositivi.

Per quanto riguarda il progetto argomento di questa tesi, si è stabilito di realizzare

come “banco di prova” un anello per il controllo della velocità di rotazione di un

motore. Di seguito si riporta la descrizione della realizzazione della catena d’uscita e di

quella d’ingresso nel progetto.

3.4.1. Output

La catena delle uscite prevede come organo attuatore il motore. Essendo

Sensore

Sensore

Sensore

Sensore

Con

dizi

onam

ento

Con

vers

ione

D

ati

Elaborazione

Co

nver

sion

e

Dat

i

ElaborazioneUscite dicontrollo

Attuatore

Attuatore

Attuatore

Page 86: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

86

quest’ultimo l’unico dispositivo di output messo a disposizione dal produttore, tutte le

connessioni fisiche risultano essere standardizzate e non è necessario alcun elemento di

condizionamento del segnale né, tantomeno, di conversione digitale/analogico. Pertanto,

la realizzazione fisica della catena degli output si è risolta nella connessione dell’uscita

‘A’ dell’RCX con un motore, attraverso l’apposito cavo fornito dal produttore. Per

quanto riguarda la gestione software della catena, BrickOS fornisce tutte le funzioni per

operare un controllo completo sui motori (vedi Capitolo 3), di seguito è riportata la

descrizione dell’implementazione nel thread executePID della scrittura delle uscite, che

in precedenza era stata omessa.

Nella sezione che inizializza il ciclo, viene impostata la direzione di rotazione e si

pone a 0 la velocità del motore:

motor_a_dir(fwd);

motor_a_speed(0);

All’interno del ciclo vero e proprio, la scrittura degli output viene posta di seguito

alla chiamata della funzione PID; prima d’impostare il valore di output è necessario

operare una riduzione in scala della variabile CS, in modo tale che il controllo rientri nel

range di valori ammissibili dalla funzione motor_a_speed(int speed). Si imposta quindi

la seguente proporzione 255 : (CSMAX-CSMIN) = X : (CS - CSMIN), in cui CSMAX

e CSMIN rappresentano rispettivamente gli estremi superiore ed inferiore di saturazione

della variabile CS; tali valori vengono impostati dall’utente (nel caso in esame si è

scelto CSMAX = 100 e CSMIN = 0). La sezione di codice che esegue la scrittura delle

uscite viene riportata qui di seguito.

CSraw=255*(PIDloop[0].CS-PIDrun[0]->CSmin)/(PIDrun[0]->Csmax- PIDrun[0]->CSmin);

motor_a_speed((int)CSraw);

Come si può vedere il risultato della riduzione in scala viene posto in una variabile

locale di tipo REAL Csraw, per poi essere passato alla funzione di scrittura a seguito di

una operazione di casting.

3.4.2. Input

Per quanto riguarda la catena d’acquisizione della misura, la realizzazione non è

risultata semplice come nel caso dell’uscita, in quanto Lego Mindstorms non fornisce

Page 87: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

87

un sensore in grado di rilevare direttamente la velocità di rotazione di un albero. Ad una

prima analisi, il dispositivo che più si presta a tale scopo è parso essere il sensore di

rotazione, ma, nonostante i numerosi tentativi, anche al di fuori del progetto in esame,

non si è giunti ad una soluzione accettabile, in grado di fornire una misura abbastanza

realistica per un range di velocità accettabile.

Di conseguenza, per questo progetto si è sviluppata una soluzione “ad-hoc”, che

consiste nell’utilizzare un motore come sensore di rotazione, o, meglio, come una

dinamo tachimetrica. Per rendere operativa questa soluzione, si è progettato e costruito

un circuito di condizionamento in grado di adattare il segnale prodotto dalla dinamo

tachimetrica agli ingressi dell’RCX.

Ponendo in rotazione la dinamo, questa produce una sequenza di impulsi (molto

disturbati) di ampiezza 0÷10V la cui frequenza dipende dalla velocità con cui il

dispositivo è messo in rotazione; gli ingressi dell’RCX, dal canto loro, ammettono

segnali analogici 0÷5 V su cui viene operata una conversione A/D con un convertitore a

10 bit. Per operare gli adattamenti necessari si è realizzato un dispositivo in grado di

filtrare e di ridurre l’ampiezza del segnale proveniente dalla dinamo; qui di seguito è

riportato lo schema del circuito realizzato:

Il circuito è composto da un partitore resistivo, la cui funzione è quella di dimezzare

l’ampiezza del segnale; segue un filtro passivo passa basso (RC), che ha il compito di

stabilizzare il segnale e di eliminare la componente di rumore in alta frequenza. L’uscita

del filtro rappresenta il valor medio del segnale che vi è applicato in ingresso. Non

avendo inserito uno stadio separatore fra il partitore ed il filtro RC, la costante di tempo

R1 =10 KΩ R4 =100 Ω

R2 =10 KΩ C = 100 µF

R3 =660 KΩ

R 1

R 2

R 3

C

+Vcc

-Vcc

R 4

RCX

SENSORE

LM358

LN148

Page 88: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

88

risulta essere:

ssCRRRRR

C 06,00665,0321

21 ≅=⋅

+

+⋅

L’ultimo stadio, separato tramite un buffer dal precedente, è costituito da un ponte a

diodi (per ulteriori informazioni consultare [14]) che costituisce un’interfaccia general-

porpuse per segnali compresi tra 0÷5V; esso simula all’ingresso dell’RCX, cui è

connesso, il comportamento di un sensore di luce. Pertanto, l’utilizzo del ponte consente

di avere accesso alla misura tramite la macro LIGHT_X, che in modalità attiva (vedi

Capitolo 3) fornisce valori compresi tra 0 e 100. In particolare, in corrispondenza di un

segnale d’ingresso di ampiezza 5V la macro ritorna il valore 0, mentre in assenza di

segnale (0V) il valore della macro è 100.

Nella pratica la catena d’acquisizione è realizzata calettando, tramite una ruota

dentata, un motore con funzione di dinamo al motore con funzione di attuatore. Tramite

un cavo Lego-BNC, realizzato appositamente per questo progetto, si preleva il segnale

dalla dinamo e lo si porta al circuito di condizionamento realizzato su basetta millefori.

Il segnale condizionato viene prelevato in uscita dalla scheda e portato all’ingresso 1

dell’RCX attraverso un cavo BNC-Lego.

La lettura degli ingressi avviene semplicemente tramite la seguente riga di comando:

PIDloop[0].PV = (REAL)(100-LIGHT_1); in questo modo, in assenza di segnale PV è

pari 0, mentre con 5V in ingresso PV è uguale a 100.

4. GESTIONE DEGLI EVENTI

In precedenza, si è visto come la progettazione del gestore degli eventi abbia preso le

mosse dalle seguenti assunzioni:

- il sistema deve rispondere ad ogni evento (pressione di un pulsante)

intraprendendo opportune azioni (inclusa l’azione fittizia);

- il legame fra un evento e la corrispondente azione di risposta deve essere

dinamico.

L’esigenza di poter disporre di un meccanismo flessibile e robusto allo stesso tempo, ha

portato alla concezione di due entità interagenti: il rilevatore ed il registratore degli

Page 89: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

89

eventi.

La loro implementazione si basa sostanzialmente su due elementi chiave: la funzione

di risveglio wait_event fornita da BrickOS ed i puntatori a funzione previsti dal

linguaggio C; nei prossimi paragrafi si chiarirà l’impiego di tali funzionalità nella

realizzazione del gestore degli eventi.

Si precisa fin da ora che i pulsanti “KEY_1” e “KEY_2”, cui si farà riferimento nel

codice, sono un’astrazione dei pulsanti fisici BUTTON_VIEW e BUTTON_PROGRAM

dell’RCX e risultano così definiti:

#define KEY_1 BUTTON_VIEW

#define KEY_2 BUTTON_PROGRAM

4.1. Architettura implementativa

Lo scopo di questo paragrafo è quello di fornire una visione d’insieme della struttura

implementativa cosicché, durante la successiva presentazione analitica del codice, sia

possibile collocare ciascun tassello in un quadro più ampio del quale siano già noti

confini e regole. Questo modo di procedere permetterà di individuare i meccanismi

dominanti e le relative modalità di interazione.

Al fine di semplificare la trattazione, si esaminerà tale struttura limitatamente ad un

singolo evento; per estensione, sarà poi possibile applicare gli stessi ragionamenti agli

altri eventi di sistema.

Si consideri, a titolo di esempio, l’evento KEY_1_short; la figura seguente

schematizza la struttura implementativa ad esso relativa:

Puntatore alla funzione di risposta per KEY_1_short

Generica Funzione di Risposta

Rilevatore di eventi

Funzione di Registrazione

Page 90: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

90

Anzitutto, è necessario disporre di un puntatore atto a contenere l’indirizzo di memoria

di una generica funzione priva di parametri in ingresso; all’avvio dell’applicazione,

viene inizializzato con il riferimento ad una funzione fittizia (ovvero priva di istruzioni)

opportunamente definita. Ogniqualvolta il “meccanismo di ascolto” rileva l’evento in

questione, il sistema reagisce invocando la funzione il cui indirizzo è memorizzato nel

puntatore sopraccitato. Infine, nel caso in cui si voglia associare all’evento una nuova

funzione di risposta, è sufficiente invocare la funzione di registrazione; essa richiede,

come unico parametro, proprio il nome della funzione di risposta.

A questo punto dovrebbero risultare chiari gli aspetti fondamentali del gestore degli

eventi; sulla scorta di tali informazioni si può procedere alla presentazione del codice.

4.2. Il registratore degli eventi

Per ciascuno dei cinque eventi rilevabili dal sistema, si definisce un puntatore a

funzione; pertanto, si avranno le seguenti definizioni visibili a livello globale:

void (*keyOneQuick)(void); //Azione associata a KEY_1_short

void (*keyOneAtLength)(void); //Azione associata a KEY_1_long

void (*keyTwoQuick)(void); //Azione associata a KEY_2_short

void (*keyTwoAtLength)(void); //Azione associata a KEY_2_long

void (*keyOneTwo)(void); //Azione associata a KEY_1_2

Come si può facilmente notare, tutti questi puntatori sono strutturati in modo da

contenere il riferimento a funzioni prive di parametri, caratteristica comune a tutte le

azioni di risposta.

Il passo successivo consiste nello sviluppare altrettante funzioni che permettano di

impostare correttamente questi puntatori; si consideri, ad esempio, la seguente funzione

di registrazione relativa a KEY_1_short:

void addKeyOneQuickListener(void (*performAction)())

keyOneQuick=performAction;

Essa riceve come unico parametro il nome della funzione da eseguire in risposta

all’evento ed esegue, come unica operazione, l’aggiornamento del puntatore relativo a

KEY_1_short, ponendo in esso l’indirizzo di tale funzione. In modo del tutto analogo si

definiscono le funzioni di registrazione per gli altri quattro eventi:

Page 91: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

91

void addKeyOneAtLengthListener(void (*performAction)())

keyOneAtLength=performAction;

void addKeyTwoQuickListener(void (*performAction)())

keyTwoQuick=performAction;

void addKeyTwoAtLengthListener(void (*performAction)())

keyTwoAtLength=performAction;

void addKeyOneTwoListener(void (*performAction)())

keyOneTwo=performAction;

4.2.1. L’azione fittizia

Si è parlato più volte dell’azione fittizia, considerandola sostanzialmente come

“l’assenza di azione”; a scopo di completezza se ne riporta la definizione:

void nulla()

4.2.2. L’inibizione degli eventi

Alcune attività possono essere eseguite in modo sicuro e corretto solo escludendo gli

eventi, ovvero rendendo il sistema insensibile a ciò che accade all’esterno. Questa

funzionalità è realizzata dal seguente frammento di codice:

void disableEvents()

keyOneQuick = nulla;

keyOneAtLength = nulla;

keyTwoAtLength = nulla;

keyTwoQuick = nulla;

keyOneTwo = nulla;

Sostanzialmente, si fa in modo che ciascuno dei cinque puntatori a funzione relativi agli

eventi di sistema punti all’azione fittizia.

Una volta terminate le operazioni “critiche”, sarà necessario ripristinare la reazione

agli eventi mediante opportune chiamate alle funzioni di registrazione.

Page 92: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

92

4.3. Il rilevatore degli eventi

Seguendo l’approccio dei paragrafi precedenti, si offrirà, dapprima, una visione

d’insieme del servizio, per poi arricchire la trattazione con i dettagli implementativi.

In ultima analisi, il rilevatore è costituito da due thread in esecuzione concorrente,

ciascuno dei quali è legato in modo biunivoco ad uno dei due tasti fisici messi a

disposizione dell’RCX; in particolare:

- keyOne è il thread che si propone di rilevare le pressioni del pulsante fisico view;

- keyTwo è il thread che rileva le pressioni del pulsante program.

L’attività di questi thread è basata sulle funzioni wait_event di BrickOS; la loro

esecuzione combinata permette di gestire tutti gli eventi logici definiti in fase di analisi

e specifica dei requisiti.

4.3.1. Le funzioni di risveglio

Nel capitolo due, dedicato alla descrizione dell’RCX, è stato ampiamente discusso il

modello di gestione dei task adottato da BrickOS: nel caso si voglia sospendere un

processo in attesa di un evento esterno è necessario, anzitutto, definire una funzione di

risveglio che permetta di stabilire le condizioni sotto le quali il task bloccato possa

essere “risvegliato”. Il passo successivo consiste nell’invocazione della funzione

wait_event ogniqualvolta si desideri che il processo rimanga in attesa dell’evento;

quando le condizioni stabilite nella funzione di risveglio saranno soddisfatte, il processo

passerà allo stato di attesa (wait) pronto per essere eseguito.

Per non appesantire la trattazione successiva, vengono presentate ora le funzioni di

risveglio utilizzate dai due thread introdotti in precedenza; a ciascuna di esse è associata

una breve descrizione volta a chiarirne il compito.

Funzione di Risveglio Commento

wakeup_t push(wakeup_t data)

return PRESSED(dbutton(),data);

Determina il risveglio del processo alla pressione del pulsante fisico il cui riferimento è passato come parametro; gli unici valori significativi per il parametro “data” sono KEY_1 e KEY_2.

Page 93: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

93

wakeup_t pull(wakeup_t data)

return RELEASED(dbutton(),data);

Sblocca il processo solo a fronte del rilascio del pulsante il cui riferimento è passato come parametro; chiaramente, un evento di questo tipo è subordinato ad una precedente pressione dello stesso pulsante. Come nel caso precedente i valori significativi per il parametro formale sono KEY_1 e KEY_2.

wakeup_t combinationOneTwo(wakeup_t data)

return(PRESSED(dbutton(),KEY_2)||

RELEASED(dbutton(),KEY_1));

Questa funzione di risveglio può essere invocata solo nel caso in cui KEY_1 sia stato premuto, ma non ancora rilasciato. Il task viene risvegliato se viene premuto KEY_2 oppure se viene rilasciato KEY_1.

wakeup_t wakeUpProgram(wakeup_t data)

return PRESSED(dbutton(),KEY_2) &&

!PRESSED(dbutton(),KEY_1);

Determina il risveglio del processo nel caso in cui sia premuto KEY_2, ma non KEY_1.

wakeup_t pushAKey(wakeup_t data)

return (PRESSED(dbutton(),KEY_1) ||

PRESSED(dbutton(), KEY_2));

Permette di sbloccare il task se viene premuto KEY_1 oppure KEY_2.

wakeup_t caught(wakeup_t data)

return (RELEASED(dbutton(),KEY_2)||

(sys_time-data)>2000);

Questa funzione di risveglio può essere invocata solo nel caso in cui KEY_2 sia stato premuto, ma non ancora rilasciato. Il processo viene risvegliato quando KEY_2 viene rilasciato oppure quando sono trascorsi 2 secondi dall’istante in cui KEY_2 è stato premuto.

Le informazioni finora acquisite permettono di affrontare in maniera dettagliata il

vero o proprio nucleo del rilevatore degli eventi: i thread keyOne e keyTwo.

Page 94: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

94

4.3.2. Il thread KEYONE

Questo task ha il compito di sovrintendere a tutti gli eventi logici che coinvolgono

direttamente il pulsante KEY_1: KEY_1_short, KEY_1_long, KEY_1_2. Dal punto di

vista della mera struttura implementativa, è costituito da un unico ciclo (ripetuto

all’infinito) all’interno del quale sono opportunamente collocate le funzioni di attesa

(wait_event).

La logica di funzionamento, peraltro molto semplice, può essere efficacemente

schematizzata facendo riferimento ad una generica iterazione:

- Passo 1: il processo si mette in attesa della pressione di KEY_1.

- Passo 2: una volta che il tasto è stato premuto, possono verificarsi due eventi tra

loro mutuamente esclusivi:

! l’utente rilascia KEY_1, allora il thread invoca la funzione che in

quell’istante risulta associata all’evento KEY_1_short;

! mantenendo premuto KEY_1, l’utente preme e rilascia KEY_2, allora il

thread chiama la funzione attualmente associata a KEY_1_2. In questa

situazione, per evitare che BrickOS interpreti erroneamente il rilascio di

KEY_1, è indispensabile fare uso di una variabile booleana (flag) la quale

viene posta a TRUE solo nel caso di pressione combinata dei due tasti. In

questo modo il successivo rilascio di KEY_1 non determina alcuna reazione

del sistema, ma semplicemente riporta flag al suo valore predefinito

(FALSE).

- Ritorno al Passo 1.

Il codice che permette di fornire le funzionalità sopra descritte è il seguente:

void keyOne()

int flag = FALSE; //Inizializzazione del flag al valore predefinito

while(1)

wait_event(&push,KEY_1);

time_rest = sys_time;

wait_event(&combinationOneTwo,0);

if(RELEASED(dbutton(),KEY_1))

if(flag) flag=FALSE; //Situazione in cui

Page 95: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

95

KEY_1 viene rilasciato dopo una pressione combinata con KEY_2

else (*keyOneQuick)(); //Situazione in cui KEY_1 è stato premuto e rilasciato

else

wait_event(&pull, KEY_2); //Situazione in cui KEY_1 e KEY_2 sono premuti contemporaneamente e si attende il rilascio di KEY_2

(*keyOneTwo)();

flag=TRUE;

4.3.3. Il thread KEYTWO

Si tratta del thread che governa gli eventi logici relativi al tasto KEY_2:

KEY_2_short, KEY_2_long; anch’esso, come keyOne, è composto da un unico ciclo

ripetuto all’infinito.

Facendo riferimento ad una generica iterazione, la logica funzionale può essere così

sintetizzata:

- Passo 1: il task viene sospeso sino a quando viene premuto il solo tasto KEY_2

(la pressione contemporanea dei due pulsanti non determina un cambiamento di

stato del task); il sistema memorizza, nella variabile locale time, l’istante

temporale in cui è avvenuto l’evento.

- Passo 2: il processo viene nuovamente sospeso e può essere risvegliato a fronte

del verificarsi di due eventi:

! l’utente rilascia KEY_2 prima che siano trascorsi 2 secondi, allora viene

invocata la funzione connessa all’evento KEY_2_short e viene emesso un

singolo segnale acustico.

! L’utente tiene premuto KEY_2 per un intervallo di tempo superiore ai due

secondi, allora viene chiamata la funzione legata a KEY_2_long e viene

Page 96: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

96

emesso un doppio segnale acustico. In questa situazione si introduce anche

un ritardo di tempo di 500ms per evitare che un rilascio lento del tasto venga

interpretato dal sistema come una successiva pressione breve dello stesso.

Il codice completo che costituisce il corpo di keyTwo è il seguente:

void keyTwo()

time_t time;

while(1)

time_rest = sys_time;

wait_event(&wakeUpProgram,0);

time_rest = sys_time;

time = sys_time; //Memorizzazione dell'istante temporale di pressione del tasto

wait_event(&caught,time); //Il sistema attende che l’utente rilasci KEY_1 oppure che siano trascorsi 2 secondi dall’inizio della pressione

if((sys_time-time)>2000) //condizione che discrimina la pressione lunga o breve

//Pressione lunga

dsound_system(DSOUND_BEEP);

msleep(200);

dsound_system(DSOUND_BEEP);

(*keyTwoAtLength)();

msleep(500); //ritardo necessario per evitare che a causa di un rilascio lento si rilevi anche l'evento pressione breve

else

//Pressione breve

dsound_system(DSOUND_BEEP);

(*keyTwoQuick)();

Page 97: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

97

5. GESTIONE DEI CONTESTI

Nella fase di progettazione si è definito un contesto come un legame univoco

esistente fra un preciso stato del display e l’insieme degli eventi che per esso hanno

significato; tale definizione si estende sino ad includere le azioni di risposta associate

agli eventi. E’ stato detto che la creazione di un contesto si articola in tre fasi:

- individuazione degli eventi significativi;

- implementazione delle funzioni da invocare in risposta agli eventi scelti al passo

precedente;

- implementazione della funzione che permette di registrare le azioni di risposta sui

relativi eventi; ogni volta che si invoca questa funzione, si dice che si “applica il

contesto”.

La rielaborazione dei requisiti applicativi ha portato, infine, all’individuazione di un

primo insieme di contesti su cui basare l’attività implementativa.

Da un punto di vista prettamente tecnico, la gestione dei contesti non richiede

meccanismi particolarmente sofisticati; la realizzazione orbita sostanzialmente attorno

al nucleo di registrazione degli eventi.

5.1. Realizzazione dei contesti

L’implementazione dei vari contesti viene discussa rispettando l’ordine adottato per

la loro presentazione (vedi Capitolo 5), salvo eventuali integrazioni dettate da ragioni di

realizzabilità pratica. Ad ogni contesto è dedicato un paragrafo organizzato in due

sezioni:

- descrizione funzionalità;

- registrazione eventi e descrizione azioni di risposta.

5.1.1. «Menù Selezione PID»

Offre all’utente la possibilità di selezionare un determinato regolatore e di accedere

alla modalità di modifica/visualizzazione dei suoi parametri.

La funzione di registrazione di questo contesto viene invocata automaticamente

all’avvio del software. Se il sistema è costituito da un singolo regolatore, si passa

Page 98: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

98

direttamente all’applicazione del contesto «Menù Parametri PID»; in caso contrario si

effettuano due operazioni:

- il flag menu_PID viene impostato a TRUE; ciò permette di comunicare al modulo

di visualizzazione di gestire correttamente la nuova modalità operativa.

- si registrano gli eventi in base allo schema seguente:

Evento KEY_1_short

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: switchPID()

Il sistema associa a ciascun regolatore un indice (valore numerico intero)

che permette di identificarlo univocamente; il regolatore dell’anello più

interno ha indice pari a 0, mentre quello sull’anello più esterno ha indice

pari a NUMBER_OF_PIDs-1. La variabile currentPID, definita a

livello globale, memorizza l’indice del PID attualmente selezionato

dall’utente; chiaramente può assumere valori nel range

0…NUMBER_OF_PIDs-1. Ad ogni pressione di KEY_1 corrisponde un

incremento unitario di currentPID; quando si raggiunge l’ultimo

regolatore della lista, si riparte dal primo, imponendo 0=currentPID :

if (currentPID==NUMBER_OF_PIDs-1) currentPID = 0;

else currentPID++;

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Parametri PID»

Descrizione

Funzione registrata: selectPID()

L’evento corrisponde alla richiesta dell’utente di accedere alla modifica

Page 99: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

99

dei parametri del PID attualmente selezionato. Prima di applicare il

contesto «Menù Parametri PID»:

- si riporta a FALSE il flag menu_PID;

- si chiama la funzione encode per preparare il display alla

visualizzazione del primo parametro.

5.1.2. «Menù Parametri PID»

E’ uno dei contesti più importanti in quanto permette di accedere alla

visualizzazione, nonché alla modifica, dei parametri che caratterizzano ciascun

regolatore; in un’ipotetica organizzazione gerarchica può essere considerato un’entità di

livello superiore rispetto a tutti i contesti che gestiscono le modifiche vere e proprie.

Inoltre, offre due funzionalità particolarmente importanti:

- impedisce all’utente di apportare variazioni non autorizzate ai parametri (ad

esempio: se il PID si trova in modalità automatica l’utente non può accedere al

contesto di modifica della variabile di controllo);

- seleziona, in base al tipo di parametro, il contesto adatto a gestirne le modifiche.

Gli eventi vengono registrati in base allo schema seguente:

Evento KEY_1_short

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: menuItemToDisplay()

Questa funzione fa avanzare di un elemento il menù in modo che la

nuova voce così selezionata venga visualizzata sul display fisico

dell'RCX.

Si ricorda che, a livello di gestione dei dati, lo scorrimento del menù

parametri è governato dalla funzione nextItem().

Page 100: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

100

Evento KEY_2_long

Variazione

di contesto

Se il parametro corrente è modificabile, viene applicato il contesto di

modifica ad esso corrispondente. Inoltre, l’uscita dall’ultima voce di

menù (CONF o EXIT) determina l’applicazione di «Menu Selezione

PID»

Descrizione

Funzione registrata: changeMenuItem()

Questa funzione verifica, anzitutto, che la voce attuale del menu sia

modificabile dall'utente:

if (menu[currentPID][currentItem].modifiable==TRUE) …

In base all’indice del parametro corrente (currentItem), viene

selezionato il nuovo contesto che permetterà al sistema di processare gli

opportuni eventi:

if (currentItem==POS_CONF)

//Voce = "CONF" o "EXIT"

...

else if (currentItem==POS_MODE)

//Voce = "MODE"

setContestEnumeratedItem();

...

else if (currentItem==POS_SPi)

//Voce = "SPi"

setContextIncValue();

...

else if (currentItem==POS_CS)

//Voce = "CS"

setContextIncValue();

...

else if (currentItem==POS_PV)

//Voce = "PV"

setContextPVEvolution();

...

else setContextNumericalItem();

Page 101: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

101

(Nota: i simboli POS_CONF, POS_CS, POS_PV, POS_MODE e

POS_SPi rappresentano la posizione dei relativi parametri nella struttura

dati menu[][]).

Nel caso in cui venga raggiunta l’ultima voce del menù, il sistema

procede nel seguente modo:

- se sono state effettuate modifiche, viene applicato il contesto

«Conferma o Annullamento»;

- se l’utente non ha apportato modifiche, ma c’è più di un

regolatore, viene applicato il contesto «Exit» che consente di

tornare al menù di scelta dei PID.

5.1.3. «Modifica valore lessicale»

Si affronta, ora, il primo dei tre contesti che permettono effettivamente di agire sui

parametri apportando variazioni al loro valore corrente. Un valore lessicale, come detto

in precedenza, può assumere un numero finito di valori, definiti a priori dal progettista.

Per ogni parametro di questo tipo è necessario, quindi, caricare la lista dei possibili

valori e renderla disponibile all’utente affinché possa operare la propria scelta.

Il parametro MODE, che rappresenta la modalità di funzionamento del regolatore, è

l’unico a richiedere l’applicazione del contesto in esame; la registrazione degli eventi

rispetta lo schema seguente:

Evento KEY_1_short

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: changeEnumeratedItemValue()

Allo stato attuale del progetto, questa funzione fa scorrere i due possibili

valori (MAN e AUTO) assegnabili alla voce MODE, visualizzandoli sul

display dell'RCX:

Page 102: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

102

if (currentItem==POS_MODE)

manual = manual==TRUE ? FALSE : TRUE;

La variabile booleana manual è definita a livello globale e memorizza

l’attuale modalità di funzionamento; ad ogni pressione di KEY_1 si

complementa manual. In futuro sarà resa disponibile una nuova

modalità (TUNE) corrispondente alla funzione di autotuning del

regolatore. Inoltre, è sempre possibile espandere la funzione in modo

che possa gestire numerosi parametri di tipo lessicale, ciascuno con il

proprio insieme di valori predefiniti.

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Parametri PID»

Descrizione

Funzione registrata: confirmEnumeratedItemValue()

Tenendo conto del nuovo valore assegnato dall’utente al parametro

MODE, il sistema esegue le seguenti operazioni:

- decide se rendere (o meno) modificabile la variabile di controllo

(CS);

- salva la nuova modalità di funzionamento nella struttura dati

PIDloop associata al PID corrente.

Come ultima operazione, si torna al menù dei parametri:

if (currentItem==POS_MODE)

sem_wait(semMenu);

menu[currentPID][POS_CS].modifiable = manual;

PIDloop[currentPID].MAN = manual;

sem_post(semMenu);

display.change = TRUE;

setContextMenu();

Page 103: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

103

Le primitive di sincronizzazione che compaiono nel codice vengono

trattate in separata sede.

5.1.4. «Modifica valore numerico»

Il secondo contesto di attuazione delle modifiche è concepito per i parametri

numerici il cui valore può essere impostato dall’utente in modo diretto senza dover

sottostare a particolari vincoli.

L’obiettivo è quello di rendere operativa la procedura di modifica definita in modo

qualitativo dalle specifiche di progetto.

La procedura di applicazione del contesto agisce in due fasi:

- anzitutto si attiva il lampeggio della prima cifra a sinistra del display mediante le

istruzioni:

display.blinkingDigit=0;

display.blink=TRUE;

- in seconda battuta si registrano gli eventi in base allo schema che segue:

Evento KEY_1_short

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: changeCurrentDigitValue()

Il comportamento del sistema dipende dallo stato del display:

- se sta lampeggiando una delle cinque cifre, allora si applica ad essa

un incremento unitario; in questo modo è possibile far scorrere i

valori da 0 a 9 per ogni singola cifra del display.

- se sta lampeggiando il punto decimale, allora esso viene spostato

nella posizione immediatamente successiva.

Formalizzando in codice:

if(display.blinkingDigit>=0&&display.blinkingDigit<MAX_DIGIT)

Page 104: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

104

if(display.character[display.blinkingDigit]=='9')

display.character[display.blinkingDigit]='0';

else display.character[display.blinkingDigit]++;

else if (display.blinkingDigit==5)

if(display.point==4) display.point=0;

else if(display.point==0) display.point = 2;

else display.point++;

Per maggiori dettagli riguardanti la codifica delle cifre e delle posizioni del

punto decimale, si rimanda alla sezione dedicata alla struttura dati

DISPLAY.

Evento KEY_2_short

Variazione

di contesto Applicazione del contesto «Conferma Voce Numerica».

Descrizione

Funzione registrata: changeCurrentDigitValue()

Questa funzione permette di selezionare (far lampeggiare), una dopo

l’altra, ciascuna delle cifre del display affinché sia possibile modificarne

il valore. Successivamente alla quinta cifra, viene fatto lampeggiare il

punto decimale. In questa situazione, un’ulteriore pressione di KEY_2 fa

passare alla situazione in cui lampeggiano tutte le cifre ed il punto

decimale e comporta l’applicazione del contesto «Conferma Voce

Numerica» per consentire l'annullamento o la conferma delle modifiche

apportate al parametro:

if(display.blinkingDigit==6)

display.blinkingDigit=0;

else

display.blinkingDigit++;

Page 105: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

105

if (display.blinkingDigit==6) //Tutte le cifre

lampeggiano

setContextNumericalItemConfirm();

5.1.4.1. «Conferma Voce Numerica»

Può essere considerato un’estensione del contesto «Modifica Voce Numerica». La

sua creazione è dovuta semplicemente a fattori di ordine pratico.

Gli eventi vengono registrati in conformità allo schema che segue:

Evento KEY_2_short

Variazione

di contesto Applicazione contesto «Menù Parametri PID».

Descrizione

Funzione registrata: undoNumericalItem()

Torna al menù dei parametri ignorando le modifiche apportate

dall'utente alla voce numerica corrente. Prima di uscire dal contesto

viene anche disabilitata la modalità di visualizzazione intermittente del

display:

display.blink=FALSE;

setContextMenu();

Evento KEY_2_long

Variazione

di contesto Applicazione contesto «Menù Parametri PID»

Descrizione

Funzione registrata: confirmNumericalItem()

Registra le modifiche apportate dall'utente alla voce numerica attuale e

visualizza sul display il simbolo che indica la presenza di modifiche non

Page 106: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

106

ancora confermate a secondo livello. Anche in questo caso si disabilita

la modalità di lampeggiamento:

(menu[currentPID][currentItem].value) = (float)decode();

if(currentItem!=POS_SP) display.change = TRUE;

display.blink=FALSE;

setContextMenu();

Nel caso in cui l’utente abbia modificato la voce SP o CS, non risulta

necessario visualizzare il simbolo di modifica in quanto tale variazione è

immediatamente visibile al regolatore (si ricorda che SP e CS sono

parametri descrittivi dell’anello di regolazione).

Per ulteriori informazioni sulla funzione decode, si rimanda alla sezione

dedicata alla gestione della visualizzazione.

5.1.5. «Modifica Valore Incrementale»

Si tratta del terzo ed ultimo contesto di gestione delle modifiche. Un parametro

incrementale è caratterizzato dal fatto che il suo valore attuale può essere modificato

solo attraverso un’opportuna serie di incrementi o decrementi di passo predeterminato.

L’applicazione prevede due soli parametri di questo tipo:

- set-point incrementale (SPi): consente di applicare variazioni a rampa al segnale

di riferimento. Il passo di incremento/decremento è unitario e non può essere

modificato dall’utente;

- variabile di controllo (CS): quando il regolatore funziona in modalità manuale,

l’operatore può agire direttamente sull’uscita. Il passo di incremento/decremento

è impostato dall’utente stesso per mezzo del parametro deltaCSMAN.

All’applicazione del contesto, si memorizza nella variabile memoryChange (di tipo

REAL) il valore attuale del parametro, in modo tale che sia possibile annullare le

eventuali modifiche.

Gli eventi vengono registrati con le seguenti modalità:

Page 107: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

107

Evento KEY_1_short

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: increaseIncValue();

Il comportamento dipende dal parametro considerato:

- nel caso del set-point incrementale, si incrementa di un’unità il

valore precedente e si chiama la funzione encode per rendere

immediatamente visibile la modifica;

- nel caso della variabile di controllo, si porta semplicemente a

TRUE il parametro MANinc del PID; ciò è sufficiente a

determinare un incremento del controllo (laddove consentito) pari

a deltaCSMAN.

Il codice, a meno delle primitive di sincronizzazione, è il seguente:

if(currentItem==POS_SPi)

(*menu[currentPID][currentItem].value)++;

encode(*menu[currentPID][currentItem].value); ...

else if(currentItem==POS_CS)

PIDloop[currentPID].MANinc = TRUE; ...

Come si può notare dal codice, le modifiche sono rese subito visibili al

regolatore.

Evento KEY_1_2

Variazione

di contesto Nessuna.

Descrizione

Funzione registrata: decreaseIncValue()

Il comportamento è assimilabile a quello della funzione precedente,

Page 108: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

108

salvo il fatto che, in questo caso, si deve gestire una diminuzione del

valore:

- nel caso del set-point incrementale, si decrementa di un’unità il

valore precedente e si chiama la funzione encode;

- nel caso della variabile di controllo, si porta a TRUE il parametro

MANdec del PID per determinare un decremento del controllo

(laddove consentito) pari a deltaCSMAN.

Si evita di riportare il codice in quanto analogo al caso precedente.

Ancora una volta, le modifiche risultano immediatamente visibili al

regolatore.

Evento KEY_2_short

Variazione

di contesto Applicazione del contesto «Menù Parametri PID»

Descrizione

Funzione registrata: undoIncValue()

Annulla le modifiche ripristinando il valore iniziale del parametro; a

questo scopo utilizza la variabile memoryChange:

*menu[currentPID][currentItem].value=memoryChange;

Al termine dell’operazione si torna al menù dei parametri.

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Parametri PID»

Descrizione

Funzione registrata: confirmIncValue()

Si è detto che eventuali incrementi o decrementi del set-point e della

variabile di controllo vengono resi immediatamente visibili al

regolatore; proprio per questo motivo, in caso di conferma dei nuovi

Page 109: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

109

valori non è necessario effettuare alcuna operazione sulle strutture dati.

La reazione all’evento consiste esclusivamente nel ritorno al menù dei

parametri.

5.1.6. «Evoluzione variabile controllata»

Il contesto, peraltro molto semplice, risponde all’esigenza di visualizzare sul display

l’andamento temporale della variabile controllata. La logica implementativa si basa

sulla definizione della variabile booleana trackingPV, la quale risulta visibile sia al

gestore dei contesti (che ne imposta il valore) sia al gestore del display fisico (che ne

legge il valore). Quando trackingPV è TRUE, il thread di visualizzazione si comporta in

modo tale che, ad ogni ciclo di refresh, venga aggiornata la visualizzazione della

variabile controllata.

All’applicazione del contesto, si porta a TRUE la variabile discussa in precedenza e

si registra un unico evento:

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Parametri PID»

Descrizione

Funzione registrata: exitEvolutionPVContext()

Riporta semplicemente a FALSE la variabile trackingPV e torna al menù

dei parametri.

5.1.7. «Conferma o Annullamento»

Nel caso in cui siano state apportate modiche ai parametri del regolatore attualmente

selezionato, come ultimo elemento del menù viene visualizzata la voce di conferma.

Essa permette di realizzare quella “conferma di secondo livello”, discussa nella fase di

analisi e specifica dei requisiti. E’ bene sottolineare ancora una volta, che essa riguarda

solo ed esclusivamente i parametri che descrivono la legge di controllo PID del

regolatore (guadagno, tempo integrale, …); i parametri che descrivono l’anello di

Page 110: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

110

controllo (variabile controllata, set-point, …) non sono assolutamente coinvolti

nell’operazione.

La registrazione degli eventi avviene come specificato di seguito:

Evento KEY_1_short

Variazione

di contesto Applicazione del contesto «Menù Selezione PID»

Descrizione

Funzione registrata: undo()

Annulla tutte le modiche apportate ai parametri del PID che non hanno

ancora ricevuto la conferma di secondo livello. Tecnicamente,

l’annullamento si realizza copiando i valori della struttura PIDrun su

quelli della struttura PIDedit:

...

*PIDedit[currentPID]=*PIDrun[currentPID];

...

Prima di uscire dal contesto, viene nascosto il simbolo sul display che

indica la presenza di modifiche non ancora confermate (o annullate):

...

display.change = FALSE;

...

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Selezione PID»

Descrizione

Funzione registrata: confirm()

Conferma tutte le variazioni apportate ai parametri per mezzo della

chiamata alla funzione switchPIDData; anche in questo caso viene

Page 111: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

111

disabilitato il simbolo del display associato alle modifiche:

...

switchPIDData(currentPID);

display.change = FALSE;

...

5.1.8. «Uscita Menù Parametri»

Si consideri il caso in cui il sistema sia costituito da più PID e l’utente entri nel menù

dei parametri di un regolatore e giunga all’ultima voce senza apportare alcuna

variazione. Chiaramente non sarebbe di alcuna utilità proporre la voce di conferma

(CONF). In tale situazione, si preferisce visualizzare una voce (EXIT) che consenta

all’utente di tornare al menù di selezione dei PID. Questo contesto viene applicato

proprio a tale scopo.

Si registra un unico evento, in accordo al seguente schema:

Evento KEY_2_long

Variazione

di contesto Applicazione del contesto «Menù Selezione PID»

Descrizione

Funzione registrata: backToPIDMenu()

Permette di tornare al menù di scelta dei PID.

6. VISUALIZZAZIONE DEI DATI

Questo modulo concorre, con la gestione degli eventi, alla realizzazione

dell’interfaccia utente, il suo compito è di garantire all’operatore un feed-back visivo

alle azioni intraprese per mezzo dei pulsanti. Nella fase di progettazione, descritta nel

capitolo precedente, si sono definiti gli aspetti caratterizzanti della visualizzazione che,

in questa fase, rappresentano le linee guida per l’implementazione.

Per quanto riguarda l’organizzazione interna dei dati da presentare, si è stabilito di

Page 112: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

112

raggruppare tutti i parametri relativi ad un singolo PID all’interno di un unico menù,

concepito come una collezione di voci (vedi capitolo 5). I vari menù sono, a loro volta,

raggruppati in una apposita struttura, la cui dimensione viene definita staticamente in

base al numero di regolatori presenti nel sistema.

Per quanto concerne la presentazione delle informazioni, si è stabilito di realizzare

una struttura dati (DISPLAY), che mappa in memoria l’LCD. Un thread apposito,

denominato “video”, si occuperà di scrivere il contenuto di tale struttura sul display

fisico. Con questa soluzione sarà sufficiente scrivere ciò che si desidera far apparire a

video nell’apposita struttura, per ottenerne l’automatica visualizzazione sull’LCD.

L’architettura del modulo può essere riassunta visivamente nella seguente figura:

Tale architettura consente di mantenere totalmente indipendente la rappresentazione

interna dei dati dalla loro visualizzazione, ottenendo una netta separazione tra le

funzioni di competenza di ciascuna area; ciò permette di relegare all’interno del thread

video tutti i numerosi problemi che BrickOS presenta nella gestione del display.

Nel seguito si affronteranno individualmente le tre aree che costituiscono gli

elementi cardine dell’architettura del modulo in questione:

− Area “menù”: riguarda l’organizzazione interna dei dati e la tecnica prescelta per

la loro gestione.

− Area “display”: descrive la modellizzazione del display fisico, sottolineando il

Page 113: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

113

fatto che essa rappresenta il punto di contatto fra l’organizzzazione interna dei

dati e la loro visualizzazione.

− Area “video”: definisce il thread che si occupa di portare in visualizzazione sul

display fisico i dati posti nella struttura DISPLAY.

6.1. Menù

La descrizione interna dei dati da visualizzare si risolve nella definizione ed

implementazione di una struttura che rappresenti i menù, opportunamente corredata da

una serie di funzioni che su di essa operano.

In fase di progettazione si è stabilito d’organizzare il menù come una collezione di

“voci”.Ciascuna voce è un’istanza della struttura dati VOCE_MENU:

typedef struct

char *name;

REAL *value;

BOOL modifiable;

VOCE_MENU;

In essa il campo name rappresenta l’etichetta che verrà visualizzata sul display

quando si seleziona la voce, mentre il campo value è un puntatore al corrispettivo

parametro nella struttura PIDLOOPDATA o PIDPARAM, a seconda che la voce sia

relativa ad un parametro dell’anello o del regolatore. Infine, il campo modifiable indica

se la voce è modificabile o meno dall’utente.

Dovendo gestire la situazione in cui vi siano più menù (uno per ogni regolatore) si

stabilisce che essi siano rappresentati attraverso una matrice, in cui su una dimensione

vengono riportati i regolatori presenti nel sistema, mentre sull’altra vengono elencate le

voci corrispondenti al menù di ciascun regolatore. In particolare, tutti i menù avranno la

medesima struttura, qui di seguito riportata:

Indice Voce menù Tipo Descrizione

0 K Voce numerica modificabile

Valore dell’azione proporzionale,

necessita di conferma di secondo

livello.

Page 114: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

114

1 Ti Voce numerica modificabile

Valore del tempo integrale,

necessita di conferma di secondo

livello.

2 Td Voce numerica modificabile

Valore del tempo derivativo,

necessita di conferma di secondo

livello.

3 N Voce numerica modificabile

Stabilisce il polo in alta frequenza

relativo al filtro sull’azione

derivativa, necessita di conferma di

secondo livello.

4 b Voce numerica modificabile

Peso sul set point nell’azione

proporzionale, necessita di

conferma di secondo livello.

5 c Voce numerica modificabile

Peso sul set point nell’azione

derivativa, necessita di conferma di

secondo livello.

6 Ts Voce numerica modificabile

Tempo di campionamento,

necessita di conferma di secondo

livello.

7 CSmax Voce numerica modificabile

Limite superiore di saturazione,

necessita di conferma di secondo

livello.

8 CSmin Voce numerica modificabile

Limite inferiore di saturazione,

necessita di conferma di secondo

livello.

9 deltaCSman Voce numerica modificabile

solo in modalità manuale

Passo di variazione di CS in

modalità manuale, necessita di

conferma di secondo livello.

Page 115: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

115

10 SP Voce numerica modificabile

Set point del regolatore, non

necessita di conferma di secondo

livello.

11 SPi Voce numerica modificabile

incrementalmente

Set point del regolatore, non

necessita di conferma di secondo

livello.

12 PV Voce numerica non

modificabile Misura della variabile controllata

13 CS

Voce numerica modificabile

incrementalmente solo in

modalità manuale

Variabile di controllo del sistema,

uscita del regolatore; non necessita

di conferma di secondo livello.

14 MODE Voce lessicale modificabile

Permette d’impostare la modalità di

lavoro, non necessita di conferma di

secondo livello.

15 CONF Voce di conferma Viene visualizzata solo se sono

avvenute modifiche sulle altre voci.

15 EXIT Voce di ritorno al menù PID

Viene visualizzata se non ci sono

modifiche in un sistema con più

PID.

Come stabilito nella fase di analisi e specifica dei requisiti, le due voci CONF ed

EXIT sono in una relazione di mutua esclusione; per tanto, considerando solo gli aspetti

di visualizzazione, non nasce la necessità di creare nel menù due voci distinte, in quanto

sarà sufficiente far apparire a video delle etichette diverse.

Dalla schematizzazione della tabella, risulta evidente che le dimensioni della

struttura sono definite staticamente e non subiscono variazioni durante l’esecuzione;

pertanto, si decide di implementare la matrice dei menù utilizzando un array

bidimensionale. Questa soluzione consente una gestione efficiente dello spazio occupato

in memoria, la quale in questo progetto rappresenta sicuramente una risorsa scarsa.

Page 116: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

116

Inoltre, è noto che gli array permettono accessi diretti, molto rapidi, ai singoli elementi

della matrice.

L’implementazione di questa soluzione avviene, in primo luogo, definendo le

costanti che stabiliscono le dimensioni della matrice: SIZE_MENU, per quanto riguarda

il numero di voci, è definita univocamente pari a 16. Per quanto riguarda il numero dei

regolatori presenti nel sistema si definisce NUMBER_OF_PIDs, il cui valore può essere

impostato staticamente (prima di compilare ed eseguire l’applicativo) secondo le

esigenze del controllo da operare.

Della matrice viene creata una sola istanza tramite la seguente dichiarazione della

variabile menu:

VOCE_MENU menu[NUMBER_OF_PIDs][SIZE_MENU];

Ad essa sarà possibile accedere per mezzo di due indici: currentPID e currentItem;

in particolare, currentPID potrà assumere solo il valore 0 nel caso in cui nel sistema sia

presente un solo anello di regolazione.

Per la gestione della variabile menu sono messe a disposizione due funzioni:

loadMenu() e nextItem() qui di seguito descritte.

6.1.1. Inizializzazione del menù

La funzione loadMenu() ha il compito di inizializzare il menù; per ciascun regolatore

definito nel sistema vengono create le rispettive sedici voci, ciascuna costruita

impostando il nome della voce, l’eventuale riferimento al valore numerico ed indicando

se la voce in questione è modificabile o meno. A titolo d’esempio, di seguito si riporta

l’inizializzazione del parametro K del primo regolatore (PID 0):

menu[0][0].name="K";

menu[0][0].value=&(PIDedit[0]->K);

menu[0][0].modifiable = TRUE;

6.1.2. Scorrimento del menù

Nonostante l’implementazione per mezzo di array metta a disposizione la possibilità

di eseguire accessi random in maniera rapida ed efficiente, nel rispetto delle specifiche,

si fornisce all’utente solamente la possibilità di passare in rassegna sequenzialmente le

Page 117: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

117

varie voci che compongono un menù. Ciò è realizzato attraverso la funzione nextItem(),

la quale non fa altro che passare alla voce successiva del menù.

L’azione svolta si può ricondurre semplicemente all’incremento dell’indice

currentItem a cui vengono applicati una serie di controlli; fra essi, il più significativo è

certamente quello che permette di gestire l’eventuale visualizzazione dell’ultima voce di

menù.

Anzitutto, questa decisione viene presa solo quando si è giunti alla penultima voce

del menù (ovvero se currentItem = = SIZE_MENU-2) e l’utente chiede di visualizzare

la voce successiva. In questa situazione, si verifica se sono state apportate delle

modifiche ai parametri (display.change = = TRUE); in caso affermativo l’indice

currentItem viene incrementato e la voce CONF viene visualizzata. In caso negativo, si

verifica se nel sistema sono presenti più regolatori (NUMBER_OF_PIDs>1); in caso

positivo l’indice currentItem viene incrementato e si visualizzerà la voce EXIT,

altrimenti l’indice viene riportato a 0 e nessuna delle due precedenti voci verrà

visualizzata.

6.2. Display

Come già detto, la struttura DISPLAY mappa in memoria il dispositivo LCD e

costituisce, pertanto, il punto di contatto tra la rappresentazione interna dei dati e la

visualizzazione degli stessi; di essa è fornita in appendice al capitolo l’implementazione.

In questo paragrafo s’intende discuterne gli aspetti salienti, mostrando come alcune

logiche di funzionamento della visualizzazione dei dati siano state implementate a

partire dalla definizione di appositi campi nella struttura dati in questione.

Nel sistema è definita un’unica variabile di tipo DISPLAY, chiamata display, in

quanto vi è un solo dispositivo di visualizzazione da gestire.

Nella definizione dei campi della struttura si sono tenuti in considerazione due

aspetti: la modellizzazione di un dispositivo fisico e la necessità di fornire una serie di

informazioni ausiliarie, utili al thread video per una corretta visualizzazione. Nel

paragrafo che segue si prende in considerazione solo il primo aspetto, mentre il secondo

sarà affrontato nel paragrafo in cui si descrive il thread di scrittura sull’LCD.

Page 118: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

118

6.2.1. Modellizzazione del display fisico

Nell’attività di modellizzazione si è proceduto individuando sul display fisico gli

elementi necessari a comunicare le informazioni utili e a ciascuno di essi si è fatto

corrispondere un campo nella struttura dati:

− i cinque digit del display sono rappresentati attraverso un vettore di caratteri così

definito: char character[MAX_DIGIT].

− il punto decimale, che fisicamente può assumere solo tre posizioni, viene

mappato attraverso una variabile point che assume i valori definiti dalla seguente

enumerazione:

enum pointPosition left=4,mid_left=3,mid_right=2,right=1,none=0, in cui

vengono definite quattro possibili posizioni (oltre all’assenza del punto) in

previsione di poter utilizzare un ulteriore segmento del display come punto

decimale, posizionato tra l’ultimo e il penultimo digit a destra. Poiché questa

soluzione non è ancora possibile, si utilizzano come punti decimali i soli

segmenti che per tale fine sono stati introdotti dal costruttore; pertanto, il valore

right per ora non viene utilizzato.

− l’ultimo elemento fisico che è stato mappato è il simbolo di modifica, per esso si

è scelto un piccolo quadrato al di sopra delle cinque cifre a cui nella struttura

DISPLAY si fa corrisponde una variabile booleana: BOOL change.

Alla struttura appena descritta sono associate alcune funzioni, fra cui le due più

importanti sono encode e decode; la prima permette di scrivere sulla struttura, mentre la

seconda di leggere. Prima di entrare nel dettaglio implementativo di queste funzioni, se

ne vogliono definire i diversi ambiti applicativi e le differenti finalità d’impiego, in

modo tale che la successiva descrizione nel dettaglio sia più comprensibile.

6.2.2. Interazioni con la struttura DISPLAY

Per le modalità in base alle quali è stata definita l’architettura del modulo di

visualizzazione, sembrerebbe logico definire solamente una funzione di scrittura in

corrispondenza di un unico flusso di dati che, dalla struttura menù, porta al display i

valori dei parametri da visualizzare. In questo flusso si visualizzano dati già

memorizzati, cioè dati ai quali non sono state apportate delle modifiche. Da qui nasce

Page 119: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

119

l’esigenza d’individuare un nuovo flusso, che consenta all’operatore di vedere le

modifiche che sta apportando su un parametro; in altre parole si deve poter visualizzare

il valore di un parametro prima che avvenga la conferma di primo livello. I due flussi

sono schematizzati nella figura seguente e contraddistinti dalla lettera a) per quanto

riguarda i dati memorizzati, e dalla lettera b) per i dati a cui si apportano modifiche.

nextItem encode (b)

decode (b)

encode (a)

MENU ’ PID

D ISPLA Y

Alla luce delle considerazioni fatte, si passa a descrivere l’implementazione delle

funzioni che operano sulla variabile display.

6.2.2.1. Funzione di scrittura

Il compito della funzione encode(double value) è quello di scrivere nel vettore

character della variabile display il valore che le viene passato come parametro.

Il nome ‘encode’ chiarifica ciò che in pratica svolge questa funzione: codifica un

valore numerico in una sequenza di caratteri, occupandosi anche di impostare

correttamente la posizione del punto decimale (valore della variabile point); in questo

modo garantisce una corretta e completa visualizzazione del dato. Questa funzione non

fa nulla di particolarmente complesso, quindi in una situazione normale non

necessiterebbe di particolare attenzione. Tuttavia, nell’implementazione si sono

incontrate alcune difficoltà a causa delle risicate librerie di funzioni che corredano

BrickOS. Sostanzialmente il sistema operativo non fornisce alcuna funzione utile allo

scopo. Pertanto, si è dovuto sopperire alle mancanze di BrickOS attraverso la “re-

Page 120: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

120

implementazione” di funzioni C (si veda appendice “Librerie”). Nel far questo si è

sicuramente perso il vantaggio dell’elevato grado di ottimizzazione delle librerie

standard.

Alla luce di queste considerazioni, l’implementazione di encode assume una nuova

veste, degna di essere riportata in questa trattazione.

Per prima cosa la funzione converte il parametro value in una stringa di caratteri; il

risultato della conversione è scritto nella variabile locale string. Tale operazione avviene

per mezzo della funzione ecvt, la quale riceve, fra gli altri, un parametro di tipo intero:

dec; in cui viene scritto il numero di decimali della variabile value, secondo la regola

evidenziata nella seguente tabella, in cui X rappresenta una qualsiasi cifra compresa tra

1 e 9:

Tipo di numero Valore di dec

XXX,XX 3

XX,XXX 2

X,XXXX 1

0,XXXX 0

0,0XXX -1

0,00XX -2

0,000X -3

Utilizzando dec è possibile impostare correttamente la posizione dell’eventuale

punto decimale sul display. Se il valore di dec è maggiore di zero sarà sufficiente

eseguire il seguente assegnamento: display.point = MAX_DIGIT-dec, altrimenti la

variabile point assumerà il valore 4, che nell’enumerazione corrisponde a left.

Particolare attenzione va riposta nel caso in cui dec sia minore o uguale a zero;

in questa situazione, infatti, la funzione ecvt elimina tutte le cifre zero a sinistra della

prima cifra non nulla, rendendo così necessario reintrodurre tali cifre. Per far questo, si

trasla il contenuto della variabile string verso destra e si introduce nelle posizioni

lasciate vuote il carattere 0. In particolare, se dec è pari a 0, si trasla a destra di una

Page 121: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

121

posizione, se dec vale -1 si trasla a destra di due e così via. Tale operazione è svolta da

un’apposita funzione denominata shift.

In questo modo, tutte le informazioni necessarie alla visualizzazione di un

numero vengono immesse nella struttura DISPLAY.

6.2.2.2. Funzione di lettura

La funzione decode() consente di “leggere” il numero impostato nella struttura

DISPLAY; nella pratica svolge l’operazione inversa di encode: decodifica una sequenza

di caratteri in un valore numerico. Anche in questo caso, l’assenza di librerie utili ha

reso più complicata l’implementazione di una funzionalità, che, di per se, è banale.

Per prima cosa, tramite la funzione atof si converte il vettore di caratteri della

variabile display in valore numerico, in seguito il numero ottenuto viene diviso per la

potenza di dieci appropriata per ottenere il valore finale correttamente convertito:

value = value/pow(10,display.point)

6.2.2.3. Inizializzazione della variabile display

L’inizializzazione della variabile display è affidata alla funzione setUpDisplay(), la

quale imposta a zero tutte le cifre e disabilita la visualizzazione del simbolo di modifica.

Inoltre, si occupa di eseguire il set-up di tutti i campi di controllo che nella trattazione

della struttura DISPLAY non sono ancora stati introdotti, ma che verranno presentati nel

prossimo paragrafo.

void setUpDisplay()

display.character[0]='\0';

display.character[1]='\0';

display.character[2]='\0';

display.character[3]='\0';

display.character[4]='\0';

display.point=none;

display.sign=0;

display.change=FALSE;

display.swap=TRUE;

display.blinkingDigit=0;

display.blink=FALSE;

Page 122: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

122

6.3. Video

Conclusa la descrizione della rappresentazione interna dei dati, la quale considera

che un valore sia scritto a video nel momento stesso in cui viene impostato nella

variabile display, si affronta ora la descrizione del thread video, il cui compito è quello

di operare l’effettiva scrittura sul display LCD. All’interno del thread sono racchiuse

tutte le attività d’interazione con il dispositivo fisico che avvengono per mezzo delle

funzioni che BrickOS mette a disposizione.

Prima di affrontare nel dettaglio l’implementazione di video, si vuole concludere la

presentazione della struttura dati DISPLAY riportando la descrizione dei campi che

forniscono informazioni di servizio, utili alle operazioni di scrittura.

6.3.1. Campi di controllo nella struttura DISPLAY

Sostanzialmente le informazioni di controllo di cui necessita il task video sono

inerenti al lampeggio di cifre e simboli e relative alla sostituzione della voce

attualmente visualizzata.

In primo luogo, si affronta la necessità di far lampeggiare uno o più elementi del

display, siano essi cifre o punti decimali. A tale scopo si predispongono due campi nella

struttura DISPLAY:

− blink di tipo booleano, indica se il lampeggio deve avvenire o meno (se TRUE

avviene il blinking)

− blinkingDigit, di tipo unsigned int, indica quale (o quali) elemento del display deve

apparire ad intermittenza. La seguente tabella riporta l’indice che a ciascun elemento

viene associato nella variabile blinkingDigit.

Elementi del display Valore di blinkingDigit

Cifra_1 (prima a sinistra) 0

Cifra_2 1

Cifra_3 2

Cifra_4 3

Page 123: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

123

Cifra_5 4

Punto Decimale (vale per tutti e tre) 5

Tutti (5 cifre più l’eventuale punto) 6

L’ultimo campo di cui necessita il thread video è una variabile booleana denominata

swap, la quale, durante la consultazione dei parametri di un regolatore, indica il

passaggio alla successiva voce del menù. A questo punto della trattazione sarebbe

prematuro spiegare la necessità di questo campo; per ora basti sapere che swap viene

settata TRUE ogni volta che si passa da una voce di menù alla successiva e che viene

riportata a FALSE non appena video rileva l’evento.

E’ possibile a questo punto passare alla descrizione dell’implementazione del thread

video.

6.3.2. Thread Video

La funzione svolta da questo task, seppure importante e necessaria, non è

strettamente indispensabile ai fini della regolazione vera e propria operata su un

processo, anzi, si può vedere il tempo di CPU da essa occupato come una limitazione

imposta all’attività di regolazione. Infatti, video è posto in esecuzione concorrente con i

thread che si occupano di eseguire i vari regolatori PID. Se è vero, che nella

configurazione con un solo regolatore, l’esecuzione di video non ostacola l’attività

primaria del sistema è altrettanto vero che, nel caso di vari anelli di regolazione

contemporaneamente gestiti dal sistema, il thread di visualizzazione introduce una

limitazione sulla massima frequenza di campionamento dei diversi regolatori attivi.

Alla luce di queste considerazioni, nell’implementazione di video si é individuato

nella velocità d’esecuzione il principale requisito da soddisfare. Pertanto, solo

considerando la necessità d’ottenere un task molto efficiente, si possono giustificare

molte scelte implementative, che dal punto di vista dell’organizzazione logica del

codice presentano delle incongruenze.

Il thread video è organizzato in due diverse sezioni eseguite in muta esclusione. La

prima si occupa del “Menù PID”, ovvero permette all’utente di selezionare il PID ai cui

Page 124: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

124

parametri intende accedere. La seconda è incaricata di visualizzare il menù parametri

del regolatore selezionato, al quale si farà riferimento con il nome di “Menù Param”. La

mutua esclusione fra le due sezioni è garantita da una variabile globale booleana:

menù_PID, il cui valore viene impostato ad un livello logico superiore da parte del

gestore degli eventi.

6.3.2.1. Menu PID

Permette all’utente di selezionare un regolatore su cui intervenire, ovviamente

l’esecuzione di video può entrare in questa sezione solo se nel sistema sono presenti

almeno due regolatori, in caso contrario viene tralasciata. Menù PID presenta due

modalità di lavoro:

− modalità high-mode: attiva se l’utente è ‘operativo’, ovvero se effettivamente sta

intervenendo sui pulsanti dell’RCX. Più precisamente, la condizione che deve essere

soddisfatta per restare in high-mode è che l’ultima pressione di un pulsante sia

avvenuta da meno di 15 secondi. Per rilevare questa situazione, si utilizza un time

marker, rappresentato dalla variabile globale time_rest, in cui si fissa l’istante

temporale della pressione di uno dei due tasti. Dalla differenza tra l’istante di tempo

attuale (fornito da BrickOS tramite sys_time) e la variabile time_rest è possibile

misurare il tempo trascorso dall’ultima pressione. La condizione da soddisfare è

quindi la seguente: (sys_time-time_rest) < 15000; è da notare che l’unità di misura

temporale in BrickOS è il millesimo di secondo. In high-mode si visualizza

semplicemente l’etichetta relativa al regolatore attualmente selezionato, individuato

dall’indice currentPID. Tale visualizzazione avviene con un periodo di refresh di

500 ms.

− modalità low-mode: attivata se l’operatore non interviene sui pulsanti da almeno 15

secondi. In low-mode sul display viene visualizzata la scritta ‘LOW’ ed il thread

viene posto in attesa che un tasto qualsiasi venga premuto. La sospensione

dell’esecuzione avviene per mezzo della chiamata wait_event(&pushAKey,0), in cui

la condizione di risveglio puschAKey è definita dal seguente blocco di codice:

wakeup_t pushAKey(wakeup_t data)

return (PRESSED(dbutton(),KEY_1) ||

PRESSED(dbutton(), KEY_2));

Page 125: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

125

Alla pressione di uno dei due pulsanti, il sistema reagisce riattivando il thread video e

riportandolo in high-mode.

Quando il task entra in low-mode si ottiene un risparmio della capacità elaborativa

della CPU. In questo modo, il resto del sistema non risulta intralciato dal thread di

visualizzazione dei dati.

6.3.2.2. Menu Param

In questa modalità il thraed ha il compito primario di visualizzare il menù dei

parametri relativo al regolatore attualmente selezionato; tale menù è costituito

principalmente da una serie di voci numeriche alle quali si aggiungono solo due voci

lessicali. Oltre a questo deve poter far lampeggiare le varie voci (come descritto nella

fase di specifica) ed eseguire il tracking di un valore, che consiste nel far apparire in

tempo reale il valore di una variabile.

La descrizione del codice non seguirà l’ordine della sequenza di istruzioni che lo

compongono, si preferisce, infatti, discutere l’implementazione a seconda del tipo di

visualizzazione. In generale, si può affermare che questa sezione di codice è costituita

da una serie di controlli, in base ai quali si predispone il contenuto di una variabile

locale string, la quale, come ultima istruzione (attività) del ciclo, verrà scritta sul

display.

− Visualizzazione di una voce numerica

Consiste nel far apparire sul display, per alcuni istanti, l’etichetta che identifica la

voce e nel mostrare, successivamente, il valore numerico associato. Per fare ciò, in

primo luogo, si controlla se è stata selezionata una nuova voce (display.swap = =

TRUE); in caso positivo si riporta a FALSE la variabile display.swap, si pulisce lo

schermo attraverso la funzione cls() e, dopo una breve attesa, si scrive sul display

per alcuni istanti il nome della voce selezionata. La funzione che consente di

scrivere sul display è la seguente: cputs(menu[currentPID][currentItem].name). A

questo punto, per visualizzare il valore si copia il vettore display.character nella

variabile locale string, quest’ultima verrà visualizzata per mezzo della funzione

cputs(string).

Per quanto riguarda l’eventuale punto decimale la sua apposizione avviene tramite il

seguente segmento di codice:

Page 126: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

126

switch(display.point+offset)

case 4: dlcd_show(LCD_4_DOT);break;

case 3: dlcd_show(LCD_3_DOT);break;

case 2: dlcd_show(LCD_2_DOT);break;

Da notare l’impiego della funzione dlcd_show, una procedura di basso livello

messa a disposizione dal S.O. che consente di visualizzare un singolo segmento del

display dell’RCX. In questo caso si visualizza uno dei tre punti decimali, ai quali si

accede per mezzo delle macro LCD_4_DOT (punto a sinistra), LCD_3_DOT (punto

centrale) e LCD_2_DOT (punto a destra). L’utilità della variabile locale offset, che

in questa funzionalità non sarebbe necessaria, verrà spiegata in seguito descrivendo

il lampeggio di cifre e simboli.

Ad ogni ciclo di refresh, di periodo pari a circa 500ms, vengono ripetute tutte queste

operazioni. Nel caso in cui display.swap risultasse FALSE (l’evento nuova voce è

già stato rilevato) non viene visualizzata l’etichetta, ma semplicemente il valore

numerico della voce.

− Visualizzazione di una voce lessicale

Il thread video riconosce di dover scrivere una voce di questo tipo in base

all’indice currentItem.

Se questo risulta essere pari a POS_MODE si deve gestire la scelta fra la modalità di

funzionamento manuale o automatica. In questo caso si deve, anzitutto, eliminare il

punto decimale (display.point = 0); in seguito si testa la variabile globale manual, il

cui valore è gestito ad un livello logico superiore da parte della “Gestione dei

contesti”. Se manual è TRUE nella variabile string si compone la seguente etichetta:

‘MAN ?’, altrimenti si compone l’etichetta ‘AUTO?’. Queste scritte rappresentano

delle richieste di conferma alla scelta operata, alle quali l’operatore può rispondere

confermando oppure annullando l’impostazione.

Se l’indice currentItem è pari a POS_CONF, significa che l’operatore ha apportato

delle modifiche al menù ed ora è giunto alla richiesta di conferma di tali modifiche

(voce CONF), oppure non ha apportato modifiche, ed essendo presenti più

regolatori, è posto difronte alla scelta di uscire dall’attuale menù (voce EXIT). In

ogni caso, dopo aver eliminato l’eventuale punto decimale e visualizzato la corretta

Page 127: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

127

etichetta (CONF o EXIT), nella variabile string viene composta l’etichetta ‘CONF?’

come richiesta di conferma alla scelta fatta.

Anche per quanto riguarda la voce lessicale l’ultima operazione svolta è la

scrittura della variabile string.

A questo punto della trattazione, si vuol far notare che per quanto riguarda le

etichette, la visualizzazione non passa attraverso la struttura DISPLAY. Questa

scelta, che viene meno all’impostazione data dall’architettura del modulo, si è resa

necessaria, in quanto il passaggio attraverso la struttura che mappa il display fisico

sarebbe inutile (nessuna conversione stringa/numero e numero/stringa è necessaria)

e comporterebbe solo un overhead all’attività del task video.

− Lampeggio di una voce numerica

Questa funzionalità è attivata in relazione alla modifica di una voce numerica. Per

fare apparire ad intermittenza uno o più elementi del display si è deciso di adottare il

seguente procedimento: ad una prima iterazione di questo segmento di codice, sul

display sono visualizzati tutti gli elementi che compongono il numero in questione.

Al ciclo successivo, solo gli elementi che devono lampeggiare vengono cancellati,

mentre il resto del numero viene riscritto. Continuando ad eseguire in sequenza

queste due fasi si produce l’effetto di far apparire in maniera intermittente gli

elementi voluti per tutto il tempo necessario.

Sulla base della descrizione qui sopra riportata, si passa ora alla discussione

dell’implementazione di tale meccanismo.

In primo luogo si verifica la condizione per entrare in questa sezione di codice:

display.blink == TRUE && flag == TRUE. La prima variabile controlla se è

richiesto il lampeggio, mentre flag è utilizzata per ottenere la discriminazione tra le

due fasi che compongono l’intermittenza. Questa variabile viene complementata al

termine di ogni ciclo del thread. Quando la condizione è verificata, per prima cosa si

individua quale elemento del numero deve lampeggiare:

! se display.blinkingDigit è minore di 5, significa che deve lampeggiare un solo

carattere, così lo si cancella attraverso la seguente istruzione:

string[display.blinkingDigit] = blank, dove blank corrisponde allo spazio

vuoto (blank = ‘ ‘).

! se display.blinkingDigit è pari a 5 sarà il punto decimale a dover lampeggiare.

Page 128: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

128

Per far ciò si pone offset = - display.point, in questo modo la somma di offset

e display.point risulta zero ed il segmento di codice preposto alla scrittura non

rileverà nessun punto da visualizzare (tale segmento è stato riportato nella

sezione “Visualizzazione voce numerica”.

! se display.blinkingDigit è uguale a 6, significa che tutti gli elementi che

compongono il numero devono lampeggiare, pertento si cancellerà l’eventuale

punto, con la tecnica appena descritta e le cinque cifre ponendo ciascun

elemento di string pari blank.

La scelta di utilizzare le variabili locali string e offset trova in questa procedura

la sua spiegazione. Infatti, operando sulle due variabili si evita d’intervenire

direttamente sulla struttura DISPLAY consentendo all’operatore di modificare i

parametri a suo piacimento senza correre il rischio di perdere informazioni.

− Tracking di una variabile

Consentire il monitoraggio di una variabile è un’attività irrinunciabile in un

regolatore PID; nel progetto in questione si è stabilito di applicare questa

funzionalità alla Process Value. Per implementarla è necessario operare un continuo

aggiornamento della variabile display invocando ad ogni ciclo del thread la funzione

encode. Questa funzionalità viene attivata quando la variabile globale trackingPV

viene settata TRUE, il controllo di quest’ultima è operato ad un livello logico

superiore da parte della “Gestione dei contesti”. L’implementazione del tracking

avviene attraverso la seguente riga di codice:

if(trackingPV) encode((double)PIDloop[currentPID].PV);

Si conclude la trattazione delle funzionalità offerte da video, riportando

l’implementazione della visualizzazione del simbolo di modifica, che utilizza

l’istruzione dlcd_show di cui si è già parlato.

if(display.change)

dlcd_show(SYMBOL_OF_CHANGE);

else dlcd_hide(SYMBOL_OF_CHANGE);

Si è definito SYMBOL_OF_CHANGE in rappresentanza della macro LCD_DOT_0 che

individua il simbolo del display selezionato a tale scopo.

Page 129: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

129

7. LIBRERIE

Con il termine “libreria” si vuole indicare un insieme di funzioni accessorie,

generalmente basate su algoritmi standard, che offrono servizi largamente utilizzati dai

programmatori durante lo sviluppo delle applicazioni.

BrickOS, oltre ad essere un sistema operativo per l’RCX, rappresenta anche un

ambiente di sviluppo per il programmatore; pertanto, dovrebbe rendere disponibili una

serie di librerie volte a facilitare l’attività di implementazione e, al contempo, ad

aumentarne l’efficacia. Allo stato attuale del suo sviluppo, BrickOS fornisce una sola

libreria (Math.h) costituta da una sola funzione che permette di generare un numero

casuale (random()). Purtroppo, anche la realizzazione di nuove librerie risulta

problematica, in quanto non sono ancora stati definiti con precisione gli standard di

sviluppo, le procedure di messa in opera e le regole di visibilità. Inoltre, le librerie non

possono essere caricate dinamicamente in memoria, come avviene per i programmi

utente, ma devono essere compilate insieme all’intero sistema operativo e scaricate con

esso sull’RCX.

Per tutte queste ragioni, si è scelto di implementare le funzioni di libreria come

semplici funzioni definite nello stesso ambiente operativo dell’applicazione di controllo.

Alcune di esse sono state costruite a partire da algoritmi standard disponibili in

letteratura, altre sono state progettate ex-novo. E’ possibile classificarle in:

- Libreria Matematica: permette di eseguire operazioni di natura aritmetica o

algebrica. Include le seguenti funzioni:

! pow: calcola la potenza di un numero con esponente intero;

! modf: restituisce la parte intera e la parte decimale di un numero reale;

! idexp: riceve in ingresso due numeri e ritorna il prodotto del primo per il

quadrato del secondo.

- Libreria Stringhe: permette di manipolare singoli caratteri o sequenze di

caratteri. Include le seguenti funzioni:

! isdigit: riceve un parametro di tipo char e restituisce TRUE se si tratta di

una cifra (0…9), FALSE altrimenti;

! ecvt: converte un valore numerico di tipo double in una stringa di caratteri;

! atof: converte una sequenza di caratteri in un valore numerico di tipo

Page 130: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

130

double;

! strcat: concatena due stringhe eliminando gli eventuali spazi vuoti.

La disponibilità di altre librerie avrebbe certamente facilitato alcune fasi dello

sviluppo, ma il costo della loro realizzazione avrebbe abbondantemente superato gli

effettivi benefici.

8. AVVIO DELL’APPLICAZIONE

Quando l’utente preme il pulsante RUN dell’RCX, BrickOS invoca la funzione

main() del programma attualmente selezionato; essa, pertanto, assolve l’importante

compito di avvio del software di controllo.

Può essere logicamente scomposta in due sezioni:

- inizializzazione: comprende tutte le operazioni preliminari da eseguire affinché il

sistema sia pronto ad elaborare i dati e ad interagire con il mondo esterno.

Sostanzialmente, a ciascuna delle tre macroaree (gestione degli eventi, gestione

della visualizzazione, funzione di controllo) individuate in fase di progetto

corrisponde un’opportuna funzione di inizializzazione; inoltre, è necessario

impostare le condizioni iniziali dei due semafori utilizzati per la

sincronizzazione:

setUpPID();

setUpDisplay();

loadMenu();

setContextPID();

sem_init(semDisplay, mutexDisplay, 1);

sem_init(semMenu, mutexMenu, 1);

- avvio dei thread: crea e manda in esecuzione i thread per la gestione della

visualizzazione e degli eventi; ad essi si aggiunge un thread per ogni regolatore

che compone il sistema di controllo.

execi(&video,0,NULL,1,DEFAULT_STACK_SIZE); //Visualizzazione

execi(&keyOne,0,NULL,1,DEFAULT_STACK_SIZE); //Eventi

execi(&keyTwo,0,NULL,1,DEFAULT_STACK_SIZE); //Eventi

Page 131: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

131

execi(&executePID,0,NULL,1,DEFAULT_STACK_SIZE); //PID 0

...

9. SINCRONIZZAZIONE

Quando il software viene strutturato come un set di unità concorrenti (thread)

eseguite in parallelo, risulta necessario utilizzare alcune primitive di sincronizzazione

che permettano di vincolare l’ordine in cui vengono svolte le operazioni da parte dei

vari task (vedi [3]). I semafori rappresentano l’unico meccanismo di sincronizzazione

offerto da BrickOS; nell’ambito del progetto essi vengono utilizzati al solo scopo di

garantire l’accesso in mutua esclusione alle risorse condivise del sistema.

9.1. I semafori

I semafori sono meccanismi di sincronizzazione a basso livello, utilizzati

principalmente quando la comunicazione interprocessuale si realizza tramite variabili

condivise (vedi [3] e [4]). Si può pensare ad essi come a variabili che hanno un valore

intero (s) e tre operazioni associate:

- L’inizializzazione (con un valore non negativo);

- L’operazione “wait”: decrementa il valore del semaforo; se il valore diventa

negativo, il processo che esegue la wait viene sospeso. In termini di pseudo-

codice:

if (s>0)

then s = s-1;

else «sospendi il processo corrente»;

- L’operazione “post”: incrementa il valore del semaforo; se il valore non è

positivo allora uno dei processi sospesi sull’operazione wait viene risvegliato. La

definizione, in pseudo-codice, è la seguente:

if («c’è un processo sospeso sul semaforo»)

then «sveglia il processo»

else s = s+1;

Si consideri una generica risorsa condivisa. Per garantire l’accesso in mutua

Page 132: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

132

esclusione, si associa un semaforo a tale risorsa e lo si inizializza a 1; in questo modo, il

primo processo che esegue wait potrà accedere alla risorsa ed il valore verrà posto a 0.

In seguito, se un altro processo cercherà di accedere alla stessa risorsa, la troverà

occupata, verrà sospeso e il valore di s diventerà -1. Non c’è limite al numero di task

che possono essere sospesi in attesa della risorsa. Quando il processo iniziale rilascia la

risorsa, s viene incrementato e uno dei processi in attesa (se ce ne sono) verrà tolto dalla

coda dei processi sospesi associata al semaforo e potrà accedere alla risorsa non appena

sarà riattivato dal sistema operativo.

9.2. Risorse condivise

Si consideri la situazione in cui il sistema di controllo sia costituito da un singolo

regolatore. In questo caso, all’avvio dell’applicazione verranno lanciati in esecuzione:

- il thread di gestione del display (video);

- i due thread di gestione degli eventi (keyOne e keyTwo);

- il thread che realizza il controllo vero e proprio (executePID).

Un’attenta analisi permette di individuare le risorse condivise, ovvero le strutture dati

sulle quali si basa la comunicazione interprocessuale:

- la variabile display viene scritta dal gestore dei contesti (in risposta agli eventi

generati dall’utente) e letta dal gestore del display (ad ogni ciclo di

visualizzazione);

- le variabili che contengono i parametri del regolatore (PIDa e PIDb) e dell’anello

(PIDloop) possono essere lette e/o scritte sia dal gestore dei contesti (in risposta

agli eventi generati dall’utente) che dalla funzione di controllo vera e propria.

A partire da queste informazioni, è stata elaborata la seguente strategia di

sincronizzazione:

- si definisce un semaforo per la sola variabile display:

sem_t* semDisplay; //Definizione del semaforo

int mutexDisplay = 1; //Valore intero associato al semaforo

sem_init(semDisplay, mutexDisplay, 1); //Inizializzazione

Ogni accesso critico dal punto di vista della concorrenza dovrà rispettare il

seguente schema:

Page 133: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

133

sem_wait(semDisplay); //Accesso alla risorsa

... //Operazioni su display

sem_post(semDisplay); //Rilascio della risorsa

Un possibile esempio è dato proprio dal processo di visualizzazione: quando

parte un nuovo ciclo di refresh del display, il thread video esegue sem_wait sul

semaforo semDisplay; da questo punto in poi, nessuno può accedere a display.

Terminate tutte le operazioni necessarie, video rilascia la risorsa invocando la

funzione sem_post, dopodiché viene sospeso fino al prossimo ciclo di refresh.

- Le variabili PIDa, PIDb e PIDloop vengono protette definendo un semaforo sulla

variabile menu:

sem_t* semMenu;

int mutexMenu = 1;

sem_init(semMenu, mutexMenu, 1);

Questa scelta è giustificata dal fatto che tutte le operazioni di lettura e scrittura

dei parametri, critiche dal punto di vista della concorrenza, possono avvenire

solo tramite la struttura menu; in altri termini, essa costituisce l’unico punto di

accesso a tali parametri. Proteggendo ogni accesso critico a menu, si proteggono

indirettamente anche le variabili associate al regolatore.

A titolo di esempio si consideri la funzione invocata nel caso in cui l’utente

confermi le modifiche apportate ad una voce numerica:

void confirmNumericalItem()

...

sem_wait(semMenu);

*(menu[currentPID][currentItem].value) = (float)decode();

sem_post(semMenu);

setContextMenu();

Prima di concludere la sezione dedicata alla sincronizzazione, è utile precisare che

non tutti gli accessi alle variabili sopraccitate sono protetti mediante l’utilizzo dei

semafori; si è scelto, infatti, di agire solo ed esclusivamente sulle operazioni critiche in

un’ottica di concorrenza fra processi, al fine di preservare e garantire la correttezza

dell’applicazione.

Page 134: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

134

10. Appendice A: STRUTTURE DATI

******************************

* DEFINE *

******************************

#define NUMBER_OF_PIDs 1

#define SIZE_MENU 16

#define MAX_DIGIT 5

#define KEY_1 BUTTON_VIEW

#define KEY_2 BUTTON_PROGRAM

#define SYMBOL_OF_CHANGE LCD_DOT_0

#define POS_SP 10

#define POS_SPi 11

#define POS_PV 12

#define POS_CS 13

#define POS_MODE 14

#define POS_CONF 15

#define MAX_SP 99999

#define TRUE 1

#define FALSE 0

*****************************************

* DEFINIZIONE TIPI E STRUTTURE DATI *

*****************************************

typedef float REAL;

typedef unsigned char BOOL;

typedef struct

REAL K;

REAL Ti;

Page 135: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

135

REAL Td;

REAL N;

REAL b;

REAL c;

REAL Ts;

REAL CSmax;

REAL CSmin;

REAL deltaCSMAN;

PIDPARAMS;

typedef struct

REAL SP;

REAL SPold;

REAL PV;

REAL PVold;

REAL CS;

REAL CSold;

REAL Dold;

BOOL MAN;

BOOL MANinc;

BOOL MANdec;

BOOL HIsat;

BOOL LOsat;

BOOL NoInc;

BOOL NoDec;

BOOL ForceMAN;

BOOL IAmRunning;

PIDLOOPDATA;

typedef struct

char character[MAX_DIGIT];

char sign;

enum pointPosition

left=4,mid_left=3,mid_right=2,right=1,none=0 point;

BOOL change;

BOOL swap;

BOOL blink;

Page 136: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 6 - Implementazione

136

unsigned int blinkingDigit;

DISPLAY ;

typedef struct

char *name;

REAL *value;

BOOL modifiable;

VOCE_MENU;

***************************************

* DICHIARAZIONE VARIABILI GLOBALI *

***************************************

PIDPARAMS PIDa[NUMBER_OF_PIDs],PIDb[NUMBER_OF_PIDs],

*PIDedit[NUMBER_OF_PIDs],*PIDrun[NUMBER_OF_PIDs];

PIDLOOPDATA PIDloop[NUMBER_OF_PIDs];

DISPLAY display;

VOCE_MENU menu[NUMBER_OF_PIDs][SIZE_MENU];

int currentItem=0;

int currentPID=0;

BOOL menu_PID = FALSE;

time_t time_rest = 0;

BOOL trackingPV = FALSE;

sem_t* semDisplay;

int mutexDisplay = 1;

sem_t* semMenu;

int mutexMenu = 1;

BOOL manual;

float memoryChange=0;

Page 137: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

137

Capitolo 7

Test e verifica

Page 138: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

138

In questo capitolo si discuterà la fase di test e verifica dell’applicazione.

1. INTRODUZIONE

L’analisi di correttezza dell’applicazione costituisce un problema concettualmente

diverso a seconda che si considerino i requisiti informali espressi dall’utente o le

specifiche rigorose di progetto. Nel primo caso si parla di convalida, ovvero quel

complesso di attività volte ad appurare la capacità del software sviluppato di soddisfare

le reali necessità dell’utente finale; nel secondo caso, invece, si attua una verifica del

prodotto, con l’obiettivo primario di controllarne la correttezza rispetto alle specifiche

progettuali.

Verifica e convalida vivono un legame di complementarietà; certamente, si tratta di

attività piuttosto complesse che coinvolgono numerosi aspetti del ciclo di vita del

software: dalla definizione dei fattori di qualità, allo studio di metodi per il controllo di

ciascun passo di sviluppo, alla formalizzazione di tecniche per il collaudo del prodotto

finale.

La convalida dell’applicazione, diffusamente trattata in questo capitolo, si basa su

due differenti tecniche di analisi:

- analisi statica: permette di rilevare anomalie basandosi unicamente

sull’osservazione diretta del codice. In altre parole, si tratta di verificare la

validità di determinate proprietà indipendentemente dall’esecuzione;

- analisi dinamica: prevede che il programma venga eseguito per particolari dati di

ingresso, considerati “critici” al fine di rilevare eventuali anomalie.

Nella fase di implementazione, le singole funzionalità di ciascun modulo sono state

sottoposte ad accurata sperimentazione; si ritiene poco opportuno descrivere tutti questi

micro-test, in quanto si appesantirebbe notevolmente la trattazione senza apportare un

reale valore aggiunto.

Nel corso della campagna di test, si è rivelata particolarmente vantaggiosa ed

efficace l’idea di organizzare ciascun modulo del sistema in due parti: la prima, detta

“kernel”, realizza una pura elaborazione dei dati in completa autonomia rispetto

all’RCX; la seconda, invece, realizza il collegamento fra il “kernel” ed il mondo esterno

Page 139: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

139

per mezzo dell’RCX.

Il capitolo è organizzato in due sezioni principali:

- test di modulo: parte dedicata alla verifica dei singoli moduli che costituiscono il

software;

- test di integrazione e di sistema: parte dedicata al controllo delle modalità di

interazione fra i vari moduli e al test dell’intera applicazione da eseguire

sull’RCX.

2. TEST DI MODULO

Ciascuno dei tre moduli realizzati durante la fase di implementazione, viene

estrapolato dal contesto dell’intero sistema di controllo e considerato singolarmente;

l’esecuzione dei test richiede, pertanto, la creazione di un ambiente di lavoro “simulato”

che possa fornire al modulo gli input richiesti ed accettare gli output da esso prodotti,

così che si possa verificare la correttezza delle elaborazioni compiute.

2.1. Test esecuzione KERNEL

In questo paragrafo si presentano le prove sperimentali cui è stata sottoposta tutta

quella parte di codice che realizza la vera e propria elaborazione dei dati e che risulta

sostanzialmente indipendente dalla piattaforma hardware sulla quale può essere

eseguita. Questa caratteristica si traduce immediatamente nella possibilità di eseguire

buona parte dei test su PC, con tutti i vantaggi del caso; in particolar modo, si può

disporre degli strumenti avanzati di debug forniti dai moderni ambienti di sviluppo.

2.1.1. Accesso ai dati

Il software di controllo deve fornire un apposito menù attraverso il quale l’utente

possa agire, in visualizzazione o in modifica, sui parametri di ciascun regolatore. Le

parti di codice di cui s’intende accertare la correttezza sono:

- la struttura dati menu e le funzioni che operano su essa;

- le due strutture dati relative all'algoritmo di regolazione (PIDPARAMS e

Page 140: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

140

PIDLOOP).

- il gestore dei contesti;

Per realizzare il test su PC è necessario simulare il contesto d’esecuzione delle

funzioni da verificare, al fine di creare una mini-applicazione che permetta di scegliere

un regolatore e di far scorrere a video il menù dei suoi parametri; l’applicazione, inoltre,

deve offrire la possibilità di modificare il valore delle voci numeriche, lessicali ed

incrementali, rispettando le procedure previste nelle specifiche di progetto.

Per fare questo è indispensabile simulare le attività svolte dal rilevatore degli eventi e

della visualizzazione dei dati. Per quanto riguarda la prima, i cinque possibili eventi da

rilevare sono simulati per mezzo della tastiera, con la seguente convenzione:

Per ciò che concerne la visualizzazione dei dati, invece, il monitor del PC viene

utilizzato per emulare il display fisico dell’RCX; pertanto, è necessario definire

un’apposita funzione (chiamata stampa()) che visualizzi, oltre al nome ed al valore di

ciascun parametro, una serie di informazioni di controllo: posizione del punto decimale,

attivazione/disattivazione della modalità di lampeggio, attivazione/disattivazione del

simbolo di modifica, modalità di funzionamento del regolatore. Per completezza se ne

riporta il codice:

void stampa()

if(display.swap)

printf("\nNome: ",menu[currentPID][currentItem].name);

printf("\nCifre: %s",display.character);

printf("\nPunto: %d",display.point);

Tasto Evento corrispondente (simulato)

“1” KEY_1_short

“2” KEY_2_short

“3” KEY_2_long

“4” KEY_1_2

“5” KEY_1_long

Page 141: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

141

printf("\nModifica: %d",display.change);

if(display.blink)

printf("\nCifra blink%d",display.blinkingDigit);

printf("\nModalità effettiva:%d",PIDloop[currentPID].MAN);

printf("\n");

A questo punto è possibile presentare i vari casi di test; si partirà dalle situazioni più

semplici per arrivare, via via, a quelle più complesse e critiche ai fini della correttezza.

2.1.1.1. Scorrimento dei menù

Obiettivo

Verificare che il software gestisca in modo opportuno lo scorrimento ciclico dei vari

menù.

Modalità operativa

All’avvio dell’applicazione, si fa scorrere (tasto “1”) interamente il menù dei PID per

più volte, per appurare se il completamento di un ciclo determini comportamenti

indesiderati. Il secondo passo prevede la selezione (tasto “2”) di uno dei regolatori

disponibili e lo scorrimento (tasto “1”) del menù parametri ad esso relativo, con le

stesse modalità viste sopra. Non attuando alcuna modifica, ci si aspetta di vedere

“EXIT” come ultima voce; la pressione del tasto “2” in corrispondenza di essa deve

riportare alla lista dei regolatori.

Risultati

Data la semplicità delle azioni intraprese, è logico aspettarsi un buon comportamento

del sistema già alla prima esecuzione del test. L’unico problema riscontrato è quello

relativo alla visualizzazione della voce “EXIT”; l’anomalia è da ricondursi ad un’errata

formulazione della condizione di visualizzazione di tale etichetta nella funzione

nextItem(), la cui versione corretta risulta essere:

...

if(currentItem==SIZE_MENU-2)

if(display.change==TRUE)

currentItem++;

menu[currentPID][currentItem].name = "CONF ";

Page 142: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

142

else

if(display.change==FALSE && NUMBER_OF_PIDs>1)

currentItem++;

menu[currentPID][currentItem].name="EXIT ";

else currentItem = 0;

...

2.1.1.2. Modifica voce numerica

Obiettivo

Verificare che il sistema rispetti la procedura prevista per questo tipo di parametro

(selezione e modifica di ogni singola cifra, impostazione punto decimale) e, soprattutto,

che la conferma/annullamento di primo livello operino correttamente.

Modalità operativa

Si seleziona un regolatore, si visualizza un parametro numerico (ad esempio “K”) e si

entra nella modalità di modifica (tasto “2”). A questo punto si selezionano, in sequenza,

ciascuna delle cinque cifre ed il punto decimale (tasto “2”), apportando le opportune

variazioni (tasto “1”). Infine, si conferma il nuovo valore per il parametro. Il simbolo di

modifica, ora, deve essere attivo.

Dopo aver riavviato l’applicazione, si eseguono operazioni analoghe sullo stesso

parametro, stavolta annullando le modifiche apportate. Il simbolo di modifica deve

rimanere disattivato.

Si riavvia nuovamente l’applicazione e si agisce su due distinti parametri numerici

(ad esempio “Ti” e “Td”): per il primo si confermano, mentre per il secondo si

annullano le modifiche.

Risultati

Per quanto possa sembrare contraddittorio, un test ha esito positivo quando permette

di rilevare anomalie nel codice, così come succede in questo caso. Si procederà per

ordine di individuazione:

Page 143: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

143

- l’applicazione si blocca sempre al momento della conferma di primo livello. Il

problema è dovuto ad una errata gestione dell’incremento di blinkingDigit a

fronte dell’evento KEY_2_short; ciò impedisce al sistema di applicare il contesto

di conferma nella situazione in cui lampeggiano tutte le cifre ed il punto

decimale. L’istruzione seguente permette di risolvere la questione:

...

if(display.blinkingDigit==6) display.blinkingDigit=0;

else

display.blinkingDigit++;

if (display.blinkingDigit==6)

setContextNumericalItemConfirm();

...

- A seguito della conferma del nuovo valore non risulta possibile visualizzare i

parametri successivi; in altre parole, sembra che il sistema sia insensibile agli

eventi. Il problema non si verifica in caso di annullamento delle modifiche.

L’errore consiste nella mancata riapplicazione del contesto «Menù Parametri» al

termine della funzione confirmNumericalItem() che realizza la conferma di primo

livello. Anomalie di questo tipo sono facili da sanare, ma molto difficili da

individuare.

- La conferma di primo livello delle modifiche non ha alcun effetto; infatti,

facendo scorrere il menù sino a tornare al parametro precedentemente modificato,

il sistema ripropone il valore iniziale. La soluzione di questo problema ha

richiesto un investimento non trascurabile in termini di tempo; l’esecuzione

passo-passo del codice ha permesso di rilevare errori nella gestione dei puntatori

presenti nelle strutture dati PIDLOOP, PIDPARAMS e menu. Si tratta, perlopiù,

di errori che ricorrono frequentemente nelle applicazioni in cui si fa uso di

puntatori; per questo motivo se ne omette la descrizione dettagliata.

- Infine, sono emerse altre anomalie di secondaria importanza (ad esempio: la

mancata attivazione del simbolo di modifica laddove richiesto, l’impossibilità di

Page 144: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

144

spostare il punto decimale) che non vengono presentate in quanto la loro matrice

non è di natura squisitamente concettuale; nella maggior parte dei casi, infatti, si

tratta di dimenticanze e/o errori di battitura.

2.1.1.3. Modifica voce lessicale

Obiettivo

Verificare la correttezza della procedura prevista per questo tipo di parametro. Allo

stato attuale, il menù dei parametri contiene una sola voce lessicale: la modalità di

funzionamento.

Modalità operativa

Una volta entrati nel contesto di modifica della voce MODE, il sistema deve proporre

due soli valori fra cui scegliere: MAN e AUTO. Trattandosi di un parametro descrittivo

dell’anello di controllo, la modifica risulta immediatamente visibile al regolatore (non è

necessaria la conferma di secondo livello); in base alla scelta operata, il sistema decide

se l’utente può accedere in modifica alla voce CS.

Risultati

Il test, così come il codice cui esso fa riferimento, non nasconde particolari insidie,

soprattutto alla luce delle correzioni sinora apportate. Non si rilevano, pertanto,

problemi degni di nota.

2.1.1.4. Modifica voce incrementale

Obiettivo

Verificare che il sistema rispetti la procedura prevista per questo tipo di parametro.

All’interno della struttura menu sono presenti due sole voci incrementali (SPi e CS),

ciascuna delle quali è caratterizzata da un passo d’incremento differente; pertanto, si

vuole valutare la capacità del sistema di impostare il passo di avanzamento corretto,

nonché l’operatività della conferma.

Modalità operativa

Dopo aver selezionato un PID, si accede alla voce SPi e si effettuano operazioni sia

Page 145: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

145

d’incremento (tasto “1”) che di decremento (tasto “4”), facendo attenzione al fatto che il

valore del set-point rimanga nel range 0…MAXSP (dove MAXSP è una costante,

definibile in compilazione, che esprime il valore massimo assumibile dal set-point). Il

passo di incremento/decremento deve essere unitario.

In seguito, si riavvia l’applicazione, si porta il regolatore in modalità manuale e si

agisce sul parametro CS, verificando che il passo di incremento/decremento corrisponda

al valore attuale di deltaCSMAN. Lasciando il regolatore in modalità automatica, deve

essere bloccato l’accesso a CS in modalità di modifica.

Risultati

L’esecuzione del test non porta alla luce alcuna anomalia; le operazioni di

incremento/decremento, così come l’impostazione del passo di variazione, vengono

effettuate correttamente per entrambi i parametri. La logica di accesso alla voce CS

risponde perfettamente ai requisiti progettuali.

2.1.1.5. Conferma (o annullamento) di secondo livello

Obiettivo

Verificare che:

- in caso di conferma, le modifiche apportate dall’utente diventino operative

(visibili al regolatore);

- in caso di annullamento, per ciascun parametro vengano ripristinati i valori

precedenti alle modifiche.

In entrambi i casi il sistema deve tornare al menù di scelta dei PID.

Modalità operativa

Si seleziona un regolatore, si rettificano alcune voci e si confermano i nuovi valori; a

questo punto si accede nuovamente al menù dei parametri e, facendolo scorrere, si

devono leggere i valori precedentemente inseriti. Utilizzando strumenti di debug, si

accede direttamente alle variabili PIDedit e PIDrun associate al regolatore e si verifica

che esse contengano i valori corretti.

E’ evidente che, in caso di annullamento, il sistema deve ripristinare i valori iniziali e

nelle variabili sopra citate non deve rimanere alcuna traccia delle modifiche.

Page 146: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

146

Risultati

Gli interventi correttivi effettuati in occasione dei test precedenti, permettono di

giungere a questo punto con una struttura elaborativa sufficientemente affidabile e

robusta; pertanto, le operazioni di conferma o annullamento vengono portate a termine

in modo regolare, senza sollevare eccezioni.

2.1.2. Algoritmo di controllo

L’algoritmo di controllo, che rappresenta il vero e proprio “cuore” del sistema, ha

coperto buona parte della trattazione: dall’introduzione teorica della legge PID, alla

progettazione del contesto di esecuzione, all’implementazione nell’ambiente BrickOS.

La funzione PID, che rappresenta l’equivalente discreto del regolatore, è stata

realizzata attraverso una semplice attività di codifica dell’algoritmo standard in

linguaggio C; per questo motivo non dovrebbero sorgere, nella fase di test, problemi di

natura concettuale.

Per convalidare la funzione PID è necessario disporre di un processo da controllare;

si può pensare di simulare tale processo discretizzando la sua funzione di trasferimento

e codificandola in linguaggio C. Si consideri il seguente sistema:

Nel dominio del tempo si avrà:

)()()( tetVdt

tdVCR =+

Ponendo RC=τ e passando nel dominio della trasformata di Laplace si trova la

funzione di trasferimento del processo ( )(sG ):

τsCRssEsVsG

sVsCRsVsE

+=

+==

+=

11

11

)()()(

)()()(

Per controllare il sistema è possibile utilizzare un regolatore PI, la cui funzione di

trasferimento risulta essere:

Page 147: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

147

I

IP sT

sTKsR +=

1)( con

==

1P

I

KT τ

L’anello di regolazione assume la seguente configurazione:

A questo punto è necessario discretizzare la funzione di trasferimento del processo

utilizzando «Eulero all’indietro»

−=SzT

zs 1 :

ττ

τ

++−

=

−+=

S

S

S

S

TTkEkVkV

zzTzTzG

)()1()(

)1()(

***

*

Infine, si imposta: FCMR µ100,30 =Ω= ; da cui: 1103 −⋅=τ .

La funzione processo realizza l’equivalente discreto della rete RC:

...

REAL vprec = 0;

...

void processo(REAL controlSignal)

REAL v;

v = (vprec*0.3 + controlSignal*0.03)/(0.03 + 0.3);

vprec = v;

Il regolatore PI viene tarato nel modo seguente:

Parametro Valore

K 1.00

TI 0.30

TD 0.00

Page 148: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

148

b 0.50

TS 0.03

Si dispone, ora, di tutte le informazioni necessarie per simulare il controllo del

sistema.

La simulazione viene eseguita sia su PC che su RCX. I risultati, riportati in

appendice, sentenziano un corretto funzionamento della procedura su entrambe le

piattaforme.

2.2. Test interazione KERNEL-RCX

In questa fase di test, il principale obiettivo è verificare il corretto funzionamento

della parte di codice che si occupa di mettere in comunicazione il “kernel”

dell’applicazione con il mondo esterno. Più precisamente, si verificano le operazioni

d’interazione con l’hardware, realizzate per mezzo delle API che BrickOS mette a

disposizione.

All’interno di ciascun modulo del sistema, si trova una parte di codice che si occupa

esclusivamente del controllo dell’hardware:

- Modulo di “Gestione degli eventi”: la rilevazione degli eventi costituisce

l’attività d’interazione con l’hardware, la quale si concretizza nella gestione dei

pulsanti dell’RCX per mezzo dei thread: keyOne e keyTwo.

- Modulo di “Visualizzazione dei dati”: il dispositivo hardware gestito è il display;

del controllo di tale dispositivo si occupa il thread video.

- Modulo di “Esecuzione del PID”: l’interazione con l’hardware è rappresentata

dalla lettura degli ingressi e dalla scrittura delle uscite. A queste due attività non è

dedicato, come negli altri casi, un task specifico, in quanto vengono

implementate come due sezioni di codice all’interno del thread executePID.

Per ognuna delle tre sezioni, qui sopra riportate, sono condotte delle prove specifiche

per verificarne la correttezza; nei paragrafi che seguono si riporta la descrizione di

tali prove.

Page 149: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

149

2.2.1. Controllo dei pulsanti

Come già accennato, questa attività viene svolta dai thread keyOne e keyTwo, il cui

compito è quello di rilevare gli eventi.

Obiettivo

L’obiettivo della campagna di test sui due thread è di accertare che siano in grado di

rilevare tutti gli eventi previsti nella definizione del sistema:

- KEY_1_short → pressione breve tasto 1 (pulsante VIEW)

- KEY_1_long → pressione lunga tasto 1

- KEY_2_short → pressione breve tasto 2 (pulsante PRGM)

- KEY_2_long → pressione lunga tasto 2

- KEY_1_2 → pressione combinata tasto1 + tasto2

Pertanto, si vuole accertare sia il funzionamento individuale di ciascun task, sia il

loro funzionamento combinato.

Metodo operativo

Per realizzare il test si crea un apposito «main program», nel quale i due thread

vengono lanciati in esecuzione concorrente:

int main()

execi(&keyOne,0,NULL,1,DEFAULT_STACK_SIZE);

execi(&keyTwo,0,NULL,1,DEFAULT_STACK_SIZE);

Al fine di rendere più agevole l’esecuzione del test, si apportano delle piccole

aggiunte al codice dei task, che consentono la visualizzazione di etichette riportanti il

nome dell’evento rilevato.

Il test vero e proprio avviene scaricando il programma di prova sull’RCX e agendo

sui pulsanti al fine di generare tutti gli eventi previsti, più volte e in diverso ordine.

Risultati

I test condotti si dimostrano efficaci, infatti permettono sia di rilevare alcuni piccoli

errori nel codice, che di perfezionare alcuni meccanismi. Le correzioni apportate

portano alla realizzazione di un sistema di rilevazione degli eventi particolarmente

Page 150: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

150

efficiente e robusto, che soddisfa appieno le esigenze progettuali.

2.2.2. Controllo del display

La verifica del funzionamento del thread video, preposto alla gestione del display, è

una attività complessa ed estesa rispetto a quella relativa ai pulsanti. Infatti, non è

possibile individuare un numero finito di eventi/scenari da esaminare, ma si può

soltanto individuare un insieme di casi significativi.

Obiettivo

L’attività di test è volta ad accertare che il task realizzi correttamente tutte le

funzionalità che gli sono richieste: visualizzazione dei due tipi di menù (menù PID e

menù Param), rispetto delle modalità di funzionamento (high-mode e low-mode),

visualizzazione di tutti i tipi di voci di menù (numerica e lessicale), visualizzazione

dell’etichetta al cambio di voce, esposizione del simbolo di modifica e lampeggio di

cifre e punti.

Metodo operativo

Per realizzare il test su video è necessario, in primo luogo, simulare il contesto di

esecuzione del task; per far questo si inizializzano le varibili menu e display. Si procede

poi ad implementare vari programmi di prova che, una volta in esecuzione, impegnino il

thread in una serie di attività che consentano di accertarne il corretto funzionamento.

Di seguito è riportato il codice di un programma di prova per la verifica delle

funzionalità di base del thread: visualizzazione di cifre numeriche e di etichette,

scrittura del punto in tutte le posizioni possibili, lampeggio, sia individuale che

collettivo, di tutti gli elementi e, infine, visualizzazione del simbolo di modifica.

int main()

//inizializzazione delle variabili display e menu

inizializzaDisplay();

caricaMenu();

//lancio del thread video

execi(&video,0,NULL,1,DEFAULT_STACK_SIZE);

Page 151: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

151

//test sul punto decimale

display.punto=sinistra;

msleep(500); //attesa di 500 msec.

display.punto=centro_sinistra;

msleep(500);

display.punto= centro_destra;

msleep(500);

//test sul cambio di voce

display.cambio=TRUE; //deve essere visualizzata

//l’etichetta relativa

//test sul lampeggio

display.blink=TRUE;

display.cifraBlink=0; // prima cifra a sinistra

sleep(2); //attesa di 2 sec.

display.cifraBlink=1; // seconda cifra

sleep(2);

display.cifraBlink=2; // terza cifra

sleep(2);

display.cifraBlink=3; // quarta cifra

sleep(2);

display.cifraBlink=4; // quinta cifra

sleep(2);

display.cifraBlink=5; // punto in tutte le posizioni

sleep(2);

display.punto=sinistra;

sleep(2);

display.punto=centro_sinistra;

sleep(2);

display.punto= centro_destra;

sleep(2);

display.cifraBlink=6; // tutte le cifre più il punto

sleep(2);

display.blink=FALSE;

//test sul simbolo di modifica

display.modifica=TRUE;

Page 152: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

152

Il seguente codice di prova serve per verificare altre funzionalità di video: dopo

l’inizializzazione del contesto e il lancio in esecuzione del thread, si verifica la corretta

visualizzazione dei menù dei PID e dei parametri. In particolare, in “menu PID” si

provano le due modalità di lavoro (high-mode e low-mode) mentre in “menu Param” si

verifica la possibilità di modificare il valore di una cifra mentre sta lampeggiando.

int main()

int i;

//inizializzazione delle variabili display e menu

inizializzaDisplay();

caricaMenu();

//lancio del thread video

execi(&video,0,NULL,1,DEFAULT_STACK_SIZE);

// test menu

// 1 menu PID

menu_PID=TRUE; //ingresso nel menu PID

currentPID=0; //PID da visualizzare

// 1.1 high-mode

for (i=1;i<NUMBER_OF_PIDs;i++)

currentPID=i; //scorrimento del menu

sleep(16); //attesa per entrare in low-mode

// 1.2 low-mode

sleep(3);

menu_PID=FALSE; //uscita dal menu PID

// 2 menu Param

//test modifica di cifre che lampeggiano

display.blink=TRUE;

sleep(3);

display.cifraBlink=0; //lampeggio prima cifra a sin.

Page 153: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

153

sleep(2);

display.carattere[0]='7'; //modifica prima cifra a sin.

sleep(3);

display.cifraBlink=1;

sleep(2);

display.carattere[1]='7';

sleep(3);

display.cifraBlink=2;

sleep(2);

display.carattere[2]='7';

sleep(3);

display.cifraBlink=3;

sleep(2);

display.carattere[3]='7';

sleep(3);

display.cifraBlink=4;

sleep(2);

display.carattere[4]='7';

sleep(3);

Per verificare le restanti funzionalità del thread, si implementano altri programmi di

prova, di cui non si riporta il codice per evitare un eccessivo appesantimento della

trattazione. La modalità operativa rimane, comunque, invariata: si eseguono i

programmi di prova sull’RCX e, laddove la scritta sul display si discosta dalla

visualizzazione prevista, si individua un malfunzionamento, cui corrisponde nel codice

un errore da correggere.

Risultati

La campagna di test consente di individuare e correggere vari errori, portando, così,

alla stesura di un codice in cui è verificata la capacità minima del thread di realizzare le

funzionalità richieste. I casi di test implementati, però, non coprono tutta la casistica

necessaria a certificare la robustezza del codice; a livello di test di modulo, tuttavia, si

valuta più oneroso progettare e realizzare una campagna di test più approfondita e

completa, che relegare l’ulteriore verifica in una fase successiva, a livello di test di

sistema. In pratica, una volta accertata la sostanziale correttezza del task video, si è

Page 154: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

154

preferisce testarlo in maniera più approfondita attraverso l’uso dell’applicazione

completa.

2.2.3. Lettura ingressi e scrittura uscite

Le operazioni di lettura degli ingressi e scrittura delle uscite possono essere

considerate su due differenti livelli di astrazione:

- da un punto di vista “software”, si riconducono a due semplici istruzioni: la

macro LIGHT_X (con 3,2,1=X ), che permette di leggere i dati provenienti dal

sensore X, e l’istruzione motor_X_speed, che consente di impostare la potenza

erogata all’organo attuatore (motore X). Trattandosi di operazioni banali, non si

ritiene utile eseguire una campagna di test solo su esse; inoltre, considerando il

fatto che eventuali errori run-time potranno essere rilevati nella successiva fase di

test del sistema, si ritiene sufficiente, a livello di test sui singoli moduli, eseguire

un’ispezione statica del codice.

- da un punto di vista “hardware”, tali operazioni si realizzano, rispettivamente, per

mezzo di una catena di acquisizione ed una di attuazione. Il corretto

funzionamento della catena di attuazione è garantito dal sistema operativo, in

quanto si tratta, in ultima analisi, di impostare la velocità di un motore. Di

conseguenza, si è deciso di eseguire un’indagine più approfondita sul

funzionamento della catena di acquisizione, la cui realizzazione non è stata

affatto semplice ed ha richiesto la costruzione di componenti hardware “ad-hoc”

e l’utilizzo di device non standard. Si rimanda il lettore alla consultazione

dell’Appendice B per quanto riguarda le prove condotte sulla catena di

acquisizione.

3. TEST DI INTEGRAZIONE E DI SISTEMA

Conclusa la fase di test e verifica condotta sui singoli moduli, si passa ora alla fase

d’integrazione, in cui si uniscono tutti i moduli per formare l’applicazione finita, la

quale verrà posta in esecuzione sull’RCX e testata in maniera approfondita al fine di

rilevarne eventuali malfunzionamenti.

Page 155: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

155

3.1. Accesso ai dati

In questo paragrafo si vogliono descrivere i test condotti per accertare il corretto

funzionamento del meccanismo di gestione dei menù, attraverso il quale l’utente possa

accedere, in visualizzazione o in modifica, ai parametri di ciascun regolatore.

In buona sostanza, si vogliono ripercorrere le prove condotte nell’omonima fase a

livello di singolo modulo, questa volta con la finalità di rilevare malfunzionamenti

causati da problemi di interazione/integrazione fra i moduli.

Per realizzare queste prove si è inizializzato un sistema con più anelli di regolazione,

nessuno dei quali, però, viene collegato al relativo processo fisico.

3.1.1. Scorrimento dei menù

Obiettivo

Verificare che il software gestisca in modo opportuno lo scorrimento ciclico dei

menù e che le modalità operative del menù dei PID (high-mode e low-mode) vengano

rispettate.

Modalità operativa

All’avvio dell’applicazione, si fa scorrere (tasto “View”) interamente il menù dei PID

per più volte, per appurare se il completamento di un ciclo determini comportamenti

indesiderati. Verificata la modalità high-mode, non si interviene più sui pulsanti,

ponendosi in attesa che il sistema di visualizzazione entri in low-mode (visualizzazione

dell’etichetta “LOW”). Il passo successivo consiste nel premere un tasto qualsiasi per

riportare il sistema in high-mode, per poi procedere con la selezione (tasto “Prgm”) di

uno dei regolatori disponibili e lo scorrimento (tasto “View”) del menù parametri ad

esso relativo.

Non si attua alcuna modifica; pertanto ci si aspetta di vedere “EXIT” come ultima

voce; la pressione del tasto “Prgm” in corrispondenza di essa deve riportare alla lista dei

regolatori.

Risultati

Nonostante sia la prima attivazione del sistema completo, l’applicazione, aiutata

Page 156: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

156

dalla semplicità delle operazioni, si comporta in modo soddisfacente svolgendo tutte le

attività secondo le previsioni. Va riportato che si riscontra una fastidiosa lentezza nello

scorrimento dei parametri, dovuta ad un tempo di visualizzazione delle etichette troppo

lungo. Pertanto, si interviene riducendo il tempo di esposizione dell’etichetta della voce

di menù selezionata.

3.1.2. Modifica voce numerica

Obiettivo

Verificare che il sistema esegua correttamente la procedura prevista per questo tipo

di parametro (selezione e modifica di ogni singola cifra, impostazione punto decimale),

prestando particolare attenzione agli aspetti di visualizzazione (lampeggio di cifre e

punto decimale).

Modalità operativa

Si seleziona un regolatore, si visualizza un parametro numerico (ad esempio “K”) e si

entra nella modalità di modifica (tasto “Prgm”). A questo punto la prima cifra a sinistra

deve apparire ad intermittenza; su di essa è ora possibile operare modifiche

(tasto”View”) al termine delle quali si passa alla cifra successiva (tasto “Prgm”).

Seguendo questo procedimento si scorrono, facendo lampeggiare una alla volta, tutte le

cinque cifre ed il punto decimale, fino a quando tutti gli elementi del display appaiono

ad intermittenza. A questo punto si conferma il nuovo valore per il parametro. Il

simbolo di modifica, ora, deve essere attivo.

Dopo aver riavviato l’applicazione, si eseguono operazioni analoghe sullo stesso

parametro, stavolta annullando le modifiche apportate. Il simbolo di modifica deve

rimanere disattivato.

Si riavvia nuovamente l’applicazione e si agisce su due distinti parametri numerici

(ad esempio “Ti” e “Td”): per il primo si confermano, mentre per il secondo si

annullano le modifiche.

Risultati

Il test si rivela efficiente, in quanto consente di individuare alcune anomalie che

minano la correttezza del comportamento del sistema. Fortunatamente, a questo punto

Page 157: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

157

dello sviluppo, gli errori individuati nel codice non sono di natura concettuale, ma

semplicemente frutto della distrazione o di dimenticanze, perciò la correzione non

implica il ripensamento di alcuni meccanismi, come, invece, si era temuto in una prima

fase.

3.1.3. Modifica voce lessicale

Obiettivo

Verificare la correttezza della procedura prevista per questo tipo di parametro. Allo

stato attuale, il menù dei parametri contiene una sola voce lessicale: la modalità di

funzionamento. E’ necessario verificare, inoltre, che solo in corrispondenza della

modalità manuale sia possibile modificare il valore della voce CS.

Modalità operativa

Una volta entrati nel contesto di modifica della voce MODE, il sistema deve proporre

due soli valori fra cui scegliere: MAN e AUTO. Trattandosi di un parametro descrittivo

dell’anello di controllo, la modifica risulta immediatamente visibile al regolatore (non è

necessaria la conferma di secondo livello).

In un primo momento, si seleziona la modalità MAN, in corrispondenza di tale

impostazione, si scorre il menù fino a raggiungere la voce CS, che deve essere possibile

modificare (secondo la procedura “modifica di una voce incrementale”, trattata nel

prossimo paragrafo).

La seconda fase consiste nel ritornare alla voce MODE, reimpostare la modalità

AUTO ed in corrispondenza di tale selezione accertare che non sia più possibile

modificare la voce CS.

Risultati

Il test non mette in luce alcun malfunzionamento, il che suggerisce di ripetere le

prove seguendo un diverso ordine nell’eseguire le operazioni. Anche a seguito di queste

nuove procedure non si riscontrano malfunzionamenti. Si affida ai successivi test,

riguardanti un regolatore che interagisce con un processo reale, la verifica definitiva

della selezione della modalità operativa.

Page 158: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

158

3.1.4. Modifica voce incrementale

Obiettivo

Verificare la corretta esecuzione della procedura prevista per questo tipo di

parametro. All’interno della struttura menu sono presenti due sole voci incrementali

(SPi e CS), ciascuna delle quali è caratterizzata da un passo di incremento differente;

pertanto, si vuole valutare la capacità del sistema di impostare il passo di avanzamento

corretto, nonché l’operatività della conferma.

Modalità operativa

Dopo aver selezionato un PID, si accede alla voce SPi e si effettuano operazioni sia

di incremento (tasto “View”) che di decremento (tasto “View” + tasto”Prgm”). Il passo

d’incremento/decremento deve essere unitario.

In seguito, si riavvia l’applicazione, si porta il regolatore in modalità manuale e si

agisce sul parametro CS, verificando che il passo d’incremento/decremento corrisponda

al valore attuale di deltaCSMAN.

Risultati

La prima esecuzione del test rivela una certa difficoltà nelle operazioni di modifica

del valore, in quanto il sistema non reagisce in modo deterministico agli eventi; la

situazione può essere descritta nel seguente modo:

- il semplice incremento unitario del set-point non va sempre a buon fine.

- alcune volte un generico decremento ha, come effetto collaterale, un successivo

incremento del valore.

Essendo sicuri della correttezza individuale di ciascun modulo che interviene

nell’esecuzione di questa procedura, si giunge ad individuare in un problema di

sincronizzazione la fonte dell’anomalia. Infatti, si è dimenticato di racchiudere le

operazioni di accesso alle risorse condivise in un blocco del tipo:

sem_wait(semMenu);

...

...

...

sem_post(semMenu);

Page 159: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

159

A seguito delle modifiche apportate il sistema si comporta correttamente, anche per

quanto riguarda la voce CS, per la quale non si riscontra alcun problema.

3.1.5. Conferma (o annullamento) di secondo livello

Obiettivo

Verificare che:

- in caso di conferma, le modifiche apportate dall’utente diventino operative

(visibili al regolatore);

- in caso di annullamento, per ciascun parametro vengano ripristinati i valori

precedenti alle modifiche.

In entrambi i casi il sistema deve tornare al menù di scelta dei PID.

Modalità operativa

Si seleziona un regolatore, si apportano variazioni ad alcune voci e si confermano i

nuovi valori; a questo punto si accede nuovamente al menù dei parametri e, facendolo

scorrere, si devono leggere i valori precedentemente inseriti. In caso di annullamento, il

sistema deve ripristinare i valori iniziali e nelle variabili puntate da PIDrun e PIDedit

non deve rimanere alcuna traccia delle modifiche.

Risultati

A questo punto del test, quasi tutti i meccanismi legati alla gestione dei dati sono

testati. Quindi è lecito ritenere che l’assenza di anomalie durante la prova sia dovuta alla

sostanziale correttezza del codice in esame.

3.2. Test di carico

Questo test viene eseguito al fine di quantificare la potenza elaborativa dell’RCX. Sia

la progettazione che la successiva implementazione, sono state eseguite tenendo in

particolare considerazione il fatto che l’applicazione fa parte di un sistema “embedded”,

in cui la scarsità di alcune risorse di primaria importanza (ad esempio: tempo CPU,

memoria RAM, …) hanno imposto l’adozione di politiche di ottimizzazione e

risparmio. Esemplare, in tal senso, è il caso del thread video, concepito e strutturato per

Page 160: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

160

minimizzare “l’overhead” relativo alla visualizzazione dei dati.

E’ lapalissiano che l’unico modulo veramente critico dal punto di vista delle

prestazioni temporali è quello che costituisce la realizzazione digitale dell’algoritmo

PID: un mancato rispetto dei vincoli da esso imposti determina l’instabilità dell’intero

sistema. L’attenzione, pertanto, è completamente rivolta al thread executePID, che

esegue in sequenza le tre fasi del ciclo di controllo:

- lettura degli ingressi;

- calcolo della variabile di controllo;

- scrittura delle uscite.

Detto TS il tempo di campionamento determinato in fase di sintesi del regolatore, è

tassativo che il ciclo sopraccitato venga eseguito esattamente ogni TS secondi, pena

l’instabilità e l’imprevedibilità del controllo. Il rispetto di questo vincolo deve

assolutamente essere garantito per ogni regolatore che fa parte del sistema.

Il carico di lavoro complessivo imposto all’RCX è direttamente proporzionale al

numero di regolatori presenti (si ricorda che ad ogni PID corrisponde un thread);

ovviamente, le prestazioni temporali offerte diminuiscono all’aumentare dei regolatori.

Nel seguito si discutono i risultati ottenuti eseguendo la prova di carico in due differenti

situazioni: singolo PID o coppia di PID.

3.2.1. Sistema comprendente un solo PID

In questo paragrafo vengono presentati due differenti test, eseguiti inserendo degli

opportuni “time marker” all’interno della funzione executePID; si ritiene opportuno, ai

fini della chiarezza espositiva, riproporre una schematizzazione di tale funzione:

void executePID()

//Inizializzazione

...

//Ciclo di controllo

while(1)

//1a fase: lettura ingressi

...

//2a fase: calcolo variabile di controllo

...

//3a fase: scrittura uscite

Page 161: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

161

...

//Funzione WAIT_EVENT che temporizza l’esecuzione

//del PID

...

3.2.1.1. Test A: tempo di esecuzione

Obiettivo

Misurare il lasso di tempo che intercorre fra l’istante di inizio di lettura degli ingressi

e l’istante finale di scrittura delle uscite; in altre parole si vuole sapere quanto durano,

nel complesso, le tre fasi del ciclo (escluso il tempo di attesa imposto dalla funzione

wait_event).

Modalità operativa

Si definisce la variabile START (di tipo time_t) e vi si memorizza l’istante temporale

di inizio ciclo; prima dell’invocazione di wait_event si calcola la differenza fra sys_time

(macro definita in BrickOS che fornisce l’istante di tempo attuale) e START.

Risultati

Numerose esecuzioni del test portano a stabilire che il tempo richiesto per la sola

elaborazione dei dati (prime tre fasi del ciclo) può essere quantificato in 10-11ms.

3.2.1.2. Test B: periodo di campionamento

Obiettivo

Verificare che venga rispettato il periodo di campionamento imposto dal regolatore

ed individuare il valore limite di TS che il sistema è in grado di rispettare (TSmin)

Modalità operativa

Si intende contare il numero di cicli completi eseguiti nell’arco di un secondo da

parte del sistema; se il tempo di campionamento TS è effettivamente rispettato, allora il

valore ottenuto deve essere pari a quello teorico, così calcolato:

][][1000

msTms

S

Page 162: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

162

La realizzazione del conteggio richiede semplicemente una variabile intera, inizializzata

a zero ed incrementata di un’unità all’inizio di ciascun ciclo; un “time-marker” permette

di bloccare il conteggio quando è trascorso 1 secondo dall’inizio del primo ciclo.

La prova ha inizio impostando la frequenza di campionamento pari al valore minimo

applicabile che, con la risoluzione attuale, è di 0.001 sec. Se tale valore è rispettato si

individua anche il limite di TS; altrimenti si calcola, sulla base del numero di cicli

compiuti, il valore di TSmin. In seguito, ulteriori prove vengono ripetute per confermare

la correttezza del dato calcolato.

Risultati ottenuti

Nelle condizioni di carico stabilite, l’RCX garantisce l’esecuzione di un massimo di

40 cicli al secondo, corrispondenti ad un periodo di campionamento pari a 25ms. Quelle

appena citate devono essere considerate prestazioni limite; per ragioni di sicurezza e

correttezza nell’elaborazione dei dati si ritiene opportuno considerare il valore di 30ms

come limite inferiore al periodo di campionamento.

3.2.2. Sistema comprendente due PID

Per effettuare il test di carico in questa nuova situazione, si possono seguire le

modalità operative appena descritte. La conclusione che se ne trae non è, purtroppo,

confortante; infatti, le prestazioni temporali offerte subiscono un brusco declino: per

evitare un sovraccarico del sistema, il limite inferiore al tempo di campionamento è pari

a circa 80ms per entrambi i regolatori. Questo, ovviamente, costituisce una forte

limitazione alle applicazioni pratiche effettivamente realizzabili.

3.3. Test finale di regolazione

L’obiettivo di questo test è quello di verificare se l’applicazione, nel suo complesso,

dispone di tutti i requisiti che caratterizzano un buon regolatore digitale: affidabilità,

sicurezza, robustezza, usabilità ed ergonomicità dell’interfaccia utente.

Nel capitolo dedicato all’implementazione, si è già accennato al fatto che si vuole

realizzare, come “banco di prova” del prodotto sviluppato, un anello per il controllo

della velocità di rotazione di un motore, al quale è applicata un’elica simmetrica rispetto

Page 163: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

163

al suo asse; un secondo motore, coassiale al precedente, viene utilizzato come dinamo

tachimetrica.

Il sistema può essere schematizzato nel modo seguente:

Il test si snoda nelle seguenti fasi:

- taratura PID su RCX;

- risposta a variazioni a scalino del set-point;

- applicazione disturbi di carico ed analisi del comportamento;

- funzionamento in modalità manuale.

A conferma dei risultati ottenuti, si presentano alcuni grafici ottenuti dal rilevamento dei

valori assunti dalla variabile controllata; le componenti di rumore ed i disturbi introdotti

dalla catena di acquisizione impediscono una lettura “pulita” dei segnali, per cui gli

andamenti presentati sono affetti da evidenti “perturbazioni”.

Infine, si precisa che i grafici ed i relativi commenti hanno il solo scopo di

dimostrare la correttezza delle elaborazioni eseguite dal sistema; ulteriori dissertazioni

sulle dinamiche di processo e sull’opportunità di effettuare interventi volti ad un

affinamento del controllo esulano dagli scopi di questo capitolo.

3.3.1. Prima fase: taratura del regolatore

Per realizzare il controllo di velocità sopra descritto, si utilizza un regolatore PI, la

cui taratura ha, essenzialmente, base empirica:

Page 164: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

164

Parametro Valore

K 3.00

TI 0.30

TD 0.00

b 0.50

TS 0.03

3.3.2. Seconda fase: variazione a scalino del set-point

Dopo aver impostato correttamente i parametri del regolatore, si impone una variazione

a scalino al set-point, portando il segnale di riferimento ad un valore pari a 100 (si

ricorda che tale parametro può variare nel range 0…MAXSP); la risposta del sistema è

sintetizzata dal grafico seguente (sull’asse delle ascisse è riportato il tempo, mentre

sull’asse delle ordinate la process-value):

Il controllo reagisce, come previsto, aumentando la potenza erogata al motore e questo

determina un aumento della velocità di rotazione. Se, una volta giunti a regime, si

riporta a 0 il set-point, si osserva un nuovo transitorio, al termine del quale l’elica risulta

essere priva di movimento:

Page 165: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

165

3.3.3. Terza fase: disturbi di carico

In questo paragrafo si vuole studiare il comportamento del sistema in presenza di due

differenti disturbi di carico (ciascuno applicato separatamente): aumento dell’attrito e

disturbo sinusoidale.

3.3.3.1. Aumento dell’attrito

Si imposta il set-point al valore 60 e si attende che il sistema giunga a regime:

A questo punto, utilizzando un opportuno meccanismo ad ingranaggi, si simula un

aumento della forza di attrito che si oppone al moto di rotazione; il controllo risponde al

disturbo aumentando la potenza erogata al motore. L’attrito è tale da portare in

saturazione il regolatore; pertanto, la velocità effettiva non raggiunge il valore di

riferimento attualmente impostato:

Infine, rimuovendo il disturbo si dà vita ad un nuovo transitorio che riporta il sistema

nella situazione iniziale:

Page 166: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

166

3.3.3.2. Disturbo sinusoidale

Come nel caso precedente, si imposta il segnale di riferimento al valore 100. A

questo punto si applica una zavorra ad una delle due estremità dell’elica; ciò da origine

ad un disturbo di carico sinusoidale:

Nella parte del percorso circolare in cui la forza di gravità favorisce la rotazione, il

regolatore deve diminuire la potenza erogata al motore, per evitare che il moto subisca

un’accelerazione indesiderata; nella parte rimanente del circuito, invece, il regolatore

deve aumentare la potenza in uscita per contrastare l’effetto della gravità ed evitare,

così, una decelerazione dell’elica. Alla luce di queste considerazioni, si comprende

l’andamento della variabile controllata:

Page 167: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

167

3.3.4. Quarta fase: funzionamento in modalità manuale

Sino ad ora si è analizzato il funzionamento del regolatore in modalità automatica; in

questa fase, si vuole studiare la situazione in cui l’operatore, impostando la modalità

manuale, interviene sul processo tramite un’azione diretta sulla variabile di controllo.

Il test si suddivide in due parti:

- analisi delle commutazioni A/M e M/A;

- controllo del processo in manuale.

3.3.4.1. Commutazioni A/M e M/A «bumpless»

Anzitutto si deve appurare se le commutazioni manuale/automatico ed

automatico/manuale avvengono realmente senza “salti”, così come stabilito nelle

specifiche di progetto. Per rispondere a questo interrogativo è sufficiente operare nel

seguente modo:

- con il regolatore in automatico, si impone una variazione a scalino del set-point,

si attende che il sistema giunga a regime e si passa in modalità manuale; da

questo momento in poi, a meno di un intervento da parte dell’operatore, la

variabile di controllo deve rimanere bloccata al valore che essa aveva nell’istante

in cui è avvenuta la commutazione;

- a partire da questa situazione, l’operatore impone una variazione alla variabile di

controllo (ma lascia immutato il set-point) e verifica che essa abbia effetto sul

processo. Infine, si riporta il regolatore in automatico, prestando attenzione al

fatto che il controllo non subisca brusche variazioni. Al termine del transitorio

innescato dalla commutazione, la variabile controllata avrà raggiunto

nuovamente il set-point.

I dati emersi dall’esecuzione del test permettono di concludere che le commutazioni

della modalità di funzionamento avvengono nel pieno rispetto delle specifiche.

3.3.4.2. Controllo del processo

Si tratta di una prova molto semplice, volta ad accertare che le variazioni imposte

dall’operatore alla variabile di controllo abbiano realmente effetto sul processo. Dalla

semplice osservazione del sistema, risulta evidente che incrementando o decrementando

il valore del parametro CS si verifica, rispettivamente, un incremento o un decremento

Page 168: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

168

della velocità di rotazione. Questa percezione trova, poi, conferma nelle misurazioni

effettuate lungo la catena di acquisizione e di attuazione per alcuni valori campione di

CS.

3.3.5. Osservazioni

A conclusione del test finale di regolazione si vogliono riassumere i principali

risultati ottenuti:

- l’applicazione aderisce in misura soddisfacente alle specifiche di progetto e

risponde in modo adeguato ai requisiti “formulati dall’utente”;

- il modulo di controllo appare affidabile e robusto. All’interno dei limiti

individuati è sempre garantito il rispetto dei vincoli temporali;

- l’interfaccia utente raggiunge un buon livello di ergonomicità ed usabilità.

In estrema sintesi, il prodotto sviluppato può essere considerato un “buon regolatore”

per alcune applicazioni di interesse pratico; è doveroso aggiungere che:

- allo stato attuale è stato implementato un insieme minimo di funzionalità; nel

prossimo futuro il sistema sarà arricchito con una funzione di autotaratura e si

pensa già ad un possibile collegamento in rete fra più RCX.

- il termine “buon regolatore” deve essere contestualizzato nello scenario delle

limitazioni imposte dall’uso combinato di BrickOS e RCX.

4. PROBLEMI NOTI

Si ritiene opportuno, a chiusura di questo capitolo, segnalare alcuni problemi rilevati

durante l’esecuzione dei vari test, per i quali non è ancora stata trovata una soluzione

efficace:

- MODIFICA PARAMETRI

! Frequenza: circa 1 caso su 100 (solo nel caso di singolo anello di controllo)

! Descrizione: all’atto della conferma di primo livello delle modifiche

apportate ad uno dei parametri che descrivono il regolatore, il sistema inizia

a comportarsi in modo anomalo; in particolare, l’azione di controllo sembra

perdere parte della sua efficacia, pur continuando a gestire il processo in

Page 169: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

169

maniera accettabile. Il problema cessa di esistere all’atto della conferma di

secondo livello.

I parametri che descrivono l’anello di controllo non sono affetti da questo

tipo di anomalia.

! Azioni intraprese: non è ancora stato possibile identificare uno scenario

preciso, ovvero un insieme di condizioni al di sotto delle quali si verifica il

fenomeno; ciò è principalmente dovuto alla sua sporadicità. Le attività di

debug e di analisi statica del codice non hanno portato, sino ad ora, risultati

degni di nota.

- SCORRIMENTO MENU’ PARAMETRI

! Descrizione: si consideri il menù dei parametri per un generico regolatore;

se l’utente preme ripetutamente il tasto KEY_1 senza rispettare i tempi di

visualizzazione di ogni singola voce, il display entra in uno stato di

inconsistenza sino a quando tutti gli eventi generati dall’utente attraverso la

pressione del tasto non sono stati “consumati” dal sistema.

! Azioni intraprese: l’introduzione delle primitive di sincronizzazione non ha

permesso di risolvere il problema; esiste la possibilità di inibire gli eventi

nel passaggio da una voce all’altra, ma, data la struttura implementativa, si

tratta di una soluzione poco praticabile.

- FUNZIONAMENTO CONTINUO

! Descrizione: a causa di un bug presente in BrickOs, l’applicazione può

funzionare ininterrottamente per un periodo massimo di 49.7 giorni,

dopodiché l’RCX va in crash e il sistema deve essere riavviato.

5. APPENDICE A: funzione PID

5.1. Test su PC

5.1.1. L’applicazione

Anzitutto si ritiene opportuno presentare gli aspetti essenziali del codice che ha

Page 170: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

170

permesso di verificare il corretto funzionamento dell’algoritmo di controllo.

Inizialmente il set-point viene impostato a 5.0; quando il sistema arriva a regime, si

riporta il segnale di riferimento a 0.

#include<stdio.h>

#include<conio.h>

#include<math.h>

#define TRUE 1

#define FALSE 0

typedef float REAL;

typedef unsigned char BOOL;

typedef struct ... PIDPARAMS;

typedef struct ... PIDLOOPDATA;

//Variabili globali

PIDPARAMS thePID;

PIDLOOPDATA theLOOP;

REAL vprec = 0;

//Funzione di controllo (vedi capitolo 6)

void PID(PIDPARAMS* R, PIDLOOPDATA* L)

...

//Funzione che simula la rete RC

void processo(REAL controlSignal)

REAL v;

v = (vprec*0.3 + controlSignal*0.03)/(0.03 + 0.3);

vprec = v;

theLOOP.PV = v;

void main(void)

int i = 0;

//Inizializzazione PID

Page 171: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

171

thePID.K = 1.0;

thePID.Ti = 0.3;

thePID.Td = 0.0;

thePID.N = 5.0;

thePID.b = 0.5;

thePID.c = 0.0;

thePID.Ts = 0.03;

thePID.CSmax = 100.0;

thePID.CSmin = 0.0;

thePID.deltaCSMAN = 0.5;

theLOOP.SP = 0.0;

theLOOP.SPold = 0.0;

theLOOP.PV = 0.0;

theLOOP.PVold = 0.0;

theLOOP.CS = 0.0;

theLOOP.CSold = 0.0;

theLOOP.Dold = 0.0;

theLOOP.MAN = FALSE;

theLOOP.MANinc = FALSE;

theLOOP.MANdec = FALSE;

theLOOP.HIsat = FALSE;

theLOOP.LOsat = FALSE;

theLOOP.NoInc = FALSE;

theLOOP.NoDec = FALSE;

theLOOP.ForceMAN = FALSE;

clrscr();

//I ciclo di controllo: SP=5.0

theLOOP.SP = 5.0;

for(i=1;i<=100;i++)

PID(&thePID,&theLOOP);

processo(theLOOP.CS);

printf("\n%d:%f %f",i,theLOOP.PV,theLOOP.CS);

Page 172: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

172

//II ciclo di controllo: SP=0

theLOOP.SP = 0.0;

for(i=1;i<=100;i++)

PID(&thePID,&theLOOP);

processo(theLOOP.CS);

printf("\n%d: %f %f",i,theLOOP.PV,theLOOP.CS);

5.1.2. I dati rilevati

Passo di campionamento Set-Point

Control Signal (CS)

Process Value (PV)

1 5 3,000000 0,272727 2 5 3,200000 0,538843 3 5 3,380000 0,797130 4 5 3,542000 1,046664 5 5 3,687800 1,286767 6 5 3,819020 1,516972 7 5 3,937118 1,736985 8 5 4,043406 1,946660 9 5 4,139066 2,145969

10 5 4,225159 2,334987 11 5 4,302643 2,513865 12 5 4,372379 2,682820 13 5 4,435141 2,842122 14 5 4,491627 2,992077 15 5 4,542464 3,133022 16 5 4,588217 3,265312 17 5 4,629395 3,389320 18 5 4,666456 3,505423 19 5 4,699811 3,614004 20 5 4,729830 3,715442 21 5 4,756847 3,810116 22 5 4,781162 3,898392 23 5 4,803046 3,980634 24 5 4,822742 4,057189 25 5 4,840467 4,128396 26 5 4,856421 4,194580 27 5 4,870779 4,256052 28 5 4,883701 4,313111 29 5 4,895331 4,366040 30 5 4,905798 4,415109 31 5 4,915218 4,460574

Page 173: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

173

32 5 4,923697 4,502676 33 5 4,931327 4,541644 34 5 4,938194 4,577693 35 5 4,944375 4,611028 36 5 4,949937 4,641838 37 5 4,954944 4,670302 38 5 4,959449 4,696589 39 5 4,963504 4,720854 40 5 4,967154 4,743245 41 5 4,970438 4,763898 42 5 4,973394 4,782943 43 5 4,976055 4,800499 44 5 4,978449 4,816676 45 5 4,980605 4,831579 46 5 4,982544 4,845303 47 5 4,984289 4,857938 48 5 4,985860 4,869567 49 5 4,987274 4,880268 50 5 4,988547 4,890111

[omissis] 90 5 4,999830 4,996818 91 5 4,999847 4,997093 92 5 4,999863 4,997345 93 5 4,999876 4,997575 94 5 4,999888 4,997786 95 5 4,999899 4,997978 96 5 4,999909 4,998153 97 5 4,999918 4,998314 98 5 4,999927 4,998460 99 5 4,999934 4,998594

100 5 4,999941 4,998717

Variazione a scalino del set-point

101 0 1,999947 4,726101 102 0 1,799952 4,460088 103 0 1,619957 4,201894 104 0 1,457961 3,952446 105 0 1,312165 3,712420 106 0 1,180948 3,482286 107 0 1,062853 3,262338 108 0 0,956568 3,052722 109 0 0,860911 2,853467 110 0 0,774820 2,664499 111 0 0,697338 2,485666 112 0 0,627604 2,316751 113 0 0,564844 2,157487 114 0 0,508360 2,007566 115 0 0,457524 1,866653 116 0 0,411771 1,734391

Page 174: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

174

117 0 0,370594 1,610410 118 0 0,333535 1,494330 119 0 0,300181 1,385771 120 0 0,270163 1,284352 121 0 0,243147 1,189697 122 0 0,218832 1,101437 123 0 0,196949 1,019211 124 0 0,177254 0,942669 125 0 0,159529 0,871475 126 0 0,143576 0,805302 127 0 0,129218 0,743840 128 0 0,116296 0,686791 129 0 0,104667 0,633870 130 0 0,094200 0,584809 131 0 0,084780 0,539352 132 0 0,076302 0,497257 133 0 0,068672 0,458294 134 0 0,061805 0,422250 135 0 0,055624 0,388920 136 0 0,050062 0,358115 137 0 0,045056 0,329655 138 0 0,040550 0,303373 139 0 0,036495 0,279111 140 0 0,032846 0,256723 141 0 0,029561 0,236072 142 0 0,026605 0,217030 143 0 0,023944 0,199476 144 0 0,021550 0,183301 145 0 0,019395 0,168401 146 0 0,017455 0,154678 147 0 0,015710 0,142045 148 0 0,014139 0,130417 149 0 0,012725 0,119718 150 0 0,011453 0,109876

[omissis] 190 0 0,000169 0,003182 191 0 0,000152 0,002906 192 0 0,000137 0,002654 193 0 0,000123 0,002424 194 0 0,000111 0,002214 195 0 0,000100 0,002022 196 0 0,000090 0,001846 197 0 0,000081 0,001686 198 0 0,000073 0,001539 199 0 0,000066 0,001405 200 0 0,000059 0,001283

Page 175: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

175

5.1.3. Il grafico

0,000000

1,000000

2,000000

3,000000

4,000000

5,000000

6,000000

1 10 19 28 37 46 55 64 73 82 91 100 109 118 127 136 145 154 163 172 181 190 199

Passo di campionamento

PVCSSP

Il grafico, che riassume efficacemente i dati presentati in tabella, evidenzia un

funzionamento corretto dell’algoritmo di controllo. Ulteriori commenti sulla dinamica

del processo e sull’andamento dei segnali esulano dagli scopi di questa trattazione.

Il codice completo dell’applicazione, la tabella dei dati ed il grafico sono disponibili

nella cartella TEST_PID contenuta nel CD-ROM allegato.

5.2. Test su RCX

5.2.1. L’applicazione

Per verificare il funzionamento dell’algoritmo di controllo sull’RCX, è sufficiente

inserire nel codice la funzione processo vista in precedenza e modificare la funzione

executePID nel seguente modo:

void executePID()

...

while (1)

//Simulazione processo

PID(PIDrun[0],&PIDloop[0]);

Page 176: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

176

processo(PIDloop[0].CS);

//Questo ritardo è inserito al fine di consentire la //lettura dei valori di PV e CS dal display dell'RCX

msleep(3000);

5.2.2. I dati rilevati

E’ quasi superfluo dire che dal display dell’RCX si leggono gli stessi dati rilevati

durante la simulazione su PC, infatti:

- le funzioni PID e processo, che rappresentano, rispettivamente, l’equivalente

digitale del regolatore e della rete RC, sono assolutamente deterministiche: a

fronte degli stessi dati in ingresso propongono sempre gli stessi dati in uscita;

- non essendoci catene di acquisizione e di attuazione, le due funzioni si scambiano

valori esatti, ovvero privi di quegli errori e di quelle imprecisioni che fatalmente

affliggono ogni misura di un fenomeno fisico.

Per completezza, si precisa che i valori prodotti da questa simulazione hanno una

risoluzione minore rispetto a quelli prodotti dal PC; infatti, l’RCX può visualizzare un

massimo di quattro cifre decimali.

6. APPENDICE B: catena di acquisizione

Per verificare il corretto funzionamento della catena di acquisizione si introduce una

prova specifica al di fuori della campagna condotta sull’intero sistema. Il principale

obiettivo, oltre che rilevare malfunzionamenti, è la raccolta di dati utili al fine di

valutare la bontà del meccanismo realizzato per l’acquisizione della velocità di

rotazione del motore.

6.1. Descrizione del test

Si utilizza un semplice processo costituito da due motori calettatti sullo stesso asse:

uno assume funzione di motore, l’altro funzione di dinamo tachimetrica. Trascurando la

Page 177: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

177

resistenza opposta dalla dinamo, si può considerare che il motore evolva senza carico.

Per il controllo di tale processo si è implementato il seguente programma di prova:

int main()

/* INIZIALIZZAZIONI */

int vel=0;

ds_active(&SENSOR_1);

motor_a_dir(fwd);

motor_a_speed(vel);

/* LANCIO DEL THREAD DI VISUALIZZAZIONE */

execi(&leggi,0,NULL,1,DEFAULT_STACK_SIZE);

while(1)

wait_event(&push,0); //ATTESA PRESSIONE TASTO

vel++; // INCREMENTO VELOCITA’

lcd_int(vel); // SCRITTURA VELOCITA’ MOTORE

msleep(300); // ATTESA DI 300 msec.

cls(); // PULIZIA DISPLAY

wait_event(&pull,0); //ATTESA RILASCIO TASTO

motor_a_speed(vel); //IMPOSTAZIONE VELOCITA’

/* FUNZIONE CHE RILEVA LA PRESSIONE DEL TASTO VIEW */

wakeup_t push(wakeup_t data)

return PRESSED(dbutton(),BUTTON_VIEW);

/* FUNZIONE CHE RILEVA IL RILASCIO DEL TASTO VIEW */

wakeup_t pull(wakeup_t data)

return RELEASED(dbutton(),BUTTON_VIEW);

/* THREAD CHE SI OCCUPA DI LEGGERE E VISUALIZZARE IL VALORE MISURATO DAL SENSORE */

void leggi()

Page 178: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

178

while(1)

lcd_int(LIGHT_1);

msleep(500);

Il programma consente, ad ogni pressione del tasto VIEW, d’incrementare

unitariamente il valore corrispondente alla potenza applicata al motore (inizializzata a 0

all’avvio dell’applicazione). Durante il normale funzionamento, la misura della velocità

di rotazione viene visualizzata sul display; solo durante la pressione del tasto viene

scritto il valore della potenza erogata al motore.

Il test consiste nell’applicare al motore tutti i possibili valori di potenza (0÷255) e, in

corrispondenza di ciascuno di essi, rilevare la misura riportata sul display dell’RCX ed

il valore di tensione prelevato in uscita dal filtro RC del circuito di condizionamento. I

dati raccolti sono riportati nel successivo paragrafo.

6.2. Risultati del test

Potenza Vf [V] Misura

0 0 95 1 0 95 2 0 95 3 0 95 4 0,1 94 5 0,2 93 6 0,4 87 7 0,5 81 8 0,6 77 9 1 70

10 1,1 65 11 1,5 62 12 1,6 57 13 1,7 55 14 1,9 52 15 2 50 16 2,1 48 17 2,2 46 18 2,3 45 19 2,3 44 20 2,5 41

21 2,5 40 22 2,5 39 23 2,6 36 24 2,7 36 25 2,8 36 26 2,8 35 27 2,8 35 28 2,8 35 29 2,8 35 30 2,8 35 31 2,8 35 32 2,9 33 33 3 33 34 3 33 35 3 33 36 3 33 37 3,1 32 38 3,2 25 39 3,3 20 40 3,3 20 41 3,3 20 42 3,5 19

43 3,5 19 44 3,5 19 45 3,5 18 46 3,5 17 47 3,5 17 48 3,5 17 49 3,5 16 50 3,5 16 51 3,6 15 52 3,6 15 53 3,6 15 54 3,7 14 55 3,7 14 56 3,7 14 57 3,7 14 58 3,8 12 59 3,8 12 60 3,8 12 61 3,8 12 62 3,8 11 63 3,8 11 64 3,8 11

Page 179: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

179

65 3,9 11 66 3,9 11 67 3,9 11 68 3,9 10 69 3,9 10 70 3,9 10 71 3,9 10 72 4 9 73 4 9 74 4 9 75 4 9 76 4 9 77 4 9 78 4 9 79 4 9 80 4 9 81 4 9 82 4 9 83 4,1 7 84 4,1 7 85 4,1 7 86 4,1 7 87 4,1 7 88 4,1 7 89 4,1 7 90 4,1 7 91 4,1 7 92 4,1 7 93 4,1 7 94 4,1 7 95 4,1 7 96 4,1 6 97 4,1 6 98 4,1 6 99 4,1 6 100 4,1 6 101 4,1 6 102 4,1 6 103 4,1 6 104 4,1 5 105 4,1 5 106 4,1 5 107 4,2 5 108 4,2 5 109 4,2 5 110 4,2 5 111 4,2 5 112 4,2 5 113 4,2 5 114 4,2 5 115 4,2 5

116 4,2 5 117 4,2 5 118 4,2 5 119 4,2 5 120 4,2 5 121 4,2 5 122 4,2 5 123 4,2 5 124 4,2 5 125 4,2 5 126 4,2 5 127 4,2 5 128 4,2 5 129 4,2 5 130 4,2 5 131 4,2 5 132 4,2 5 133 4,2 5 134 4,2 5 135 4,2 4 136 4,2 4 137 4,2 4 138 4,2 4 139 4,2 4 140 4,2 4 141 4,2 4 142 4,2 4 143 4,3 4 144 4,3 4 145 4,3 4 146 4,3 4 147 4,3 4 148 4,3 4 149 4,3 4 150 4,3 4 151 4,3 4 152 4,3 4 153 4,3 4 154 4,3 4 155 4,3 4 156 4,3 4 157 4,3 4 158 4,3 4 159 4,3 4 160 4,3 4 161 4,3 4 162 4,3 4 163 4,3 4 164 4,3 4 165 4,3 4 166 4,3 4

167 4,3 4 168 4,3 4 169 4,3 4 170 4,3 4 171 4,3 4 172 4,3 4 173 4,3 4 174 4,3 4 175 4,3 4 176 4,3 4 177 4,3 4 178 4,3 4 179 4,3 4 180 4,3 4 181 4,3 4 182 4,3 4 183 4,3 4 184 4,3 4 185 4,3 4 186 4,3 4 187 4,3 4 188 4,3 4 189 4,3 4 190 4,3 4 191 4,3 4 192 4,3 4 193 4,3 4 194 4,3 4 195 4,3 4 196 4,3 4 197 4,3 4 198 4,3 4 199 4,3 4 200 4,3 4 201 4,3 4 202 4,4 3 203 4,4 3 204 4,4 3 205 4,4 3 206 4,4 3 207 4,4 3 208 4,4 3 209 4,4 3 210 4,4 3 211 4,4 3 212 4,4 3 213 4,4 3 214 4,4 3 215 4,4 3 216 4,4 3 217 4,4 3

Page 180: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7 - Test e verifica

180

218 4,4 3 219 4,4 3 220 4,4 3 221 4,4 3 222 4,4 3 223 4,4 3 224 4,4 3 225 4,4 3 226 4,4 3 227 4,4 3 228 4,4 3 229 4,4 3 230 4,4 3

231 4,4 3 232 4,4 3 233 4,4 3 234 4,4 3 235 4,4 3 236 4,4 3 237 4,4 3 238 4,4 3 239 4,4 3 240 4,4 3 241 4,4 3 242 4,4 3 243 4,4 3

244 4,4 3 245 4,4 3 246 4,4 3 247 4,4 3 248 4,4 3 249 4,4 3 250 4,4 3 251 4,4 3 252 4,4 3 253 4,4 3 254 4,4 3 255 4,4 3

Il seguente grafico esprime la relazione fra la potenza applicata al motore e la

velocità acquisita attraverso la catena degli input.

0102030405060708090

100

0 50 100 150 200 250 300Potenza Applicata

Mis

ura

Acq

uisi

ta

Dall’osservazione dei dati raccolti emerge, in maniera evidente, un fatto già

introdotto nel Capitolo 3: attraverso la funzione motor_X_speed(int speed) non si

imposta direttamente un valore di velocità di rotazione, ma bensì la potenza applicata

dal motore. Il grafico aiuta a mettere in evidenza questo fatto; in esso, infatti, si può

vedere che per valori bassi di potenza, a fronte di piccole variazioni della potenza

Page 181: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 7

181

applicata, si riscontrano significative variazioni della velocità rilevata, mentre

significativi incrementi, applicati a valori di potenza elevati, non producono rilevanti

variazioni nella misura di velocità. Tale andamento è reso ancor più evidente dal fatto

che al motore è applicato un carico ridotto.

Per concludere, si può affermare che, anche se le misure realizzate non sono

particolarmente stabili, complessivamente la catena di acquisizione soddisfa le esigenze

progettuali. Bisogna, infatti, tenere presente che il sistema di misura della velocità,

realizzato per questo progetto, è unico nell’ambiente BrickOS.

Page 182: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 8

182

Capitolo 8

Conclusioni

Page 183: Progettazione e realizzazione di un regolatore PID su architettura ...

Capitolo 8

183

1. CONCLUSIONI

Alla luce degli esiti dei test e di ulteriori prove, svolte al di fuori della campagna di

verifica e convalida, si possono considerare raggiunti gli obiettivi iniziali del progetto. Il

sistema realizzato ha dimostrato di poter regolare in maniera soddisfacente un processo

reale, fornendo un’interfaccia utente che, pur essendo assai spartana, risulta essere

efficiente. Inoltre, gli accorgimenti implementativi, adottati nella realizzazione

dell’applicazione, consentono alla stessa di poter essere sviluppata ulteriormente

attraverso l’aggiunta di nuove funzionalità (ad esempio autotuning) e di poter essere

inserita all’interno di un sistema di controllo più vasto, costituito da una rete di

dispositivi RCX.

Il prodotto realizzato, ovviamente, non può, e non deve, essere posto a diretto

confronto con prodotti “professionali” analoghi, a causa delle forti limitazioni introdotte

dal supporto hardware, ma soprattutto perché non è questa la finalità per cui è stato

realizzato. In realtà, più che il prodotto stesso (unico nell’ambiente RCX-BrickOS),

sono le attività di progettazione e realizzazione del regolatore ad assumere importanza,

in quanto hanno costituito per gli autori una valida opportunità per mettere in pratica le

conoscenze acquisite nel loro percorso formativo, rivelandosi un importante momento

di apprendimento e crescita. Sotto questo punto di vista, il progetto descritto assume

grande importanza, in particolare tenendo conto del carattere fortemente

interdisciplinare delle attività svolte, che spaziano dall’ingegneria del software

(organizzazione e gestione metodica di un progetto) sino all’automazione (fondamenti e

tecnologia dei sistemi di controllo), passando attraverso argomenti diversi tra loro quali:

sistemi operativi (sincronizzazione interprocessuale e gestione delle risorse condivise)

ed elettronica (progettazione e costruzione di un circuito di condizionamento).

A fronte di tutte le valutazioni precedenti, non si può che valutare in maniera

positiva il progetto, il che è vero, a maggior ragione, se si considera il fatto che esso

rientra di diritto in una vivace comunità ricca di spunti come quella di BrickOS, oltre

che nell’ambito accademico. Pertanto, il lavoro svolto si propone anche come un punto

di appoggio per nuovi progetti, nella speranza che siano anch’essi così proficui.

Page 184: Progettazione e realizzazione di un regolatore PID su architettura ...

Bibliografia

184

Bibliografia

Page 185: Progettazione e realizzazione di un regolatore PID su architettura ...

Bibliografia

185

1. Testi

[1] A. Leva, “Introduzione al PID industriale”, aprile 2000.

[2] G. Magnani, “Tecnologie dei sistemi di controllo”, Italia, McGraw-

Hill, marzo 2000.

[3] C. Ghezzi, M. Jazayeri, “Programming language concepts”, USA,

John Wiley & Sons, 1998.

[4] W. Stallings, “Sistemi Operativi”, Jackson Libri.

[5] A. Fuggetta, C. Ghezzi, S. Morasca, A. Morzenti, M. Pezzè,

“Ingegneria del software”, Italia, Mondadori Informatica.

2. Siti web e documentazione

[6] LegOS Homepage, http://legOS.sourceforge.net

[7] Luis Villa, “The LegOS HOWTO”, http://legos.sourceforge.net/HOWTO

! versione .ps: http://legos.sourceforge.net/HOWTO/HOWTO.ps

[8] S. Nilsson, “Introduction to the LegOS Kernel”,

! versione .ps:

http://www.docs.uu.se/docs/undergrad/instances/spring2001/rt_systems_dvp

_mnp/assignments/intro_to_LegOS_kernel.ps

! versione .pdf:

http://www.docs.uu.se/docs/undergrad/instances/spring2001/rt_systems_dvp

_mnp/assignments/intro_to_LegOS_kernel.pdf

[9] LegOS Command Reference 10-0.2.4,

http://legos.sourceforge.net/docs/CommandRef.html

[10] Gruppo di discussione Lugnet (Lego User's Group NETwork),

http://www.lugnet.com

[11] K. Proudfoot, “RCX Internals”, Technical report,

http://graphics.stanford.edu/~kekoa/rcx, 1998-1999.

Page 186: Progettazione e realizzazione di un regolatore PID su architettura ...

Bibliografia

186

[12] M. K. Christiansen, M. H. Pedersen, T. Glaesner, “Solving the

priority inversion problem in legOS”, AUC, 2000

[13] Hitachi Single-Chip Microcomputer H8/3297 Series hardware

manual.

[14] Raccolta progetti hardware per RCX,

http://www.plazaearth.com/usr/gasperi/lego.htm

Page 187: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

187

Sommario

Page 188: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

188

Capitolo 1 __________________________________________________________ 1

1. IL PROGETTO_____________________________________________________ 2

2. ORGANIZZAZIONE DEL TESTO ____________________________________ 4 2.1. Cenni teorici sul controllo PID ___________________________________________ 4 2.2. Ambiente operativo ____________________________________________________ 4 2.3. Descrizione del progetto ________________________________________________ 4

Capitolo 2 __________________________________________________________ 6

1. INTRODUZIONE___________________________________________________ 7

2. LEGGE DI CONTROLLO PID _______________________________________ 8 2.1. Azione proporzionale___________________________________________________ 8 2.2. Azione integrale_______________________________________________________ 9 2.3. Azione derivativa______________________________________________________ 9

3. ACCORGIMENTI IMPLEMENTATIVI ______________________________ 10 3.1. Derivatore reale ______________________________________________________ 10 3.2. Forma standard ISA ___________________________________________________ 11

3.2.1. Risposta al Set-Point______________________________________________ 12 3.2.2. Risposta al Disturbo di Carico ______________________________________ 13

3.3. Wind-up dell’integratore _______________________________________________ 13 3.4. Commutazione manuale/automatico ______________________________________ 14

4. REALIZZAZIONE DIGITALE ______________________________________ 16 4.1. Equivalente Discreto del PID____________________________________________ 16

4.1.1. Scelta della frequenza di campionamento _____________________________ 17 4.1.2. PID Posizionale e PID Incrementale _________________________________ 18

4.2. Pseudo-codice di un regolatore PID_______________________________________ 19

Capitolo 3 _________________________________________________________ 24

1. INTRODUZIONE__________________________________________________ 25

2. RCX _____________________________________________________________ 25 2.1. CPU _______________________________________________________________ 26 2.2. ROM & firmware_____________________________________________________ 26 2.3. RAM esterna ________________________________________________________ 27 2.4. Porte d’ingresso ______________________________________________________ 27 2.5. Porte d’uscita ________________________________________________________ 27

Page 189: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

189

3. BRICKOS ________________________________________________________ 28 3.1. Il kernel di BrickOS ___________________________________________________ 29

3.1.1. Temporizzazioni_________________________________________________ 29 3.1.2. Gestione dei Tasks _______________________________________________ 30

3.1.2.1. Linking dinamico dei programmi utente _____________________________ 31 3.1.2.2. La funzione execi ______________________________________________ 32 3.1.2.3. La struttura organizzativa dei task__________________________________ 32 3.1.2.4. Lo scheduler __________________________________________________ 33

3.1.3. Gestione della memoria ___________________________________________ 34 3.1.3.1. Allocazione della memoria _______________________________________ 35 3.1.3.2. Deallocazione della memoria _____________________________________ 35

3.1.4. Comunicazioni Interprocessuali _____________________________________ 36 3.1.4.1. Semafori _____________________________________________________ 36

3.1.5. IR Networking __________________________________________________ 37 3.2. Gestione delle periferiche ______________________________________________ 37

3.2.1. Motori_________________________________________________________ 37 3.2.2. Sensori ________________________________________________________ 38

3.2.2.1. Sensori di luce_________________________________________________ 39 3.2.2.2. Sensori di rotazione_____________________________________________ 40 3.2.2.3. Sensori di contatto______________________________________________ 41

3.2.3. Display LCD____________________________________________________ 41 3.2.4. Pulsanti ________________________________________________________ 42

3.3. Osservazioni_________________________________________________________ 43

Capitolo 4 _________________________________________________________ 44

1. INTRODUZIONE__________________________________________________ 45

2. UN MODELLO PER IL PROCESSO DI SVILUPPO ____________________ 45 2.1. Modello a Spirale_____________________________________________________ 46 2.2. Modello a Cascata ____________________________________________________ 47

3. ANALISI E SPECIFICA DEI REQUISITI _____________________________ 48 3.1. Realizzazione di un PID digitale _________________________________________ 49

3.1.1. Funzioni di controllo _____________________________________________ 50 3.1.2. Interfaccia verso il processo ________________________________________ 50

3.1.2.1. Input ________________________________________________________ 50 3.1.2.2. Output _______________________________________________________ 50

3.1.3. Interfaccia operatore______________________________________________ 51 3.1.3.1. Display ______________________________________________________ 51

Page 190: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

190

3.1.3.2. Pulsanti fisici e pulsanti logici ____________________________________ 51 3.1.3.3. Regole generali ________________________________________________ 51 3.1.3.4. Menù PID ____________________________________________________ 53 3.1.3.5. Menù parametri ________________________________________________ 53 3.1.3.6. Modifica parametri PID _________________________________________ 54 3.1.3.7. Gestione variabile di controllo ____________________________________ 56 3.1.3.8. Gestione del set-point ___________________________________________ 56 3.1.3.9. Conferma o annullamento delle modifiche ___________________________ 56

Capitolo 5 _________________________________________________________ 58

1. INTRODUZIONE__________________________________________________ 59

2. MODULARIZZAZIONE____________________________________________ 59 2.1. Applicazione dei concetti di modularizzazione ______________________________ 60

3. STRUTTURE DATI ________________________________________________ 61 3.1. Logica di funzionamento _______________________________________________ 64

4. ARCHITETTURA DELL’APPLICAZIONE ___________________________ 65

5. GESTIONE DEGLI EVENTI ________________________________________ 65 5.1. Progettazione del gestore degli eventi _____________________________________ 67

5.1.1. Il rilevatore degli eventi ___________________________________________ 67 5.1.2. Il registratore degli eventi__________________________________________ 67

6. GESTIONE DEI CONTESTI ________________________________________ 68 6.1. Operare con i contesti _________________________________________________ 69 6.2. Individuazione dei contesti _____________________________________________ 69

Capitolo 6 _________________________________________________________ 74

1. INTRODUZIONE__________________________________________________ 75

2. ACCORGIMENTI IMPLEMENTATIVI ______________________________ 75

3. ESECUZIONE DEL PID ____________________________________________ 77 3.1. Contesto d’esecuzione del regolatore______________________________________ 78

3.1.1.1. Cambio del contesto di esecuzione _________________________________ 78 3.2. Algoritmo di regolazione _______________________________________________ 79

3.2.1. Funzione di inizializzazione _______________________________________ 79 3.2.2. Funzione di regolazione ___________________________________________ 81

3.3. Thread d’esecuzione del PID ____________________________________________ 82 3.4. Interfacciamento verso il processo________________________________________ 84

Page 191: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

191

3.4.1. Output_________________________________________________________ 85 3.4.2. Input __________________________________________________________ 86

4. GESTIONE DEGLI EVENTI ________________________________________ 88 4.1. Architettura implementativa ____________________________________________ 89 4.2. Il registratore degli eventi ______________________________________________ 90

4.2.1. L’azione fittizia _________________________________________________ 91 4.2.2. L’inibizione degli eventi___________________________________________ 91

4.3. Il rilevatore degli eventi ________________________________________________ 92 4.3.1. Le funzioni di risveglio ___________________________________________ 92 4.3.2. Il thread KEYONE _______________________________________________ 94 4.3.3. Il thread KEYTWO ______________________________________________ 95

5. GESTIONE DEI CONTESTI ________________________________________ 97 5.1. Realizzazione dei contesti ______________________________________________ 97

5.1.1. «Menù Selezione PID»____________________________________________ 97 5.1.2. «Menù Parametri PID»____________________________________________ 99 5.1.3. «Modifica valore lessicale» _______________________________________ 101 5.1.4. «Modifica valore numerico» ______________________________________ 103

5.1.4.1. «Conferma Voce Numerica»_____________________________________ 105 5.1.5. «Modifica Valore Incrementale» ___________________________________ 106 5.1.6. «Evoluzione variabile controllata»__________________________________ 109 5.1.7. «Conferma o Annullamento» ______________________________________ 109 5.1.8. «Uscita Menù Parametri» _________________________________________ 111

6. VISUALIZZAZIONE DEI DATI ____________________________________ 111 6.1. Menù _____________________________________________________________ 113

6.1.1. Inizializzazione del menù _________________________________________ 116 6.1.2. Scorrimento del menù____________________________________________ 116

6.2. Display____________________________________________________________ 117 6.2.1. Modellizzazione del display fisico __________________________________ 118 6.2.2. Interazioni con la struttura DISPLAY _______________________________ 118

6.2.2.1. Funzione di scrittura ___________________________________________ 119 6.2.2.2. Funzione di lettura_____________________________________________ 121 6.2.2.3. Inizializzazione della variabile display _____________________________ 121

6.3. Video _____________________________________________________________ 122 6.3.1. Campi di controllo nella struttura DISPLAY __________________________ 122 6.3.2. Thread Video __________________________________________________ 123

6.3.2.1. Menu PID ___________________________________________________ 124 6.3.2.2. Menu Param _________________________________________________ 125

Page 192: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

192

7. LIBRERIE_______________________________________________________ 129

8. AVVIO DELL’APPLICAZIONE ____________________________________ 130

9. SINCRONIZZAZIONE ____________________________________________ 131 9.1. I semafori __________________________________________________________ 131 9.2. Risorse condivise ____________________________________________________ 132

10. Appendice A: STRUTTURE DATI ________________________________ 134

Capitolo 7 ________________________________________________________ 137

1. INTRODUZIONE_________________________________________________ 138

2. TEST DI MODULO _______________________________________________ 139 2.1. Test esecuzione KERNEL _____________________________________________ 139

2.1.1. Accesso ai dati _________________________________________________ 139 2.1.1.1. Scorrimento dei menù __________________________________________ 141 2.1.1.2. Modifica voce numerica ________________________________________ 142 2.1.1.3. Modifica voce lessicale _________________________________________ 144 2.1.1.4. Modifica voce incrementale _____________________________________ 144 2.1.1.5. Conferma (o annullamento) di secondo livello _______________________ 145

2.1.2. Algoritmo di controllo ___________________________________________ 146 2.2. Test interazione KERNEL-RCX ________________________________________ 148

2.2.1. Controllo dei pulsanti ____________________________________________ 149 2.2.2. Controllo del display ____________________________________________ 150 2.2.3. Lettura ingressi e scrittura uscite ___________________________________ 154

3. TEST DI INTEGRAZIONE E DI SISTEMA __________________________ 154 3.1. Accesso ai dati ______________________________________________________ 155

3.1.1. Scorrimento dei menù____________________________________________ 155 3.1.2. Modifica voce numerica__________________________________________ 156 3.1.3. Modifica voce lessicale __________________________________________ 157 3.1.4. Modifica voce incrementale _______________________________________ 158 3.1.5. Conferma (o annullamento) di secondo livello_________________________ 159

3.2. Test di carico _______________________________________________________ 159 3.2.1. Sistema comprendente un solo PID _________________________________ 160

3.2.1.1. Test A: tempo di esecuzione _____________________________________ 161 3.2.1.2. Test B: periodo di campionamento ________________________________ 161

3.2.2. Sistema comprendente due PID ____________________________________ 162 3.3. Test finale di regolazione______________________________________________ 162

3.3.1. Prima fase: taratura del regolatore __________________________________ 163

Page 193: Progettazione e realizzazione di un regolatore PID su architettura ...

Sommario

193

3.3.2. Seconda fase: variazione a scalino del set-point________________________ 164 3.3.3. Terza fase: disturbi di carico ______________________________________ 165

3.3.3.1. Aumento dell’attrito ___________________________________________ 165 3.3.3.2. Disturbo sinusoidale ___________________________________________ 166

3.3.4. Quarta fase: funzionamento in modalità manuale ______________________ 167 3.3.4.1. Commutazioni A/M e M/A «bumpless» ____________________________ 167 3.3.4.2. Controllo del processo__________________________________________ 167

3.3.5. Osservazioni ___________________________________________________ 168

4. PROBLEMI NOTI ________________________________________________ 168

5. APPENDICE A: funzione PID ______________________________________ 169 5.1. Test su PC _________________________________________________________ 169

5.1.1. L’applicazione _________________________________________________ 169 5.1.2. I dati rilevati ___________________________________________________ 172 5.1.3. Il grafico ______________________________________________________ 175

5.2. Test su RCX________________________________________________________ 175 5.2.1. L’applicazione _________________________________________________ 175 5.2.2. I dati rilevati ___________________________________________________ 176

6. APPENDICE B: catena di acquisizione _______________________________ 176 6.1. Descrizione del test __________________________________________________ 176 6.2. Risultati del test _____________________________________________________ 178

Capitolo 8 ________________________________________________________ 182

1. CONCLUSIONI __________________________________________________ 183

Bibliografia ______________________________________________________ 184

1. Testi ____________________________________________________________ 185

2. Siti web e documentazione __________________________________________ 185

Sommario ________________________________________________________ 187