Sommario:

EAL-Industri4.0-RFID Dataopsamling Til Database: 10 passaggi (con immagini)
EAL-Industri4.0-RFID Dataopsamling Til Database: 10 passaggi (con immagini)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 passaggi (con immagini)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 passaggi (con immagini)
Video: Industry 4.0 Internet of Things, Technology Evolution & Big Data. How Technology Changes Our Lives 2024, Luglio
Anonim
EAL-Industri4.0-RFID Dataopsamling Til Database
EAL-Industri4.0-RFID Dataopsamling Til Database

Dette projekt omhandler opsamling af vægtdata, registrering af identiteter vha. RFID, lagring di dati nel database MySQL vha. node-RED, samt fremvisning og behandling di dati opsamlede e il programma C# formò un'applicazione Windows Form. Vi forestiller os følgende:

Vi har en produktionslinje som producerer leverpostej i 200g foliebakker. Tutti i tipi di tag RFID e di tag RFID e di etichettatura, oltre a un indeholder e un ID unikt (UID = Unique Identifier, in codice a 32 bit, 8 caratteri esadecimale) per l'identificazione dell'intero numero di elementi. Da færdigvægten af hver enkelt bakke leverpostej kan svinge (afhængig af råvarer, fordampning i ovn mm), og da kunderne hver har et specifikt krav færdigvægten, bruges UID tagget til at knylevation hver enkelt leverpostejer til én specific kunde. Kunderne er supermarkedskæder:

1. Irma. Vægten på Irmas luksus leverpostej skal holde sig inden per +/- 5%, altså minimo 190g og maksimum 210g.

2. Bruges. Vægten på Brugsens leverpostej skal holde sig inden per +/- 10%, altså minimo 180 g og massimo 220 g.

3. Aldi. Vægten på Aldis sconto leverpostej skal holde sig inden per +/- 15%, altså minimo 170g og maksimum 230g.

Der er således følgende sorteringer:

Range0: fuori range

Gamma 1: minimo 190 g/massimo 210 g

Gamma2: minimo 180 g/massimo 220 g

Gamma3: minimo 170 g/massimo 230 g

Passaggio 1: Opsamling dati Af per Vægt Samt Registrazione Af UID

Opsamling Af Data per Vægt Samt Registrazione Af UID
Opsamling Af Data per Vægt Samt Registrazione Af UID

Fino all'acquisizione dei dati per la visualizzazione, come la registrazione dei tag RFID e la vendita su Arduino MEGA2560 con lettore/scrittore RFID-RC522. Da vi ikke har nogen vægt, simulerer vi data for vægten med et potmeter tilsluttet en analog indgang på Arduinoen.

Følgende opstilling er anvendt:

1 stk potmeter 25k lineært. Yder-benene er tilsluttet hhv. GND e +5V, intermedi e bassi AN0

RFID-RC522 per schede Arduino per schede Arduino Porta SPI per dimensioni:

SDA -> pin 53

SCK -> pin52

MOSI ->pin51

MISO->pin50

IRQ ->NC

GND -> GND

RST -> pin5

3,3 V -> 3,3 V

Dati opsamlede, per hhv. UID e vægten, invia per den serielle port som en komma-separeret tekststreng videre til node-Red som står per den efterfølgende præsentation på et dashboard og lagring nel database.

Passaggio 2: programma Arduino

Il programma Arduino include il file biblioteker SPI.h og MFRC522.h per la maggior parte dei codici RFID. I starten af programt initialiseres de anvendte variabile. Der laves en instans af MFRC522. I Setup blocchi inizializzate per serielle forbindelse, porta SPI og MFRC522. Scansioni successive ai tag RFID. For ikke at sende det samme UID afsted flere gange efter hinanden, er der lavet en stump kode som tjekker for dette. Non hai più scannet e tag UID, carica una serie di nyUID con il netop læste UID. Hvis array nyUID er forskellig fra oldUID er tale om et nyt UID som kan sendes på den serielle port. Hvis nyUID e oldUID er ens, er der tale om samme UID tag og UID'et skal ignoreres. Hvis der er tale om et nyt UID, invia UID'et på den serielle port sammen med en læst værdi fra den serielle port. Den analoge værdi skaleres til området 150-250. I dati inviano alcuni tekststreng komma-separeret. Som det sidste sættes oldUID = nyUID, således e koden klart fino a læse et nyt RFID tag.. Densate funktion i programter er den funktion som sammenligner 2 arrays. Funktionen returnerer true hvis array'ne er ens, og false hvis array'ne er forskellige.

#includere

#include // Questo programma esegue la scansione delle schede RFID utilizzando la scheda di lettura/scrittura RDIF-RC522. // Viene letto l'UID, viene letto un pin analogico. Il valore analogico 0-1023 viene scalato a 150-250. // L'UID e il valore analogico vengono inviati come testo separato da virgole sulla porta seriale utilizzando 9600, N, 8, 1. // È stata prestata attenzione a inviare ogni UID solo una volta di seguito, // è necessario un nuovo UID presente prima che lo stesso UID possa essere inviato nuovamente. // Questa funzione viene implementata nel codice confrontando gli array: oldUIDnyUID nella funzione array_cmp(oldUID, nyUID)

constexpr uint8_t RST_PIN = 5;

constexpr uint8_t SS_PIN = 53; int sensorePin = A0; int Valore = 0; String StringValue = "0000"; byte oldUID[4] = {}; byte nyUID[4] = {};

MFRC522 mfrc522(SS_PIN, RST_PIN); // Crea un'istanza MFRC522.

configurazione nulla()

{ Serial.begin(9600); // Avvia una comunicazione seriale SPI.begin(); // Avvia il bus SPI mfrc522. PCD_Init(); // Avvia MFRC522 }

ciclo vuoto()

{ // Cerca nuove carte if (! mfrc522. PICC_IsNewCardPresent()) { return; } // Seleziona una delle carte if (! mfrc522. PICC_ReadCardSerial()) { return; } //carica nyUID con il tag UID for (byte i = 0; i < mfrc522.uid.size; i++) { nyUID = mfrc522.uid.uidByte; } // if oldUIDnyUID if (!array_cmp(oldUID, nyUID)) { // invia il tag UID sulla porta seriale for (byte i = 0; i 1000) { Value = 1000; } Valore = (Valore / 10) + 150; // invia il valore analogico scalato Serial.print(Value); // invia nuova riga Serial.println(); //set oldUID = nyUID for (byte z = 0; z < 4; z++) oldUID[z] = nyUID[z]; } // aspetta 1 sec delay(1000); }

// confronta 2 array…

boolean array_cmp(byte a, byte b) { bool test = true; //verifica che ogni elemento sia lo stesso. se solo uno non lo è, restituisce false for (byte n = 0; n < 4; n++) { if (a[n] != b[n]) test = false; // if on byte non uguale, test = false } if (test == true) return true; altrimenti restituisce false; }

Passaggio 3: Nodo-RED, Lagring Af Data I Database

Nodo-RED, Lagring Af Data I Database
Nodo-RED, Lagring Af Data I Database
Nodo-RED, Lagring Af Data I Database
Nodo-RED, Lagring Af Data I Database

Følgende flower er lavet i node-RED:

COM4 er den serielle forbindelse hvor data modtages fra Arduino boardet. Funzionalità "Dividi e ottieni valore" e "Dividi e ottieni UID" Teksstrengen ved kommaet og returnere hhv vægten and UID. Vgten bruges til fremvisning på dashboardet et linechart og en scale. UID fremvises i et tekstfelt. Funktionen test_sound advarer verbalt med sætningen "Out of range", hvis vægten er under 170g eller over 230g, dvs i range 0.

Dividi e ottieni valore:

var output = msg.payload.split(', ');

temp = {carico utile:(output[1])}; temperatura di ritorno;

Dividi e ottieni UID:

var output = msg.payload.split(", ");

temp = {carico utile:output[0]}; temperatura di ritorno;

suono_test:

var numero = parseInt(msg.payload);

if (numero >230 || numero<170) { newMsg = {payload:"Fuori intervallo"}; restituisce nuovoMsg; } else { newMsg = {payload:""}; ritorna nuovoMsg; }

Funzioni Split string ", " indsætter et timestamp, UID e vægten nel database patedb.patelog.

var output = msg.payload.split(", "); //dividi msg.payload per virgola in array

UIDTag = output[0]; //prima parte in prima posizione [0] ValueTag = output[1]; //seconda parte in seconda posizione [1]

var m = {

topic: "INSERT INTO patedb.patelog (timestamp, UID, peso) VALUES('"+new Date().toISOString()+"', '"+ UIDTag +"', '"+ValueTag+"');" }; ritorno m;

Patelog er en MySQL database forbindelse so er sat op med følgende parametro:

Host: localhost

Porta: 3306

Utente: root

Database: patedb

Passaggio 4: progettazione del database

Database-design
Database-design

Databasen patedb indeholder 4 tabeller

Patelog er dataopsamlingstabellen, tilskrives data af node-RED og C# programt

ordertable er en tabel som indeholder data om de genemførte ordrer, tilskrives data af C# programt

customertable er et kunderegister

rangetable er en tabel som indeholder grænseværdierne for de i C# programt benyttede ranges.

Passaggio 5: Patelog

Patelog
Patelog

Tabellen patelog indeholder folgende 6 kolonner:

pateID (int) er chiave primaria og inkrementeres automatisk.

Timestamp, UID e vægt er af typen varchar (med forskellig max længde)

rangeNr er af typen tinyint (beregnes og tilføjes af C# programt)

orderID er af typen int (orderID tilføjes af C# programt)

Node-RED tilføjer ikke værdier til kolonnerne rangeNr og orderID. rangeNr og orderID tillader NULL værdier, det bruges i C# programt til at detektere de rækker som skal tilskrives værdier for rangeNr og orderID

Passaggio 6: tabella degli ordini

Tabella degli ordini
Tabella degli ordini

indeholder tabella ordinabile 5 kolonner:

orderID (int) er det aktuelle ordrenummer

orderQuant (mediumint) er ordens pålydende antal

quantProduced (mediumint) er antal der rent faktisk er produceret på ordren. (Tlles a C# programt)

comment (tinytext) er en eventuel kommentar til ordren.

customerID (int) er det aktuelle kundenummer på ordren.

Passaggio 7: tabella clienti

Customertable
Customertable

customertable indeholder 6 kolonner:

customerID (int) er chiave primaria og auto inc.

nome, indirizzo, telefono, e-mail (varchar) med forskellig max længde

rangeNr (int)

Step 8: Rangetable

Rangetable
Rangetable

portatarga indeholder 3 kolonner:

rangeNr (int) er chiave primaria og auto inc.

rangeMin (int)

rangeMax (int)

Passaggio 9: programma C#

Programma C#
Programma C#

Når der produceres en ordre leverpostej, er proceduren følgende:

Kundenummer, ordrenummer, ordreantal og en eventuel kommentar indtastes i C# programt (i praksis overføres det digitalt fra virksomhedens ordresystem. Produktionen startes nu ved tryk på 'start'- knappen. på et transportbånd) Samhørende værdier af UID og den aktuelle vægt sendes serielt til node-RED, som viser de opsamlede data på dashboard 'et. Samtidig skrives timestamp, UID og vægt i en ny række i patednv. tidspunkt ikke tilskrives værdier til rangeNr og orderID vil de have værdien NULL.

Med e timerinterval undersøger C# programt patedb.patelogtabellen for nye tilkomne rækker med NULL værdier i rangeNr kolonnen. Når der er detekteret en række med NULL værdi, beregnes rangeNr og det tilføjes sammen med det aktuelle orderID. Når en ordre er produceret, afsluttes ordren ved tryk på”stop”- knappen. Når ordren afsluttes, tilføjes en række til patedb.ordertable med de aktuelle ordredata. Non si può ordinare, non è possibile eseguire operazioni di dati e visualizzare tabelle di fremvises e provare a eseguire operazioni di forskellige knapper nel gruppo Update DataGridview. ordertable kan også vises, og der kan søges ordredata på individueller UID'er eller kundedata på individuelle ordrer.

usando System;usando System. Collections. Generic; utilizzando System. ComponentModel; utilizzando System. Data; utilizzando System. Drawing; utilizzando System. Linq; utilizzando System. Text; utilizzando System. Threading. Tasks; utilizzando System. Windows. Forms; utilizzando MySql. Data. MySqlClient;

spazio dei nomi show_data_from_database

{ public partial class Form1: Form { MySqlConnection connection = new MySqlConnection("datasource=localhost; username=root; password=''"); int NumeroRiga = 0; // Variabile per la memorizzazione del valore pateID int RangeNumber = 0; //Variabile per memorizzare rangenumber int peso =0; // Variabile per memorizzare il peso int OrderNr = 0; // Variabile per memorizzare OrderNR int QuantProduced = 0; //Variabile per memorizzare la quantità prodotta int NumberOfRows = 0; //numero di righe con null.. bool ProdRunning = false; //Variabile che indica se i pulsanti di avvio e arresto sono stati attivati intlimits = new int[6];// inizializza l'array int CustomerID; // Variabile per memorizzare customerID public Form1() { InitializeComponent(); load_table(); // chiama load_table }

void load_table()

{ MySqlCommand command = new MySqlCommand("SELECT * FROM patedb.patelog ORDER BY timestamp DESC;", connection); prova { adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder(); adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } }

vuoto privato SetRowOrder()

{ dataGridView1. Columns["pateID"]. DisplayIndex = 0; // Il suo kan rækkefølgen af kolonner ndres dataGridView1. Columns["timestamp"]. DisplayIndex = 1; // Il suo kan rækkefølgen af kolonner ndres dataGridView1. Columns["UID"]. DisplayIndex = 2; // Her kan rækkefølgen af kolonner ndres dataGridView1. Columns["weight"]. DisplayIndex = 3; // Il suo kan rækkefølgen af kolonner ndres dataGridView1. Columns["rangeNr"]. DisplayIndex = 4; // Il suo kan rækkefølgen af kolonner ndres dataGridView1. Columns["orderID"]. DisplayIndex = 5; // Il suo kan rækkefølgen af kolonner ændres }

private void GetData_Click (mittente oggetto, EventArgs e) // Legge la tabella del database e gli ordini per Timestamp

{ load_table(); }

private void btnRefreshUID_Click (mittente oggetto, EventArgs e) //

{ string timeStr = "SELECT * FROM patedb.patelog ORDER BY UID;"; comando MySqlCommand = new MySqlCommand(timeStr, connessione); prova { adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder(); adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } }

private void btnRefreshValue_Click (mittente oggetto, EventArgs e)

{ string weightSort = "SELECT * FROM patedb.patelog ORDER BY CAST(weight AS SIGNED INTEGER);"; comando MySqlCommand = new MySqlCommand(weightSort, connection); prova { adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder(); adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } }

private void ChkNullBtn_Click (mittente oggetto, EventArgs e)

{ if (ProdRunning) { CheckTableForNull(); load_table(); } }

private void CheckTableForNull()

{ //Controlla/imposta l'intervallo del timer minimo 100 ms int i; int. TryParse(textTimer1. Text, out i); if (i <100) { timer1. Stop(); io = 100; timer1. Intervallo = i; MessageBox. Show("Valore minimo i 100mS"); timer1. Start(); } else { timer1. Intervallo = i; } textTimer1. Text = timer1. Interval. ToString(); //Controlla se sono disponibili righe con null nella tabella, restituisce il numero di righe nella variabile:NumberOfRows string weightStr = ""; string chkNull = "SELECT COUNT(*) FROM patedb.patelog WHERE rangeNR IS NULL ORDER BY pateID LIMIT 1;"; comando MySqlCommand = new MySqlCommand(chkNull, connessione); prova { connessione. Open(); NumberOfRows = Convert. ToInt32(command. ExecuteScalar()); connessione. Chiudi(); } catch (eccezione es.) { MessageBox. Show(ex. Message); } infine { if (NumberOfRows != 0) { try { //Seleziona il numero pateID più basso dove rangeNr è NULL string readID = "SELECT pateID FROM patedb.patelog WHERE rangeNR IS NULL ORDER BY pateID ASC LIMIT 1;"; MySqlCommand cmdID = new MySqlCommand(readID, connessione); { connessione. Apri(); RowNumber = (int)cmdID. ExecuteScalar(); //numero intero!! connessione. Chiudi(); } listPateID. Text = RowNumber. ToString(); // legge il numero PateID selezionato // Seleziona il peso dalla stringa rownumber selezionata row = RowNumber. ToString(); stringa readweight = "SELECT peso FROM patedb.patelog WHERE pateID=" + riga; MySqlCommand cmdweight = new MySqlCommand(readweight, connection); { connessione. Apri(); weightStr = (string)cmdweight. ExecuteScalar(); //Corda !! connessione. Chiudi(); } peso = int. Parse(weightStr); // converti in int txtWeight. Text = weight. ToString(); // print int RangeNumber = 0; if (peso>= limiti[0] && peso = limiti[2] && peso = limiti[4] && peso <= limiti[5]) { RangeNumber = 3; } } txtRange. Text = RangeNumber. ToString(); AggiornaLog(); } catch (eccezione es.) { MessageBox. Show(ex. Message); } QuantProduced = QuantProduced + 1; } } } private void btnStart_Click (mittente oggetto, EventArgs e) { if (ProdRunning == false) { int valtest; prova { CustomerID = int. Parse(txtCustomerNr. Text); //read customerID } catch { MessageBox. Show("Inserisci i dati di produzione e premi il pulsante 'start'."); }

stringa test = "SELECT COUNT(*) FROM patedb.customertable WHERE customerID ="+CustomerID;

MySqlCommand cmdtestcustomer = new MySqlCommand(test, connection); { connessione. Apri(); valtest = Convert. ToInt32(cmdtestcustomer. ExecuteScalar()); // restituisce 0 se il cliente non esiste connection. Close(); } if (valtest==1) // se il cliente esiste nel database - avvia la produzione { try { OrderNr = int. Parse(txtOrderNumber. Text); ProdRunning = vero; timer1. Start(); textTimer1. Text = timer1. Interval. ToString(); ReadLimits(); } catch (eccezione es.) { MessageBox. Show("Inserisci i dati di produzione e premi il pulsante 'start'."); } } else MessageBox. Show("Cliente non presente nel database, riprova"); } //Limiti di lettura(); }

private void ReadLimits()

{ // Legge i limiti da rangetable, range da 1 a 3 int counter = 0; for (int rangeNr = 1; rangeNr < 4; rangeNr++) { string readmin = "SELECT rangeMin FROM patedb.rangetable WHERE rangeNr=" + rangeNr; MySqlCommand cmdmin = new MySqlCommand(readmin, connection); { connessione. Apri(); limit[counter] = (int)cmdmin. ExecuteScalar(); contatore = contatore + 1; connessione. Chiudi(); } // MessageBox. Show(counter. ToString()); stringa readmax = "SELECT rangeMax FROM patedb.rangetable WHERE rangeNr=" + rangeNr; MySqlCommand cmdmax = new MySqlCommand(readmax, connection); { connessione. Apri(); limit[counter] = (int)cmdmax. ExecuteScalar(); contatore = contatore + 1; connessione. Chiudi(); } } // fine del ciclo }

privato void UpdateLog()

{ // AGGIORNA rangeNR e orderID string Range = RangeNumber. ToString(); string Order = OrderNr. ToString(); string update = "UPDATE patedb.patelog SET rangeNr= "+Range+', ' + "orderID= "+OrderNr+" WHERE pateID="+RowNumber; MySqlCommand updatecmd = new MySqlCommand(aggiornamento, connessione); prova { connessione. Open(); updatecmd. ExecuteNonQuery(); connessione. Chiudi(); } catch (eccezione es.) { MessageBox. Show(ex. Message); } }

private void btnStop_Click(mittente oggetto, EventArgs e)

{ if (ProdRunning == true) { timer1. Stop(); ProdRunning = false; UpdateOrderTable(); } else { MessageBox. Show("Nessuna produzione ancora iniziata. Inserisci i dati e premi il pulsante 'start'"); } }

private void UpdateOrderTable()

{ string insert = "INSERT INTO patedb.ordertable (orderID, orderQuant, quantProduced, comment, customerID) VALUES ('" + this.txtOrderNumber. Text + "', '" + this.txtOrderQuant. Text + "', '"+ QuantProduced. ToString()+"', '"+this.txtComment. Text+"', '"+this.txtCustomerNr. Text+"');"; MySqlCommand insertcmd = new MySqlCommand(insert, connection); prova { connessione. Open(); insertcmd. ExecuteNonQuery(); connessione. Chiudi(); QuantProdotto = 0; } catch (eccezione es.) { MessageBox. Show(ex. Message); } }

private void timer1_Tick (mittente oggetto, EventArgs e)

{ CheckTableForNull(); load_table(); }

private void btnShowOrderTable_Click(mittente oggetto, EventArgs e)

{ if (ProdRunning == false) { MySqlCommand command = new MySqlCommand("SELECT * FROM patedb.ordertable ORDER BY orderID DESC;", connection); prova { adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } } else { MessageBox. Show("Premi stop per visualizzare la tabella degli ordini"); } }

private void btnShowOrderDetails_Click(mittente oggetto, EventArgs e)

{ if (ProdRunning == false) { string test = ("SELECT patedb.ordertable.orderID, orderQuant, quantProduced, comment, customerID FROM patedb.ordertable INNER JOIN patedb.patelog ON patedb.patelog.orderID= patedb.ordertable.orderID WHERE patedb.patelog. UID = '" + txtShowOrderDetails. Text + "'"); comando MySqlCommand = new MySqlCommand(test, connection); prova { connessione. Open(); Adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } connessione. Close(); } else { MessageBox. Show("Premi stop per visualizzare i dettagli dell'ordine"); } }

private void btnShowCustomerDetails_Click(mittente oggetto, EventArgs e)

{ if (ProdRunning == false) { string test = ("SELECT patedb.customertable.customerID, nome, indirizzo, telefono, e-mail, rangeNr FROM patedb.customertable INNER JOIN patedb.ordertable ON patedb.ordertable.customerID= patedb.customertable. customerID WHERE patedb.ordertable.orderID = '" + txtShowCustomerDetails. Text + "'"); comando MySqlCommand = new MySqlCommand(test, connection); prova { adattatore MySqlDataAdapter = new MySqlDataAdapter(); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable(); adapter. Fill(dbdataset); BindingSource bsource = new BindingSource(); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update(dbdataset); } catch (eccezione es.) { MessageBox. Show(ex. Message); } } else { MessageBox. Show("Premi stop per visualizzare i dettagli del cliente"); } } }

}

Consigliato: