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

Tabelle 1. Eigenschaften des Ergebnisknotens
Eigenschaft Wert

Knotenadresse

hdvisionsystems/lumiscan-ai-object-matching/<network name>/output/result

Zugriff

Schreibgeschützt

Datentyp

FlatBuffers

Adresse des registrierten Typs

types/hdvisionsystems/lumiscan-ai-object-matching/object_detection

Schemadatei

object_detection.fbs

Schema-Namespace

hdv.object_detection2d

Root-Typ

Result

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_Datalayer und CXA_Flatbuffers sind im Library Manager des SPS-Projekts referenziert. CXA_Datalayer liest Knoten vom Data Layer. CXA_Flatbuffers stellt 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:

  1. Melden Sie sich an der Weboberfläche von ctrlX OS an und öffnen Sie Manage app data (siehe Ordnerstruktur von LumiScan AI Object Matching).

  2. Öffnen Sie den Ordner lumiscan-ai-object-matching/schemas/flatbuffers.

  3. Klicken Sie in der Spalte Actions von object_detection.fbs auf 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 schemas wird beim Start der Anwendung angelegt, nach der Lizenzprüfung. Existiert der Ordner nicht, ist die Anwendung nicht erfolgreich gestartet. Prüfen Sie, ob eine gültige Lizenz installiert ist, und lesen Sie das Systemprotokoll. Siehe Der Ordner schemas existiert nicht.

Die Anwendung löscht den Ordner schemas bei jedem Start und legt ihn neu an. Bearbeiten Sie keine Dateien in diesem Ordner; Änderungen gehen verloren. Das Schema passt immer zur installierten Version der Anwendung.

Schritt 2: Schema in das SPS-Projekt importieren

  1. Öffnen Sie in ctrlX PLC Engineering das SPS-Projekt.

  2. Klicken Sie im Gerätebaum mit der rechten Maustaste auf Application.

  3. Wählen Sie Import from FlatBuffers file…​.

  4. Wählen Sie die heruntergeladene Datei object_detection.fbs.

Gerätebaum von ctrlX PLC Engineering mit dem geöffneten Kontextmenü von Application auf Import from FlatBuffers file
Abbildung 1. Import from FlatBuffers file

PLC Engineering fügt der Anwendung die folgenden Funktionsbausteine hinzu. Ihre Namen bestehen aus dem Schema-Namespace und dem Typnamen.

Tabelle 2. Vom Import erzeugte Funktionsbausteine
Funktionsbaustein Zweck

hdv_object_detection2d_Result

Wurzel der Nachricht. Liefert den besten Score und die beste Klasse sowie den Zugriff auf das Array der Instanzen.

hdv_object_detection2d_Instance

Ein erkanntes Objekt: Klassenindex, Score und Bounding Box.

hdv_object_detection2d_OrientedBoundingBox

Mittelpunkt, Größe und Winkel der Bounding Box einer Instanz.

hdv_object_detection2d_InstanceTVec

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:

  1. Wählen Sie in der Menüleiste von PLC Engineering Tools > Library Repository…​.

Menü Tools von ctrlX PLC Engineering mit hervorgehobenem Befehl Library Repository
Abbildung 2. Befehl Library Repository
  1. Suchen Sie nach CXA_Datalayer, wählen Sie die Bibliothek aus und klicken Sie auf Open.

Dialog Find Library mit dem Suchbegriff CXA_Datalayer und der ausgewählten Bibliothek CXA_Datalayer
Abbildung 3. Suche nach der Bibliothek CXA_Datalayer

Schritt 3: Ergebnis im SPS-Programm lesen

  1. Führen Sie eine Inferenz mit dem Handshake aus, der in Inferenz starten beschrieben ist.

  2. Warten Sie, bis die Inferenz abgeschlossen ist, und prüfen Sie, ob sie erfolgreich war: inference/ready ist wieder True und output/package-identifier ist um eins gestiegen. Bei control/inference/execute prüfen Sie stattdessen, ob status/code 0 ist.

  3. Lesen Sie den Knoten hdvisionsystems/lumiscan-ai-object-matching/<network name>/output/result mit dem Funktionsbaustein DL_ReadNodeValue der Bibliothek CXA_Datalayer. Der Funktionsbaustein liefert den Wert in einem DL_NodeValue.

  4. Übergeben Sie Adresse und Größe des Puffers (GetData und GetSize des DL_NodeValue) an getRootAsResult von hdv_object_detection2d_Result.

  5. 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.

Tabelle 3. Im Beispiel verwendete Methoden
Wert Methode Typ Einheit oder Bereich

Anzahl der Instanzen

fbResult.getInstancesLength()

UDINT

Instanz nach Index

fbResult.getInstances(j, result)

BOOL

TRUE, wenn die Instanz existiert

Score

fbInstance.GetScore()

REAL

0.0 bis 1.0

Klassenindex

fbInstance.GetClassIndex()

ULINT

Index in class-names

Bounding Box

fbInstance.getOrientedBoundingBox()

POINTER TO hdv_object_detection2d_OrientedBoundingBox

x des Mittelpunkts

pBox^.GetCenterX()

REAL

Pixel

y des Mittelpunkts

pBox^.GetCenterY()

REAL

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.

Tabelle 4. Result (table, Root-Typ)
Feld Typ Beschreibung

instances

[Instance]

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).

best_index

ulong

Index der Instanz mit dem höchsten Score in instances. Immer 0, solange die Instanzen nach Score sortiert sind.

best_score

float

Score der besten Instanz, im Bereich 0.0 bis 1.0.

best_class_index

ulong

Klassenindex der besten Instanz.

image_id

ulong

Package Identifier des Eingabebilds, zu dem das Ergebnis gehört. In Versionen vor Oktober 2026 war es ein 16-Bit-short.

image_name

string

Nicht verwendet.

requested_timestamp

ulong

Zeitpunkt, zu dem die Anwendung den Inferenz-Request angenommen hat, den die SPS auf True gesetzt hatte.

timestamp

ulong

Zeitstempel des Eingabebilds. Typ und Auflösung hängen von der Zeitstempelquelle der Anwendung lumiscan-cam-driver ab, die das Bild geliefert hat.

status

ulong

Nicht verwendet. Prüfen Sie den Ausgang mit status/code (siehe Statuscode-Werte).

Tabelle 5. Instance (struct)
Feld Typ Beschreibung

oriented_bounding_box

OrientedBoundingBox

Position, Größe und Orientierung des erkannten Objekts im Bild.

class_index

ulong

Index der erkannten Klasse (siehe Klassennamen und Klassenfilter).

score

float

Score der Erkennung, im Bereich 0.0 bis 1.0.

Tabelle 6. OrientedBoundingBox (struct)
Feld Typ Einheit Beschreibung

center_x

float

Pixel

Horizontale Position des Box-Mittelpunkts.

center_y

float

Pixel

Vertikale Position des Box-Mittelpunkts.

width

float

Pixel

Breite der Box.

height

float

Pixel

Höhe der Box.

angle

float

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.
Tabelle 7. Knoten zu den Klassen
Adresse Zugriff Beschreibung

hdvisionsystems/lumiscan-ai-object-matching/<network name>/setting/class-names

Schreibgeschützt

Klassennamen des Netzes. Mit der Standardzuordnung ist die Position eines Namens im Array sein Klassenindex.

hdvisionsystems/lumiscan-ai-object-matching/<network name>/input/class-filters

Beschreibbar

Klassennamen, die in das Ergebnis aufgenommen werden. Lassen Sie das Array leer, um die Filterung zu deaktivieren.

Anwendung aktualisieren

Laden Sie nach einem Update der Anwendung das Schema erneut herunter und importieren Sie es erneut in das SPS-Projekt, damit das SPS-Programm das Schema der installierten Version verwendet.