Vai al contenuto
PLC Forum


Considerazione "personale" su costo ambienti di sviluppo


Marco Mondin

Messaggi consigliati

8 ore fa, Marco Mondin ha scritto:

Alcune cose sono fatte davvero bene, come esempio mi viene da pensare al sistema di autotuning dei PID termici, che permette di ridurre l'intervento umano alle ultime affinature permettendo di risparmiare enormi quantità di tempo, in quanto un PID termico è sempre tedioso da tarare per la sua natura molto lenta ed i tempi fisici di riscaldamento/raffreddamento che non possono essere accorciati.

Mi fa piacere che qualcosa di Siemens ti piaccia ;-) , ma la funzione PID non riguarda l'ambiente di sviluppo in senso stretto. Poi, pensa che in tanti anni che lavoro con PLC Siemens, non ho mai usato una sola volta l'autotuning dei PID. Per due motivi: il primo è che, molto spesso, l'impianto non ti consente di seguire le variazioni di set point richieste per l'autotuning, ed il secondo è che, per tarare un PID, basta un po' di esperienza.
Ma, tornando all'ambiente di sviluppo, io mi riferisco alla facilità di inserire dispositivi nella configurazione hardware, all'integrazione in un unico ambiente di PLC, HMI, drive, a cose tipo il poter aggiungere un segmento in testo strutturato in un blocco in ladder, alla semplicità di gestione dell'interfaccia delle variabili dei blocchi, a funzioni di messa in servizio molto intuitive, a funzioni di trace altrettanto intuitive, a poter modificare il valore delle variabili agendo direttamente nei blocchi dati, senza dover per forza inserire le variabili in una tabella di watch od altro.
Per esempio, l'integrazione di PLC e HMI (una vera integrazione, non come era con il Wincc Flexible e il Simatic Manager), con variabili condivise, ti permette di modificare a piacere le variabili nel PLC, senza dover mettere mano al programma HMI. Addirittura, se nel PLC hai una struttura di variabili appoggiata ad un tipo di dati, e questa struttura viene usata nel HMI, se modifichi il tipo di dati si aggiorna in automatico anche l'HMI.
Poi la dichiarazione di array senza dimensione, o i dati "Variant", ti permettono di scrivere un codice molto flessibile.
Molto comodo poi, appena vai online, vedere al volo se il tuo programma corrisponde a quello presente nel PLC, avere subito in evidenza eventuali blocchi diversi, poter controllare le differenze, poter fare l'upload dal PLC dei singoli blocchi. Collegarsi ad un PLC e non essere certi di avere il programma allineato, è uno dei drammi peggiori per un programmatore.

 

9 ore fa, Marco Mondin ha scritto:

TIA è mostruosamente avaro di risorse, ed un ambiente di sviluppo poco scattante per alcuni sviluppatori è un incubo. Le licenze sono spropositatamente care, assolutamente non allineate a cosa offre. È lacunoso sull'object oriented, segue la sua strada separata dagli standard IEC. Ha una gestione dei dati con le DB che mascherano in modo veramente old school, una gestione dei dati che sotto in realtà è moderna e derivata dall'informatica pura. Nel 2020 dipendere da dati come M I(E) O(A) DB etc... è un po' masochistico, non parliamo della gestione degli OB che poteva avere un senso negli anni 90', ma oggi...!
Il difetto più grosso è la lingua! In informatica ormai per convenzione si da come standard assodato l'inglese (Se ne potrebbe discutere ore se è un bene o un male, ma in un mondo globalizzato anche qua uno standard è indispensabile e forse la lingua più usata è il male minore), perché è il più usato nel mondo e perché è brutto vedere applicativi arlecchino con le lingue. Fa molto disordine. Loro sono maniaci del tedesco!

Che dire, forse sbaglio, ma mi viene da pensare che, forse, non conosci il TIA molto bene. La gestione dei dati organizzata in DB io la considero un grande vantaggio, non uno svantaggio. Che poi, dei DB, se vuoi, non te ne importa nulla. Soprattutto usando i DB "ottimizzati", nel programma fai riferimento solo al nome delle variabili. In quanto a dipendere da "M I(E) O(A) DB etc.", non capisco. I merker, in realtà, oggi, si usano pochissimo. Praticamente solo quelli di sistema e poco più. Ingressi ed uscite fisici ci sono in tutti i PLC. Che poi la mappatura sia fatta in un file o nella "tabella delle variabili", cosa cambia? Ma, anche in questo caso, nel programma usi sempre solo il nome, mai l'indirizzo. E, se cambi l'indirizzo di un modulo di I/O, non devi cambiare assolutamente nulla nel programma.
In quanto alla lingua, ti basta impostare il TIA con mnemonico internazionale, ed è fatta. Non devi usare per forza il tedesco. Che poi, indipendentemente dall'impostazione, se nel codice scrivi "I0.0" oppure "E0.0", digerisce entrambe le scritture, e ti mette subito il nome della variabile.

 

Link al commento
Condividi su altri siti


14 ore fa, batta ha scritto:

Mi fa piacere che qualcosa di Siemens ti piaccia 😉

Diamo a Cesare ciò che è di Cesare.

Quote

ma la funzione PID non riguarda l'ambiente di sviluppo in senso stretto. Poi, pensa che in tanti anni che lavoro con PLC Siemens, non ho mai usato una sola volta l'autotuning dei PID. Per due motivi: il primo è che, molto spesso, l'impianto non ti consente di seguire le variazioni di set point richieste per l'autotuning, ed il secondo è che, per tarare un PID, basta un po' di esperienza.

Normalmente non uso funzioni di autotuning nemmeno io, ma una sera con 4 ore di fermo impianto per manutenzione, mi sono trovato a dover mettere un PID a un sistema veramente mal progettato, dove c'era un corpo metallico da 1 dm³ circa di volume, scaldato da una resistenza grossa come il tappo di una biro, con accoppiamento fatto male (Infatti bruciavano resistenze come non ci fosse un domani) e avevo un target di temperatura 170°C +/- 2°C da mantenete all'estremità opposta del corpo metallico (un parallelepiedo 60x60x300).
Chi aveva realizzato la macchina aveva messo un 1200, relè statici e avevano provato a farlo con isteresi, quando lo ho visto mi si sono rizzati i capelli (Ma come si fa a poter minimamente pensare di controllare un sistema così ad isteresi???), ho subito modificato l'applicativo e messo un PID che su SIEMENS è già bello pronto e fatto. Il problema è che per la fortissima inerzia termica di un sistema così mal progettato tararlo a mano mi avrebbe richiesto troppo tempo, in quanto ci andavano 20 minuti per andare in temperatura, quindi non avevo tempo per monitorare un grafico e affinare i coefficienti, di conseguenza l'autotuning fu una manna. Dovetti solo aggiustare un po' il derivativo e riuscii a restare nei range necessari.
Ci sono situazioni in cui nemmeno io uso gli autotuning, ma per esempio un autotuning ben fatto su un anello di velocità di un motore lavora meglio di come lavoro io e ci mette molto meno. Mi viene in questo caso da pensare alla autotaratura dell'anello di velocità dei brushless TDE macno o B&R, entrambi eccezionali. Diverso per quello di posizione non considero mai gli autotuning, faccio sempre a manina.

 

Quote


Poi la dichiarazione di array senza dimensione, o i dati "Variant", ti permettono di scrivere un codice molto flessibile.

 Questa è una bella cosa, soprattutto per chi è abituato a linguaggi moderni con i container dinamici (Lists, Hashs, Maps, Vectors, etc). In Codesys è abbozzata e funziona male e ne sento la mancanza.
 

Quote

Molto comodo poi, appena vai online, vedere al volo se il tuo programma corrisponde a quello presente nel PLC, avere subito in evidenza eventuali blocchi diversi, poter controllare le differenze, poter fare l'upload dal PLC dei singoli blocchi. Collegarsi ad un PLC e non essere certi di avere il programma allineato, è uno dei drammi peggiori per un programmatore.

Si, ma... Ci sono pro e contro... Se uno vuole con B&R e Codesys può trasferire anche il sorgente, che rimane un archivio nel dispositivo runtime. Io preferisco non farlo, ma di contro ci vuole metodo rigoroso a mantenere i sorgenti e posso capire non sia facile.

 

Quote

Che dire, forse sbaglio, ma mi viene da pensare che, forse, non conosci il TIA molto bene.

Senza dubbio non ti sbagli, ci ho lavorato pochissimo e solo per integrazioni di pezzi di SW e modifiche, come il recovery disaster del PID dove il softwarista originario non rispondeva nemmeno più al telefono. Io ero lì per altro e mi sono offerto (gratis) di risolvergli il problema.

 

Quote

La gestione dei dati organizzata in DB io la considero un grande vantaggio, non uno svantaggio.

Questo è il punto per me invece dolente, Più che altro la vedo statica. Sono a tutti gli effetti strutture, ma dichiarazione ed istanza coincidono e questo non mi piace, in quanto richiede il copia incolla, quando invece sarebbe molto più comoda la multi istanza. Omron per esempio ha messo sul sysmac le strutture vere e proprie, che poi a molti che non le hanno mai usate creino confusione, come la crea la multi istanza (visto tante volte) è un altro discorso. Poi magari non conoscendo bene TIA si possono fare più istanze dello stesso DB, ma non ho visto come. Il discorso ottimizzazione o meno, riguarda per me solo l'organizzazione in memoria, se non sono ottimizzate si può accedere in modo contiguo alla memoria e convertire una struttura(DB) in un pacchetto dati serializzato per ricostruirlo in un altro luogo, su quella ottimizzata non si può. Infatti tool come s7com di node.js leggono e scrivono DB solo se non ottimizzate. Tutto qua.
 

Quote

I merker, in realtà, oggi, si usano pochissimo. Praticamente solo quelli di sistema e poco più. Ingressi ed uscite fisici ci sono in tutti i PLC. Che poi la mappatura sia fatta in un file o nella "tabella delle variabili", cosa cambia? Ma, anche in questo caso, nel programma usi sempre solo il nome, mai l'indirizzo. E, se cambi l'indirizzo di un modulo di I/O, non devi cambiare assolutamente nulla nel programma.
In quanto alla lingua, ti basta impostare il TIA con mnemonico internazionale, ed è fatta. Non devi usare per forza il tedesco. Che poi, indipendentemente dall'impostazione, se nel codice scrivi "I0.0" oppure "E0.0", digerisce entrambe le scritture, e ti mette subito il nome della variabile.

Si, immagino che tu li usi poco, in quanto anche se sovente abbiamo visioni diverse, ho capito dalle tue parole che sei molto metodico e lavori bene, tuttavia mi imbatto sovente in applicativi fatti con il TIA in cui chi li ha fatti non usa minimamente quello che oggi si chiama IO Map. Non mi piace l'idea di avere indirizzi M di sistema, è una cosa pericolosa secondo me, ma questione personale. Diciamo che il TIA lascia un po' troppa libertà ai macellai di lavorare senza IO Map.
Diciamo che odio tutto ciò che non ha un nome preciso che indirizzi almeno a cosa indichi. Sono uno di quelli che odiano i magic numbers sugli applicativi PC per esempio.

Per farti un esempio di quanto io odio i magic numbers, quello che segue è il codice per trasmettere i pacchetti per un tracer a 4 tracce, pesca i dati da un buffer circolare creato da CODESYS in shared memory e li invia in TCP ai client che hanno necessità di tracciare graficamente o eventualmente registrare con un logger.
Anche nei calcoli numerici uso massicciamente costanti per indicare ogni cosa indica ogni pezzo di un qualunque calcolo.

#include "scopemanager.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
#include <QSettings>
#include <QDebug>
#include <QtMath>

ScopeManager::ScopeManager(ProcessAreaValuesScope *scoperArea, QObject *parent) : QObject(parent),
    area(scoperArea),
    m_tmScopeCheck(TM_DEF_CHECK_SCOPE_DATA),
    indexBuffer(0),
    time(0)
{
}

void ScopeManager::initalize()
{
    server = new QTcpServer(this);
    connect(server, &QTcpServer::destroyed, this, &ScopeManager::stopped);
    checkTimer = new QTimer(this);
    checkTimer->setSingleShot(true);
    connect(checkTimer, &QTimer::timeout, this, &ScopeManager::checkScope);
    QSettings setup;
    setup.beginGroup("Scope");
    if (!setup.contains("LISTEN_PORT"))
        setup.setValue("LISTEN_PORT", LISTEN_PORT);
    if (!setup.contains("LISTEN_ADDRESS"))
        setup.setValue("LISTEN_ADDRESS", LISTEN_ADDRESS);
    QHostAddress listenAddress(setup.value("LISTEN_ADDRESS").toString());
    quint16 listenPort(quint16(setup.value("LISTEN_PORT").toUInt()));
    setup.endGroup();
    connect(server, &QTcpServer::newConnection, this, &ScopeManager::newConnection);
    server->listen(listenAddress, listenPort);
    checkScope();
    emit initialized();
}

void ScopeManager::requestStop()
{
    server->close();
    checkTimer->stop();
    checkTimer->deleteLater();
    server->deleteLater();
}

void ScopeManager::checkScope()
{
    while (area->timeRead[indexBuffer] != area->timeWrite[indexBuffer]) {
        for (int index = 0; index < SCOPE_ACTIVE_TRACKS; index++)
            tracks[index].append((&area->scopeTrackA)[index][indexBuffer]);
        times.append(time);
        time++;
        area->timeRead[indexBuffer] = area->timeWrite[indexBuffer];
        indexBuffer++;
        if (indexBuffer == SCOPE_BUFFER_SIZE)
            indexBuffer = 0;
    }
    if (!times.isEmpty()) {
        QByteArray packet;
        quint16 numElems = quint16(times.size());
        quint16 vecSzTrack = numElems * sizeof (double);
        quint16 vecSzTime = numElems * sizeof (quint64);
        quint16 pkSize = 2 * sizeof(quint16) + SCOPE_ACTIVE_TRACKS * vecSzTrack + vecSzTime;
        packet.resize(pkSize);
        char *start = packet.data();
        *(reinterpret_cast<quint16 *>(start)) = pkSize;
        start += sizeof(quint16);
        *(reinterpret_cast<quint16 *>(start)) = numElems;
        start += sizeof(quint16);
        for (int index = 0; index < NUM_NET_TRACKS; index++) {
            memcpy(start, tracks[index].data(), vecSzTrack);
            start += vecSzTrack;
            tracks[index].clear();
        }
        memcpy(start, times.data(), vecSzTime);
        times.clear();
        foreach (QTcpSocket *socket, clients)
            socket->write(packet, pkSize);
    }
    checkTimer->start(m_tmScopeCheck);
}

void ScopeManager::newConnection()
{
    while (server->hasPendingConnections()) {
        clients.append(server->nextPendingConnection());
        connect(clients.last(), &QTcpSocket::disconnected, this, &ScopeManager::removeClient);
        connect(clients.last(), &QTcpSocket::destroyed, this, &ScopeManager::removeClient);
        clients.last()->write("Disabled\x1b" + QByteArray::number(0) + "\r\n");
        for (int index = 0; index < NUM_SCOPE_TRACKS; index++) {
            QByteArray name(reinterpret_cast<char *>(&area->trackNames[index * SZ_NAME_TRACKS]), -1);
            if (!name.isEmpty())
                clients.last()->write(name + "\x1b" + QByteArray::number(area->trackTids[index]) + "\r\n");
        }
        clients.last()->write("\x1b\x1b");
    }
}

void ScopeManager::removeClient()
{
    QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());
    if (client)
        clients.removeAll(client);
}

int ScopeManager::tmScopeCheck() const
{
    return m_tmScopeCheck;
}

void ScopeManager::setTmScopeCheck(int tmScopeCheck)
{
    m_tmScopeCheck = tmScopeCheck;
}

 

Modificato: da Marco Mondin
Link al commento
Condividi su altri siti

5 ore fa, Marco Mondin ha scritto:

quando invece sarebbe molto più comoda la multi istanza

Non so se come "multi istanza" intendiamo la stessa cosa ma, nel Siemens, esiste da tantissimo tempo.
Inoltre io faccio largo uso di quelli che Siemens chiama "Tipo di Dati" (UDT nel Simatic Manager). Se una struttura la utilizzo anche due sole volte (o anche una sola volta, se penso possa tornarmi comodo) creo sempre il "Tipo di dati" di questa struttura. In caso di modifiche, basta modificare solo il tipo di dati. Questo risulta comodo anche per passare i parametri ad una funzione: si dichiarano all'interno della funzione come IN/OUT e, in una sola riga, si passa tutta la struttura. Potrebbero anche essere dichiarati come INPUT o OUTPUT ma, in questo caso, oltre a limitare l'accesso in una sola direzione (a volte utile, a volte limitativo), nella funzione verrebbe creata una copia completa dell'intera struttura, generando inutile spreco di memoria e di lavoro per la CPU. Passando invece la struttura come IN/OUT, viene generato un puntatore, con benefici sia per il risparmio di memoria, sia per i tempi di accesso alle variabili (soprattutto se ottimizzate).
La suddivisione in DB la ritengo quindi utile perché ti permette di suddividere i dati secondo la loro funzione. Banalizzando: un DB "Setup", un DB "Hmi", un DB "work"...

 

5 ore fa, Marco Mondin ha scritto:

Non mi piace l'idea di avere indirizzi M di sistema, è una cosa pericolosa secondo me, ma questione personale.

Come merker di sistema intendo flags tipo "FisrstScan", "AlwaysOn" e "AlwaysOff" (tra l'altro usati solo nel ladder, dato che in strutturato è molto più comodo usare "True" e "False"), clock con diverse frequenza (di solito usati per lampeggi e simili). Poi, anche questi merker di sistema, o li passo alle funzioni come parametri, o li appoggio a variabili locali della funzione.

 

5 ore fa, Marco Mondin ha scritto:

Diciamo che odio tutto ciò che non ha un nome preciso che indirizzi almeno a cosa indichi.

Su questo sono assolutamente d'accordo. Ora, nel TIA, se tu richiami un indirizzo al quale non è stato assegnato un nome, viene assegnato automaticamente il nome "Tag_xxx". Certo, non dice nulla riguardo la funzione, ma solo per dire che il programma lavora con i nomi, e non con gli indirizzi.
Nel Simatic Manager questo non c'era ma, nei miei programmi, per sapere se un certo indirizzo era utilizzato o meno, non ti serviva fare il cross reference: se non aveva un nome, era sicuramente libero.

 

5 ore fa, Marco Mondin ha scritto:

Sono uno di quelli che odiano i magic numbers sugli applicativi PC per esempio.

Anche qui sfondi una porta aperta. Solo per cose estremamente banali mi capita di usare un numero. Per tutto il resto, si usano le costanti.
Per fare un esempio: mi trovo spesso a lavorare su impastatrici. Come standard, quasi sempre si prevedono 10 fasi con 10 ingredienti per ogni fase. Ma quei due 10 sono due costanti, usate nella dichiarazione degli array, nei cicli FOR, e in tutti i punti dove serve. Se devo modificare il numero di fasi o di ingredienti da gestire, cambio solo il valore della relativa costante.
 

 

Dai, vedo che, almeno qualche volta, sono molti di più i punti sui quali ci troviamo d'accordo di quelli in disaccordo 😉

Modificato: da batta
Link al commento
Condividi su altri siti

  • Livio Orsini locked this discussione

gli accodamenti non sono consentiti, inoltre questa discussione è inattiva da oltre 20 mesi.

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

Ospite
Questa discussione è chiusa alle risposte.
×
×
  • Crea nuovo/a...