KI-GESTÜTZTE DOKUMENTATION
Was möchten Sie wissen?
Verbindung mit Tulip
Tulip ist eine No-Code-MES- / Connected-Frontline-Operations-Plattform. Die OV10i-Kamera kommuniziert mit Tulip über Node-RED, das auf der Kamera läuft — derselbe Flow-Editor, den Sie auch für PLC-, MQTT- und andere I/O-Integrationen verwenden. Tulip kann:
- Eine Inspektion über eine Bedienertaste oder ein App-Ereignis auslösen.
- Die ROI-bezogenen und globalen Pass/Fail-Ergebnisse sowie Aufnahme-Metadaten empfangen.
- Das aktive Recipe 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 KI gesehen hat.
Diese Anleitung führt Sie Schritt für Schritt durch alle vier Integrationspunkte.
Architektur
┌────────────────────────────┐ ┌──────────────────────────────┐
│ TULIP │ │ OV10i │
│ │ │ │
│ ┌──────────────────┐ │ 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, wo Sie alle vier Integrationen erstellen.

Wenn Sie Ihre Tulip-Connector-URL fest in den Node-RED-Flow einbauen, ist der Flow an ein einziges Deployment gebunden. Definieren Sie stattdessen eine TULIP_ENDPOINT-Umgebungsvariable 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 der Linie erneut importieren. Siehe Environment Variables für das vollständige Muster.
Transportprotokoll wählen: HTTP oder MQTT
| Option | Wann verwenden | Hinweise |
|---|---|---|
| HTTP (empfohlen für die meisten Tulip-Bereitstellungen) | Tulip Connector Functions rufen HTTP-Endpunkte nativ auf. Der einfachste Weg, um von einem Tulip-Widget-Button aus auszulösen. | Funktioniert ohne zusätzliche Infrastruktur. Tulip → Kamera und Kamera → Tulip verwenden beide einfache POST-Aufrufe. |
| MQTT | In Ihrer Anlage 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 UA | Sie betreiben eine Tulip Edge MC-Instanz mit dem OPC UA Connector. | Die OV10i wird mit vorinstallierten OPC UA Node-RED-Blöcken ausgeliefert. |
Der Rest dieser Anleitung verwendet in den Beispielen HTTP – 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. Kamera aus einer Tulip-App auslösen
Ein Tulip-Bediener drückt einen Button → die Connector Function von Tulip ruft einen HTTP-Endpunkt auf, auf den das Node-RED der Kamera lauscht → Node-RED löst eine Aufnahme aus.
Node-RED-Seite: Trigger empfangen
Im IO Block der Kamera (Advanced Mode → Node-RED) bauen Sie Folgendes auf:
[ HTTP IN: POST /trigger ]──▶[ Trigger node ]──▶[ HTTP Response: 200 ok ]
- Ziehen Sie einen http in-Node aus der Kategorie network in den Flow.
- Method:
POST - URL:
/trigger
- Method:
- Verdrahten Sie ihn mit dem OV-spezifischen Trigger-Node (unter block logic in der OV-Palette). Der Trigger-Node startet die Aufnahme-Pipeline der Kamera.
- Fügen Sie einen http response-Node hinzu, damit der Tulip Connector sofort ein
200 OKzurückbekommt (lassen Sie Tulip nicht auf die AI-Inferenz warten – das Ergebnis fließt asynchron zurück, siehe Abschnitt 2). - Klicken Sie auf Deploy.
Der Endpunkt ist jetzt unter http://<CAMERA_IP>/node-red/trigger erreichbar (das HTTP-Root von Node-RED ist unter /node-red/ eingebunden).
Tulip-Seite: Trigger über einen Button aufrufen
In Ihrem Tulip-Konto:
- Gehen Sie zu Apps → Connectors und erstellen Sie einen neuen HTTP Connector, falls noch nicht vorhanden.
- Setzen Sie den Host auf die IP-Adresse Ihrer Kamera und den Port auf
80(oder443, falls Sie HTTPS aktiviert haben). - Erstellen Sie eine neue Connector Function namens
Trigger Camera:- Method:
POST - Endpoint:
/node-red/trigger - Für einen einfachen Trigger werden kein Body und keine Eingabeparameter benötigt – die Kamera verwendet die aktive Recipe.
- Method:
- Speichern und testen Sie die Connector Function. Sie sollten eine 200-Antwort sehen und die Kamera sollte ein Bild aufnehmen.
- 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 auf den Button tippt, löst die Kamera aus.
Wenn Sie mit jedem Trigger eine Seriennummer oder Teile-ID übergeben möchten, ändern Sie die Tulip Connector Function so, dass sie Eingaben akzeptiert (z. B. serial_number), und fügen Sie diese in den Request Body ein. Auf der Kameraseite empfängt Ihr HTTP IN-Node sie als msg.payload, und Sie können sie in einer Flow-Variable ablegen, damit der Ergebnis-Sendeflow (Abschnitt 2) sie an den Inspection Report anhängen kann.
2. Ergebnisse zurück an Tulip senden
Nach der Bildaufnahme der Kamera wird der All Block Outputs-Node mit dem vollständigen Inspektionsergebnis ausgelöst. Das Muster:
[ All Block Outputs ]──▶[ Function: format for Tulip ]──▶[ HTTP Request: POST to Tulip ]
Flow aufbauen
- Verbinden Sie einen function-Node nach dem All Block Outputs-Node.
- Die Funktion konsolidiert die Ergebnisse pro ROI zu einem einzigen globalen Pass/Fail 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;
- Verbinden Sie ihn mit einem http request-Node:
- Method:
POST(oder verwenden Siemsg.methodaus der obigen Funktion) - URL:
${TULIP_ENDPOINT}(aus der Umgebungsvariablen gelesen) oder die fest codierte Tulip Connector URL - Return:
a UTF-8 string(oder JSON, falls Ihr Tulip-Endpunkt JSON zurückgibt)
- Method:
- Verbinden Sie einen debug-Node nach dem HTTP-Request, damit Sie die Antwort von Tulip während des Tests einsehen können.
- Klicken Sie auf Deploy.
Tulip-Seite: Ergebnisse empfangen
In Tulip:
- 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.
- Konfigurieren Sie die Logik Ihrer Tulip-App so, dass sie auf den eingehenden Payload reagiert (z. B. eine Statusanzeige aktualisieren, in eine Table protokollieren, einen Zähler erhöhen).
Speziell für Tulip Tables besteht das Muster darin, ein POST an https://<your-tulip-instance>.tulip.co/api/v3/tables/<table_id>/records mit den Feldern result, serial_number, 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 der ID aktiviert.
Rezept-ID finden
- Öffnen Sie das Rezept im Recipe Editor.
- Sehen Sie sich die Adressleiste Ihres Browsers an:
/recipes/15/editor→ die ID ist15.
Recipe-Switch-Flow erstellen
[ HTTP IN: POST /change-recipe ]──▶[ Function: format request ]──▶[ HTTP Request: POST localhost:5001/pipeline/activate ]──▶[ HTTP Response ]
- HTTP IN-Node:
POST /change-recipe. Tulip ruft diesen mit einem Body wie{ "id": 15 }auf. - Function-Node — die Recipe-ID an die interne API der Kamera weitergeben:
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;
- HTTP Request-Node:
- Method:
POST - URL:
localhost:5001/pipeline/activate - Return:
a parsed JSON object
- Method:
- HTTP Response-Node, damit die Connector Function von Tulip einen Statuscode zurückerhält.
Innerhalb von Node-RED auf der Kamera lautet der Recipe-Switch-Endpoint 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 aufzurufen; er ist nur für kamerainterne Flows zugänglich.
Bei älterer Firmware (vor v18.92) lautete die URL http://[CAMERA_IP]/edge/pipeline/activate. Falls Sie ä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 verwenden.
Tulip-Seite: Recipe-Switch aufrufen
- Fügen Sie eine Connector Function
Switch Recipeauf demselben HTTP Connector hinzu. - Method:
POST, Endpoint:/node-red/change-recipe. - Fügen Sie einen Input-Parameter
recipe_id(Number) hinzu. - Setzen Sie den Request-Body auf
{ "id": $recipe_id }. - Verknüpfen Sie in Ihrer Tulip-App einen Barcode Scanner-Trigger oder ein Dropdown-Widget, um diese Funktion mit der entsprechenden Recipe-ID aufzurufen.
Der Bediener scannt einen Barcode → Tulip ermittelt die Recipe-ID für das jeweilige Teil → die Connector Function ruft die Kamera auf → die Kamera wechselt das Recipe in weniger als 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. Der OV10i verfügt über eine eingebaute HMI-URL, die die letzte Aufnahme mit darüber eingezeichneten Bounding-Box- und ROI-Overlays zurückgibt:
http://<CAMERA_IP>/live-feed

So binden Sie es in eine Tulip-App ein:
- Fügen Sie ein Image Widget zu Ihrem Tulip-Step hinzu.
- Setzen Sie die Image URL auf eine Tulip-Variable, die Sie aus dem Inspektionsergebnis befüllen, oder auf eine statische URL, falls jede Kamera einen eigenen Dashboard-Step hat.
- Das einfachste Muster:
http://<CAMERA_IP>/live-feedfest hinterlegen und bei jeder Aufnahme automatisch aktualisieren lassen (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 Rohaufnahme (ohne Bounding Boxes) möchten, verwenden Sie stattdessen image_url aus msg.payload — das ist eine aufnahmespezifische URL, die auf das in der Kamera-Library gespeicherte Bild verweist.
Wenn Sie mehrere Kameras an derselben Linie mit jeweils eigener IP haben, 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 nachfolgende Flow kombiniert alle vier Integrationen: Trigger HTTP IN, ergebnissendender HTTP Request, Rezept-Umschalter und einen Debug-Node. 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 weiterhin den Node All Block Outputs mit tulip_results_format verbinden (er ist im obigen JSON nicht enthalten, da dieser Node OV-spezifisch ist und bereits in jedem Flow existiert).
Troubleshooting
| Symptom | Ursache / Lösung |
|---|---|
Tulip Connector gibt connection refused zurück | Kamera und Tulip Edge Device befinden sich nicht im selben Netzwerk, oder die Kamera-Firewall 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öst | Deploy in Node-RED nach dem Hinzufügen des Nodes vergessen, oder die URL enthält einen Tippfehler (muss mit / beginnen, nicht mit /node-red/). |
| Rezeptumschaltung gibt 404 zurück | Falscher 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 von innerhalb Node-RED verwendet. |
/live-feed zeigt in Tulip ein schwarzes Bild | Die Kamera hat noch keine Aufnahme gemacht, oder das Bild wurde nicht aktualisiert. Hängen Sie ?t={{Date.now()}} an, um das Image Widget zu einem erneuten Abruf zu zwingen. |
| Tulip erhält ein 200, aber keinen Ergebnis-Body | Die 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 verbunden und deployed ist. |
| Per-ROI-Ergebnisse sind unübersichtlich / Tulip benötigt nur pass/fail | Genau deshalb konsolidiert der Function-Node alles in ein einzelnes `result: "pass" |
Nächste Schritte
- Umgebungsvariablen — Halten Sie
TULIP_ENDPOINTund andere deployment-spezifische Konfigurationen aus dem Flow heraus. - Verbindung zur SPS (EtherNet/IP & PROFINET) — für parallele SPS-Integration neben Tulip.
- Overview Node-RED Custom Blocks — Referenz für die OV-spezifischen Palette-Nodes (Trigger, All Block Outputs usw.).
- Ausgänge einrichten (Schritt 5) — Hier fügt sich Node-RED in den umfassenderen Pass/Fail-Flow ein.