Índice:

EAL-Industri4.0-RFID Dataopsamling Til Database: 10 etapas (com imagens)
EAL-Industri4.0-RFID Dataopsamling Til Database: 10 etapas (com imagens)

Vídeo: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 etapas (com imagens)

Vídeo: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 etapas (com imagens)
Vídeo: TPM 2.0 Unveiled: Empowering IT Pros with Trusted Platform Module Insights 2024, Novembro
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 af data in MySQL database vha. node-RED, samt fremvisning e behandling af de opsamlede data i et C # program in form at Windows Form Application. Vi forestiller os følgende:

Vi har en produktionslinje som produtor leverpostej i 200g foliebakker. Todos os udstyres de alavanca de færdigbagte após afkøling med et RFID tag in plasticlåget / labelen, some indeholder et unikt ID (UID = Unique Identifier, er en 32 bits kode, 8 hexadecimale karakterer) para entydig identifikation af hver enkelt bakke leverpostej. 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 maga færdigvægten, bruges UID Tagget dotado pelo knytte hver enkelt Leverpostej til en specifik lagerlokation relativos lageret, hvor der Kun lagres leverpostejer til én specifik kunde. Kunderne er supermarkedskæder:

1. Irma. Avalie på Irmas luksus leverpostej skal holde sig inden para +/- 5%, mínimo 190g e máximo 210g.

2. Brugsen. Veja no Brugsens leverpostej skal holde sig inden para +/- 10%, mínimo 180g e máximo 220g.

3. Aldi. Vægten på Aldis desconto de taxa postej skal holde sig inden para +/- 15%, altså mínimo 170g e máximo 230g.

Der er således følgende sorteringer:

Intervalo 0: fora do intervalo

Faixa 1: mínimo 190g / máximo210g

Faixa 2: mínimo 180g / máximo220g

Faixa 3: mínimo 170g / máximo230g

Etapa 1: Opsamling Af Data para Vægt Samt Registrering Af UID

Opsamling Af Data para Vægt Samt Registrering Af UID
Opsamling Af Data para Vægt Samt Registrering Af UID

Até a obtenção de dados para vægt, mesmo registro de tags RFID e anvendt em Arduino MEGA2560 com leitor / gravador RFID-RC522. Da vi ikke har nogen vægt, simulador 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 og + 5V, midterbenet er tilsluttet AN0

RFID-RC522 er tilsluttet Arduino boardets SPI port på følgende måde:

SDA -> pino 53

SCK -> pin52

MOSI -> pin51

MISO-> pin50

IRQ -> NC

GND -> GND

RST -> pin5

3,3 V -> 3,3 V

De opsamlede data, para hhv. UID e vægten, envia på den serielle port som en komma-separeret tekststreng videre to node-Red som står for den efterfølgende præsentation på et dashboard e lagring in en database.

Etapa 2: programa Arduino

I Arduino programmet inkluderes de to biblioteker SPI.h og MFRC522.h para at kunne bruge RFID læseren. I starten af programmet initialiseres de anvendte variable. Der laves en instans af MFRC522. I Setup blokken initialiseres den serielle forindelse, SPI porten og MFRC522. Desrespeite a leitura após as etiquetas RFID. For ikke e sende det samme UID afsted flere gange efter hinanden, er der lavet en stump kode som tjekker for dette. Når der er scannet et UID tag, loades arary nyUID med det netop læste UID. Hvis array nyUID er forskellig fra oldUID er der tale om et nyt UID que kan sendes på den serielle port. Hvis nyUID e oldUID er ens, er der tale om mesmo tag UID e UID'et skal ignoreres. Hvis der er tale om et nyt UID, sendes 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. Os dados são enviados para você. Som det sidste sættes oldUID = nyUID, således e koden klart to læse et nyt tag RFID.. Den sidste funktion i programmet er den funktion som sammenligner 2 arrays. Retornador de função true hvis array'ne er ens, og false hvis array'ne er forskellige.

#incluir

#include // Este programa verifica os cartões RFID usando a placa de leitura / gravação RDIF-RC522. // UID é lido, um pino analógico é lido. O valor analógico 0-1023 é escalado para 150-250. // UID e valor analógico são enviados como texto separado por vírgulas na porta serial usando 9600, N, 8, 1. // Cuidado foi tomado para enviar cada UID apenas uma vez em uma linha, // um novo UID deve ser presente antes que o mesmo UID possa ser enviado novamente. // Esta função é implementada no código comparando matrizes: oldUID nyUID na função array_cmp (oldUID , nyUID )

constexpr uint8_t RST_PIN = 5;

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

MFRC522 mfrc522 (SS_PIN, RST_PIN); // Cria instância MFRC522.

void setup ()

{Serial.begin (9600); // Inicia uma comunicação serial SPI.begin (); // Inicia o barramento SPI mfrc522. PCD_Init (); // Iniciar MFRC522}

void loop ()

{// Procure por novos cartões if (! Mfrc522. PICC_IsNewCardPresent ()) {return; } // Selecione um dos cartões if (! Mfrc522. PICC_ReadCardSerial ()) {return; } // carregar nyUID com tag UID para (byte i = 0; i <mfrc522.uid.size; i ++) {nyUID = mfrc522.uid.uidByte ; } // if oldUID nyUID if (! array_cmp (oldUID, nyUID)) {// enviar tag UID na porta serial para (byte i = 0; i 1000) {Value = 1000; } Valor = (Valor / 10) + 150; // envia valor analógico em escala Serial.print (Value); // enviar nova linha Serial.println (); // definir oldUID = nyUID para (byte z = 0; z <4; z ++) oldUID [z] = nyUID [z]; } // aguarde 1 seg. delay (1000); }

// compare 2 matrizes …

boolean array_cmp (byte a , byte b ) {bool test = true; // teste cada elemento para ser o mesmo. se apenas um não for, retorna falso para (byte n = 0; n <4; n ++) {if (a [n]! = b [n]) teste = falso; // se o byte não for igual, teste = falso} se (teste == verdadeiro) retornar verdadeiro; senão retorna falso; }

Etapa 3: Node-RED, banco de dados Lagring Af Data I

Node-RED, banco de dados Lagring Af Data I
Node-RED, banco de dados Lagring Af Data I
Node-RED, banco de dados Lagring Af Data I
Node-RED, banco de dados Lagring Af Data I

Følgende flow er lavet i node-RED:

COM4 é uma série de proibições de modtages de dados hvor do painel Arduino. Funktionerne "Split and Get value" e "Split and Get UID" splitter teksstrengen ved kommaet e returnere hhv vægten e UID. Vægten bruges to fremvisning på dashboardet i et linechart and en scale. UID fremvises i et tekstfelt. Funktionen test_sound advarer verbalt med sætningen "Out of range", hvis vægten er abaixo de 170g ou acima de 230g, dvs i range 0.

Dividir e obter valor:

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

temp = {carga útil: (saída [1])}; return temp;

Dividir e obter UID:

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

temp = {carga útil: saída [0]}; return temp;

test_sound:

var number = parseInt (msg.payload);

if (número> 230 || número <170) {newMsg = {carga útil: "Fora do intervalo"}; return newMsg; } else {newMsg = {carga útil: ""}; return newMsg; }

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

var output = msg.payload.split (","); // divida msg.payload por vírgula na matriz

UIDTag = saída [0]; // primeira parte na primeira posição [0] ValueTag = output [1]; // segunda parte na segunda posição [1]

var m = {

tópico: "INSERT INTO patedb.patelog (timestamp, UID, weight) VALUES ('" + new Date (). toISOString () + "', '" + UIDTag + "', '" + ValueTag + "');" }; return m;

Patelog er en banco de dados MySQL proíbe alguns outros sat op med følgende parametre:

Host: localhost

Porta: 3306

Usuário: root

Banco de dados: patedb

Etapa 4: projeto do banco de dados

Desenho de banco de dados
Desenho de banco de dados

Databasen patedb indeholder 4 tabeller

patelog er dataopsamlingstabellen, tilskrives data af node-RED og C # programmet

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

customertable er et kunderegister

rangetable er en tabel som indeholder grænseværdierne para de i C # programmet benyttede range.

Etapa 5: Patelog

Patelog
Patelog

Tabellen patelog indeholder folgende 6 kolonner:

pateID (int) er chave primária og inkrementeres automatisk.

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

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

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

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

Etapa 6: Ordertable

Ordertable
Ordertable

ordertable indeholder 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. (Tælles af C # programmet)

comentário (tinytext) er en eventuel kommentar til ordren.

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

Etapa 7: personalizável

Customertable
Customertable

customertable indeholder 6 kolonner:

customerID (int) er chave primária og auto inc.

nome, endereço, telefone, e-mail (varchar) med forskellig max længde

rangeNr (int)

Etapa 8: ajustável

Rangetable
Rangetable

rangetable indeholder 3 kolonner:

rangeNr (int) er chave primária og auto inc.

rangeMin (int)

rangeMax (int)

Etapa 9: Programa C #

Programa C #
Programa C #

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

Kundenummer, ordrenummer, ordreantal og en eventuel kommentar indtastes i C # programmet (i praksis overføres det digitalt fra virksomhedens ordresystem. på et transportbånd) Samhørende værdier of UID e den aktuelle vægt sendes serielt to node-RED, so viser of opsamlede data på dashboard 'et. tidspunkt ikke tilskrives mais værdier til rangeNr e orderID vil de ter værdien NULL.

Med et timerinterval undersøger C # programmet patedb.patelogtabellen para 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. Når en ordre er afsluttet, kan kan de opsamlede data i patelog tabellen fremvises ved at trykke på de forskellige knapper i gruppen Atualizar DataGridview. ordertable kan også vises, og der kan søges ordredata på individueller UID'er eller kundedata på individuelle ordrer.

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

namespace show_data_from_database

{classe pública parcial Form1: Formulário {conexão MySqlConnection = new MySqlConnection ("datasource = localhost; username = root; password = ''"); int RowNumber = 0; // Variável para armazenar o valor pateID int RangeNumber = 0; // Variável para armazenar o rangenumber int weight = 0; // Variável para armazenar o peso int OrderNr = 0; // Variável para armazenar OrderNR int QuantProduced = 0; // Variável para armazenar a quantidade produzida int NumberOfRows = 0; // número de linhas com nulos.. bool ProdRunning = false; // Variável que indica se os botões iniciar e parar foram ativados int limits = new int [6]; // inicializar array int CustomerID; // Variável para armazenar customerID public Form1 () {InitializeComponent (); load_table (); // chame load_table}

void load_table ()

{Comando MySqlCommand = new MySqlCommand ("SELECT * FROM patedb.patelog ORDER BY timestamp DESC;", conexão); tente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); }}

private void SetRowOrder ()

{dataGridView1. Columns ["pateID"]. DisplayIndex = 0; // Her kan rækkefølgen af kolonner ændres dataGridView1. Columns ["timestamp"]. DisplayIndex = 1; // Her 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; // Her kan rækkefølgen af kolonner ændres dataGridView1. Columns ["rangeNr"]. DisplayIndex = 4; // Her kan rækkefølgen af kolonner ændres dataGridView1. Columns ["orderID"]. DisplayIndex = 5; // Seu kan rækkefølgen af kolonner ændres}

private void GetData_Click (object sender, EventArgs e) // Lê a tabela do banco de dados e pedidos por carimbo de data / hora

{load_table (); }

private void btnRefreshUID_Click (objeto remetente, EventArgs e) //

{string timeStr = "SELECT * FROM patedb.patelog ORDER BY UID;"; Comando MySqlCommand = novo MySqlCommand (timeStr, conexão); tente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); }}

private void btnRefreshValue_Click (objeto remetente, EventArgs e)

{string weightSort = "SELECT * FROM patedb.patelog ORDER BY CAST (weight AS SIGNED INTEGER);"; Comando MySqlCommand = novo MySqlCommand (weightSort, conexão); tente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); }}

private void ChkNullBtn_Click (objeto remetente, EventArgs e)

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

private void CheckTableForNull ()

{// Verificar / definir intervalo de tempo mínimo 100 ms int i; int. ExperimenteParse (textTimer1. Text, out i); if (i <100) {timer1. Stop (); i = 100; timer1. Interval = i; MessageBox. Show ("Valor mínimo i 100 ms"); timer1. Start (); } else {timer1. Interval = i; } textTimer1. Text = timer1. Interval. ToString (); // Verifique se alguma linha com nulo está disponível na tabela, retorna o número de linhas na variável: NumberOfRows string weightStr = ""; string chkNull = "SELECT COUNT (*) FROM patedb.patelog ONDE rangeNR É NULO ORDEM POR pateID LIMIT 1;"; Comando MySqlCommand = novo MySqlCommand (chkNull, conexão); tente {connection. Open (); NumberOfRows = Convert. ToInt32 (command. ExecuteScalar ()); conexão. Fechar (); } catch (Exceção ex) {MessageBox. Show (ex. Message); } finalmente {if (NumberOfRows! = 0) {try {// Seleciona o menor número pateID onde rangeNr é NULL string readID = "SELECIONE pateID FROM patedb.patelog ONDE rangeNR É NULL ORDER BY pateID ASC LIMIT 1;"; MySqlCommand cmdID = novo MySqlCommand (readID, conexão); {connection. Open (); RowNumber = (int) cmdID. ExecuteScalar (); // inteiro !! conexão. Fechar (); } listPateID. Text = RowNumber. ToString (); // lê o número PateID selecionado // Seleciona o peso do rownumber string row = RowNumber. ToString (); string readweight = "SELECIONE o peso FROM patedb.patelog WHERE pateID =" + linha; MySqlCommand cmdweight = novo MySqlCommand (peso de leitura, conexão); {connection. Open (); weightStr = (string) cmdweight. ExecuteScalar (); //Fragmento !! conexão. Fechar (); } peso = int. Parse (weightStr); // converter para int txtWeight. Text = weight. ToString (); // imprime int RangeNumber = 0; if (peso> = limites [0] && peso = limites [2] && peso = limites [4] && peso <= limites [5]) {RangeNumber = 3; }} txtRange. Text = RangeNumber. ToString (); UpdateLog (); } catch (Exceção ex) {MessageBox. Show (ex. Message); } QuantProduced = QuantProduced + 1; }}} private void btnStart_Click (objeto remetente, EventArgs e) {if (ProdRunning == false) {int valtest; tente {CustomerID = int. Parse (txtCustomerNr. Text); // leia o ID do cliente} catch {MessageBox. Show ("Insira os dados de produção e pressione o botão 'iniciar'."); }

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

MySqlCommand cmdtestcustomer = novo MySqlCommand (teste, conexão); {connection. Open (); valtest = Convert. ToInt32 (cmdtestcustomer. ExecuteScalar ()); // retorna 0 se o cliente não existe conexão. Close (); } if (valtest == 1) // se o cliente existe no banco de dados - inicie a produção {tente {OrderNr = int. Parse (txtOrderNumber. Text); ProdRunning = true; timer1. Start (); textTimer1. Text = timer1. Interval. ToString (); ReadLimits (); } catch (Exception ex) {MessageBox. Show ("Insira os dados de produção e pressione o botão 'iniciar'."); }} else MessageBox. Show ("O cliente não está no banco de dados, tente novamente"); } // ReadLimits (); }

private void ReadLimits ()

{// Lê limites de rangetable, intervalo de 1 a 3 int counter = 0; for (int rangeNr = 1; rangeNr <4; rangeNr ++) {string readmin = "SELECIONE rangeMin FROM patedb.rangetable WHERE rangeNr =" + rangeNr; MySqlCommand cmdmin = novo MySqlCommand (readmin, conexão); {connection. Open (); limites [contador] = (int) cmdmin. ExecuteScalar (); contador = contador + 1; conexão. Fechar (); } // MessageBox. Show (counter. ToString ()); string readmax = "SELECIONE rangeMax FROM patedb.rangetable WHERE rangeNr =" + rangeNr; MySqlCommand cmdmax = novo MySqlCommand (readmax, conexão); {connection. Open (); limites [contador] = (int) cmdmax. ExecuteScalar (); contador = contador + 1; conexão. Fechar (); }} // fim do loop}

private void UpdateLog ()

{// ATUALIZAR rangeNR & orderID string Range = RangeNumber. ToString (); string Order = OrderNr. ToString (); string update = "UPDATE patedb.patelog SET rangeNr =" + Range + ',' + "orderID =" + OrderNr + "WHERE pateID =" + RowNumber; MySqlCommand updatecmd = novo MySqlCommand (atualização, conexão); tente {connection. Open (); updatecmd. ExecuteNonQuery (); conexão. Fechar (); } catch (Exceção ex) {MessageBox. Show (ex. Message); }}

private void btnStop_Click (objeto remetente, EventArgs e)

{if (ProdRunning == true) {timer1. Stop (); ProdRunning = false; UpdateOrderTable (); } else {MessageBox. Show ("Nenhuma produção iniciada ainda. Insira os dados e pressione o botão 'iniciar'"); }}

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 = novo MySqlCommand (inserir, conexão); tente {connection. Open (); insertcmd. ExecuteNonQuery (); conexão. Fechar (); QuantProduced = 0; } catch (Exceção ex) {MessageBox. Show (ex. Message); }}

private void timer1_Tick (objeto remetente, EventArgs e)

{CheckTableForNull (); load_table (); }

private void btnShowOrderTable_Click (objeto remetente, EventArgs e)

{if (ProdRunning == false) {comando MySqlCommand = new MySqlCommand ("SELECT * FROM patedb.ordertable ORDER BY orderID DESC;", conexão); tente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Pressione parar para acessar a tabela de pedidos"); }}

private void btnShowOrderDetails_Click (objeto remetente, 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 ONDE patedb.patelog. UID = '"+ txtShowOrderDetails. Text +"' "); Comando MySqlCommand = novo MySqlCommand (teste, conexão); tente {connection. Open (); Adaptador MySqlDataAdapter = novo MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); } conexão. Fechar (); } else {MessageBox. Show ("Pressione parar para ver os detalhes do pedido"); }}

private void btnShowCustomerDetails_Click (objeto remetente, EventArgs e)

{if (ProdRunning == false) {string test = ("SELECT patedb.customertable.customerID, name, address, phone, email, rangeNr FROM patedb.customertable INNER JOIN patedb.ordertable ON patedb.ordertable.customerID = patedb.customertable. customerID WHERE patedb.ordertable.orderID = '"+ txtShowCustomerDetails. Text +"' "); Comando MySqlCommand = novo MySqlCommand (teste, conexão); tente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = command; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adaptador. Atualizar (dbdataset); } catch (Exceção ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Pressione parar para obter os detalhes do cliente"); }}}

}

Recomendado: