DEV Community

Sptii
Sptii

Posted on

Building an Edge-AI Computer Vision Pipeline for Real-Time Industrial Safety Interlocks

In high-risk manufacturing and process industries, optical smoke detectors and thermal threshold sensors often react too late. By the time ambient heat reaches a ceiling-mounted sensor, a thermal runaway event or chemical leak may already be underway.

To solve this, modern industrial engineering leverages Edge-AI vision processing. By running lightweight object detection models directly on edge devices (like NVIDIA Jetson modules) connected to local RTSP cameras, facilities can detect hazards in under 100 milliseconds and trigger safety interlocks before physical damage occurs.

In this tutorial, we will build a production-grade Python pipeline that ingests camera streams, runs inference using YOLOv8, and publishes real-time hazard events via MQTT to SCADA networks.

Architecture: Async Edge-AI Pipeline

To achieve sub-100ms latency without dropping frames, the video ingestion loop must run asynchronously from the inference and telemetry dispatchers:
[ RTSP Stream ] ──► [ Async Frame Grabber ]


[ Lock-Free Queue ]


[ TensorRT FP16 Inference Engine ]


[ MQTT Event Dispatcher ] ──► [ PLC / SCADA Interlock ]

1. Zero-Copy Frame Ingestion with OpenCV

Standard OpenCV VideoCapture blocks processing execution. When running deep learning inference, frame buffers stack up, introducing several seconds of visual lag.

We resolve this by running a dedicated daemon thread that constantly flushes stale frames, keeping only the latest image buffer in memory.
`import cv2
import threading
import queue
import time

class RealTimeRTSPStreamer:
def init(self, stream_url: str):
self.cap = cv2.VideoCapture(stream_url)
self.q = queue.Queue(maxsize=1)
self.running = True

    if not self.cap.isOpened():
        raise ConnectionError(f"Failed to open stream at {stream_url}")

def start(self):
    threading.Thread(target=self._capture_loop, daemon=True).start()
    return self

def _capture_loop(self):
    while self.running:
        ret, frame = self.cap.read()
        if not ret:
            time.sleep(0.01)
            continue

        # Flush queue to maintain zero frame lag
        if not self.q.empty():
            try:
                self.q.get_nowait()
            except queue.Empty:
                pass
        self.q.put(frame)

def get_frame(self):
    return self.q.get() if not self.q.empty() else None

def stop(self):
    self.running = False
    self.cap.release()`
Enter fullscreen mode Exit fullscreen mode

2. Ingesting YOLOv8 & Dispatching MQTT Telemetry

Next, we process incoming frames using a TensorRT-optimized model and publish hazard payloads via MQTT when bounding box confidence crosses our threshold.
`import json
import paho.mqtt.client as mqtt
from ultralytics import YOLO

Initialize MQTT Client for SCADA Interlock Communication

mqtt_client = mqtt.Client(client_id="Vision_Safety_Node_01")
mqtt_client.connect("192.168.1.50", 1883, 60) # Internal SCADA Broker IP
mqtt_client.loop_start()

Load YOLOv8 Model (Optimized via TensorRT Engine for Edge Acceleration)

model = YOLO("yolov8n-hazard.engine")

stream = RealTimeRTSPStreamer("rtsp://admin:pass@192.168.1.100:554/live").start()

CONFIDENCE_CUTOFF = 0.70

try:
while True:
frame = stream.get_frame()
if frame is None:
time.sleep(0.005)
continue

    # Run inference in FP16 precision
    results = model.predict(source=frame, conf=CONFIDENCE_CUTOFF, verbose=False)

    for result in results:
        for box in result.boxes:
            confidence = float(box.conf[0])
            class_id = int(box.cls[0])
            coords = box.xyxy[0].cpu().numpy().tolist()

            if confidence >= CONFIDENCE_CUTOFF:
                payload = {
                    "node_id": "BAY_04_CAMERA",
                    "event": "THERMAL_HAZARD_DETECTED",
                    "confidence": round(confidence, 3),
                    "bbox": coords,
                    "timestamp": time.time()
                }

                # Dispatch trigger to SCADA system
                mqtt_client.publish("factory/safety/interlock", json.dumps(payload), qos=1)
                print(f"[CRITICAL] Interlock Payload Dispatched: {payload}")
Enter fullscreen mode Exit fullscreen mode

except KeyboardInterrupt:
stream.stop()
mqtt_client.loop_stop()
print("Pipeline Terminated.")`

3. Optimizing Models for Low-Power Edge Devices

For deployment on industrial hardware (e.g., NVIDIA Jetson AGX or industrial PCs), export the PyTorch model to TensorRT with half-precision floating points (FP16):
# Exporting PyTorch model to TensorRT engine
yolo export model=yolov8n-hazard.pt format=engine device=0 half=True

This reduces execution latency from ~45ms (PyTorch CPU) down to ~6ms (TensorRT CUDA), freeing up computing resources for multi-camera processing on a single edge node.

Industrial Integration & Safety System Compliance

Computer vision algorithms provide rapid situational awareness, but they must operate as part of a structured safety architecture. Aligning automated alerts with established engineering protocols—such as quantitative risk assessments and OSHA process safety guidelines—ensures that automated interlocks complement physical relief systems without causing false-positive shutdown cascades.

To explore deeper technical guides on risk assessment workflows, industrial compliance frameworks, and plant safety engineering, check out the resources at sptii.com.

Top comments (0)