---
title: "Streams (experimentell)"
description: "Streams der LumiScan-Apps - Publish und Subscribe, die Knoten eines Produzenten und eines Konsumenten, Starten und Stoppen, keep-latest-output, was gespeichert wird, Warteschlangengrößen, der Ergebnis-Envelope und seine Lineage."
product: "LumiScan Keryx"
component: "lumiscan-keryx-de"
version: "1.0.0"
display_version: "1.0.0.7"
latest_version: true
language: "de"
url: "https://docs.hdvisionsystems.com/de/lumiscan-keryx-de/1.0.0/streams.html"
---

# Streams (experimentell) – LumiScan Keryx

> [!IMPORTANT]
> Streams sind **experimentell**: im Cam Driver ab v2.3.0, in AI Object Matching ab v2.2.0 und in Calibration ab v2.1.0. Ihre Knoten können sich noch ändern. Prüfen Sie einen Stream mit Ihrer Kamera und Ihrem Netz, bevor Sie sich darauf verlassen.

Ein Stream verarbeitet jedes Element, das eine Quelle erzeugt, sobald es eintrifft: Kamerabilder in AI Object Matching, einem Finder oder einem Code Reader; Detektionen oder Punkte in Calibration. Es gibt keinen Request pro Element. Der Produzent sendet jedes Element, ein Konsument verarbeitet es und sendet sein Ergebnis. Produzent und Konsument arbeiten gleichzeitig; deshalb ist ein Stream schneller als ein Execute-Aufruf pro Element.

## Produzenten und Konsumenten {#roles}

| App | Rolle |
| --- | --- |
| Cam Driver | erzeugt Bilder auf `<camera>/control/publish/output/stream/frame` |
| AI Object Matching | konsumiert Bilder, erzeugt Detektionen auf `<module>/control/subscribe/output/stream/result` |
| Template Finder, Object Finder, Area Detector, Text Reader | konsumieren Bilder, erzeugen ihre Ergebnisse auf `<module>/control/subscribe/output/stream/result` |
| DMC, QR, Aztec und Barcode Reader | konsumieren Bilder, erzeugen Codes auf `<app>/control/subscribe/output/stream/result` |
| Calibration | konsumiert Punkte oder das Ergebnis einer anderen App, erzeugt 3D-Punkte auf `<module>/control/subscribe/output/stream/points` und `plain-points` |

**Ein Konsument hat eine Quelle.** Um zwei Kameras zu verarbeiten, verwenden Sie zwei Module.

## Der Produzent: der Cam Driver {#producer}

Alle Adressen beginnen mit `hdvisionsystems/lumiscan-cam-driver/<camera>/`.

| Adresse | Typ | Bedeutung |
| --- | --- | --- |
| `control/publish/execute` | Methode | wendet die folgenden Eingaben gemeinsam an |
| `control/publish/input/enable` | bool | veröffentlicht, solange `true` |
| `control/publish/input/keep-latest-output` | bool | schreibt jedes Bild zusätzlich in die normale Ausgabe |
| `control/publish/input/tag` | string | das Tag auf seinen Bildern; wird in der Moduldatei gespeichert |
| `control/publish/output/stream/frame` | FlatBuffers | jedes Bild, gesendet |
| `control/publish/output/stream/active` | bool | der Stream läuft |
| `control/publish/output/stream/statistics/…` | uint64 | Zähler |

Der Cam Driver triggert die Kamera nie von selbst. Ein Bild kommt, wenn die Kamera per Hardware oder per `control/trigger/execute` getriggert wird oder wenn ihr Trigger-Modus aus ist und sie frei läuft. Der Stream benötigt eine verbundene Kamera; `connect-camera`, `disconnect-camera` und `reset` stoppen einen laufenden Stream. Siehe das Handbuch des Cam Driver.

## Ein Konsument {#consumer}

Dieselben Knoten in jedem Konsumenten, unter `<module>/` (bei einem Code Reader: unter `<app>/`):

| Adresse | Typ | Bedeutung |
| --- | --- | --- |
| `control/subscribe/execute` | Methode | prüft, speichert und wendet die folgenden Eingaben an |
| `control/subscribe/input/enable` | bool | Stream-Modus |
| `control/subscribe/input/address` | string | die eine Quelle: der Stream-**Ordner** des Produzenten |
| `control/subscribe/input/tag` | string | das Tag auf der Ausgabe dieses Moduls; leer: die Modul-ID |
| `control/subscribe/input/queue-size` | uint32 | wie viele Elemente warten dürfen |
| `control/subscribe/input/keep-latest-output` | bool | schreibt jedes Ergebnis zusätzlich in die normale Ausgabe |
| `control/unsubscribe/execute` | Methode | entfernt die Quelle, die angegeben ist durch … |
| `control/unsubscribe/input/address` | string | … diese Adresse; eine andere Adresse wird abgelehnt |
| `setting/stream/…` | schreibgeschützt | was angewendet und gespeichert ist: `enable`, `address`, `tag`, `queue-size`, `keep-latest-output` |
| `control/subscribe/output/stream/active` | bool | der Stream läuft |
| `control/subscribe/output/stream/<result>` | FlatBuffers | jedes Ergebnis, gesendet |
| `control/subscribe/output/stream/statistics/…` | uint64 | Zähler, alle 250 ms veröffentlicht, bei jedem Start zurückgesetzt |

Die Finder und Code Reader haben außerdem `control/subscribe/output/stream/last-failure`: warum das letzte Element fehlgeschlagen ist.

Was die Quelle eines Konsumenten enthalten muss, steht als JSON Schema auf `hdvisionsystems/<app>/system/meta/subscription-schema`.

## Stream starten und stoppen {#running}

**Die Eingaben wirken erst bei `execute`.** `enable` allein zu schreiben startet nichts.

1. Starten Sie den Produzenten: Schreiben Sie an der Kamera `control/publish/input/enable` = `true` und rufen Sie dann `control/publish/execute` auf. Warten Sie, bis `control/publish/output/stream/active` `true` ist.
2. Schreiben Sie am Konsumenten `control/subscribe/input/address`, zum Beispiel `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`.
3. Schreiben Sie optional `tag`, `queue-size` und `keep-latest-output`.
4. Schreiben Sie `control/subscribe/input/enable` = `true` und rufen Sie dann `control/subscribe/execute` auf.
5. Warten Sie, bis `control/subscribe/output/stream/active` `true` ist. Ab dann treffen Ergebnisse ein.
6. Zum Stoppen schreiben Sie `enable` = `false` und rufen erneut `execute` auf.

Gut zu wissen:

- Der Stream-Modus ist ein **Pegel**, kein Befehl: Der Stream läuft, solange das angewendete `enable` `true` ist.
- Die Eingaben sind mit den angewendeten Werten vorbelegt; ändern Sie also nur, was Sie brauchen, und rufen Sie `execute` auf.
- Ein Konsument kann vor seinem Produzenten gestartet werden. Ergebnisse treffen ein, sobald Elemente eintreffen. Ein fehlgeschlagenes Abonnement wird alle 5 s erneut versucht, solange der Stream läuft.
- Eine andere Adresse ersetzt die Quelle.
- `enable` = `true` ohne Adresse wird abgelehnt (`Rejected`, ctrlX `DL_INVALID_VALUE`), und nichts ändert sich.

## Calibration als Konsument {#calibration-source}

Auch Calibration erhält einen Stream-Ordner, und ihre Moduldatei gibt an, welchen Knoten darin sie lesen und wie sie ihn in Punkte umwandeln soll: einen `onEntry`-Schritt im Abschnitt `stream`. Um die Objekte zu lesen, die AI Object Matching findet, nennt der Schritt den Knoten `result`, die Liste darin und die Felder, die den Punkt bilden. Ohne einen solchen Schritt liest Calibration ihre Quelle als einfaches Zahlen-Array, wie eine SPS-Variable sie liefert. Siehe das Handbuch von Calibration.

## Neuestes Ergebnis behalten {#keep-latest}

Mit eingeschaltetem `keep-latest-output` wird jedes Element - bzw. jedes Ergebnis - zusätzlich in die normale Ausgabe des Moduls geschrieben, so wie ein Aufruf auf Anfrage es schreiben würde, und `output/package-identifier` wird gezählt. Eine SPS, die die normale Ausgabe liest, sieht dann das neueste Stream-Ergebnis. Ist es ausgeschaltet, veröffentlicht der Stream nur unter `…/stream/…`, und die normale Ausgabe behält das Ergebnis des letzten Aufrufs.

Stream-Ergebnisse sind FlatBuffers-Datensätze. Für eine SPS schalten Sie `keep-latest-output` in dem Modul ein, dessen Ergebnis Sie benötigen, und lesen dessen einfache Ausgabeknoten. Calibration veröffentlicht außerdem `plain-points`: alle Punkte eines Ergebnisses in einem `float32`-Array `x0, y0, z0, x1, …`, ohne Lineage.

## Was bei einem Neustart erhalten bleibt {#saved}

| Was | Erhalten | Wie |
| --- | --- | --- |
| Der Stream eines Konsumenten (`enable`, `address`, `tag`, `queue-size`, `keep-latest-output`) | ja | `control/subscribe/execute` und `control/unsubscribe/execute` speichern ihn im Abschnitt `stream` der Einstellungsdatei des Moduls, bevor sie ihn anwenden. Ein Konsument, dessen gespeichertes `enable` `true` ist, abonniert beim Start von selbst |
| Der Stream des Cam Driver | **nein** | nur sein `tag` wird gespeichert. Rufen Sie nach jedem Start erneut `control/publish/execute` mit `enable` = `true` auf |
| Die Kameraverbindung | nein | führen Sie nach jedem Start den Handshake `connect-camera` aus |

Lässt sich eine Datei nicht schreiben, antwortet `execute` mit `CreationFailed` (ctrlX `DL_CREATION_FAILED`), und nichts ändert sich.

Der Abschnitt `stream` der Einstellungsdatei eines Konsumenten:

```json
"stream": {
    "enable": false,
    "address": "hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream",
    "tag": "",
    "queueSize": 1,
    "keepLatestOutput": false,
    "onEntry": []
}
```

## Warteschlangengröße {#queue}

| App | Bereich | Standard | Wenn die Warteschlange voll ist |
| --- | --- | --- | --- |
| AI Object Matching, die Finder, die Code Reader | 1 bis 64 | 1 | ein neues Element verdrängt das älteste |
| Calibration | 1 bis 4096 | 64 | ein neues Element verdrängt das älteste wartende |

Ein Element, das aus einer vollen Warteschlange verdrängt wird, zählt als **übersprungen**.

## Streams und einzelne Operationen {#collisions}

Während ein Stream läuft, werden Operationen abgelehnt, mit denen er kollidieren würde:

- Cam Driver: `capture/ready` ist `false`; `capture/execute` antwortet mit `InvalidOperationMode` (ctrlX `DL_INVALID_OPERATION_MODE`). Wiederholen Sie nicht in einer Schleife. Um während des Streamings einzelne Bilder aufzunehmen, lesen Sie `…/stream/frame` der Kamera, oder schalten Sie `keep-latest-output` ein und lesen Sie `output/image`, wenn sich `output/package-identifier` ändert.
- AI Object Matching: `inference/ready` ist `false`; ein Handshake-Request endet mit Status `100002`.
- Finder: Eine Methode, die aufgerufen wird, während ein Bild verarbeitet wird, wird als belegt abgelehnt.
- Code Reader: `execute` und der Stream behindern sich nicht; jedes Bild wird von einem eigenen Detektor gelesen.

Wird der Stream des Cam Driver gestoppt, verbindet er die Kamera neu, damit `capture` wieder funktioniert; das dauert etwa zwei Sekunden. Warten Sie, bis `capture/ready` `true` ist. Wechseln Sie so selten wie möglich zwischen Stream und Capture.

## Die Kette verfolgen {#counters}

Jede App zählt unter `…/stream/statistics/`, was sie empfängt. Der erste Zähler, der nicht steigt, zeigt, wo eine Kette stehen bleibt:

| App | Zähler |
| --- | --- |
| Cam Driver | `frames`, `published-frames`, `lost-frames`, `incomplete-frames` |
| AI Object Matching | `received-frames`, `inferred-frames`, `skipped-frames`, `failed-frames`, `lost-frames` |
| Finder, Code Reader | `received-frames`, `processed-frames`, `skipped-frames`, `failed-frames`, `lost-frames` |
| Calibration | `received-updates`, `transformed-updates`, `skipped-updates`, `failed-updates`, `lost-updates` |

`lost-` zählt Elemente, die nie eingetroffen sind, ermittelt aus Lücken in den Sequenznummern; `skipped-` Elemente, die aus einer vollen Warteschlange verdrängt wurden; `failed-*` Elemente, die nicht verarbeitet werden konnten.

## Das Ergebnis: ein Envelope mit seiner Lineage {#envelope}

Jedes Stream-Ergebnis ist ein **Envelope**: zuerst die Lineage (Herkunftskette) des Elements, dann die Nutzdaten - dasselbe Ergebnis wie die Nicht-Stream-Ausgabe der App, mit einigen Unterschieden, die im Handbuch der jeweiligen App beschrieben sind.

Die **Lineage** listet jedes Modul auf, das das Element durchlaufen hat. Jeder Schritt hat:

| Feld | Bedeutung |
| --- | --- |
| `producer` | die Data-Layer-Adresse des Moduls, zum Beispiel `hdvisionsystems/lumiscan-cam-driver/camera1` |
| `tag` | das Tag des Moduls, oder seine Modul-ID, wenn das Tag leer ist |
| `run` | wann der Stream des Produzenten gestartet wurde (µs seit der Epoche); ein neuer Lauf zählt wieder ab 1 |
| `sequence` | die Nummer des Elements im Lauf: 1, 2, … ohne Lücken, eine Lücke ist also ein verlorenes Element |
| `time_us` | wann der Schritt ausgeführt wurde |
| `settings_hash` | der Hash der Einstellungen, mit denen der Schritt ausgeführt wurde, wie auf `setting/settings-hash` |
| `elapsed_us` | wie lange der Schritt gedauert hat |
| `external_id` | die eigene Nummer des Produzenten für das Element, zum Beispiel die Block-ID der Kamera |

Die Lineage enthält höchstens 16 Schritte: den Ursprung und die neuesten. Ein geänderter `settings_hash` bedeutet, dass sich eine Einstellung geändert hat. Jeder Hash wird einmalig in `settings-history/` im Einstellungsordner der App gespeichert, sodass sich die Einstellungen hinter einem Ergebnis nachschlagen lassen.

Um auf einem PC ein Bild durch die Kette zu verfolgen, verwenden Sie **LumiScan Keryx Utilities**, siehe [Werkzeuge](https://docs.hdvisionsystems.com/de/lumiscan-keryx-de/1.0.0/tools.html#utilities).
