土地形状スキャン025 [FriendlyCore編]GNSSデータ受信プログラムに時刻更新機能を追加

造成

 

前回、ログファイルのタイムスタンプを正確な時刻にするため、GNSS受信機データから時間情報を抽出し、OS(Linux)の正確な時間に更新するpythonプログラムを作成し、動作確認まで到達。

GNSS受信プログラムとの統合と不具合と修正

OS時間更新プログラムとGNSS受信プログラムを統合し、自動起動のためのsystemd用設定ファイルに登録するが、自動起動がされない不具合が発生。

pythonプログラム自体を直接実行すると正常に動作する。

ログを調べてみる。

$ sudo systemctl status autognssctrl.service
● autognssctrl.service - Auto GNSS Control program
   Loaded: loaded (/etc/systemd/system/autognssctrl.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Fri 2021-04-02 02:52:06 UTC; 2 years 7 months ago
  Process: 463 ExecStart=/usr/bin/python3 /home/yuji/python_work/work_gnsslogger_006.py (code=exited, status=1/FAILURE)
 Main PID: 463 (code=exited, status=1/FAILURE)

Apr 02 02:52:01 NanoPi-NEO systemd[1]: Started Auto GNSS Control program.
Apr 02 02:52:06 NanoPi-NEO python3[463]: Traceback (most recent call last):
Apr 02 02:52:06 NanoPi-NEO python3[463]:   File "/home/yuji/python_work/work_gnsslogger_006.py", line 6, in 
Apr 02 02:52:06 NanoPi-NEO python3[463]:     import serial
Apr 02 02:52:06 NanoPi-NEO python3[463]: ImportError: No module named 'serial'
Apr 02 02:52:06 NanoPi-NEO systemd[1]: autognssctrl.service: Main process exited, code=exited, status=1/FAILURE
Apr 02 02:52:06 NanoPi-NEO systemd[1]: autognssctrl.service: Unit entered failed state.
Apr 02 02:52:06 NanoPi-NEO systemd[1]: autognssctrl.service: Failed with result 'exit-code'.

import serial でエラーが出ている

ネットを調べたり試行錯誤の末、systemdが動作する起動時のユーザーや権限の環境とプログラムが正常動作する現在の環境が違っていることがわかり、合わせるように修正。

修正前:

$ cat /etc/systemd/system/autognssctrl.service
[Unit]
Description=Auto GNSS Control program
[Service]
ExecStart=/usr/bin/python3 /home/yuji/python_work/work_gnsslogger_006.py
[Install]
WantedBy=multi-user.target

修正後:

$ cat /etc/systemd/system/autognssctrl.service
[Unit]
Description=Auto GNSS Control program
[Service]
ExecStart=/usr/bin/sudo /usr/bin/python3 /home/yuji/python_work/work_gnsslogger_006.py
User=yuji
[Install]
WantedBy=multi-user.target

この修正により、起動直後からGNSS受信プログラムが自動実行されることを確認。

タイムゾーンの設定

GNSS受信プログラムが自動実行されたので、ボタンを押してログ取得を行い、LANケーブルを挿して母艦から共有フォルダにあるログファイルを確認したところ、タイムスタンプがおかしい。

以前のようにOSイメージ作成時の数年前のタイムスタンプではないが半日近くずれている。

タイムゾーンが日本に設定されていないことが判明。

$ date
Sun Nov 12 11:04:43 UTC 2023
$ sudo timedatectl set-timezone Asia/Tokyo
$ date
Sun Nov 12 20:20:12 JST 2023

これでログファイルのタイムスタンプも正しく反映されることを確認

統合したプログラム

ここまで作成したpythonプログラムは以下の通り

#!/usr/bin/python3
#import sys
import subprocess
import re
from datetime import datetime, timedelta, timezone
import serial
import serial.serialutil as srlutil
import RPi.GPIO as GPIO
import time


#PA0
PIN_NUM_LED = 11
#PA3
PIN_NUM_SWITCH = 15

GPIO.setmode(GPIO.BOARD)
GPIO.setup(PIN_NUM_LED, GPIO.OUT)
GPIO.setup(PIN_NUM_SWITCH, GPIO.IN, pull_up_down=GPIO.PUD_UP)

pwm = GPIO.PWM (PIN_NUM_LED,0.2)
pwm.start(20)

timezone = 9
dtnow = datetime.now()
print(dtnow)

ser = serial.Serial("/dev/ttyACM0", 115200, timeout=2)
while True:
        rsvline = ser.readline()
        if rsvline[0] != ord("$"):
                ser.reset_input_buffer()
                continue

        try:
                line = rsvline.decode('ascii')
        except Exception as e:
                print(e)
                ser.reset_input_buffer()
                continue

        line = line.strip()
        items = line.split(",")
        if re.search("\$..RMC",items[0]):
                print(line)
                (dummy1,day,month,year,dummy2)= re.split("(..)(..)(..)",items[9])
                (dummy1,hour,minute,sec,msec10,dummy2) = re.split("(..)(..)(..)\.(.*)",items[1])
                print("20%s/%s/%s %s:%s:%s.%s"%(year,month,day,hour,minute,sec,msec10))
                dt = datetime(2000 + int(year),int(month),int(day),
                        int(hour),int(minute),int(sec),int(msec10)*10000) + timedelta(hours=timezone)
                if dt > dtnow:
                        ser.close()
                        gnsstime = dt.strftime("%Y-%m-%d %H:%M:%S")
                        subprocess.call(["/usr/bin/timedatectl", "set-time", gnsstime])
                        dtnow = datetime.now()
                        print(dtnow)
                        #sys.exit(0)
                        break

        ser.reset_input_buffer()

ser.close()

pwm.ChangeFrequency(1)

cmd="str2str -in serial://ttyACM0:115200#ubx -out /home/share/`date +%Y%m%d%H%M%S`.ubx"

state=0

try:

        while True:
                if GPIO.input(PIN_NUM_SWITCH)==0:
                        time.sleep(1)           #0.1s wait
                        if state==0:
                                subrun=subprocess.Popen("exec " + cmd, shell=True)
                                pwm.ChangeDutyCycle(20)
                                state=1
                        elif state==1:
                                subrun.kill()
                                pwm.ChangeDutyCycle(0)
                                state=0

except KeyboardInterrupt:
        pass

pwm.stop()
GPIO.cleanup()
タイトルとURLをコピーしました