dott.cicala Inserito: 2 ottobre 2017 Segnala Share Inserito: 2 ottobre 2017 Dovrei leggere una posizione da un encoder SSI tramite la cts21 settata a 400kHz ed eseguire 8 confronti per poi attivare o meno 8 uscite. In pratica una specie di modulo camme. Quello che mi rende perplesso è che il tutto deve avvenire in 2ms massimi, essere ripetibile e preciso. Usando uno scheduled interrupt che richiama il task(int2) ogni 0.2ms considerando le poche righe che servirebbero e le prestazioni delle uscite OD211 secondo voi ce la faccio? Link al commento Condividi su altri siti More sharing options...
lelos Inserita: 3 ottobre 2017 Segnala Share Inserita: 3 ottobre 2017 ciao ho provato in passato , ma il task richiamato non deve essere lungo altrimenti il tempo di scansione si adegua. i dati messi su datasheet sono teorici. Se l'encoder gira lento ok ma se gira per esempio a 500 giri/min o più non è preciso , esperienza provata e testata , poi dipende cosa intendi per ripetibile e preciso. Link al commento Condividi su altri siti More sharing options...
dott.cicala Inserita: 3 ottobre 2017 Autore Segnala Share Inserita: 3 ottobre 2017 Il mio task esegue solo questo (* CALCOLO COEFFICIENTI CONVERSIONE POSIZIONE *) IF NOT clc_ok THEN K:=((INT_TO_REAL(CorsaGiro) )/(INT_TO_REAL(ImplusiGiro)))* 10,0; clc_ok:=TRUE; END_IF; (* POSIZIONE ATTUALE *) ACTUAL_POS:=(REAL_TO_INT((INT_TO_REAL( ENCODER)*K))) +OFFSET; iPOSITION:=ACTUAL_POS; (* CALCOLO VELOCITA' *) CNT:=CNT+1; CNT:=CNT MOD SWEEP; IF CNT=0 THEN BUFFER:=ACTUAL_POS; ELSIF CNT=(SWEEP-1) THEN ACT_VEL:=(ABS((ACTUAL_POS-BUFFER1)*100))/18; END_IF; (*SPAZIO PERCORSO PER ANTICIPO*) Sp1:=(ACT_VEL*tANTICIPO)/1000; (* GENERO CAMME *) inPos[0]:= (ACTUAL_POS>= (START1[0]-Sp1)AND ACTUAL_POS<=(STOP1[0]-Sp1)) OR (ACTUAL_POS>= (START2[0]-Sp1) AND ACTUAL_POS<=(STOP2[0]-Sp1)); inPos[1]:= (ACTUAL_POS>= (START1[1]-Sp1)AND ACTUAL_POS<=(STOP1[1]-Sp1)) OR (ACTUAL_POS>= (START2[1]-Sp1) AND ACTUAL_POS<=(STOP2[1]-Sp1)); inPos[2]:= (ACTUAL_POS>= (START1[2]-Sp1)AND ACTUAL_POS<=(STOP1[2]-Sp1)) OR (ACTUAL_POS>= (START2[2]-Sp1) AND ACTUAL_POS<=(STOP2[2]-Sp1)); inPos[3]:= (ACTUAL_POS>= (START1[3]-Sp1)AND ACTUAL_POS<=(STOP1[3]-Sp1)) OR (ACTUAL_POS>= (START2[3]-Sp1) AND ACTUAL_POS<=(STOP2[3]-Sp1)); inPos[4]:= (ACTUAL_POS>= (START1[4]-Sp1)AND ACTUAL_POS<=(STOP1[4]-Sp1)) OR (ACTUAL_POS>= (START2[4]-Sp1) AND ACTUAL_POS<=(STOP2[4]-Sp1)); inPos[5]:= (ACTUAL_POS>= (START1[5]-Sp1)AND ACTUAL_POS<=(STOP1[5]-Sp1)) OR (ACTUAL_POS>= (START2[5]-Sp1) AND ACTUAL_POS<=(STOP2[5]-Sp1)); inPos[6]:= (ACTUAL_POS>= (START1[6]-Sp1)AND ACTUAL_POS<=(STOP1[6]-Sp1)) OR (ACTUAL_POS>= (START2[6]-Sp1) AND ACTUAL_POS<=(STOP2[6]-Sp1)); inPos[7]:= (ACTUAL_POS>= (START1[7]-Sp1)AND ACTUAL_POS<=(STOP1[7]-Sp1)) OR (ACTUAL_POS>= (START2[7]-Sp1) AND ACTUAL_POS<=(STOP2[7]-Sp1)); (* COMANDO USCITE *) OUT1:= ENABLE AND ((Ts_ENABLE AND Ts_C1) OR inPos[0]); OUT2:= ENABLE AND ((Ts_ENABLE AND Ts_C2) OR inPos[1]); OUT3:= ENABLE AND ((Ts_ENABLE AND Ts_C3) OR inPos[2]); OUT4:= ENABLE AND ((Ts_ENABLE AND Ts_C4) OR inPos[3]); OUT5:= ENABLE AND ((Ts_ENABLE AND Ts_C5) OR inPos[4]); OUT6:= ENABLE AND ((Ts_ENABLE AND Ts_C6) OR inPos[5]); OUT7:= ENABLE AND ((Ts_ENABLE AND Ts_C7) OR inPos[6]); OUT8:= ENABLE AND ((Ts_ENABLE AND Ts_C8) OR inPos[7]); La velocità di rotazione dell'encoder è 60 rpm Link al commento Condividi su altri siti More sharing options...
max.riservo Inserita: 3 ottobre 2017 Segnala Share Inserita: 3 ottobre 2017 Guardando le specifiche da te evidenziate qualcosa non torna. Se il tempo di ON è max 0,1 ms e quello di OFF è max 0,8 ms e hai un IRQ ogni 0,2 ms mi viene banalmente da pensare che il tempo massimo per gestire una transizione ON/OFF è di 1,1 ms (può essere meno ma al limite può essere questo). Ammesso che l' evento sia elaborabile realmente in meno di 0,2 ms resta il fatto che 0,8 ms come tempo di OFF impediscono una corretta gestione delle transizione. Io imposterei lo scheduler con un tempo di 2 ms (o almeno superiore a 1 ms). Non so quanto si possa migliorare del codice mostrato, forse si potrebbe tentare di sostituire le conversioni in real_int (e viceversa) utilizzando solo dei long int (non conosco il mondo Omron e non so come vengano chiamati e se esistano) .... Potresti anche leggermente velocizzare l' attivazione delle uscite utilizzando il 'cortocircuito' degli operatori booleani : (* COMANDO USCITE *) IF ENABLE THEN OUT1:= inPos[0] OR (Ts_ENABLE AND Ts_C1); OUT2:= inPos[1] OR (Ts_ENABLE AND Ts_C2); OUT3:= inPos[2] OR (Ts_ENABLE AND Ts_C3); OUT4:= inPos[3] OR (Ts_ENABLE AND Ts_C4); OUT5:= inPos[4] OR (Ts_ENABLE AND Ts_C5); OUT6:= inPos[5] OR (Ts_ENABLE AND Ts_C6); OUT7:= inPos[6] OR (Ts_ENABLE AND Ts_C7); OUT8:= inPos[7] OR (Ts_ENABLE AND Ts_C8); ELSE OUT1:= Always_OFF; 'Bit sempre a zero - verificare l' equivalente Omron OUT2:= Always_OFF; OUT3:= Always_OFF; OUT4:= Always_OFF; OUT5:= Always_OFF; OUT6:= Always_OFF; OUT7:= Always_OFF; OUT8:= Always_OFF; END_IF; Link al commento Condividi su altri siti More sharing options...
dott.cicala Inserita: 3 ottobre 2017 Autore Segnala Share Inserita: 3 ottobre 2017 Grazie per i suggerimenti. Effettivamente ho omesso qualche informazione in merito al funzionamento del sistema e alla scelta delle uscite statiche standard piuttosto che veloci, le quali non essendo necessarie, determinano un risparmio non indifferente per il cliente. In pratica, l'evento che devo gestire non è altro che una spruzzata (ovvero otto) la cui durata minima non è mai inferiore ai 50ms. L'encoder, per la corsa effettiva dell'asse di 1000mm, effettua un unico giro, poi ritorna. Non è necessario inibire l'emissione della camma durante il ritorno. L'asse effettua la sua corsa in 2500ms alla velocità di 400mm/s. Per 50ms di eccitazione, la spruzzata disegna un tratto di 20mm. Considerando i ritardi di commutazione dell'uscita si ha che: per 0,1 ms necessari per l'eccitazione dell'uscita, l'asse ha percorso 0,04mm per 0,8 ms necessari alla diseccitazione dell'uscita, l'asse ha percorso 0,32mm I ritardi "meccanici" vengono gestiti manualmente (è una specifica cliente) tramite il parametro anticipo [ms] La precisione richiesta è 1mm. La scelta del task schedulato è ovviamente dovuta al fatto che eseguendo questa funzione nel ciclo libero, la risposta non sarebbe costante nel tempo. Calcolando il tempo di esecuzione di ogni istruzione, il richiamo del blocco funzione ecc ecc, mi risulta che servano meno di 50us per eseguire il tutto. E' realistico? Se così fosse, richiamare il blocco funzione ogni 200us dovrebbe garantire un buon margine. Link al commento Condividi su altri siti More sharing options...
Messaggi consigliati
Crea un account o accedi per commentare
Devi essere un utente per poter lasciare un commento
Crea un account
Registrati per un nuovo account nella nostra comunità. è facile!
Registra un nuovo accountAccedi
Hai già un account? Accedi qui.
Accedi ora