Lezione 15 di 18

RI Lezione 15

🤖 Robotica Industriale · V Anno · Lezione 15

Registri di posizione PR[ ] e offset 📍

PR[ ] come variabili di posizione · Offset Condition · Deposito su griglia dinamica · LPOS / JPOS

⏱️ Durata stimata: 75–90 min 📊 Livello: Avanzato (V anno) 🔧 Strumenti: Simulatore web · Editor TP · Pannello DATA 📋 Prerequisiti: Lezioni 06–14

📍 Il robot smette di essere rigido. Finora ogni posizione era fissa: insegnata una volta, uguale per sempre. Con i registri di posizione PR[ ] e la tecnica dell’offset il TCP può spostarsi dinamicamente — calcolato a runtime in base a registri R[ ]. Una griglia 4×6 diventa raggiungibile con un solo punto insegnato e un loop. È la tecnica che abilita palletizzazione, pick-from-feeder, deposito matriciale.

🎯 Obiettivi della lezione

  • Capire la struttura di un PR[ ] e come si differenzia da un P[ ]
  • Assegnare e modificare singoli componenti di un PR[ ] dal codice TP
  • Usare PR[ ] come offset con la sintassi L P[n] … OFFSET, PR[m]
  • Costruire il pattern deposito su griglia con loop annidato + offset calcolato
  • Leggere la posizione corrente del robot in PR[ ] con LPOS e JPOS

📖 1. Teoria

1.1 — Struttura di un PR[ ]

Un registro di posizione PR[ ] è una variabile che contiene una posizione completa nello stesso formato di P[ ]: sei componenti (X, Y, Z, W, P, R) più il frame di riferimento. Sono disponibili PR[1]…PR[100]. La differenza cruciale rispetto a P[ ] è che PR[ ] può essere scritto e modificato dal codice TP a runtime — le sue componenti si assegnano come variabili.

Caratteristica P[ ] — Registro posizione PR[ ] — Registro posizione variabile
Come si scrive Solo via teach (jog + RECORD) Teach oppure assegnazione TP a runtime
Modificabilità Solo offline, non dal codice Ogni componente modificabile dal codice
Uso tipico Posizioni fisse della cella Offset, posizioni calcolate, posizione corrente
Range P[1]…P[999] PR[1]…PR[100]
Persistenza Conservato dopo spegnimento Conservato dopo spegnimento

Ogni componente di un PR[ ] è accessibile con la notazione a punto: PR[n, k] dove k è il numero del componente:

PR[1, 1] = valore     ! componente X (mm)
PR[1, 2] = valore     ! componente Y (mm)
PR[1, 3] = valore     ! componente Z (mm)
PR[1, 4] = valore     ! componente W (gradi — Yaw)
PR[1, 5] = valore     ! componente P (gradi — Pitch)
PR[1, 6] = valore     ! componente R (gradi — Roll)

📌 Convenzione indici PR[ ]: PR[1]–PR[10] per offset di processo · PR[11]–PR[20] per posizioni calcolate · PR[91]–PR[99] per posizione corrente (LPOS/JPOS). Non sovrascrivere PR[ ] in uso: se PR[1] è l’offset colonna, non usarlo anche come buffer temporaneo in un altro punto del programma.

1.2 — Azzeramento di un PR[ ]

Prima di usare un PR[ ] come offset è fondamentale azzerare tutti i componenti non usati. Se PR[1] ha residui da un’esecuzione precedente nelle componenti W, P, R, l’offset ruoterà l’orientamento del TCP oltre a spostarlo — quasi certamente indesiderato.

! Azzeramento completo di PR[1] prima dell’uso come offset
PR[1, 1]=0                           ! X = 0
PR[1, 2]=0                           ! Y = 0
PR[1, 3]=0                           ! Z = 0
PR[1, 4]=0                           ! W = 0 (nessuna rotazione)
PR[1, 5]=0                           ! P = 0
PR[1, 6]=0                           ! R = 0

Poi si assegnano solo i componenti che devono avere un valore diverso da zero:

! Offset puro in X e Y — esempio: colonna 2, riga 1 di un vassoio
PR[1, 1]=R[37]                     ! offset X = valore calcolato in R[37]
PR[1, 2]=R[36]                     ! offset Y = valore calcolato in R[36]
! PR[1,3..6] già azzerati — nessun offset in Z né in orientamento

1.3 — Sintassi OFFSET nel movimento

La parola chiave OFFSET, PR[n] aggiunge alla fine dell’istruzione di movimento: il TCP si sposta nella posizione P[ ] più l’offset contenuto in PR[n]. La posizione base P[ ] non viene modificata — l’offset è applicato solo per quella singola esecuzione dell’istruzione.

L P[21:PLACE_REF] 150mm/sec FINE OFFSET, PR[1]
Posizione di riferimento insegnata
Punto base della griglia — non cambia mai
Offset da aggiungere
Calcolato a runtime dal loop
OFFSET funziona con J, L e C — esempi
Istruzione Comportamento
L P[21] 150mm/sec FINE OFFSET, PR[1] Movimento lineare a P[21]+PR[1] — traiettoria rettilinea con offset
J P[21] 80% FINE OFFSET, PR[1] Movimento articolare a P[21]+PR[1] — percorso curvo, più veloce
L P[20] 200mm/sec CNT50 OFFSET, PR[1] Approccio con offset e continuazione — usato per il transito verso il punto di lavoro
⚠️ OFFSET è riferito al User Frame attivo quando UF≠0. Se UF=0 (World Frame), l’offset è in coordinate world. Verificare sempre il frame attivo prima di usare OFFSET su celle con User Frame personalizzato.

1.4 — Pattern completo: deposito su griglia con OFFSET

Questo è il pattern più usato nelle applicazioni industriali con PR[ ]: un punto di riferimento insegnato (angolo della griglia) e un loop che calcola l’offset per ogni cella e lo applica al movimento. Una griglia N×M richiede solo 2 punti insegnati (riferimento + approccio) invece di 2×N×M punti.

! ============================================================
! DEPOSITO SU GRIGLIA 3×4 con OFFSET
! P[60] = punto riferimento cella (0,0) della griglia
! P[59] = approccio riferimento (P[60] con Z+150)
! PR[1] = offset corrente (aggiornato ogni cella)
! ============================================================

! — Init parametri griglia —
1: R[30:RIGA ]=0
2: R[31:COL ]=0
3: R[32:N_RIG]=3                          ! 3 righe
4: R[33:N_COL]=4                          ! 4 colonne
5: R[34:P_RIG]=50                          ! passo riga (mm in Y)
6: R[35:P_COL]=60                          ! passo colonna (mm in X)

! — Azzeramento PR[1] —
7: PR[1,1]=0
8: PR[1,2]=0
9: PR[1,3]=0
10: PR[1,4]=0
11: PR[1,5]=0
12: PR[1,6]=0

! — Loop esterno: righe —
13: LBL[2]
14: R[31]=0                                     ! reset colonna

! — Loop interno: colonne —
15: LBL[3]

! Calcola offset cella corrente
16: PR[1,1]=R[31]*R[35]                     ! offset X = col × passo_col
17: PR[1,2]=R[30]*R[34]                     ! offset Y = riga × passo_riga

! — PRESA (dal nastro — senza offset) —
18: J P[10:APPR_PICK] 80% CNT100
19: L P[11:PICK ] 150mm/sec FINE
20: DO[1]=ON
21: WAIT DI[1]=ON TIMEOUT, LBL[99]
22: L P[10:APPR_PICK] 150mm/sec FINE

! — DEPOSITO CON OFFSET —
23: J P[59:APPR_REF ] 80% CNT100 OFFSET, PR[1]
24: L P[60:PLACE_REF] 150mm/sec FINE OFFSET, PR[1]
25: DO[1]=OFF
26: WAIT DI[1]=OFF TIMEOUT, LBL[98]
27: L P[59:APPR_REF ] 150mm/sec FINE OFFSET, PR[1]

! Avanza colonna
28: R[31]=R[31]+1
29: IF R[31]<R[33], JMP LBL[3]

! Avanza riga
30: R[30]=R[30]+1
31: IF R[30]<R[32], JMP LBL[2]

! Griglia completata (12 celle)
32: J P[1:HOME] 100% FINE
33: DO[4]=ON                                     ! vassoio pieno

✅ Nota sulla risalita con OFFSET (riga 27): la risalita usa lo stesso PR[1] del deposito — quindi il robot sale verticalmente sopra la cella appena riempita, non sopra il punto di riferimento. Questo è esattamente il comportamento voluto: approccio verticale sopra ogni cella individuale, non diagonale rispetto al riferimento.

1.5 — LPOS e JPOS: leggere la posizione corrente

LPOS (Linear POSition) e JPOS (Joint POSition) sono istruzioni che scrivono la posizione TCP corrente del robot in un PR[ ]. LPOS scrive le coordinate cartesiane X/Y/Z/W/P/R; JPOS scrive i valori degli assi J1…J6.

PR[90]=LPOS                        ! leggi posizione cartesiana corrente → PR[90]
PR[91]=JPOS                        ! leggi posizione assi corrente → PR[91]

Usi tipici di LPOS:

Uso Esempio
Salva posizione attuale come riferimento dinamico PR[90]=LPOS poi usa PR[90] come base per offset successivi
Verifica che il robot sia in home prima di avviare PR[90]=LPOS · IF PR[90,3]<200, JMP LBL[99] (Z troppo basso)
Debug: leggi posizione dopo un movimento sospetto PR[99]=LPOS — poi leggi PR[99] dal pannello DATA

💻 2. Esempi guidati nel simulatore

Esempio A — Offset semplice: stesso punto, tre altezze diverse

  1. Insegna P[60] in una posizione qualsiasi (es. X=200, Y=0, Z=100).
  2. Azzeramento PR[1]: scrivi le 6 righe PR[1,k]=0.
  3. Scrivi il programma:
    ! visita P[60] a 3 altezze diverse con OFFSET su Z
    1: PR[1,1]=0 · PR[1,2]=0 · PR[1,3]=0
    2: PR[1,4]=0 · PR[1,5]=0 · PR[1,6]=0
    3: J P[1:HOME] 100% FINE
    4: PR[1,3]=50
    5: L P[60] 150mm/sec FINE OFFSET, PR[1]
    ! TCP va a Z=150 (100+50)
    6: PR[1,3]=0
    7: L P[60] 150mm/sec FINE OFFSET, PR[1]
    ! TCP va a Z=100 (posizione base)
    8: PR[1,3]=-50
    9: L P[60] 150mm/sec FINE OFFSET, PR[1]
    ! TCP va a Z=50 (100-50)
    10: J P[1:HOME] 100% FINE
  4. Esegui con STEP. Dopo ogni movimento apri il pannello DATA → Position Registers e verifica il valore di PR[1,3] e la posizione TCP corrente. Usa LPOS per confermare.
  5. Verifica: il robot tocca esattamente Z=150, Z=100, Z=50 nelle tre soste.

Esempio B — Fila lineare: 5 posizioni in X con offset

  1. Insegna P[60] a X=100, Y=0, Z=80 (prima posizione della fila).
  2. Scrivi il programma:
    1: PR[1,1]=0 · PR[1,2]=0 · PR[1,3]=0
    2: PR[1,4]=0 · PR[1,5]=0 · PR[1,6]=0
    3: R[31]=0
    4: R[35]=50
    5: J P[1:HOME] 100% FINE
    6: LBL[3]
    7: PR[1,1]=R[31]*R[35]
    ! offset X = indice × passo
    8: L P[60] 150mm/sec FINE OFFSET, PR[1]
    9: WAIT 0.30(sec)
    10: R[31]=R[31]+1
    11: IF R[31]<5, JMP LBL[3]
    12: J P[1:HOME] 100% FINE
  3. Esegui. Il robot visita 5 posizioni a X=100, 150, 200, 250, 300 (passo 50 mm).
  4. Modifica R[35]=30 prima di eseguire: passo diventa 30 mm, posizioni a X=100, 130, 160, 190, 220.
  5. Aggiungi una riga PR[99]=LPOS dopo il WAIT e verifica che PR[99,1] corrisponda al valore atteso di X.

Esempio C — Griglia 2×3 completa con approccio/lavoro

  1. Insegna P[59] (approccio riferimento, Z+120 rispetto a P[60]) e P[60] (lavoro riferimento).
  2. Implementa il loop annidato della sezione 1.4 ridotto a griglia 2×3 (passo X=60, passo Y=50). Sostituisci la presa con WAIT 0.20(sec).
  3. Esegui con STEP le prime 3 celle (prima riga). Per ogni cella verifica nel pannello DATA:
    • R[30] e R[31] (indici riga e colonna correnti)
    • PR[1,1] e PR[1,2] (offset X e Y calcolati)
    • PR[99,1] e PR[99,2] (posizione effettiva TCP via LPOS — aggiungi PR[99]=LPOS dopo il deposito)
  4. Verifica che posizione effettiva = posizione riferimento + offset calcolato.
  5. Esegui a velocità normale (RUN): le 6 celle devono essere visitate in ordine riga per riga.

🏋️ 3. Esercizi

🟢 Esercizio 1 — Calcolo manuale offset griglia (Facile)

Una griglia ha punto di riferimento a X=150, Y=50, Z=80. Passo colonne=45 mm in X, passo righe=40 mm in Y. Calcola i valori di PR[1,1] e PR[1,2] (offset X e Y) per ciascuna delle 6 celle di una griglia 2×3, e le coordinate assolute X,Y risultanti:

Cella (R=0,C=0): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?
Cella (R=0,C=1): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?
Cella (R=0,C=2): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?
Cella (R=1,C=0): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?
Cella (R=1,C=1): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?
Cella (R=1,C=2): PR[1,1]=?, PR[1,2]=?, X_TCP=?, Y_TCP=?

Verifica i calcoli nel simulatore usando PR[99]=LPOS dopo ogni deposito e confrontando PR[99,1] e PR[99,2] con i valori attesi.

🔵 Esercizio 2 — Integra griglia nel PICK_SORT_3 (Medio)

Modifica il programma PICK_SORT_3 della Lezione 14 in modo che la zona A non abbia un unico punto di deposito P[21], ma una griglia 2×3 (6 celle). I parametri: passo X=60 mm, passo Y=50 mm, punto riferimento P[21] è la cella (0,0).

Aggiungi R[20:COL_A] e R[21:RIG_A] come indici della cella corrente nella zona A. Ogni volta che un pezzo di tipo 1 viene depositato in zona A, avanza alla cella successiva (colonna per colonna, poi riga). Quando la griglia è piena (R[2]=6), accendi DO[7]=ON (zona A satura) e reindirizza i pezzi di tipo 1 agli scarti finché DO[7] non viene spento (reset esterno).

Implementa solo la zona A — le zone B e C rimangono a punto singolo.

🟠 Esercizio 3 — Palletizzazione a strati (Medio)

Un pallet riceve scatole su 2 strati sovrapposti, ciascuno con griglia 3×4 (12 scatole per strato, 24 totali). Ogni scatola è alta 80 mm. Il punto di riferimento P[70] è la cella (strato=0, riga=0, col=0) del pallet.

Scrivi il programma con loop a tre livelli annidati (strato → riga → colonna) che calcola PR[2] per ogni scatola: PR[2,1]=col×60 (offset X), PR[2,2]=riga×50 (offset Y), PR[2,3]=strato×80 (offset Z).

L’approccio deve tenere conto dello strato: Z approccio = Z riferimento + strato×80 + 120 mm di clearance. Implementa la logica con R[38]=strato (0..1), R[30]=riga (0..2), R[31]=colonna (0..3). Verifica nel simulatore che le 24 posizioni siano corrette usando LPOS.

🟣 Esercizio 4 — Ripresa da interruzione a metà griglia (Difficile)

Il programma di deposito su griglia 3×4 viene interrotto (allarme o stop operatore) dopo aver riempito le prime 7 celle. Al riavvio, il robot deve riprendere dalla cella 8 — non ricominciare dalla cella 0.

Implementa la logica di ripresa: R[1:CONT_TOT] conta i pezzi depositati (persistente tra spegnimento e accensione). All’avvio il programma verifica se R[1]>0 e in tal caso calcola gli indici di riga e colonna di ripresa usando DIV e MOD: R[30]=R[1] DIV R[33], R[31]=R[1] MOD R[33]. Se R[1]=0 (prima accensione) ricomincia dalla cella (0,0).

Verifica: esegui 7 cicli, interrompi, riavvia — il robot deve partire dalla cella 8 con i registri di indice corretti. Verifica anche il caso R[1]=12 (griglia già piena): il programma deve rilevarlo e accendere DO[4] senza eseguire nessun deposito.


❓ 4. Quiz di verifica

1. Perché è necessario azzerare tutti i 6 componenti di PR[1] prima di usarlo come offset, anche se si modificano solo PR[1,1] e PR[1,2]?

Mostra risposta

Perché PR[ ] è persistente: conserva i valori dell’esecuzione precedente dopo lo spegnimento del controller. Se nell’esecuzione precedente PR[1,3] era stato impostato a –30 (offset Z di –30 mm) e ora si vuole usare PR[1] solo come offset X/Y, dimenticare di azzerare PR[1,3] aggiungerà –30 mm in Z a ogni movimento con OFFSET, PR[1]. Il robot scenderebbe 30 mm più in basso del previsto ad ogni cella — potenzialmente collidendo con i pezzi già depositati o con la struttura del vassoio. L’azzeramento completo garantisce uno stato noto prima di impostare i soli componenti necessari.


2. In un movimento L P[60] 150mm/sec FINE OFFSET, PR[1], P[60] viene modificato permanentemente dall’offset?

Mostra risposta

No. L’offset viene applicato solo per quella singola esecuzione dell’istruzione — P[60] rimane invariato nella memoria del controller. Il TCP si sposta fisicamente a P[60]+PR[1], ma il valore registrato di P[60] è immutato. Questo è il vantaggio fondamentale di OFFSET rispetto a modificare direttamente P[60]: si può usare lo stesso punto base per tutte le celle della griglia e cambiare solo PR[1] a ogni iterazione, senza mai riscrivere P[60]. Se si modificasse P[60] a ogni cella, si perderebbe il punto di riferimento originale.


3. Perché nella riga 27 del programma griglia (L P[59:APPR_REF] … OFFSET, PR[1]) si usa lo stesso PR[1] del deposito e non PR[1] azzerato?

Mostra risposta

Perché P[59] (approccio riferimento) ha la stessa X,Y di P[60] ma con Z+150. Applicando lo stesso offset PR[1] anche alla risalita, il robot sale verticalmente sopra la cella appena depositata — cioè a X=P[60].X+PR[1,1], Y=P[60].Y+PR[1,2], Z=P[60].Z+150. Se si usasse PR[1] azzerato per la risalita, il robot tornerebbe all’approccio della cella (0,0) invece di salire sopra la cella corrente — traiettoria diagonale che traverserebbe i pezzi già depositati nelle celle precedenti. L’offset coerente approccio/lavoro/risalita garantisce la simmetria verticale che abbiamo imparato nella Lezione 07.


4. Qual è la differenza tra LPOS e JPOS, e quando si usa ciascuno?

Mostra risposta

LPOS (Linear POSition) scrive la posizione TCP nelle coordinate cartesiane del frame attivo: X, Y, Z in mm e W, P, R in gradi. JPOS (Joint POSition) scrive gli angoli attuali degli assi J1…J6 in gradi. Si usa LPOS quando si vuole lavorare con coordinate spaziali del TCP — verificare posizione, calcolare offset cartesiani, debug. Si usa JPOS quando si vuole salvare una configurazione degli assi indipendente dal TCP — ad esempio per memorizzare la posizione di home in termini di assi e verificare che il robot sia esattamente in quella configurazione prima di avviare un ciclo. JPOS è più affidabile di LPOS per le verifiche di home perché elimina l’ambiguità delle soluzioni cinematiche multiple a parità di posizione TCP.


5. Una griglia 4×5 richiede quanti punti P[ ] insegnati con il metodo OFFSET rispetto al metodo tradizionale (un punto per cella)?

Mostra risposta

Metodo tradizionale: 4×5=20 punti di lavoro + 20 punti di approccio = 40 punti P[ ] da insegnare, verificare e mantenere. Con il metodo OFFSET: 1 punto di riferimento (P[60]) + 1 approccio di riferimento (P[59]) = 2 punti P[ ] totali, più i parametri griglia in R[ ] (passi e dimensioni). Risparmio: 38 punti. Vantaggi aggiuntivi: se il vassoio si sposta di 10 mm, con il metodo tradizionale bisogna correggere 40 punti; con OFFSET si corregge solo P[60] e tutti i 20 depositi si aggiornano automaticamente. Se si cambia il passo (es. da 60 mm a 70 mm), con OFFSET basta modificare R[35] — con il metodo tradizionale bisogna spostare fisicamente 20 punti uno per uno.


📚 Riepilogo della lezione

Cosa hai imparato oggi:
  • PR[n,k] — registro di posizione variabile, componente k (1=X … 6=R), modificabile dal codice TP
  • Azzerare tutti i 6 componenti prima dell’uso come offset — la persistenza può introdurre residui inattesi
  • OFFSET, PR[n] nella riga di movimento — applica l’offset solo per quella esecuzione, P[ ] rimane invariato
  • Risalita con stesso PR[n] del deposito — simmetria verticale sopra ogni cella, non diagonale verso il riferimento
  • Pattern griglia: 2 punti insegnati + parametri R[ ] + loop annidato = N×M celle senza insegnare ogni punto
  • PR[n]=LPOS / PR[n]=JPOS — legge la posizione corrente del robot per verifica e debug

Prossima lezione →

Lezione 16 — Ottimizzazione delle traiettorie
CNT vs FINE · Velocità ottimale per tipo di movimento · Profili di accelerazione.
Ridurre i tempi ciclo senza sacrificare sicurezza e precisione.

© Prof. D. Bertolino · Robotica Industriale FANUC ER-4iA · Lezione 15 di 18