Zugriff auf Ergebnisdaten mit FlatBuffers
Diese Seite gilt für ctrlX OS (ctrlX CORE oder ctrlX IPC): Sie beschreibt, wie ein ctrlX-SPS-Programm das Ergebnis liest.
LumiScan AI Object Matching veröffentlicht das Ergebnis jeder Inferenz auf dem ctrlX Data Layer als binäre FlatBuffers-Nachricht. Ein SPS-Programm kann diese Nachricht nur mit dem Schema interpretieren, das ihren Aufbau beschreibt. Die Anwendung stellt deshalb die Schemadatei object_detection.fbs bereit.
Dieses Kapitel beschreibt, wie Sie das Schema beziehen, wie Sie es in ctrlX PLC Engineering importieren und wie Sie das Ergebnis lesen, einschließlich Position und Score eines erkannten Objekts.
Ergebnisknoten
| Eigenschaft | Wert |
|---|---|
Knotenadresse |
|
Zugriff |
Schreibgeschützt |
Datentyp |
FlatBuffers |
Adresse des registrierten Typs |
|
Schemadatei |
|
Schema-Namespace |
|
Root-Typ |
|
Der Knoten enthält das Ergebnis der letzten Inferenz. Lesen Sie ihn erst, nachdem die Inferenz abgeschlossen und erfolgreich war: Beim Handshake ist output/package-identifier um eins gestiegen (status/code ist am Ende jeder über den Handshake angeforderten Inferenz 3); bei control/inference/execute ist status/code 0. Siehe Ausgang einer Inferenz und Statuscode-Werte.
Voraussetzungen
-
ctrlX PLC Engineering 2.6 oder neuer.
-
Die Bibliotheken
CXA_DatalayerundCXA_Flatbufferssind im Library Manager des SPS-Projekts referenziert.CXA_Datalayerliest Knoten vom Data Layer.CXA_Flatbuffersstellt die Basis-Funktionsbausteine der FlatBuffers-Funktionsbausteine bereit, die der Import erzeugt. Prüfen Sie nach dem Import den Library Manager. Fehlt eine Bibliothek, fügen Sie sie dort hinzu (siehe auch Die ctrlX-Data-Layer-Bibliothek installieren). -
LumiScan AI Object Matching ist installiert und wurde mindestens einmal mit einer gültigen Lizenz gestartet (siehe Voraussetzungen).
Schritt 1: Schemadatei beziehen
Die Anwendung kopiert das Schema bei jedem Start in ihren Anwendungsdatenordner auf der ctrlX CORE. So laden Sie es herunter:
-
Melden Sie sich an der Weboberfläche von ctrlX OS an und öffnen Sie Manage app data (siehe Ordnerstruktur von LumiScan AI Object Matching).
-
Öffnen Sie den Ordner
lumiscan-ai-object-matching/schemas/flatbuffers. -
Klicken Sie in der Spalte Actions von
object_detection.fbsauf das Download-Symbol und speichern Sie die Datei auf dem Engineering-PC.
Alternativ laden Sie die Datei über WebDAV herunter (siehe Daten hochladen).
|
Der Ordner Die Anwendung löscht den Ordner |
Schritt 2: Schema in das SPS-Projekt importieren
-
Öffnen Sie in ctrlX PLC Engineering das SPS-Projekt.
-
Klicken Sie im Gerätebaum mit der rechten Maustaste auf Application.
-
Wählen Sie Import from FlatBuffers file….
-
Wählen Sie die heruntergeladene Datei
object_detection.fbs.
PLC Engineering fügt der Anwendung die folgenden Funktionsbausteine hinzu. Ihre Namen bestehen aus dem Schema-Namespace und dem Typnamen.
| Funktionsbaustein | Zweck |
|---|---|
|
Wurzel der Nachricht. Liefert den besten Score und die beste Klasse sowie den Zugriff auf das Array der Instanzen. |
|
Ein erkanntes Objekt: Klassenindex, Score und Bounding Box. |
|
Mittelpunkt, Größe und Winkel der Bounding Box einer Instanz. |
|
Zum Lesen der Ergebnisse nicht erforderlich (siehe Bekannte Meldung: Identifier 'VectorT' not defined). |
Bekannte Meldung: Identifier 'VectorT' not defined
Je nach Version von ctrlX PLC Engineering zeigt der Editor des Funktionsbausteins hdv_object_detection2d_InstanceTVec die Meldung Identifier 'VectorT' not defined. Die Meldung beeinträchtigt das Lesen der Ergebnisse nicht. Ursachen und Schritte sind unter Fehlerbehebung beschrieben:
Die ctrlX-Data-Layer-Bibliothek installieren
Ist Import from FlatBuffers file… im Kontextmenü nicht verfügbar, fehlt die ctrlX-Data-Layer-Bibliothek. Installieren Sie sie wie folgt und wiederholen Sie dann Schritt 2:
-
Wählen Sie in der Menüleiste von PLC Engineering Tools > Library Repository….
-
Suchen Sie nach
CXA_Datalayer, wählen Sie die Bibliothek aus und klicken Sie auf Open.
Schritt 3: Ergebnis im SPS-Programm lesen
-
Führen Sie eine Inferenz mit dem Handshake aus, der in Inferenz starten beschrieben ist.
-
Warten Sie, bis die Inferenz abgeschlossen ist, und prüfen Sie, ob sie erfolgreich war:
inference/readyist wieder True undoutput/package-identifierist um eins gestiegen. Beicontrol/inference/executeprüfen Sie stattdessen, obstatus/code0 ist. -
Lesen Sie den Knoten
hdvisionsystems/lumiscan-ai-object-matching/<network name>/output/resultmit dem FunktionsbausteinDL_ReadNodeValueder BibliothekCXA_Datalayer. Der Funktionsbaustein liefert den Wert in einemDL_NodeValue. -
Übergeben Sie Adresse und Größe des Puffers (
GetDataundGetSizedesDL_NodeValue) angetRootAsResultvonhdv_object_detection2d_Result. -
Lesen Sie die Felder des Ergebnisses mit den
get-Methoden der erzeugten Funktionsbausteine.
|
Die erzeugten Funktionsbausteine lesen den empfangenen Puffer an Ort und Stelle; sie kopieren ihn nicht. Verwenden oder kopieren Sie die Werte, bevor der Knoten erneut gelesen wird. |
Beispiel: Position und Score einer Instanz lesen
Das Array instances des Ergebnisses ist nach Score absteigend sortiert. Instanz 0 ist daher die Instanz mit dem höchsten Score. Das Beispiel liest die Position (x, y), den Score und den Klassenindex dieser Instanz.
Deklaration:
PROGRAM PRG_ReadObjectMatchingResult
VAR
// Data Layer access (CXA_Datalayer)
fbReadResult : DL_ReadNodeValue;
nvResult : DL_NodeValue; // receives the FlatBuffers buffer
bRead : BOOL; // set to TRUE to read the node once
sNode : STRING(255) := 'hdvisionsystems/lumiscan-ai-object-matching/<network name>/output/result';
// FlatBuffers readers, generated by "Import from FlatBuffers file..."
fbResult : hdv_object_detection2d_Result;
fbInstance : hdv_object_detection2d_Instance;
pBox : POINTER TO hdv_object_detection2d_OrientedBoundingBox;
// Values of the instance with the highest score
bFound : BOOL;
rX : REAL; // x of the bounding box center [pixel]
rY : REAL; // y of the bounding box center [pixel]
rScore : REAL; // score [0.0 - 1.0]
uClassIndex : ULINT; // index into class-names
END_VAR
Implementierung:
// 1. Read the node. A rising edge on bRead starts one read.
fbReadResult(Execute := bRead, NodeName := sNode, NodeValue := nvResult);
IF fbReadResult.Done THEN
bFound := FALSE;
IF nvResult.GetSize() > 0 THEN
// 2. Point the generated reader at the received buffer.
fbResult.getRootAsResult(data := nvResult.GetData(), size := nvResult.GetSize());
// 3. The instances are sorted by score, so instance 0 has the highest score.
IF fbResult.getInstancesLength() > 0 THEN
IF fbResult.getInstances(j := 0, result := ADR(fbInstance)) THEN
rScore := fbInstance.GetScore();
uClassIndex := fbInstance.GetClassIndex();
// 4. The position is part of the bounding box.
pBox := fbInstance.getOrientedBoundingBox();
IF pBox <> 0 THEN
rX := pBox^.GetCenterX();
rY := pBox^.GetCenterY();
bFound := TRUE;
END_IF
END_IF
END_IF
END_IF
END_IF
// 5. End the access.
IF fbReadResult.Done OR fbReadResult.Error THEN
bRead := FALSE;
fbReadResult(Execute := bRead, NodeName := sNode, NodeValue := nvResult);
END_IF
Ersetzen Sie <network name> in sNode durch den Namen des Netzes. Setzen Sie bRead erst auf TRUE, nachdem die Inferenz abgeschlossen und erfolgreich war (siehe Schritt 3). Ist fbReadResult.Error TRUE, werten Sie fbReadResult.ErrorID und fbReadResult.ErrorIdent aus.
| Wert | Methode | Typ | Einheit oder Bereich |
|---|---|---|---|
Anzahl der Instanzen |
|
|
|
Instanz nach Index |
|
|
|
Score |
|
|
0.0 bis 1.0 |
Klassenindex |
|
|
Index in |
Bounding Box |
|
|
|
x des Mittelpunkts |
|
|
Pixel |
y des Mittelpunkts |
|
|
Pixel |
Die Sortierung nach Score ist das Verhalten der aktuellen Version. Das Schema erlaubt, dass die Sortierreihenfolge in einer künftigen Version konfigurierbar wird. getBestIndex() von hdv_object_detection2d_Result liefert immer den Index der Instanz mit dem höchsten Score; er ist 0, solange die Instanzen nach Score sortiert sind. Verwenden Sie ihn statt des festen Index 0, wenn das Programm unabhängig von der Sortierreihenfolge bleiben soll.
|
Alle Instanzen lesen
Um alle Instanzen auszuwerten, durchlaufen Sie das Array in einer Schleife. Da die Instanzen nach Score sortiert sind, kann die Schleife bei der ersten Instanz unter einem Mindest-Score abbrechen. Das folgende Fragment ersetzt Schritt 3 der Implementierung. Es benötigt die zusätzlichen Deklarationen i : UDINT; und rMinScore : REAL := 0.5;.
i := 0;
WHILE i < fbResult.getInstancesLength() DO
IF fbResult.getInstances(j := i, result := ADR(fbInstance)) THEN
rScore := fbInstance.GetScore();
IF rScore < rMinScore THEN
EXIT; // sorted by score: no instance with a higher score follows
END_IF
pBox := fbInstance.getOrientedBoundingBox();
IF pBox <> 0 THEN
rX := pBox^.GetCenterX();
rY := pBox^.GetCenterY();
// Use or store the values of instance i here.
END_IF
END_IF
i := i + 1;
END_WHILE
Verwenden Sie keine FOR-Schleife mit der vorzeichenlosen Anzahl (FOR i := 0 TO count - 1): Ist die Anzahl 0, läuft die Obergrenze auf den größten UDINT-Wert über.
Aufbau des Ergebnisses
Die folgenden Tabellen beschreiben den Inhalt von object_detection.fbs. Die Schemadatei ist die maßgebliche Definition.
| Feld | Typ | Beschreibung |
|---|---|---|
|
|
Erkannte Objekte, nach Score absteigend sortiert (höchster Score zuerst). Das Array kann Objekte verschiedener Klassen enthalten; das SPS-Programm muss die benötigte Klasse auswählen (siehe Klassennamen und Klassenfilter). |
|
|
Index der Instanz mit dem höchsten Score in |
|
|
Score der besten Instanz, im Bereich 0.0 bis 1.0. |
|
|
Klassenindex der besten Instanz. |
|
|
Package Identifier des Eingabebilds, zu dem das Ergebnis gehört. In Versionen vor Oktober 2026 war es ein 16-Bit- |
|
|
Nicht verwendet. |
|
|
Zeitpunkt, zu dem die Anwendung den Inferenz-Request angenommen hat, den die SPS auf True gesetzt hatte. |
|
|
Zeitstempel des Eingabebilds. Typ und Auflösung hängen von der Zeitstempelquelle der Anwendung |
|
|
Nicht verwendet. Prüfen Sie den Ausgang mit |
| Feld | Typ | Beschreibung |
|---|---|---|
|
|
Position, Größe und Orientierung des erkannten Objekts im Bild. |
|
|
Index der erkannten Klasse (siehe Klassennamen und Klassenfilter). |
|
|
Score der Erkennung, im Bereich 0.0 bis 1.0. |
| Feld | Typ | Einheit | Beschreibung |
|---|---|---|---|
|
|
Pixel |
Horizontale Position des Box-Mittelpunkts. |
|
|
Pixel |
Vertikale Position des Box-Mittelpunkts. |
|
|
Pixel |
Breite der Box. |
|
|
Pixel |
Höhe der Box. |
|
|
Grad |
Orientierung der Box. Die aktuelle Implementierung kann negative Winkel liefern; gehen Sie nicht davon aus, dass der Wert auf den Bereich 0.0 bis 360.0 normiert ist. |
Klassennamen und Klassenfilter
Mit der Standard-Klassenzuordnung bezeichnet class_index eine Klasse über ihre Position im Array der Klassennamen, das für das Netz konfiguriert ist. Verwenden Sie die folgenden Knoten, um Klassen aufzulösen und einzuschränken:
Ist eine eigene Neuzuordnung der Klassenindizes konfiguriert, folgt der veröffentlichte Klassenindex dieser Zuordnung und kann von der Position in setting/class-names abweichen. Interpretieren Sie das Ergebnis anhand der konfigurierten Zuordnung.
|
| Adresse | Zugriff | Beschreibung |
|---|---|---|
|
Schreibgeschützt |
Klassennamen des Netzes. Mit der Standardzuordnung ist die Position eines Namens im Array sein Klassenindex. |
|
Beschreibbar |
Klassennamen, die in das Ergebnis aufgenommen werden. Lassen Sie das Array leer, um die Filterung zu deaktivieren. |