CSI IMX477 Camera Not Ready After Boot (Jetson Orin NX , Autostart)

Hi,

I’m working with a Jetson Orin board and using a CSI IMX477 camera, which is mapped to /dev/video0.

My code uses OpenCV and YOLOv5, and it works perfectly when run manually after boot:

bash run_.sh

However, when I try to autostart the code at boot (using a .desktop file under ~/.config/autostart/ or a systemd service), it fails to open the camera with this message:

python-repl

CopyEdit

[0] Camera not ready, retrying...
...
Camera could not be opened after retries.

Even with retries up to 10–30 seconds and adding sleep before launching, the problem remains.
Once I login and manually run the script, everything works fine.

Here’s what I’ve already tried:

  • Added sleep 20 before launching the Python script.
  • Tried up to 30 retry attempts in code (using cap = cv2.VideoCapture(gstreamer.pipline())).
  • Checked /dev/video0 existence during autorun using ls /dev/video*.
  • Using GNOME with X11, not Wayland.
  • Ensured the camera works fine manually.
  • Camera is an IMX477 (Arducam version) connected via CSI.

Question:
What is the proper way to ensure the CSI camera is available before autostarting the application on boot?

Should I wait for a specific system service to be active (like nvargus-daemon)?
Or should I create a systemd dependency?

Thanks in advance

Hello @M.S,

How is everything going?

Yeah, we believe it is necessary for your service to wait until nvargus-daemon is up and running. You can also configure your service to restart on failure.

We tried it on our side and were able to start a capture session and stream the video feed to a computer via UDP on boot. We documented it all in our wiki, you should be able to find it at:

How to start camera stream on boot with systems service - NVIDIA Jetson Tutorial

Please keep us posted and let us know if you encounter any issues.

best regards,
Andrew
Embedded Software Engineer at ProventusNova

Need wait the nvargus-daemon and DISPLAY driver is up(X11 started).

Thank you for your reply and helpful suggestions.

Yes, I read the documentation and tried to follow all the steps. I made sure that my systemd service includes the following:

[Unit]
Description=Jetson camera UDP stream on boot
After=nvargus-daemon.service
Requires=nvargus-daemon.service

[Service]
ExecStart=/home/jetson/myproject/run_.sh
Restart=on-failure
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/jetson/.Xauthority
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=graphical.target

In my script, I also activate a virtual environment before running the Python code. The camera works perfectly when I run the script manually after login, but when it runs as a systemd service at boot, I get the following repeated error:

[0] Camera not ready, retrying...
[1] Camera not ready, retrying...
...
Camera could not be opened after retries.

It seems like the service may still be starting too early, even though I added After=nvargus-daemon.service and set the DISPLAY variable.

Could you please clarify the correct way to wait for both nvargus-daemon and the X11 DISPLAY session to be fully ready before running the service?

Also, does the location of the Python virtual environment affect this? It is currently in /home/jetson/myproject/venv.

Any help or working example with virtualenv + CSI camera + systemd would be greatly appreciated.

Thanks again!

Maybe try below.

Thanks for the suggestion.

I already tried adding a .desktop file to ~/.config/autostart and verified it through Startup Applications in the Ubuntu GUI (GNOME).
My .desktop file looks like this:

Type=Application
Exec=/home/jetson/myproject/run.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name=CameraAutoRun
Comment=Start camera on boot

The script runs perfectly when launched manually after login, but fails to open the CSI camera (IMX477 on /dev/video0) when run through autostart.

It seems the nvargus-daemon or the display session (X11) may not be fully ready when autostart triggers the script. I also tried adding delays and even restarting nvargus-daemon at the beginning of the script — still no luck.

I’m also using a Python virtual environment, which activates fine manually.

If anyone has successfully made a CSI camera application autostart on Jetson (Orin), I’d really appreciate step-by-step tips.

Thanks again!

Here’s what I’ve tried:

Created a systemd service with After=nvargus-daemon.service and graphical.target.

Set the DISPLAY and XAUTHORITY variables correctly in the service.

Ensured the Python script runs fine manually from the terminal after boot.

The script is running inside a virtual environment, and I activate it properly in run.sh.

Using GNOME desktop, I also tried adding a .desktop file to ~/.config/autostart.

Even when I try to start the script over SSH (e.g., via PuTTY), the camera fails to open (cap.isOpened() == False).

I confirmed that nvargus-daemon is running before the script starts.

Still, after reboot, the script launches but fails to open the camera. In the logs, I see:

[0] Camera not ready, retrying…

[9] Camera could not be opened after retries.

Is there a reliable way to wait for both nvargus-daemon and the GUI environment (DISPLAY/X11) to fully initialize before running the script?

Any working examples or guidance would be greatly appreciated. Thanks!

If you think they need more info (e.g., OS version, Python version, JetPack), let me know and I’ll add it too.

Hello @M.S,

Thanks for the fast response.

It is very estrange how persistent that error is showing in your case.

Would it be possible for you to test with a different camera?

I wonder if it might be something related with the DTB overlay if you are using one for setting up the camera support.

best regards,
Andrew
Embedded Software Engineer at ProventusNova

Maybe build the argus_camera by below command to check the log for the failed.

sudo cmake -DDISABLE_MULTIPROCESS=ON ..
sudo make -j4

Hi everyone,

I’m still having issues with the camera setup on my Jetson device.

I tested with an IMX219 camera, but unfortunately, the problem persists.
I also tried multiple Jetson-IO overlay configurations (enabled and removed various combinations), but it did not help either.

Here’s the error log from systemctl status nvargus-daemon.service after rebooting and trying to run nvgstcapture-1.0:

SCF: Error BadParameter:  (propagating from src/api/CameraDriver.cpp, function addSourceByIndex(), line 333)
SCF: Error BadParameter:  (propagating from src/api/CameraDriver.cpp, function getSource(), line 505)
E/ libnvphs:socket: Error[2]: socket connection /var/lib/nvphs/nvphsd.ctl to PHS failed: No such file or directory
D/ libnvphs:socket: Warning: connecting to Power Hinting Service failed. Is PHS running?
E/ libnvphs: Error: NvPHSSendThroughputHints[usecase=camera, hint=MinCPU, value=4294967295, timeout_ms=1000]: queue_or_send() failed
WARNING: Cleaning up 1 outstanding streams...(Argus) Error InvalidState: Unknown stream deleted. (in src/api/CaptureSessionImpl.cpp)

The nvargus-daemon is running, but the camera does not show any output, and these errors are repeated every time I run a capture tool.

I would appreciate any suggestions on how to fully reset the device tree overlays or ensure proper camera detection. Thanks!

thanks for your help.
but I got error while executing make j4:
fetal error: Argus/ Argus,h : No such file or directory

Hello @M.S,

Thanks for keeping us posted.

Just out of curiosity, what JP version are you using ?

Can you try launching a v4l2-ctl capture command instead of the GStreamer nvargus one ?

best regards,
Andrew
Embedded Software Engineer at ProventusNova

I’m using a Jetson Orin NX with JetPack 5.1.1 (L4T 35.3.1) and a CSI IMX477 camera on /dev/video0.
When I run my Python script manually from terminal inside a virtual environment, everything works perfectly.
However, when I try to launch the same script on boot using a systemd service, it fails at cap.isOpened().

I’ve tried all suggestions (wait for camera, wait for nvargus-daemon, sleep delays, X11 env vars, logging, etc.), but none worked.

Hardware

  • Jetson Orin NX
  • JetPack 5.1.1
  • IMX477 (via CSI)
  • Also tested with IMX219 – same result
  • Device Tree modified using jetson-io to support dual camera setup (IMX219 + IMX477)

🧪 What I Tried

  • Confirmed nvargus-daemon is active via systemctl status
  • Manually tested cv2.VideoCapture() and GStreamer pipeline inside Python – works fine
  • Checked /dev/video0 exists and accessible
  • Used v4l2-ctl --all in a loop to wait for camera
  • Set proper environment variables for DISPLAY and XAUTHORITY
  • Used After=nvargus-daemon.service and Requires=nvargus-daemon.service in systemd unit

📂 run.sh

bash

CopyEdit

#!/bin/bash
LOG_FILE=/home/jetson/myproject/run_log.txt
echo "[$(date)] Starting run.sh" >> $LOG_FILE

# Activate Python virtual environment
source /home/jetson/envs/myenv/bin/activate

# Wait for /dev/video0 using v4l2-ctl
echo "[$(date)] Waiting for camera..." >> $LOG_FILE
for i in {1..20}; do
    v4l2-ctl --device=/dev/video0 --all > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "[$(date)] Camera /dev/video0 is ready." >> $LOG_FILE
        break
    fi
    echo "[$(date)] Camera not ready yet... retry $i" >> $LOG_FILE
    sleep 2
done

# Run the Python script
echo "[$(date)] Launching Python script" >> $LOG_FILE
python /home/jetson/myproject/Autorun_code.py >> $LOG_FILE 2>&1

⚙️ camera_autorun.service

ini

CopyEdit

[Unit]
Description=Autorun Python script with virtualenv and camera wait
After=nvargus-daemon.service network.target
Requires=nvargus-daemon.service

[Service]
Type=simple
User=jetson
Group=video
WorkingDirectory=/home/jetson/myproject
ExecStart=/home/jetson/myproject/run.sh
Restart=on-failure
RestartSec=5
StandardOutput=append:/home/jetson/myproject/stdout.log
StandardError=append:/home/jetson/myproject/stderr.log
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/jetson/.Xauthority"

[Install]
WantedBy=multi-user.target

🧠 Python Snippet

I’ve also added a retry loop in Python to avoid immediate failure:

print("Trying to open camera...")
cap = cv2.VideoCapture(gstreamer_pipeline(), cv2.CAP_GSTREAMER)
for i in range(10):
    if cap.isOpened():
        break
    print(f"[{i}] Camera not opened yet...")
    time.sleep(1)
assert cap.isOpened(), "Camera could not be opened"

🔍 Still Seeing Errors

  • cap.isOpened() fails after boot (via service), but works manually
  • nvargus-daemon is running but shows errors like:
SCF: Error BadParameter: Sensor config failed
NvPclOpen: PCL Open Failed
libnvphs: socket connection to PHS failed

I tried capturing a frame using v4l2-ctl --device=/dev/video0 --stream-mmap --stream-count=1 --stream-to=test.yuv and the file was created successfully. This means the V4L2 interface is working fine.

Please check argus_camera or gst-launch-1.0 instead of CV to narrow down the problem.

Thanks

Could using a virtual environment for running code be the cause of this problem?

I don’t understand what you mean. Could you please provide more detailed and specific guidance? Are you saying OpenCV is the reason for this problem?

I’ve written the following Python script to stream video from my Jetson’s IMX477 CSI camera. It uses GStreamer to show the video locally and simultaneously stream

#!/usr/bin/env python3
import gi
import signal
import sys
import time

gi.require_version(‘Gst’, ‘1.0’)
gi.require_version(‘GstVideo’, ‘1.0’)
from gi.repository import Gst, GstVideo, GLib

class CameraStreamer:
def init(self):
Gst.init(None)
self.loop = GLib.MainLoop()
self.pipeline = None
self.window_id = None

    self.pipeline_str = (
        "nvarguscamerasrc sensor-id=0 ! "
        "queue max-size-buffers=3 leaky=downstream ! "
        "video/x-raw(memory:NVMM), width=1280, height=720, framerate=30/1, format=NV12 ! "
        "nvvidconv flip-method=0 ! "
        "tee name=t ! "
        "queue ! xvimagesink sync=false async=false name=local_display "
        "t. ! queue ! videoconvert ! video/x-raw,format=RGB ! "
        "queue ! jpegenc quality=85 ! "
        "rtpjpegpay ! udpsink host=127.0.0.1 port=5000 sync=false name=network_stream"
    )

    signal.signal(signal.SIGINT, self.signal_handler)
    signal.signal(signal.SIGTERM, self.signal_handler)

def signal_handler(self, sig, frame):
    print(f"\nSignal {sig} received, stopping pipeline...")
    if self.pipeline:
        self.pipeline.set_state(Gst.State.NULL)
    self.loop.quit()

def run(self):
    
    self.pipeline = Gst.parse_launch(self.pipeline_str)
    
  
    local_sink = self.pipeline.get_by_name("local_display")
    if local_sink:
        local_sink.set_property("force-aspect-ratio", True)
    
   
    bus = self.pipeline.get_bus()
    bus.add_signal_watch()
    bus.connect("message", self.on_bus_message)

    print("Starting pipeline...")
    ret = self.pipeline.set_state(Gst.State.PLAYING)
    if ret == Gst.StateChangeReturn.FAILURE:
        print("Failed to start pipeline")
        return

    print("""
    📹 Camera Stream Active:
    - Local display: X11 window
    - Network stream: udp://127.0.0.1:5000
    Press Ctrl+C to stop
    """)
    
    try:
        self.loop.run()
    except Exception as e:
        print(f"Error: {e}")
    finally:
        print(" Pipeline stopped")
        self.pipeline.set_state(Gst.State.NULL)

def on_bus_message(self, bus, message):
    mtype = message.type
    if mtype == Gst.MessageType.EOS:
        print(" End of stream")
        self.loop.quit()
    elif mtype == Gst.MessageType.ERROR:
        err, debug = message.parse_error()
        print(f" Error: {err}\n🔧 Debug: {debug}")
        self.loop.quit()
    elif mtype == Gst.MessageType.STATE_CHANGED:
        if isinstance(message.src, Gst.Pipeline):
            old, new, pending = message.parse_state_changed()
            print(f"Pipeline state changed: {old.value_nick} → {new.value_nick}")
    return True

if name == “main”:
print(“=== 🛠 Jetson IMX477 Camera Streamer ===”)
streamer = CameraStreamer()
streamer.run()

When I manually start the script (or the service), everything works perfectly. The camera is initialized, and both local display and network streaming function as expected.

However, the problem is: the script does NOT work at boot when launched via systemd service.
The pipeline fails to start, and the camera doesn’t activate properly. Here’s my systemd service file:
[Unit]
Description=Jetson Camera Streamer
After=graphical.target nvargus-daemon.service
Requires=nvargus-daemon.service

[Service]
Type=simple
User=jetson
Group=video
Environment=“DISPLAY=:0”
Environment=“XAUTHORITY=/home/jetson/.Xauthority”
WorkingDirectory=/home/jetson
ExecStartPre=/bin/sleep 10
ExecStart=/usr/bin/python3 /path/to/streamer.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

The camera works fine with:

  • argus_camera
  • gst-launch-1.0 nvarguscamerasrc ! nvoverlaysink

I would really appreciate any help on this matter as I am currently blocked and need to solve this urgently for my project.

So you have verify the gat-launch-1.0 and argus_camera without problem by systemd?

Do you check the /var/log/syslog of nvargus-daemon log for more informaiton?

I was able to successfully stream from the CSI camera after boot using the following systemd service:

[Unit]
Description=Test GStreamer with CSI camera
After=graphical.target nvargus-daemon.service
Requires=nvargus-daemon.service

[Service]
User=jetson
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/jetson/.Xauthority
Environment=GST_PLUGIN_PATH=/usr/lib/aarch64-linux-gnu/gstreamer-1.0
ExecStartPre=/bin/sleep 10
ExecStart=/usr/bin/gst-launch-1.0 nvarguscamerasrc ! queue ! nvvidconv ! queue ! nv3dsink
Restart=on-failure

[Install]
WantedBy=graphical.target

However, what I actually need is to access the frames from the camera in Python using OpenCV, so I can process them programmatically after boot.
I would appreciate any suggestions or recommended approaches for integrating this with OpenCV, especially in a way that works reliably with systemd at boot.

Thanks in advance!