Headless Hailo on Raspberry Pi: SSH Shouldn’t Break Your Pipeline (But It Does)

Headless Hailo on Raspberry Pi (Because SSH Shouldn’t Break Your Pipeline)
⚠️ The Hailo example repository (hailo-rpi5-examples) is now marked outdated and may not receive further updates — use this guide accordingly.
There’s something mildly absurd about building a high-performance edge AI pipeline with Hailo on a Raspberry Pi — only for it to complain the moment you run it over SSH.
The Illusion of “It Works”
If you’ve used the official examples from hailo-rpi5-examples, everything looks fine at first. Plug in HDMI → run detection → bounding boxes appear → FPS prints → life is good. Then you try the exact same command over SSH. And suddenly:
drmModeSetPlane failed: Permission denied (13)
gst-resource-error-quark
The pipeline didn’t fail, only the display did. Which is worse — because now you’re debugging something that isn’t actually broken.
What’s Actually Going On
The default pipeline looks something like this:
fpsdisplaysink → autovideosink → kmssink
Here’s the problem:
autovideosinktries to be clever- On Raspberry Pi, it selects
kmssink kmssinkrequires DRM/KMS display access- SSH session = no active display
- Result = permission error from the graphics stack
This has nothing to do with Hailo. It’s just Linux being Linux. Even more confusing:
- If you start with a monitor, then unplug it → pipeline keeps running.
- If you start via SSH → it throws errors.
Bonus Confusion: Fake Errors That Look Real
While running headless, you may also see:
End-of-stream
Video rewound successfully. Restarting playback...
and
GStreamer-WARNING **: Got data flow before segment event
Tese look alarming. But they are not.
- EOS just means your input video looped
- The warning is a timing artifact in GStreamer
- Detection continues normally
And if your logs “slow down”? That’s just your own logging logic being selective.
The Fix (Ridiculously Simple, Of Course)
Remove the display entirely. Replace the GUI pipeline with:
fpsdisplaysink video-sink=fakesink sync=false
That’s it.
What This Actually Changes
- Removes
autovideosink - Removes
kmssink - Eliminates DRM plane allocation
- Keeps FPS reporting
- Makes the pipeline fully SSH-safe
The Solution:
Step 1 — Create a Headless Pipeline
Create a copy of the file …/hailo_app_python/apps/detection/detection_pipeline.py:
cp hailo-rpi5-examples/venv_hailo_rpi_examples/lib/python3.11/site-packages/hailo_apps/hailo_app_python/apps/detection/detection_pipeline.py hailo-rpi5-examples/venv_hailo_rpi_examples/lib/python3.11/site-packages/hailo_apps/hailo_app_python/apps/detection/detection_pipeline_nogui.py
Step 2 —
Replace the GUI-based display section with:
headless_display = (
"fpsdisplaysink "
"video-sink=fakesink "
"sync=false "
"text-overlay=false "
"signal-fps-measurements=true"
)
And make sure your final pipeline string ends with:
pipeline_string = (
f"{source_pipeline} ! "
f"{detection_pipeline_wrapper} ! "
f"{tracker_pipeline} ! "
f"{user_callback_pipeline} ! "
f"{headless_display}"
)
Step 3 — Modify Your Detection Script
Find this line:
from hailo_apps.hailo_app_python.apps.detection.detection_pipeline import GStreamerDetectionApp
Replace it with:
from hailo_apps.hailo_app_python.apps.detection.detection_pipeline_nogui import GStreamerDetectionApp
What we did is basically:
- Removed the display dependency
- Stopped GStreamer from trying to access DRM
- Made the pipeline compatible with SSH.
메타데이터
- post_id
- 2f71ffcc703f
- slug
- headless-hailo-on-raspberry-pi-ssh-shouldnt-break-your-pipeline-but-it-does-2f71ffcc703f
- url
- https://medium.com/@zubinbhuyan/headless-hailo-on-raspberry-pi-ssh-shouldnt-break-your-pipeline-but-it-does-2f71ffcc703f
- canonical_url
- https://medium.com/@zubinbhuyan/headless-hailo-on-raspberry-pi-ssh-shouldnt-break-your-pipeline-but-it-does-2f71ffcc703f
- author_url
- https://medium.com/@zubinbhuyan
- status
- ok
- fetched_at
- 2026-06-24 04:09:36