How to run a script on jetson orin multiple times?

Hi, I have created a shell script that runs on boot on the jetson orin device. Now how do I control this process? As in each time I want to reuse the device from start do I need to take the power off and reconnect for it to go to boot? Is there a better approach to give signal to the board to run a script or to end a script? To give context: My jetson device will operate on its own with a camera and a power source from a battery.

Usually something like this is quite simple, but you’ll have to give a lot more detail. Can you describe what the script does? Are there particular conditions it will trigger, or is it run manually sometimes over the network?

I basically want to automate taking a video for a certain duration( for example 10 minutes) from a usb camera and saving it. So for this i wrote script that runs on boot. So next time i want to run the script again instead of removing power and restarting is there a better approach? I want to keep the board headless and with only a camera. The videos will be analyzed later on in another host computer.

Where does your script exist at? Is the script run as user root, or as your regular user? Does the script work correctly without a monitor attached (sometimes video programs require a GUI to run to work correctly; you want headless, but does it already work headless)?

The service script is located at /lib/systemd/system/ and the script then executes another python script for which the path is added to the ExecStart Line. The script is run as a regular user. It works correctly sometimes and sometimes I face issues with video being saved from only one camera (I am using two cameras). But it works headless without any monitor. I was thinking that the issue was hardware/camera related for which sometimes only one camera works, do you think it can be GUI related? I am not displaying any video, its just a basic python opencv script to save frames from the camera in a video file.

Is the script at /lib/systemd/system/ part of the default system? I ask because if the script is part of the system, then one normally sym links it from “/etc/systemd/system/” (or one of the related /etc/systemd/ directories). One has the ability to use systemctl commands to stop, start, enable, disable those system scripts. If this is instead a custom script, then that script will exist somewhere else and be called by the systemd software. Where is the ExecStart script? Does this run on Python 2 or Python 3? What do you see from “python --version”?

Note that unless you’ve specially set it up, those scripts will run as user root. Running manually without sudo might run differently.

Knowing why one camera sometimes doesn’t work is something I can’t answer. Maybe if we know more and we can manually trigger and make it repeatable, then there are a lot of ways to see why it is failing sometimes.

Hi this is a custom script, and I have set it up as the following:


It runs using python3. I am not sure how I have set it up, maybe thats why its causing issues because I am running it without sudo? Let me know if you need more information. The camera I am using are the Oak D Lite Cameras, I use their XLink pipeline to recieve the video. It works fine if I am running the script normally but during the boot phase, only one camera is detected at times and its random so i am guessing it has to do with how its being called during boot. I have also added a delay for the cameras to get some time before it can start but I am still facing the issues.

Is this intended to run without graphics and just in text mode? This is what multi-user.target is. Anything running in a systemd service is running in init (init is actually a symbolic link pointed at systemd; init is the one and only first target run by the kernel itself; the kernel is UID 0, which is root…so whatever you do here runs as root unless you take steps to run as someone else).

Does your python script specifically name both cameras before returning? I’m just making a wild guess, but perhaps the return of successful XLink pipeline probably makes the service think it has succeeded in starting up, or else some other requirement needs to be added to wait for (e.g., it is possible the second camera starts, but fails because something is missing, and yet it succeeds because one camera is enough to mark as successful).

There are some variations which might work. For example, you could run python directly without the /bin/bash -c. To make things easier, would it be possible for you to actually attach the systemd script in the screenshot to the forum? I don’ t know if it would help or not, but if you can attach your python script so people can look at how the cameras start up, then that might be useful.

One more question: Does your python script do any logging? If that script logs, and provides camera start attempt information, information on failures or successes in steps, then it would be a lot easier to know where it went wrong.

Hi, thank you so much for your detailed replies. Its so helpful for me to understand where I might be going wrong. I am running a very simple script to capture the video and save them. It doesnt need any graphic it can just capture the videos from the camera without displaying it. I will try the steps you have mentioned and see what it does.

#!/usr/bin/env python3

import cv2
import depthai as dai
import contextlib

from calc import HostSpatialsCalc
from utility import *
import numpy as np
import math
import time

def createPipeline():
    # Start defining a pipeline
    pipeline = dai.Pipeline()
    # Define a source - color camera
    camRgb = pipeline.create(dai.node.ColorCamera)

    camRgb.setPreviewSize(300, 300)
    camRgb.setBoardSocket(dai.CameraBoardSocket.CAM_A)
    camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
    camRgb.setInterleaved(False)
    camRgb.setVideoSize(1920, 1080)

    # Create output
    xoutRgb = pipeline.create(dai.node.XLinkOut)
    xoutRgb.setStreamName("rgb")
    xoutRgb.input.setBlocking(False)
    xoutRgb.input.setQueueSize(1)
    

    # Define sources and outputs
    monoLeft = pipeline.create(dai.node.MonoCamera)
    monoRight = pipeline.create(dai.node.MonoCamera)


    # Properties
    monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
    monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
    monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
    monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)

    camRgb.video.link(xoutRgb.input)


    return pipeline


with contextlib.ExitStack() as stack:
    deviceInfos = dai.Device.getAllAvailableDevices()
    usbSpeed = dai.UsbSpeed.SUPER
    openVinoVersion = dai.OpenVINO.Version.VERSION_2021_4

    qRgbMap = []
    devices = []


    for deviceInfo in deviceInfos:
        deviceInfo: dai.DeviceInfo
        device: dai.Device = stack.enter_context(dai.Device(openVinoVersion, deviceInfo, usbSpeed))
        devices.append(device)
    
        mxId = device.getMxId()
        cameras = device.getConnectedCameras()
        usbSpeed = device.getUsbSpeed()
        eepromData = device.readCalibration2().getEepromData()
       

        pipeline, stereo= createPipeline()
        device.startPipeline(pipeline)

        # Output queue will be used to get the rgb frames from the output defined above
        timestr = time.strftime("%Y%m%d-%H%M%S")
        q_rgb = device.getOutputQueue(name="rgb", maxSize=4, blocking=False)
        stream_name = "rgb-" + mxId + "-" + eepromData.productName
        
        recording = (cv2.VideoWriter(f'filename_{mxId}_{timestr}.avi', cv2.VideoWriter_fourcc(*'MJPG'), 20, (1920, 1080)))
       
        qRgbMap.append((q_rgb, stream_name, recording))

      

    start_time = time.time()
 
    while(time.time() - start_time < 60):
        
        for q_rgb, stream_name , recording in qRgbMap:
          
            if q_rgb.has():
                video_in = q_rgb.get()
                recording.write(video_in.getCvFrame())

        if cv2.waitKey(1) == ord('q'):
            break
 

I don’t know if this will work, but sometimes a script run by init (systemd) will post text output to the dmesg log. I forget if it is stderr or stdout which does this. You very definitely don’t want a lot of spam, e.g., a loop of text, but you might try to add a print to stdout and a print to stderr with some debug message to test, e.g., one prints “this is stdout” and the other prints “this is stderr” (and also log boot with serial console to see if it shows up there too). If this works, then you could print a message about the basic steps for each camera becoming active, and their return value if it fails.

If that does not work, then you could literally clear a log file in “/var/log”, e.g., create “/var/log/mydebug.log”, and then append to it at various steps. The goal is to see what should be at critical steps in starting each camera. Knowing what fails (and why, e.g., return values) would help a lot in fixing this to always use both cameras.

I am still trying to understand and maybe not heading in the right direction as I am quite new to linux based programming. So I am not sure I understand how to log properly and understand that as well. The script i have shown works fine when running normally but has some other issues like the timing is off (even though I have set the time of the video to be 60 seconds for example, I get 10 seconds of video). However, when I run it on boot with and without the monitor thats when the issue occurs. So i am guessing its not to do with the script or the camera but how the script works on boot. Maybe I am wrong! Also, I tired to run the script with python directly without the /bin/bash -c but that doesnt work.

What I’m trying to do is to get your program to log the reason or return value for the missing camera. During a normal program run most output of text is to standard output, but sometimes errors go to standard error. If a script is running in init (which is what systemd is), then output can sometimes go to logs.

Consider these:

  • A normal print to this file: file=sys.stderr.
  • sys.stderr.write().

You already know how to write normally, but if you were to add one of those above to write some test message, then check logs after boot has run your script, then you might be able to see a message in logs that you’ve added. If that message happens to contain information about the error of one camera, then it might point out why this is happening. It’s one thing to know a camera isn’t showing up, but it is much more useful to know why the code sees this failing.

You could post a log line for things like each loop of “for deviceInfo in deviceInfos:” whereby you provide some way to identify which device is being added to devices, and also the current total count of devices. We don’t know what you will find, but presumably, at some point, you’ll see an error in logic or an error device (imagine for example that you see each loop adds the same camera instead of adding two unique cameras…then you’d know why only one camera shows up).

Really, the challenge is to get your script to speak up during the process of creating each pipeline. If it turns out that the second camera just is not visible yet, then perhaps the systemd script could be adapted to require both cameras (I don’t know for sure how, but try and get your script to log so we can see if that is the case).

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.