Zum Hauptinhalt springen

KI-GESTÜTZTE DOKUMENTATION

Was möchten Sie wissen?

Verbindung mit Tulip

Tulip ist eine No-Code-Plattform für MES und Connected Frontline Operations. Die OV20i-Kamera verbindet sich mit Tulip über Node-RED, das auf der Kamera läuft – derselbe Flow-Editor, den Sie auch für SPS-, MQTT- und andere I/O-Integrationen nutzen. Tulip kann:

  • Eine Inspektion über eine Bedienerschaltfläche oder ein App-Ereignis auslösen.
  • Die Ergebnisse pro ROI sowie globale Pass/Fail-Resultate inklusive Aufnahme-Metadaten empfangen.
  • Das aktive Rezept wechseln, wenn der Bediener einen Teile-Barcode scannt oder ein anderes Produkt auswählt.
  • Das Live-Bild anzeigen (mit Bounding-Box-Overlays) innerhalb einer Tulip-App, damit der Bediener sieht, was die AI gesehen hat.

Diese Anleitung führt Sie Schritt für Schritt durch jeden dieser vier Integrationspunkte.

Architektur

┌────────────────────────────┐               ┌──────────────────────────────┐
│ TULIP │ │ OV20i │
│ │ │ │
│ ┌──────────────────┐ │ HTTP/MQTT │ ┌──────────────────────┐ │
│ │ Operator Button │──────┼───trigger─────┼──▶│ Node-RED HTTP IN │──▶│
│ │ in Tulip App │ │ │ │ /trigger │ │
│ └──────────────────┘ │ │ └──────────────────────┘ │
│ │ │ │ │
│ ┌──────────────────┐ │ │ ▼ │
│ │ Tulip Connector │◀─────┼─── results ───┼─── All Block Outputs │
│ │ Function (HTTP) │ │ │ (image_url, pass/fail, │
│ └──────────────────┘ │ │ per-ROI classes) │
│ │ │ │ │
│ ┌──────────────────┐ │ │ ▼ │
│ │ Image Widget │◀─────┼── live-feed ──┼─── http://CAMERA_IP/live-feed│
│ │ (iframe URL) │ │ (HMI w/ ROI │ (shows bounding boxes │
│ └──────────────────┘ │ overlays) │ on the captured image) │
│ │ │ │
│ ┌──────────────────┐ │ │ ┌──────────────────────┐ │
│ │ Recipe Selector │──────┼─── HTTP ──────┼──▶│ /pipeline/activate │ │
│ │ (barcode / btn) │ │ │ │ {id: <recipe_id>} │ │
│ └──────────────────┘ │ │ └──────────────────────┘ │
└────────────────────────────┘ └──────────────────────────────┘

Die Brücke in der Mitte ist immer Node-RED, das innerhalb des IO Block der Kamera läuft – dort erstellen Sie alle vier Integrationen.

Node-RED-Canvas innerhalb des IO Block der Kamera – Advanced Mode der IO Logic-Stufe

Verwenden Sie Umgebungsvariablen für den Tulip-Endpunkt

Wenn Sie Ihre Tulip-Connector-URL fest im Node-RED-Flow codieren, bindet dies den Flow an eine einzelne Bereitstellung. Definieren Sie stattdessen eine Umgebungsvariable TULIP_ENDPOINT unter System Settings → Environment Variables und lesen Sie diese in Ihren HTTP Request-Nodes mit ${TULIP_ENDPOINT} aus. So können Sie denselben Flow exportieren und auf jeder Kamera in der Linie wieder importieren. Das vollständige Muster finden Sie unter Environment Variables.

Wählen Sie Ihren Transport: HTTP oder MQTT

OptionWann verwendenHinweise
HTTP (empfohlen für die meisten Tulip-Bereitstellungen)Tulip Connector Functions rufen nativ HTTP-Endpunkte auf. Der einfachste Weg, um über eine Tulip-Widget-Schaltfläche auszulösen.Funktioniert ohne zusätzliche Infrastruktur. Tulip → Kamera und Kamera → Tulip verwenden beide einfache POST-Aufrufe.
MQTTIn Ihrem Werk läuft bereits ein MQTT-Broker (Sparkplug B, IT/OT-Broker usw.) und der Tulip Edge Connector ist für die Kommunikation damit konfiguriert.Geringere Latenz bei hohem Signalaufkommen. Erfordert einen Broker.
OPC UASie betreiben eine Tulip Edge MC-Instanz mit dem OPC UA Connector.Der OV20i wird mit vorinstallierten OPC UA Node-RED-Blöcken ausgeliefert.

Im weiteren Verlauf dieses Leitfadens werden HTTP-Beispiele verwendet – das ist die Standardoption für die meisten Tulip-Bereitstellungen. Die gleichen Muster gelten für MQTT (HTTP IN / HTTP Request-Nodes durch MQTT in / MQTT out-Nodes ersetzen).

1. Auslösen der Kamera aus einer Tulip-App

Ein Tulip-Bediener drückt eine Schaltfläche → Die Tulip Connector Function ruft einen HTTP-Endpunkt auf, den Node-RED der Kamera abhört → Node-RED löst eine Aufnahme aus.

Node-RED-Seite: Trigger empfangen

Im IO Block der Kamera (Advanced Mode → Node-RED) erstellen:

[ HTTP IN: POST /trigger ]──▶[ Trigger node ]──▶[ HTTP Response: 200 ok ]
  1. Ziehen Sie einen http in-Node aus der Kategorie network hinein.
    • Method: POST
    • URL: /trigger
  2. Verbinden Sie ihn mit dem OV-spezifischen Trigger-Node (unter block logic in der OV-Palette). Der Trigger-Node startet die Aufnahme-Pipeline der Kamera.
  3. Fügen Sie einen http response-Node hinzu, damit der Tulip Connector sofort eine 200 OK-Antwort erhält (lassen Sie Tulip nicht auf die KI-Inferenz warten – das Ergebnis wird asynchron zurückgesendet, siehe Abschnitt 2).
  4. Klicken Sie auf Deploy.

Der Endpunkt ist nun unter http://<CAMERA_IP>/node-red/trigger verfügbar (der HTTP-Root von Node-RED ist unter /node-red/ eingehängt).

Tulip-Seite: Trigger über eine Schaltfläche aufrufen

In Ihrem Tulip-Konto:

  1. Gehen Sie zu Apps → Connectors und erstellen Sie einen neuen HTTP Connector, falls noch keiner vorhanden ist.
  2. Setzen Sie den Host auf die IP-Adresse Ihrer Kamera und den Port auf 80 (oder 443, falls Sie HTTPS aktiviert haben).
  3. Erstellen Sie eine neue Connector Function mit dem Namen Trigger Camera:
    • Method: POST
    • Endpoint: /node-red/trigger
    • Für einen einfachen Trigger sind keine Body- oder Eingabeparameter erforderlich – die Kamera verwendet das aktive Rezept.
  4. Speichern und testen Sie die Connector Function. Sie sollten eine 200-Antwort sehen und die Kamera sollte ein Bild aufnehmen.
  5. Fügen Sie in Ihrer Tulip-App ein Button-Widget hinzu. Wählen Sie in dessen Aktion Run Connector Function → Trigger Camera.

Wenn der Bediener die Schaltfläche antippt, löst die Kamera aus.

Zusätzlichen Kontext mit dem Trigger übergeben

Wenn Sie mit jedem Trigger eine Seriennummer oder Teile-ID übermitteln möchten, ändern Sie die Tulip Connector Function so, dass sie Eingaben akzeptiert (z. B. serial_number), und übergeben Sie diese im Request-Body. Auf der Kameraseite empfängt Ihr HTTP IN-Node sie als msg.payload, und Sie können sie in einer Flow-Variablen ablegen, damit der Flow für das Senden der Ergebnisse (Abschnitt 2) sie an den Prüfbericht anhängen kann.

2. Ergebnisse an Tulip zurücksenden

Nach der Bildaufnahme der Kamera wird der Node All Block Outputs mit dem vollständigen Inspektionsergebnis ausgelöst. Das Muster:

[ All Block Outputs ]──▶[ Function: format for Tulip ]──▶[ HTTP Request: POST to Tulip ]

Flow erstellen

  1. Verbinden Sie einen function-Node nach dem All Block Outputs-Node.
  2. Die Funktion fasst die Ergebnisse pro ROI zu einem globalen Pass/Fail zusammen und reduziert den Payload auf das, was Tulip tatsächlich benötigt:
// Read the camera's full inspection payload
const p = msg.payload || {};

// Consolidate per-ROI classifier predictions into a global pass/fail
const preds = p.classification?.predictions || [];
const allPass = preds.length > 0 && preds.every(r => r.predicted_class === 'pass');

// Optional: count segmentation defects (e.g., for thresholded fail)
const defectPixels = (p.segmentation?.blobs || [])
.reduce((s, b) => s + (b.pixel_count || 0), 0);

// Build a flat object for Tulip (Tulip Connector Functions like flat fields)
msg.payload = {
result: allPass ? "pass" : "fail",
inspection_id: p.inspection_id || null,
timestamp: new Date().toISOString(),
image_url: p.image_url || null, // see Section 4 for displaying this in Tulip
defect_pixel_count: defectPixels,
per_roi: preds.map(r => ({
roi: r.roi_name,
class: r.predicted_class,
confidence: r.confidence,
})),
// If you stashed a serial number from the trigger (see Section 1), add it:
// serial_number: flow.get('lastSerial') || null,
};

// Set headers for the outbound HTTP request
msg.headers = { 'Content-Type': 'application/json' };
msg.method = 'POST';
return msg;
  1. Verbinden Sie diesen mit einem http request-Node:
    • Method: POST (oder verwenden Sie msg.method aus der obigen Funktion)
    • URL: ${TULIP_ENDPOINT} (aus der Umgebungsvariable gelesen) oder fest codierte Tulip Connector-URL
    • Return: a UTF-8 string (oder JSON, falls Ihr Tulip-Endpunkt JSON zurückgibt)
  2. Verbinden Sie einen debug-Node nach dem HTTP-Request, damit Sie die Antwort von Tulip beim Testen einsehen können.
  3. Klicken Sie auf Deploy.

Tulip-Seite: Ergebnisse empfangen

In Tulip:

  1. Erstellen Sie eine HTTP Connector Function in Empfangsrichtung – einen Webhook-Endpunkt – oder verwenden Sie die Tables API von Tulip, um Ergebnisse in eine Tulip Table zu schreiben.
  2. Konfigurieren Sie die Logik Ihrer Tulip-App so, dass sie auf den eingehenden Payload reagiert (z. B. Statusanzeige aktualisieren, in einer Table protokollieren, Zähler hochzählen).

Speziell für Tulip Tables besteht das Muster darin, einen POST an https://<your-tulip-instance>.tulip.co/api/v3/tables/<table_id>/records mit den Feldern result, serial_number und timestamp zu senden. Verwenden Sie ein Tulip API-Token im Authorization-Header – speichern Sie das Token als Credential im HTTP Connector, nicht im Node-RED-Flow.

3. Rezepte von Tulip aus wechseln

Bediener müssen häufig zu einem anderen Rezept wechseln, wenn sich der Produkttyp ändert (Barcode-Scan, Dropdown, Dispatch). Die Kamera stellt einen integrierten HTTP-Endpunkt bereit, der ein Rezept anhand seiner ID aktiviert.

Rezept-ID ermitteln

  1. Öffnen Sie das Rezept im Recipe Editor.
  2. Sehen Sie in die Adresszeile Ihres Browsers: /recipes/15/editor → die ID ist 15.

Aufbau des Recipe-Switch-Flows

[ HTTP IN: POST /change-recipe ]──▶[ Function: format request ]──▶[ HTTP Request: POST localhost:5001/pipeline/activate ]──▶[ HTTP Response ]
  1. HTTP IN-Node: POST /change-recipe. Tulip ruft diesen Endpunkt mit einem Body wie { "id": 15 } auf.
  2. Function-Node – leitet die Recipe-ID an die kamerainterne API weiter:
const recipeId = msg.payload?.id;
if (!recipeId) {
msg.statusCode = 400;
msg.payload = { error: "missing 'id' field" };
return msg;
}
msg.headers = { 'Content-Type': 'application/json' };
msg.payload = JSON.stringify({ id: recipeId });
msg.method = 'POST';
return msg;
  1. HTTP Request-Node:
    • Method: POST
    • URL: localhost:5001/pipeline/activate
    • Return: a parsed JSON object
  2. HTTP Response-Node, damit die Connector Function von Tulip einen Statuscode zurückerhält.
Kamerainterne API-URL

Innerhalb von Node-RED auf der Kamera lautet der Endpunkt für den Recipe-Switch localhost:5001/pipeline/activate – das ist die kamerainterne Admin-API. Sie leiten die Anfrage von Tulip über Node-RED an die lokale API weiter. Versuchen Sie nicht, Port 5001 direkt von außerhalb der Kamera anzusprechen; er ist nur für kamerainterne Flows verfügbar.

Bei älterer Firmware (vor v18.92) lautete die URL http://[CAMERA_IP]/edge/pipeline/activate. Wenn Sie eine ältere Firmware verwenden und localhost:5001 nicht antwortet, greifen Sie auf die v17/v18-URL zurück. Aktualisieren Sie die Kamera-Firmware auf v18.92+, um den modernen Pfad zu nutzen.

Tulip-Seite: Recipe-Switch aufrufen

  1. Fügen Sie eine Connector Function Switch Recipe am selben HTTP-Connector hinzu.
  2. Method: POST, Endpoint: /node-red/change-recipe.
  3. Fügen Sie einen input parameter recipe_id (number) hinzu.
  4. Setzen Sie den Request-Body auf { "id": $recipe_id }.
  5. Verknüpfen Sie in Ihrer Tulip-App einen Barcode Scanner-Trigger oder ein Dropdown-Widget mit dieser Funktion und übergeben Sie die passende Recipe-ID.

Der Bediener scannt einen Barcode → Tulip ermittelt die Recipe-ID für das Teil → die Connector Function ruft die Kamera auf → die Kamera wechselt das Recipe in unter einer Sekunde.

4. Live-Bild (mit Bounding Boxes) in Tulip anzeigen

Das Image Widget von Tulip kann jede URL anzeigen, die ein Bild zurückgibt. Die OV20i verfügt über eine integrierte HMI-URL, die die zuletzt erfasste Aufnahme mit eingezeichneten Bounding-Box- und ROI-Overlays zurückgibt:

http://<CAMERA_IP>/live-feed

/live-feed zeigt das Kamerabild mit ROI-Overlay (eingezeichnete Bounding Boxes)

So binden Sie es in eine Tulip-App ein:

  1. Fügen Sie ein Image Widget zu Ihrem Tulip-Step hinzu.
  2. Setzen Sie die Image URL auf eine Tulip-Variable, die Sie aus dem Inspektionsergebnis befüllen, oder auf eine statische URL, wenn jede Kamera ihren eigenen Dashboard-Step hat.
  3. Das einfachste Muster: Hardcoden Sie http://<CAMERA_IP>/live-feed und lassen Sie es bei jeder Aufnahme automatisch aktualisieren (das Image Widget von Tulip aktualisiert sich, wenn sich seine URL oder ein Query-Parameter ändert – hängen Sie ?t={{timestamp}} an, um eine Aktualisierung zu erzwingen).

Wenn Sie die rohe Aufnahme (ohne Bounding Boxes) wünschen, verwenden Sie stattdessen image_url aus dem msg.payload – das ist eine pro Aufnahme erzeugte URL, die auf das gespeicherte Bild in der Bildbibliothek der Kamera verweist.

Ein Tulip-Step, mehrere Kameras

Wenn Sie mehrere Kameras an derselben Linie haben, jede mit einer eigenen IP, speichern Sie die Kamera-URL in einer Tulip-Variable pro App-Step und lassen Sie den Bediener auswählen, welche Station angezeigt werden soll. Das Image Widget wechselt sofort, wenn sich die Variable ändert.

Referenz-Flow (importierbares Node-RED JSON)

Der folgende Flow kombiniert alle vier Integrationen: Trigger HTTP IN, ergebnissendender HTTP Request, Rezeptumschalter und einen Debug-Knoten. Kopieren Sie das JSON, öffnen Sie Node-RED → Hamburger-Menü → Import und fügen Sie es ein.

[
{
"id": "tulip_trigger_in",
"type": "http in",
"name": "POST /trigger",
"url": "/trigger",
"method": "post",
"x": 160, "y": 100, "wires": [["tulip_trigger_fire"]]
},
{
"id": "tulip_trigger_fire",
"type": "trigger-camera",
"name": "Trigger camera",
"x": 380, "y": 100, "wires": [["tulip_trigger_resp"]]
},
{
"id": "tulip_trigger_resp",
"type": "http response",
"name": "200 ok",
"statusCode": "200",
"x": 580, "y": 100, "wires": []
},
{
"id": "tulip_results_format",
"type": "function",
"name": "Format for Tulip",
"func": "const p = msg.payload || {};\nconst preds = p.classification?.predictions || [];\nconst allPass = preds.length > 0 && preds.every(r => r.predicted_class === 'pass');\nmsg.payload = {\n result: allPass ? 'pass' : 'fail',\n timestamp: new Date().toISOString(),\n image_url: p.image_url || null,\n per_roi: preds.map(r => ({roi: r.roi_name, class: r.predicted_class, confidence: r.confidence}))\n};\nmsg.headers = {'Content-Type':'application/json'};\nmsg.method = 'POST';\nreturn msg;",
"x": 380, "y": 200, "wires": [["tulip_results_send"]]
},
{
"id": "tulip_results_send",
"type": "http request",
"name": "POST to Tulip",
"method": "POST",
"url": "${TULIP_ENDPOINT}",
"ret": "obj",
"x": 600, "y": 200, "wires": [["tulip_results_debug"]]
},
{
"id": "tulip_results_debug",
"type": "debug",
"name": "Tulip response",
"x": 800, "y": 200, "wires": []
},
{
"id": "tulip_recipe_in",
"type": "http in",
"name": "POST /change-recipe",
"url": "/change-recipe",
"method": "post",
"x": 160, "y": 300, "wires": [["tulip_recipe_format"]]
},
{
"id": "tulip_recipe_format",
"type": "function",
"name": "Format request",
"func": "const id = msg.payload?.id;\nif (!id) { msg.statusCode = 400; msg.payload = {error:'missing id'}; return msg; }\nmsg.headers = {'Content-Type':'application/json'};\nmsg.payload = JSON.stringify({id});\nmsg.method = 'POST';\nreturn msg;",
"x": 380, "y": 300, "wires": [["tulip_recipe_call"]]
},
{
"id": "tulip_recipe_call",
"type": "http request",
"name": "/pipeline/activate",
"method": "POST",
"url": "localhost:5001/pipeline/activate",
"ret": "obj",
"x": 600, "y": 300, "wires": [["tulip_recipe_resp"]]
},
{
"id": "tulip_recipe_resp",
"type": "http response",
"name": "to Tulip",
"x": 800, "y": 300, "wires": []
}
]

Sie müssen den Knoten All Block Outputs weiterhin mit tulip_results_format verbinden (er ist im obigen JSON nicht enthalten, da dieser Knoten OV-spezifisch ist und bereits in jedem Flow existiert).

Fehlerbehebung

SymptomUrsache / Lösung
Tulip Connector gibt connection refused zurückKamera und Tulip Edge Device befinden sich nicht im selben Netzwerk, oder die Firewall der Kamera blockiert Port 80. Beide müssen gegenseitig erreichbar sein; pingen Sie zuerst die Kamera vom Tulip Edge Device aus an.
Trigger HTTP IN wird nie ausgelöstVergessen, in Node-RED nach dem Hinzufügen des Knotens auf Deploy zu klicken, oder die URL enthält einen Tippfehler (muss mit / beginnen, nicht mit /node-red/).
Rezeptumschaltung gibt 404 zurückFalscher Endpunkt für Ihre Firmware. Vor v18.92 wird /edge/pipeline/activate von der Kamera-IP verwendet; ab v18.92 wird localhost:5001/pipeline/activate innerhalb von Node-RED verwendet.
/live-feed zeigt in Tulip ein schwarzes Bild anDie Kamera hat noch keine Aufnahme gemacht, oder das Bild wurde nicht aktualisiert. Hängen Sie ?t={{Date.now()}} an, um das Image Widget zum erneuten Laden zu zwingen.
Tulip erhält eine 200, aber keinen Ergebnis-BodyDie Kamera löst den Trigger aus und gibt sofort 200 zurück — das Ergebnis kommt asynchron über den ergebnissendenden Flow zurück (Abschnitt 2). Stellen Sie sicher, dass dieser Flow verdrahtet und deployt ist.
Per-ROI-Ergebnisse sind verrauscht / Tulip möchte nur pass/failGenau deshalb konsolidiert der Function-Knoten alles vor dem Senden in ein einziges Feld `result: "pass"

Wie geht es weiter