Innehållsförteckning:

EAL-Industri4.0-RFID Dataopsamling Til Database: 10 Steg (med bilder)
EAL-Industri4.0-RFID Dataopsamling Til Database: 10 Steg (med bilder)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 Steg (med bilder)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 Steg (med bilder)
Video: TPM 2.0 Unveiled: Empowering IT Pros with Trusted Platform Module Insights 2024, Juli
Anonim
EAL-Industri4.0-RFID Dataopsamling Til Database
EAL-Industri4.0-RFID Dataopsamling Til Database

Detta projekt omhandler opsamling av viktdata, registrering av identiteter vha. RFID, lagring af data i en MySQL -databas vha. node-RED, samt framvisning och behandling av de opsamlade data i och C# -program i form av en Windows Form Application. Vi forestiller oss följande:

Vi har en produktionslinje som producent leverpostej i 200g foliebakker. Alla färdiga leverantörsutrustningar utrustas med en RFID -tagg i plastlåget/etiketter, som innehåller ett unikt ID (UID = Unique Identifier, är en 32 bitars kod, 8 hexadecimale karakterer) för entydig identifikation av varje enkelt bakre leverpostej. Da färdigvægten av varje enkelt bakke leverpostej kan svinge (ansvarig av råvaror, fordampning i ovn mm), och då kunderne varje har och specifika krav færdigvægten, används UID -tagget för att knyta varje enkelt leverpost till en specifik lagerlokation på lager, där det kan lagras leverpostejer till en specifik kunde. Kunderne är supermarkedskæder:

1. Irma. Vægten på Irmas luksus leverpostej ska hålla sig inom +/- 5%, alltså minst 190g och högst 210g.

2. Brugsen. Vægten på Brugsens leverpostej ska hålla sig inom +/- 10%, alltså minst 180g och max 220g.

3. Aldi. Vægten på Aldis rabattpapper ska hållas inom +/- 15%, alltså minst 170g och högst 230g.

Der är således följande sorteringer:

Range0: utanför intervallet

Område 1: minst 190 g/max 210 g

Område 2: minst 180 g/max 220 g

Område 3: minst 170 g/max 230 g

Steg 1: Opsamling av data för Vægt Samt Registrering Af UID

Opsamling Af Data för Vægt Samt Registrering Af UID
Opsamling Af Data för Vægt Samt Registrering Af UID

Till insamling av data för vikt, samt registrering av RFID-taggar används för en Arduino MEGA2560 med en RFID-RC522 läsare/skribent. Vi har inte någon vikt, simulerer vi data for vægten med och potmeter tillsluttet en analog indgang på Arduinoen.

Följande inställning används:

1 stk potmeter 25k lineært. Yder-benene er tilsluttet hhv. GND og +5V, midterbenet är tilsluttet AN0

RFID-RC522 är tillsluttet Arduino-kort SPI-port på följande sätt:

SDA -> stift 53

SCK -> pin52

MOSI -> pin51

MISO-> pin50

IRQ -> NC

GND -> GND

RST -> pin5

3.3V -> 3.3V

De opsamlede data, för hhv. UID och vægten, skickar på den seriella porten som en kommaseparerad textsträng vidare till nod-Röd som står för den efterföljande presentationen på et instrumentpanel och lagring i en databas.

Steg 2: Arduino-program

I Arduino programmet ingåres to to biblioteker SPI.h og MFRC522.h for at kunne använda RFID læseren. Jag startar av programmet initialiseres de applicte variable. Der laves en instans af MFRC522. I Setup blokken initialiseres den serielle connection, SPI porten och MFRC522. Derefter scannes efter RFID -taggar. For ikke at sende det samme UID afsted flera gange efter varandra, det är gjort som en stumpkod som tjekker för detta. När der er scannet et UID tag, loades arary nyUID med det just läste UID. Om array nyUID är forskligt från oldUID är det berättelse om och nytt UID som kan skickas på den seriella porten. Om nyUID och oldUID är ens, är der tale om samma UID -tagg och UID'et ska ignoreres. Om der er tale om et nyt UID, skickar UID'et på den seriella porten tillsammans med en läst värde från den seriella porten. Den analoga värdet ska visas till området 150-250. Data skickar som en komma-separeret textstreng. Som det sista sattes oldUID = nyUID, således att koden klart kan läsa och nyt RFID -tagg.. Den sista funktionen i programmet är den funktion som jämförar 2 matriser. Funktionen returnerer true om array'ne är ens, och false hvis array'ne är olika.

#omfatta

#include // Detta program skannar RFID-kort med RDIF-RC522 läsare/skrivarkort. // UID läses, en analog pin läses. Analogt värde 0-1023 skalas till 150-250. // UID och analogt värde skickas som kommaseparerad text på seriell port med 9600, N, 8, 1. // Man har varit noga med att bara skicka varje UID en gång i rad, // ett nytt UID måste vara närvarande innan samma UID kan skickas igen. // Denna funktion implementeras i koden genom att jämföra matriser: oldUID nyUID i funktion array_cmp (oldUID , nyUID )

constexpr uint8_t RST_PIN = 5;

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

MFRC522 mfrc522 (SS_PIN, RST_PIN); // Skapa MFRC522 -instans.

void setup ()

{Serial.begin (9600); // Starta en seriell kommunikation SPI.begin (); // Starta SPI -buss mfrc522. PCD_Init (); // Starta MFRC522}

void loop ()

{// Leta efter nya kort om (! Mfrc522. PICC_IsNewCardPresent ()) {return; } // Välj ett av korten om (! Mfrc522. PICC_ReadCardSerial ()) {return; } // ladda nyUID med UID -tagg för (byte i = 0; i <mfrc522.uid.size; i ++) {nyUID = mfrc522.uid.uidByte ; } // if oldUID nyUID if (! array_cmp (oldUID, nyUID)) {// skicka UID -tagg på seriell port för (byte i = 0; i 1000) {Value = 1000; } Värde = (Värde / 10) + 150; // skicka skalat analogt värde Serial.print (värde); // skicka newline Serial.println (); // ställ in oldUID = nyUID för (byte z = 0; z <4; z ++) oldUID [z] = nyUID [z]; } // vänta 1 sek fördröjning (1000); }

// jämför 2 matriser …

booleskt array_cmp (byte a , byte b ) {bool test = true; // testa att varje element är detsamma. om bara en inte är det, returnera false för (byte n = 0; n <4; n ++) {if (a [n]! = b [n]) test = false; // if on byte not equal, test = false} if (test == true) return true; annars returnera falskt; }

Steg 3: Node-RED, Lagring Af Data I Database

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

Följande flöde är gjort i nod-RÖD:

COM4 är den seriella anslutningen där data mottages från Arduino boardet. Funktionerne "Split and Get value" och "Split and Get UID" splitter textstrengen vid kommaet och returnere hhv vægten och UID. Vægten används för att visa på instrumentpanelen i en linjechart och en skala. UID framvises i och textfelt. Funktionen test_sound advarer verbalt med sætningen "Out of range", om vægten är under 170g eller över 230g, dvs i intervall 0.

Dela och få värde:

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

temp = {nyttolast: (utmatning [1])}; returtemp;

Dela och få UID:

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

temp = {nyttolast: output [0]}; returtemp;

test_ljud:

var number = parseInt (msg.payload);

if (nummer> 230 || nummer <170) {newMsg = {nyttolast: "Out of range"}; returnera newMsg; } annat {newMsg = {nyttolast: ""}; returnera newMsg; }

Funktioner Split string "," indsætter and timestamp, UID and vægten i en database patedb.patelog.

var output = msg.payload.split (","); // dela msg.payload med kommatecken i array

UIDTag = output [0]; // första delen till första position [0] ValueTag = output [1]; // andra delen till andra position [1]

var m = {

ämne: "INSERT INTO patedb.patelog (tidsstämpel, UID, vikt) VÄRDEN ('"+nytt datum (). toISOString ()+"', '"+UIDTag+"', '"+ValueTag+"');" }; återvända m;

patelog är en MySQL -databasförbindelse som kan användas med följande parametrar:

Värd: lokal värd

Port: 3306

Användare: root

Databas: patedb

Steg 4: Databasdesign

Databasdesign
Databasdesign

Databasen innehåller 4 tabeller

patelog er dataopsamlingstabellen, tilskrives data af node-RED och C# program

ordertable är en tabell som innehåller data om de genemførte ordrer, tilskrives data av C# program

kundanpassad är och kundregister

rangetable är en tabell som innehåller greenseværdierne för de i C# programmet benyttede intervall.

Steg 5: Patelog

Patelog
Patelog

Tabellen patelog innehåller följande 6 kolonner:

pateID (int) är primär nyckel och inkrementeres automatiskt.

Tidsstämpel, UID & vikt är av typen varchar (med forskellig max längd)

rangeNr är av typen tinyint (beräkningar och tilfåligheter av C# program)

orderID är af typen int (orderID tilføjes af C# program)

Node-RÖD kan inte värderas till kolonnern rangeNr och orderID. rangeNr och orderID tillader NULL värden, det används i C# program för att detektera de rækker som ska tilskrives värden för rangeNr och orderID

Steg 6: Ordertable

Ordertable
Ordertable

ordertable innehåller 5 kolonner:

orderID (int) är det aktuella ordrenummer

orderQuant (mediumint) är ordens pålydende antal

quantProduced (mediumint) är antal der rent faktiskt är produceret på ordren. (Tælles af C# program)

comment (tinytext) är en eventuel kommentar till ordren.

customerID (int) är aktuell kundenummer på ordren.

Steg 7: Anpassningsbar

Anpassningsbar
Anpassningsbar

anpassningsbar innehåller 6 kolonner:

customerID (int) är primärnyckel og auto inc.

namn, adress, telefon, e -post (varchar) med forskellig max längd

rangeNr (int)

Steg 8: Räckvidd

Rangetable
Rangetable

rangetable innehåller 3 kolonner:

rangeNr (int) är primärnyckel og auto inc.

rangeMin (int)

rangeMax (int)

Steg 9: C# -program

C# -program
C# -program

När der produceres en ordre leverpostej, är proceduren följande:

Kundenummer, ordrenummer, ordreantal och en eventuel kommentar indtastes i C# program (i praktiken används det digitalt från företagets ordresystem. Produktionen startar nu med tryck på 'start'- knappen. på och transportbånd) Samhørende värderingar av UID och den aktuella vikten skickar seriell till node-RED, som visar uppsamlingsdata på instrumentpanelen 'och samtidigt skrives tidsstämpel, UID och vikt i en ny rad i patedb.patelog tabellen. tid kan inte tillskrives värden för rangeNr och orderID kommer att ha värden NULL.

Med et timerinterval undersøger C# program patedb.patelogtabellen for nye tilkomne rækker med NULL värderar i rangeNr kolonnen. När der är detektering en rad med NULL -värde, beräknad rangeNr och det tilföjes tillsammans med aktuella orderID. När en ordre är producent, avsluttar ordningen med tryck på”stop”- knappen. När ordren avsluttes, tilføjes en rad till patedb.ordertable med de aktuella ordredata. När en ordre är avslöjad, kan jag använda data i patelog tabellen för att trycka på de olika knapparna i gruppen Uppdatera DataGridview. ordertable kan också visas, och det kan söges ordredata på individueller UID'er eller kundedata på individuell ordrer.

använder System; använder System. Collections. Generic; använder System. ComponentModel; använder System. Data; använder System. Drawing; använder System. Linq; använder System. Text; använder System. Threading. Tasks; använder System. Windows. Forms; med MySql. Data. MySqlClient;

namnområde show_data_from_database

{public partial class Form1: Form {MySqlConnection connection = new MySqlConnection ("datasource = localhost; username = root; password = ''"); int radnummer = 0; // Variabel för lagring av pateID -värde int RangeNumber = 0; // Variabel för lagring av rangenumber int vikt = 0; // Variabel för lagring av vikten int OrderNr = 0; // Variabel för lagring av OrderNR int QuantProduced = 0; // Variabel för lagring av producerad kvantitet int NumberOfRows = 0; // antal rader med nullar.. bool ProdRunning = false; // Variabel som anger om start- och stoppknappar har aktiverats int limits = new int [6]; // initialize array int CustomerID; // Variabel för lagring av customerID public Form1 () {InitializeComponent (); load_table (); // call load_table}

void load_table ()

{MySqlCommand -kommando = nytt MySqlCommand ("VÄLJ * FRÅN patedb.patelog ORDER BY tidsstämpel DESC;", anslutning); prova {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = ny BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); }}

private void SetRowOrder ()

{dataGridView1. Columns ["pateID"]. DisplayIndex = 0; // Her kan följd av kolonner ändras dataGridView1. Columns ["tidsstämpel"]. DisplayIndex = 1; // Her kan följd av kolonner ändras dataGridView1. Columns ["UID"]. DisplayIndex = 2; // Her kan följd av kolonner ändras dataGridView1. Columns ["weight"]. DisplayIndex = 3; // Her kan följd av kolonner ändras dataGridView1. Columns ["rangeNr"]. DisplayIndex = 4; // Her kan följd av kolonner ändras dataGridView1. Columns ["orderID"]. DisplayIndex = 5; // Her kan följeslag av kolonner ändres}

private void GetData_Click (objektavsändare, EventArgs e) // Läser databastabell och order efter tidsstämpel

{load_table (); }

privat void btnRefreshUID_Click (objektavsändare, EventArgs e) //

{string timeStr = "VÄLJ * FRÅN patedb.patelog ORDER BY UID;"; MySqlCommand -kommando = nytt MySqlCommand (timeStr, anslutning); prova {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); }}

private void btnRefreshValue_Click (objektavsändare, EventArgs e)

{string weightSort = "SELECT * FRÅN patedb.patelog BESTÄLLNING PÅ CAST (vikt SIGNERAD INTEGER);"; MySqlCommand -kommando = nytt MySqlCommand (weightSort, anslutning); prova {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = ny BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); }}

privat tomrum ChkNullBtn_Click (objektavsändare, EventArgs e)

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

privat tomrum CheckTableForNull ()

{// Kontrollera/ställ in tidsintervall minst 100 ms int i; int. TryParse (textTimer1. Text, ut i); if (i <100) {timer1. Stop (); i = 100; timer1. Interval = i; MessageBox. Show ("Minsta värde i 100mS"); timer1. Start (); } annat {timer1. Interval = i; } textTimer1. Text = timer1. Interval. ToString (); // Kontrollera om några rader med null finns i tabellen, returnerar antalet rader i variabeln: NumberOfRows string weightStr = ""; string chkNull = "VÄLJ RÄKNE (*) FRÅN patedb.patelog VAR rangeNR ÄR NULL BESTÄLLNING PateID LIMIT 1;"; MySqlCommand -kommando = nytt MySqlCommand (chkNull, anslutning); prova {connection. Open (); NumberOfRows = Convert. ToInt32 (command. ExecuteScalar ()); anslutning. Stäng (); } catch (Undantag ex) {MessageBox. Show (ex. Message); } slutligen {if (NumberOfRows! = 0) {try {// Väljer lägsta pateID -nummer där rangeNr är NULL string readID = "SELECT pateID FRÅN patedb.patelog WHERE rangeNR IS NULL ORDER BY pateID ASC LIMIT 1;"; MySqlCommand cmdID = nytt MySqlCommand (readID, anslutning); {connection. Open (); RowNumber = (int) cmdID. ExecuteScalar (); //heltal!! anslutning. Stäng (); } listPateID. Text = RowNumber. ToString (); // läs upp valt PateID -nummer // Väljer vikt från vald radnummer för radnummer = RowNumber. ToString (); string readweight = "VÄLJ vikt FRÅN patedb.patelog WHERE pateID =" + rad; MySqlCommand cmdweight = nytt MySqlCommand (läsvikt, anslutning); {connection. Open (); weightStr = (string) cmdweight. ExecuteScalar (); // Sträng !! anslutning. Stäng (); } vikt = int. Parse (weightStr); // konvertera till int txtWeight. Text = weight. ToString (); // print int RangeNumber = 0; if (vikt> = gränser [0] && vikt = gränser [2] && vikt = gränser [4] && vikt <= gränser [5]) {RangeNumber = 3; }} txtRange. Text = RangeNumber. ToString (); UpdateLog (); } catch (Undantag ex) {MessageBox. Show (ex. Message); } QuantProduced = QuantProduced + 1; }}} private void btnStart_Click (objektavsändare, EventArgs e) {if (ProdRunning == false) {int valtest; prova {CustomerID = int. Parse (txtCustomerNr. Text); // läs customerID} catch {MessageBox. Show ("Ange produktionsdata och tryck på" start "-knappen."); }

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

MySqlCommand cmdtestcustomer = nytt MySqlCommand (test, anslutning); {connection. Open (); valtest = Convert. ToInt32 (cmdtestcustomer. ExecuteScalar ()); // returnerar 0 om kunden inte har anslutning. Close (); } if (valtest == 1) // om kunden finns i databasen - starta produktionen {prova {OrderNr = int. Parse (txtOrderNumber. Text); ProdRunning = true; timer1. Start (); textTimer1. Text = timer1. Interval. ToString (); ReadLimits (); } catch (Undantag ex) {MessageBox. Show ("Ange produktionsdata och tryck på" start "-knappen."); }} else MessageBox. Show ("Kunden finns inte i databasen, försök igen"); } // ReadLimits (); }

privat tomrum ReadLimits ()

{// Läser gränser från rangetable, intervall 1 till 3 int räknare = 0; för (int rangeNr = 1; rangeNr <4; rangeNr ++) {string readmin = "SELECT rangeMin FROM patedb.rangetable WHERE rangeNr ="+rangeNr; MySqlCommand cmdmin = nytt MySqlCommand (readmin, anslutning); {connection. Open (); gränser [räknare] = (int) cmdmin. ExecuteScalar (); räknare = räknare + 1; anslutning. Stäng (); } // MessageBox. Show (counter. ToString ()); string readmax = "SELECT rangeMax FROM patedb.rangetable WHERE rangeNr =" + rangeNr; MySqlCommand cmdmax = nytt MySqlCommand (readmax, anslutning); {connection. Open (); gränser [räknare] = (int) cmdmax. ExecuteScalar (); räknare = räknare + 1; anslutning. Stäng (); }} // slut för loop}

private void UpdateLog ()

{// UPDATE 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 = nytt MySqlCommand (uppdatering, anslutning); prova {connection. Open (); updatecmd. ExecuteNonQuery (); anslutning. Stäng (); } catch (Undantag ex) {MessageBox. Show (ex. Message); }}

private void btnStop_Click (objektavsändare, EventArgs e)

{if (ProdRunning == true) {timer1. Stop (); ProdRunning = false; UpdateOrderTable (); } else {MessageBox. Show ("Ingen produktion har påbörjats ännu. Ange data och tryck på" start "-knappen"); }}

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 = nytt MySqlCommand (infoga, anslutning); prova {connection. Open (); insertcmd. ExecuteNonQuery (); anslutning. Stäng (); QuantProduced = 0; } catch (Undantag ex) {MessageBox. Show (ex. Message); }}

private void timer1_Tick (objektavsändare, EventArgs e)

{CheckTableForNull (); load_table (); }

private void btnShowOrderTable_Click (objektavsändare, EventArgs e)

{if (ProdRunning == false) {MySqlCommand command = new MySqlCommand ("SELECT * FROM patedb.ordertable ORDER BY orderID DESC;", connection); prova {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = ny BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Tryck på stopp för att se orderTable"); }}

private void btnShowOrderDetails_Click (objektavsändare, 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 +"' ""); MySqlCommand -kommando = nytt MySqlCommand (test, anslutning); prova {connection. Open (); MySqlDataAdapter -adapter = ny MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = ny BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); } anslutning. Stäng (); } annars {MessageBox. Show ("Tryck på stopp för att visa orderinformation"); }}

private void btnShowCustomerDetails_Click (objektavsändare, 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 +"' "); MySqlCommand -kommando = nytt MySqlCommand (test, anslutning); prova {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = kommando; DataTable dbdataset = new DataTable (); adapter. Fyll (dbdataset); BindingSource bsource = ny BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Undantag ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Tryck på stopp för att se kundinformation"); }}}

}

Rekommenderad: