Vai al contenuto
PLC Forum


Centralina Per Controllo Di Relè E Sensori Da Pc


domenico.mosca

Messaggi consigliati

domenico.mosca

Ciao a tutti

sto cercando una centralina che sia in grado di pilotare 12 relè e sia in grado di leggere lo stato di 12 sensori.

Questa centralina dovrebbe essere collegabile via USB o RS232 o RS485 ed essere compatibile con linux.

Meglio ancora se sono presenti delle API che ne generalizzano e semplificano la programmazione.

Potreste segnalarmi dei modelli o delle vostre esperienze?

Praticamente dovrò controllare una macchina con un pc, utilizzando un software di controllo.

Grazie a tutti in anticipo!

Link al commento
Condividi su altri siti


  • 1 month later...
domenico.mosca

Ciao a tutti

nel rigraziarvi nuovamente per i link interessanti che mi avete fornito a suo tempo, vorrei porvi un quesito:

ho preso una scheda USBIO24, a cui ho collegato

2 I/O Combo Board

1 I/O Relay Board

Il tutto lo utilizzo per gestire una macchina spaccalegna con nastro trasportatore, blocco tronco, taglio legname, spaccalegna, etc etc, tutti i pistoni oleodinamici sono collegati a elettrovalvole che piloto con relè gestiti a loro volta dalle schede montate.

Utilizzo anche dei fine-corsa che ho collegato ai sensori delle Combo Board.

Il software è scritto in c++ in ambiente linux, ed è interfacciato ad un joystick per il controllo manuale + una procedura che fa il lavoro automatico (Avanza/Blocca/Taglia/Spacca/Sblocca/->Avanza.....)

Il problema che ho sta proprio nei sensori, in quanto ho dei problemi di lettura della scheda, a volte mi ritorna dei valori errati e mi pare che non si riesca a gestire bene il sincronismo di lettura/scrittura.

La scheda funziona in questo modo:

/*

scrivo il byte value (che deve essere un'intero) sulla porta A

*/

stream << 'A'<<(char)value;

/*

leggo il valore della porta A

*/

stream << 'a'

/*

leggo il valore della porta B

*/

stream << 'b'

/*

leggo il valore della porta B

*/

stream << 'c'

Periodicamente, leggo i valori di A,B,C in un ciclo ed è qui che ho il problema nel senso che spesso ottengo dei valori errati.

Utilizzo dei semafori per sincronizzare letture / scritture ma non mi pare che i risultati ottenuti siano affidabili.

Posto un pò del codice scritto... solo per farvi capire meglio:

/*
* letttura valori
*/
void IOHandler::ReadProcess() {

       fstream in(this->device.c_str(), ios_base::in);
       char c;

       sem_post (&this->mutex);

       while (in.good())
       {
         sem_wait (&this->mutex);

               c = in.get();
               if(in.good()){

                       this->ReadPortValues[this->PortNumber2Read] = int(c);
                       sem_post (&this->mutex);

               }
       }

       in.close();
}

/*
* scrittura/interrogazione valori
*/
while(true){
...

               this->PortNumber2Read = 0;
               out << 'A' << char(this->WritePortValues[0]);
               out.flush();
               out << 'a';
               out.flush();
               sem_post (&this->mutex);
               sem_wait (&this->mutex);
               usleep(this->SleepingInterval);

               this->PortNumber2Read=1;
               out << 'B' << char(this->WritePortValues[1]);
               out.flush();
               out << 'b';
               out.flush();
               sem_post (&this->mutex);
               sem_wait (&this->mutex);
               usleep(this->SleepingInterval);


               this->PortNumber2Read=2;
               out << 'C' << char(this->WritePortValues[2]);
               out.flush();
               out << 'c';
               out.flush();
               sem_post (&this->mutex);
               sem_wait (&this->mutex);
               usleep(this->SleepingInterval);
...
}
Forse qualcuno di voi ha già avuto esperienze con queste schede e può darmi un suo parere? Questo modo di operare è corretto? PS, ho anche provato a fare un solo thread che legge/scrive contemporaneamente, ma non vi è modo di farlo funzionare... forse questo semplificherebbe il tutto ma con il codice seguente leggo sempre e solo 0 o -1 dalla scheda: Idee?
int main(int argc, char *argv[]) {

    fstream
            out("/dev/ttyUSB0", ios_base::out|ios_base::in|ios_base::binary);
/*
configuro le porte
*/
    //4 in - 4 out
    out << "!A" << char(15);
    //8 out
    out << "!B" << char(0);
    //4 in - 4 out
    out << "!C" << char(15);

char read;
int value;

while(true){

// spengo i rele su A
        out << 'A' << (char) 0;
        out.flush();

// attendo 1 secondo
sleep(1)

// accendo il rele sulla porta 5
        out << 'A' << (char) 32;
        out.flush();
// leggo il valore della porta 5
        out << 'a'
        out.flush();
        out >> read;
        value=(int)read;
        cout << "valore di A="<<value<<endl;

}
    out.close();
    return 0;
}

Link al commento
Condividi su altri siti

Il problema principale sta nello SO del PC.

SO da ufficio sono inadatti per controlli automatici anche semplici.

I PLC basati su PC e I/O industriali, almeno quelli affidabili, hanno un loro SO vero real time.

Il rimedio che puoi tentare è acquisire gli ingressi e aggiornare le uscite a tempi fissi.

Cerco di chiarire banalizzando.

TI fai un timer che genera un interrupt. Su questo interrupt aggiorni le uscite fisiche prelevandone los tato da una tabella immagine, similmente aggiorni la tabella immagine degli ingressi copiandovi lo stato degli ingressi fisici.

Dopo di che elabori il programma usando le tabelle immagini.

Se noti il tuo sistema dovrebbe la vorare come lavorano i PLC e non è casuale.

Link al commento
Condividi su altri siti

domenico.mosca

Ciao, ti ringrazio per la risposta.

Il problema di fondo, non è come gestire lato software il programma, ma è come gestire la comunicazione con la scheda!

Nel mio caso, quello che non riesco a capire è se la comunicazione deve essere gestita con 2 processi differenti sincronizzati (uno legge, ed uno scrive) oppure se c'è modo con un'unico processo di scrivere e leggere.

Poi, che a livello di IO un PLC embedded sia più affidabile in termini di real time è fuori dubbio, è anche molto meno versatile però: nel mio caso ora ho un file XML che mi permette in modo molto veloce di customizzare i pulsanti del joystick, le uscite dei rele, le regole degli ingressi, etc etc. senza cambiare una riga di codice e senza dover ricompilare nulla.

Quello che vorrei capire io però, è possibile comunicare con queste schede utilizzando un'unico processo, ed eventualmente in che modo!

Grazie, ciao.

Link al commento
Condividi su altri siti

del_user_56966

Quello che dice Livio è esatto, la versatilità di un programma di automazione non sta nella grafica o nella semplicità d'uso

sempre che un programma come quello sopra si possa definire per tutti il più semplice... :blink:

semmai è nelle prestazioni che l'Harware permette di gestire, in tutta la tua esposizione manca un dato importante che è caratteristico

di tutte le macchine, il tempo di scan degli I/O se questo non è corretto tutto il tuo programma soprastante, Linux compreso non ti sono d'aiuto...

Poi, che a livello di IO un PLC embedded sia più affidabile in termini di real time è fuori dubbio, è anche molto meno versatile però: nel mio caso ora ho un file XML che mi permette in modo molto veloce di customizzare i pulsanti del joystick, le uscite dei rele, le regole degli ingressi, etc etc. senza cambiare una riga di codice e senza dover ricompilare nulla.

In realtà tra poco non sarà più cosi visto che sta per uscire un sistema Open Source basato su Linux che gestisce direttamente gli I/O

direttamente tramite le librerie fornite col kernal e in pratica è come se tu pilotassi la scheda audio...

lo si può programmare sia tramite C/C++, Python, Java, un Visual Basic per linux...

Link al commento
Condividi su altri siti

Poi, che a livello di IO un PLC embedded sia più affidabile in termini di real time è fuori dubbio,

A prescindere dall'affidabilità, che comunque è un problema reale, c'è il problema della fattibilità.

Se i tempi di reazione del campo sono...ere geologiche, puoi usare il tuo Hw così come lo stai usando. Però una quelsiasi macchina, anche se lenta, risponde almeno in termini di decimi di secondo. In questo caso un SO da ufficio non può essere adatto.

E' l'eterno problema di chi sa programmare un PC, crede che sia sempre una questione di programma applicativo. Invece spesso è una questione di Sw di base.

Se non puoi controllare direttamente il tuo Hw, devi avere qaulche cosa che lo fa per te in modo sicuro e affidabile. Ecco perchè, per queste applicazioni, il DOS era molto più efficace: con questo SO hai direttaemente il controllo della periferia del sistema.

Comunque il tuo problema lo può risolvere solo il fornitore dello Hw, fornendoti drivers adatti allo scopo e compatibili con lo SO che usi.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

domenico.mosca

Scusatemi se sono poco preciso, mi sto approcciando ad un mondo che per me è relativamente nuovo, quindi chiedo a voi...(spero di essere nella sezione corretta del forum, a questo punto)

La scheda USBIO24 ha una frequenza di 4 Mhz e io vorrei fare una lettura/scrittura ogni decimo di secondo.

A prescindere dal fatto che ci sono configurazioni del kernel linux che intervengono sullo scheduler e sulla sua frequenza per rendere lo scheduling dei processi più adatto alle necessità RT, ho capito che il PLC è la soluzione professionalmente ideale per questo tipo di ambienti, ma nel mio caso per vari motivi sto utilizzando un PC.

Non escludo di montare un PLC più avanti...ma il punto non è questo, il mio problema è semplicemente nel capire come fare ad utilizzare correttamente questa scheda, c'è qualcuno che magari ci ha già lavorato, (forse chi mel'ha segnalata ?) e può fornirmi dei feedback?

[edit]

a scanso di equivoci

i malfunzionamenti della scheda adesso sono dovuti sicuramente ad un'errato interfacciamento, a prescindere dall'HW che ci sta sotto e dal SO che lo gestisce, parliamo di risposte dopo 5/6 secondi o addirittura di errate letture, quindi c'è sicuramente qualcosa che non quadra...

Grazie

Modificato: da domenico.mosca
Link al commento
Condividi su altri siti

Questa scheda non l'ho mai usata (ho usato qualche volta NI, ma queste hanno vere caratteristiche RT Hw&Sw); ho dato una veloce lettura delle specifiche.

Spero tu abbia usato le DLL previste per l'ambiente Linux.

Se, come dici, puoi configurare Linux similmente all'antenato da cui ha orgine (UNIX) per schedurlare meglio i processi RT fallo!

Come ti ho scritto nel primo post devi leggere e scrivere le uscite fisiche in un momento ben preciso e tutte contemporaneamente. Il programma lo elabori sull'immagine degli ingressi letti e, similmente, aggiorni le immagini delle uscite.

Questo modo di procedere è comune a tutti i sistemi di automazione. O è trasparente per l'utilizzatore, come nel caso dei PLC, o viene schedulato nello RTOS, oppure si usa qaulche altro marchingegno.

Fanno eccezione i processi legati ad eventi particolari, generalmente gestiti ad interruzioni Hw.

Il tuo vero problema è capire in quanto tempo riesci a passare dal tuo applicativo all'uscita/ingresso fisico/a, in altri termini come interagisce il tuo applicativo con i vari livelli dello SO.

Link al commento
Condividi su altri siti

del_user_56966
parliamo di risposte dopo 5/6 secondi

Az... altro che lento è un eternità!... :lol:

ma il problema potrebbe essere tutto di carattere hardware....

come tutto di carattere software!

ma anche una miscela dei due, in questo caso serve un bel debug approfondito, devi studiarti la parte hardware e vedere se il software

che scrivi è allineato a quanto richiesto... insomma più che uno sviluppatore qui servirebbe un progettista... :lol:

Link al commento
Condividi su altri siti

cedo che la tua scheda venga vista dal sistema come una "seriale" ,quindi con dei tempi minimi di r/W verso O:S sotto ai cuali non puoi scendere , se ottieni tempi abissali e dati errati sicuramente la causa è da ricercarsi nel software (attuazione e ricezione alias asincronismo).

Se il tu scopo era creare un'interfaccia PC based su linux , forse la strada giusta era un PLC con porta mdbus attraverso la quale passavi i comandi e leggevi i dati con tempi certi (20/40ms se ben "impacchettati")

Link al commento
Condividi su altri siti

domenico.mosca

Ho contattato la ditta produttrice, vi farò sapere.

PS: le dll per linux non esistono ma è un'altro discorso....

Ciao e grazie

Link al commento
Condividi su altri siti

PS: le dll per linux non esistono ma è un'altro discorso....

meno di 30" usando google e, miracolo, guarda qua:

Precma

da cui si arriva qua, clickando su Linux Driver.

Linux_Driver

Ovviamente quando ho scritto, per abitudine, Linux DLL non ho usato un termine corretto, ma lo scopo era evidente.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

Visto che sono stato io a suggerire la scheda nel secondo messaggio, che ho anche usato con successo (programmandola in BASIC!) senza tutti questi problemi, contatta pure la Precma (che conosco bene) e esponi il problema. Vedrai che te lo risolvono.

Link al commento
Condividi su altri siti

domenico.mosca

[at]Livio Orsini

Grazie Livio, il link alla precma lo trovi nella seconda risposta di questa discussione...

comunque... i driver che uso sono quelli corretti come da documentazione e come da manuale, ma come detto più volte il problema è nel come interfacciarsi alla seriale lato software con 3 schede

Se implemento 2 processi uno che legge ed uno che scrive ho letture errate... se invece faccio un'unico processo che legge e scrive non ho proprio risposte.

[at]NoNickName

Grazie NoNickName, ho già contattato la Precma qualche giorno fa ma non mi sono stati molto d'aiuto...hanno ipotizzato dei cali di tensione sugli optoisolatori ma lo escludo, ho fatto più prove sia in officina che il laboratorio, con alimentazioni a 12VDC sia da batteria che da alimentatore e il comportamento è sempre lo stesso, sbagliato.

Io sono quasi certo che il problema sia nel mio programma, ed è questo (se leggete bene il mio post) che chiedevo semplicmente se qualcuno aveva già avuto esperienze pratiche con questa scheda ed in ambiente linux.

Comunque, ho scritto a quelli della ELEXOL, che sono i reali produttori della scheda... e vediamo cosa mi dicono loro.

Grazie, ciao.

Link al commento
Condividi su altri siti

Se implemento 2 processi uno che legge ed uno che scrive ho letture errate... se invece faccio un'unico processo che legge e scrive non ho proprio risposte.

Non è che scrivendo sempre le stesse cose risolvi il problema. Le linee da seguire ti son state indicate, poi fai come vuoi.

Link al commento
Condividi su altri siti

domenico.mosca

Ciao a tutti

confermo che il problema era legato ad una errata sincronizzazione dei due thread di lettura / scrittura.

Il mio errore era stato quello di usare un'unico semaforo sia per gestire i processi di scrittura che per gestire i processi di lettura e quindi ovviamente non si generavano dei lock esclusivi.

Se può interessare a qualcuno posto i 2 metodi che utilizzo.

void IOHandler::ReadProcess() {

    fstream in(this->device.c_str(), ios_base::in);
    char c;
    int CurrentPort = this->PortNumber2Read;

    // sblocco il processo di scrittura
    sem_post(&this->mutex_writer);

    while (in.good()) // loop while extraction from file is possible
    {
        sem_wait(&this->mutex_reader);

        c = in.get(); // get character from file
        CurrentPort = this->PortNumber2Read;


        if (in.good()) {

            this->ReadPortValues[CurrentPort] = int(c);

        } else {
            this->u->log->debug("IOHandler::ReadProcess errore di lettura");
        }
        sem_post(&this->mutex_writer);
    }

    in.close();

}

void IOHandler::WriteProcess() {
    this->u->log->debug("IOHandler::WriteProcess");

    // attendo che il processo di lettura sia pronto
    sem_wait(&this->mutex_writer);
    fstream out(this->device.c_str(), ios_base::out);

    /*
     * configuro le schede
     */
    //4 in - 4 out
    out << '!' << 'A' << char(15);
    out.flush();
    //8 out
    out << '!' << 'B' << char(0);
    out.flush();
    //4 in - 4 out
    out << '!' << 'C' << char(15);
    out.flush();


    while (true) {

        out.flush();

        /*
         * scrittura valori
         */

        this->PortNumber2Read = 0;
        out << 'A' << char(this->WritePortValues[0]);
        out.flush();
        out << 'a';
        out.flush();
        sem_post(&this->mutex_reader);
        sem_wait(&this->mutex_writer);

        this->PortNumber2Read = 1;
        out << 'B' << char(this->WritePortValues[1]);
        out.flush();
        out << 'b';
        out.flush();
        sem_post(&this->mutex_reader);
        sem_wait(&this->mutex_writer);

        this->PortNumber2Read = 2;
        out << 'C' << char(this->WritePortValues[2]);
        out.flush();
        out << 'c';
        out.flush();
        sem_post(&this->mutex_reader);
        sem_wait(&this->mutex_writer);

        // this->u->log->debug("IOHandler::WriteChannelValue A=%d,B=%d,C=%d",this->WritePortValues[0],this->WritePortValues[1],this->WritePortValues[2]);

        usleep(1000);

    }
    out.close();
}

Link al commento
Condividi su altri siti

domenico.mosca

ciao a tutti

per completezza, ho scoperto che impostando il comando 2

>Sets unit to Mode 2 (Enables transmit on pin change)

Si abilita la scheda a inviare automaticamente un comando

PORT+VALUE

ogni volta che un pin cambia valore.

Questa funzionalità è molto comoda perchè consente di evitare il polling e togliere tutte le sincronizzazioni con i semafori, alleggerendo molto il tutto.

posto il codice modificato

void IOHandler::ReadProcess() {

    fstream in(this->device.c_str(), ios_base::in);
    char c1, c2;
    int value;

    // sblocco il processo di scrittura
    sem_post(&this->mutex_writer);

    struct timespec timeout;

    while (in.good()) // loop while extraction from file is possible
    {
        c1 = in.get(); // get character from file

        switch (c1) {
        case 'a':
            this->PortNumber2Read = 0;
            break;
        case 'b':
            this->PortNumber2Read = 1;
            break;
        case 'c':
            this->PortNumber2Read = 2;
            break;
        default:
            this->PortNumber2Read = -1;
        }

        if(this->PortNumber2Read>=0){
            c2=in.get();
            value=(int)c2;
            this->ReadPortValues[this->PortNumber2Read]=value;
            this->u->log->debug("IOHandler::ReadProcess[%c]=%d",c1,value);
        }

    }

    in.close();

}

void IOHandler::WriteProcess() {
    this->u->log->debug("IOHandler::WriteProcess");

    // attendo che il processo di lettura sia pronto
    sem_wait(&this->mutex_writer);
    fstream out(this->device.c_str(), ios_base::out);
    /*
     * configuro le schede
     */
    //4 in - 4 out
    out << '!' << 'A' << char(15);
    out.flush();
    //8 out
    out << '!' << 'B' << char(0);
    out.flush();
    //4 in - 4 out
    out << '!' << 'C' << char(15);
    out.flush();

    /*
     * imposto il modo di lavoro 2 in modo che ad ogni cambiamento trasmetta automaticamente il valore
     */
    out << '2';
    out.flush();

    while (true) {
        /*
         * scrittura valori
         */
        out << 'A' << char(this->WritePortValues[0]);
        out.flush();
        usleep(5000);
        out << 'B' << char(this->WritePortValues[1]);
        out.flush();
        usleep(5000);
        out << 'C' << char(this->WritePortValues[2]);
        out.flush();
        usleep(5000);

        //        this->u->log->debug("IOHandler::WriteChannelValue A=%d,B=%d,C=%d",this->WritePortValues[0],this->WritePortValues[1],this->WritePortValues[2]);

    }
    out.close();
}

Ciao!

Link al commento
Condividi su altri siti

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 account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...