1

I have successfully coded a Python 3 Script that detects objects in a frame given my the camera. Based on those objects detected, I run commands and logic. I have tested this and I can run it via the terminal thru:

python3 /home/pi/tensorflow1/models/research/object_detection/Object_detection_picamera.py

And I don't have any issues with this. We ran our test cases and we got the results we wanted.

However, we want to "package" the RaspberryPi, and make sure that our script runs once the boot up is successful. This way, we just need to plug it in a socket and it would work. That being the case, needing to plug a monitor, a keyboard, and a mouse to the board is not an option.

After doing some research, we decided that the best approach is via systemd. I proceeded to make my systemd file as such:

sudo nano /lib/systemd/system/sample.service

and then I placed the following:

[Unit]
Description=My Sample Service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/pi/tesnorflow1/models/research/object_detection/Object_detection_picamera.py
User=pi

[Install]
WantedBy=multi-user.target

After save and exiting, I ran the following:

sudo systemctl daemon-reload
sudo systemctl enable sample.service

sudo reboot

After booting again, I have my program a couple minutes to run. I then checked the status:

sudo systemctl status sample.service

and I was greeted by an error:

Traceback:
    File "/home/pi/tensorflow1/models/research/object_detection/Object_detection_picamera.py", line 34, in <module>
        from utils import label_map_util
    File "/home/pi/tensorflow1/models/research/object_detection/utils/label_map_util.py", line 21, in <module>
        from object_detection.protos import string_int_label_map_pb2
ImportError: No module named 'object_detection' 

Which was referring to the following line:

#Import utilities
from utils import label_map_util    # <----- this line
from utils import visualization_utils as vis_utils

The interesting thing now is that if I run the script via the terminal, I don't encounter the same error message.

Clearly, there must be some timing concerns involved.

How do I run my service once I'm sure that everything has been loaded? It seems that my service is trying to run and some files have not been loaded.

Any leads would be very much appreciated.

EDIT:

With the help of @Ingo's comment, I logged the sys.path variable. I ran the code via the service, and ran the code via the terminal. After that I got the output of the service and compared it to the output of the terminal.

Initially, the following paths were NOT in the list given by the service:

/home/pi
/home/pi/tensorflow1/models/research
/home/pi/tensorflow1/models/research/slim

So I added those in my [Service] block:

[Service]
ExecStart= /usr/bin/python3 /homoe/pi/tensorflow1/models/research/object_detection/Object_detection_picamera.py
Environment="PYTHONPATH=/usr/hin/python3"
Environment="PYTHONPATH=/home/pi"
Environment="PYTHONPATH=/home/pi/tensorflow1/models/research"
Environment="PYTHONPATH=/home/pi/tensorflow1/models/research/slim"
User=pi

I saved this and rebooted. I checked and compared the output of the sys.path from the service and from the terminal, but the following paths were still not added:

/home/pi
/home/pi/tensorflow1/models/research

And I'm not sure how else to add it.

  • Does utils is a custom module or can it be imported system wide? Does it imported just the two times you listed or is there an additional location importing utils? What directory you are in when running the script from the command line successfully? – Ingo Dec 23 '18 at 12:09
  • @Ingo I think I downloaded the utils as a system wide library. There are no more instances of utils being imported. Whenever I run the command, I am in the home folder of the Raspberry Pi. But I always use the absolute file paths. – Razgriz Dec 23 '18 at 13:37
2

The unit file looks good so far except the option Type=idle. I don't believe you really need this (man systemd.service):

This may be used to avoid interleaving of output of shell services with the status output on the console. Note that this type is useful only to improve console output, it is not useful as a general unit ordering tool, ...

You should just delete the line if not needed for special console output.

The problem I suspect is that the environment is not properly set when the script is executed. You can read in man systemd.exec:

Processes started by the system are executed in a clean environment in which select variables listed below are set. System processes started by systemd do not inherit variables from PID 1, ...

So you should compare the environment settings when running from the command line with the environment settings when running as service. You are using User=pi that will by default use as WorkingDirectory= the user's home directory. That fits. The python3 interpreter does not find the module utils. It searches some paths where to find modules. These are (1):

  • The directory from which the input script was run or the current directory if the interpreter is being run interactively
  • The list of directories contained in the PYTHONPATH environment variable, if it is set. (The format for PYTHONPATH is OS-dependent but should mimic the PATH environment variable.)
  • An installation-dependent list of directories configured at the time Python is installed

So you should set in section [Service] in the unit file for example to add three paths delimited with : on linux:

Environment="PYTHONPATH=/home/pi:/home/pi/tensorflow1/models/research:/home/pi/tensorflow1/models/research/slim"

To examine the search paths you can start the interpreter python3 and execute:

>>> import sys
>>> print(sys.path)

If you insert these two statements temporary into your script you will see the output in the journal. So you will find the settings when running as service and you can compare. Look into the journal with:

rpi ~$ journalctl -b -e


References:
[1] Python Modules and Packages – An Introduction

  • I had added in the print(sys.path) command in the script. I rebooted the pi, and checked the journal, copied the output of that line. I then started the script through the terminal and then copied the output. I removed the common items, and this was left in the service: /usr/bin/python3 (I added this through theEnvironment variable in the service), and this was what the terminal had: /home/pi, home/pi/tensorflow1/models/research, /home/pi/tensorflow1/models/research/slim – Razgriz Dec 24 '18 at 6:51
  • @Razgriz That's all as expected. You set PYTHONPATH four times. The second one will overwrite the first setting and so on. Only the last one will occur. I have updated the example in my answer to set PYTHONPATH with more than on path. – Ingo Dec 24 '18 at 12:08
  • Sorry to nitpick but is there really supposed to be a double quote after the = sign in PYTHONPATH? – Razgriz Dec 24 '18 at 12:31
  • @Razgriz Oh no! That's a typo. I have corrected it. – Ingo Dec 25 '18 at 12:36

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.