スマートフォン・ジン | Smartphone-Zine

引っ越し先→ https://smartphone-zine.com/

【ドラレコ】バイク用ドラレコのラズパイのステータスLEDを光らせる。【ラズパイ】

昨日の接続では、ステータスLEDが意図したとおりに光りません。ステータスLEDが、いつもと反転しています。Raspberry pi Zero 2 WのステータスLEDは、電源ONで光り、アクセスがあると消灯することで点滅する仕様なのに、電源ONで消灯、アクセスが有ったときだけ光る、という形になってしまいます。おかしいですね。

どうも、昨日の接続では、GPIOがHIGHになったら光るようにしていたのですが、GPIOがLOWになったら光るというのが正解のようでした。

ケーブルは結局4本必要ですね。シャットダウンボタンは「ADRSZUP ゼロワン 電源保持基板」のためにGPIO 6に変更しています。GPIO3にボタンを接続し、電源ONボタンとして使います。

dtoverlay=gpio-shutdown,gpio_pin=6
dtparam=act_led_gpio=26

これで、ボタンで電源ON、ステータスLEDも意図したとおりに光るようになりました。

【ドラレコ】バイク用ドラレコのラズパイの電源ON,OFFボタンを用意する。【ラズパイ】

ラズパイは小さなパソコンです。パソコンですから、WindowsMacと同じく、シャットダウンを選択してから、電源ケーブルを抜かないとたまにmicroSDデータが壊れて起動しなくなることがあります。

バイクにRaspberry piを搭載する時に問題になるがシャットダウン方法です。

バッテリーから直接取ってもいいのですが、ラズパイの電源を切り忘れると、そのままずっとバイクのバッテリーを使い続けてしまいます。

とはいえ、ACC電源から電源を取ると、わざわざシャットダウンを選択してから電源ケーブルを抜かなければなりません。不便です。シャットダウン忘れてエンジンキーOFFにしたら、Raspberry piの電源がブチッと切れちゃいます。いきなりキーをOFFにすると、そのうちラズパイが起動しなくなるかもしません。

ということで、簡単にシャットダウンさせたいので、ボタン押下でシャットダウン開始、もう一回押したら起動、という電源ボタンを作りたいと思います。

使用したのはこのボタンです。

LED付押しボタンスイッチ(青): パーツ一般 秋月電子通商-電子部品・ネット通販

330Ωの抵抗を挟んでLEDの明るさを調整しています。

はんだ付けと配線が完成したら、ラズパイに接続して設定を変更します。

pi@raspberrypi:~ $ sudo vi /boot/config.txt

を開いて以下の設定を行います。

dtoverlay=gpio-shutdown,gpio_pin=3
dtparam=act_led_gpio=26
dtparam=act_led_trigger=timer

電源ボタンは点滅させてラズパイが生きているかどうか確認します。デフォルトだとアクセス時にランプが付くのですが、アクセスしていない時に電源ONなのかOFFなのかわからないので、常時点滅するように設定しました。

これで再起動すると反映されます。

ラズパイ起動中は常にLEDが点滅します。ボタンを押すと、シャットダウンされます。もう一度押すとラズパイの電源が入ります。

今日はここまでです。

明日の記事へ続きます。

【ドラレコ】バイクのGPSロガーとして設定【スマートバイク】

GPSロガー設定

こちらのページを参考にさせていただきました。

denor.jp

gpxloggerのオプション

pi@raspberrypi:~ $ gpxlogger --help
Usage: gpxlogger [OPTIONS] [server[:port:[device]]]

  -?                  Show this help, then exit
  --daemonize         Daemonize
  --debug LVL         Set debug level.
  --export EXPORTMETHOD  Default dbus
  --exports           List available exports, then exit
  --help              Show this help, then exit
  --interval TIMEOUT  Create new track after TIMEOUT seconds. Default 5
  --minmove MINMOVE   Minimum move in meters to log
  --output FILNAME    Send output to file FILENAME
  --reconnect         Retry when gpsd loses the fix.
  --version           Show version, then exit
  -D LVL              Set debug level.
  -d                  Daemonize
  -e EXPORTMETHOD     Default dbus 
  -f FILENAME         Send output to file FILENAME
  -h                  Show this help, then exit
  -i TIMEOUT          Create new track after TIMEOUT seconds. Default 5
  -l                  List available exports, then exit
  -m MINMOVE          Minimum move in meters to log
  -r                  Retry when gpsd loses the fix.
  -V                  Show version and exit

サービス化します

sudo nano /etc/systemd/system/gpxlogger.service

[Unit]
Description=gpxlogger service
After=gpsd.socket
# 保存先USBメディアが使用可能になるのを待つ
RequiresMountsFor=/media/usb0

[Service]
ExecStart=/bin/bash -c '/usr/bin/gpxlogger -f /media/usb0/gps_$$(date +%%Y%%m%%d%%H%%M%%S).gpx -m 20'
ExecStop=/bin/kill ${MAINPID}
Restart=always
Type=simple
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

ラズパイ起動時に実行されるように設定します。

pi@raspberrypi:~ $ sudo systemctl daemon-reload
pi@raspberrypi:~ $ sudo systemctl enable gpxlogger.service
Created symlink /etc/systemd/system/multi-user.target.wants/gpxlogger.service → /etc/systemd/system/gpxlogger.service.

今日はここまでです。

【ドラレコ】Raspberry Piで撮影したデータを自動でpCloudにアップロード【スマートバイク】

pCloudは買い切り型のプライベートクラウドです!

pCloud ー 最も安全なクラウドストレージ

ちょいちょいセールをしているので、お買い得な時に買ってしまうのがオススメです。私は前回のブラックフライデーセールで購入しました。

そのpCloudにはなんとLinux CLI用が用意されています。素晴らしいですね、これをRaspberry PIでも使えないか、試してみることにします。

元々Intel系のCPUでしか検証されていないらしいのですが、さてラズパイARM 用の pCloud CLIは動くでしょうか?

もしNetworkにつながった時点でドラレコ動画やGPSロガーの情報をクラウドにアップロードできれば最高です。ではインストールしてみましょう。

ソースコードとインストール方法の説明は以下にあります。

github.com

ではまずはビルドのための環境構築。

pi@raspberrypi:~ $ sudo apt-get install cmake zlib1g-dev libboost-system-dev libboost-program-options-dev libpthread-stubs0-dev libfuse-dev libudev-dev fuse build-essential git

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
libpthread-stubs0-dev is already the newest version (0.4-1).
libpthread-stubs0-dev set to manually installed.
libudev-dev is already the newest version (247.3-7+rpi1+deb11u1).
libudev-dev set to manually installed.
zlib1g-dev is already the newest version (1:1.2.11.dfsg-2+deb11u2).
cmake is already the newest version (3.18.4-2+rpt1+rpi1+deb11u1).
The following packages were automatically installed and are no longer required:
  libevent-core-2.1-7 libevent-pthreads-2.1-7 libopts25 raspinfo sntp
Use 'sudo apt autoremove' to remove them.
Suggested packages:
  libboost1.74-doc libboost-atomic1.74-dev libboost-chrono1.74-dev libboost-container1.74-dev libboost-context1.74-dev libboost-contract1.74-dev libboost-coroutine1.74-dev libboost-date-time1.74-dev libboost-exception1.74-dev libboost-fiber1.74-dev libboost-filesystem1.74-dev libboost-graph1.74-dev libboost-graph-parallel1.74-dev
  libboost-iostreams1.74-dev libboost-locale1.74-dev libboost-log1.74-dev libboost-math1.74-dev libboost-mpi1.74-dev libboost-mpi-python1.74-dev libboost-numpy1.74-dev libboost-python1.74-dev libboost-random1.74-dev libboost-regex1.74-dev libboost-serialization1.74-dev libboost-stacktrace1.74-dev libboost-test1.74-dev
  libboost-thread1.74-dev libboost-timer1.74-dev libboost-type-erasure1.74-dev libboost-wave1.74-dev libboost1.74-tools-dev libmpfrc++-dev libntl-dev libboost-nowide1.74-dev
The following NEW packages will be installed:
  libboost-program-options-dev libboost-program-options1.74-dev libboost-system-dev libboost-system1.74-dev libboost-system1.74.0 libboost1.74-dev libfuse-dev
0 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.
Need to get 11.4 MB of archives.
After this operation, 156 MB of additional disk space will be used.
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libboost1.74-dev armhf 1.74.0-9 [9,534 kB]
Get:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libboost-program-options1.74-dev armhf 1.74.0-9 [374 kB]                                                                                                                                                                                                     
Get:3 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf libboost-program-options-dev armhf 1.74.0.3+b1 [4,616 B]                                                                                                                                                                                                                       
Get:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libboost-system1.74.0 armhf 1.74.0-9 [242 kB]                                                                                                                                                                                                                
Get:5 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libboost-system1.74-dev armhf 1.74.0-9 [243 kB]                                                                                                                                                                                                              
Get:6 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf libboost-system-dev armhf 1.74.0.3+b1 [4,744 B]                                                                                                                                                                                                                                
Get:7 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libfuse-dev armhf 2.9.9-5 [1,018 kB]                                                                                                                                                                                                                         
Fetched 11.4 MB in 8s (1,367 kB/s)                                                                                                                                                                                                                                                                                                                
Selecting previously unselected package libboost1.74-dev:armhf.
(Reading database ... 123565 files and directories currently installed.)
Preparing to unpack .../0-libboost1.74-dev_1.74.0-9_armhf.deb ...
Unpacking libboost1.74-dev:armhf (1.74.0-9) ...
Selecting previously unselected package libboost-program-options1.74-dev:armhf.
Preparing to unpack .../1-libboost-program-options1.74-dev_1.74.0-9_armhf.deb ...
Unpacking libboost-program-options1.74-dev:armhf (1.74.0-9) ...
Selecting previously unselected package libboost-program-options-dev:armhf.
Preparing to unpack .../2-libboost-program-options-dev_1.74.0.3+b1_armhf.deb ...
Unpacking libboost-program-options-dev:armhf (1.74.0.3+b1) ...
Selecting previously unselected package libboost-system1.74.0:armhf.
Preparing to unpack .../3-libboost-system1.74.0_1.74.0-9_armhf.deb ...
Unpacking libboost-system1.74.0:armhf (1.74.0-9) ...
Selecting previously unselected package libboost-system1.74-dev:armhf.
Preparing to unpack .../4-libboost-system1.74-dev_1.74.0-9_armhf.deb ...
Unpacking libboost-system1.74-dev:armhf (1.74.0-9) ...
Selecting previously unselected package libboost-system-dev:armhf.
Preparing to unpack .../5-libboost-system-dev_1.74.0.3+b1_armhf.deb ...
Unpacking libboost-system-dev:armhf (1.74.0.3+b1) ...
Selecting previously unselected package libfuse-dev:armhf.
Preparing to unpack .../6-libfuse-dev_2.9.9-5_armhf.deb ...
Unpacking libfuse-dev:armhf (2.9.9-5) ...
Setting up libboost-system1.74.0:armhf (1.74.0-9) ...
Setting up libboost1.74-dev:armhf (1.74.0-9) ...
Setting up libfuse-dev:armhf (2.9.9-5) ...
Setting up libboost-program-options1.74-dev:armhf (1.74.0-9) ...
Setting up libboost-program-options-dev:armhf (1.74.0.3+b1) ...
Setting up libboost-system1.74-dev:armhf (1.74.0-9) ...
Setting up libboost-system-dev:armhf (1.74.0.3+b1) ...
Processing triggers for libc-bin (2.31-13+rpt2+rpi1+deb11u5) ...

作業用ディレクトリ作成して、

pi@raspberrypi:~ $ mkdir console-client

ソースコードをクローンしてきます。

pi@raspberrypi:~ $ git clone https://github.com/pcloudcom/console-client.git ./console-client/
Cloning into './console-client'...
remote: Enumerating objects: 8217, done.
remote: Counting objects: 100% (89/89), done.
remote: Compressing objects: 100% (68/68), done.
remote: Total 8217 (delta 28), reused 67 (delta 21), pack-reused 8128
Receiving objects: 100% (8217/8217), 22.39 MiB | 3.03 MiB/s, done.
Resolving deltas: 100% (5788/5788), done.
Updating files: 100% (1552/1552), done.

ソースのビルド

pi@raspberrypi:~/console-client/pCloudCC/lib/pclsync $ make fs
gcc -Wall -Wpointer-arith -O2 -g -fno-stack-protector -fomit-frame-pointer -mtune=core2 -I../sqlite -DP_ELECTRON -fPIC -DP_OS_LINUX -D_FILE_OFFSET_BITS=64 -DP_SSL_MBEDTLS -I../mbedtls/include   -c -o pcompat.o pcompat.c
cc1: error: unrecognized -mtune target: core2
cc1: note: valid arguments are: arm8 arm810 strongarm strongarm110 fa526 fa626 arm7tdmi arm7tdmi-s arm710t arm720t arm740t arm9 arm9tdmi arm920t arm920 arm922t arm940t ep9312 arm10tdmi arm1020t arm9e arm946e-s arm966e-s arm968e-s arm10e arm1020e arm1022e xscale iwmmxt iwmmxt2 fa606te fa626te fmp626 fa726te arm926ej-s arm1026ej-s arm1136j-s arm1136jf-s arm1176jz-s arm1176jzf-s mpcorenovfp mpcore arm1156t2-s arm1156t2f-s cortex-m1 cortex-m0 cortex-m0plus cortex-m1.small-multiply cortex-m0.small-multiply cortex-m0plus.small-multiply generic-armv7-a cortex-a5 cortex-a7 cortex-a8 cortex-a9 cortex-a12 cortex-a15 cortex-a17 cortex-r4 cortex-r4f cortex-r5 cortex-r7 cortex-r8 cortex-m7 cortex-m4 cortex-m3 marvell-pj4 cortex-a15.cortex-a7 cortex-a17.cortex-a7 cortex-a32 cortex-a35 cortex-a53 cortex-a57 cortex-a72 cortex-a73 exynos-m1 xgene1 cortex-a57.cortex-a53 cortex-a72.cortex-a53 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a55 cortex-a75 cortex-a76 cortex-a76ae cortex-a77 neoverse-n1 cortex-a75.cortex-a55 cortex-a76.cortex-a55 neoverse-v1 neoverse-n2 cortex-m23 cortex-m33 cortex-m35p cortex-m55 cortex-r52 native
make: *** [<builtin>: pcompat.o] Error 1

おっとここでエラーです。

cc1: error: unrecognized -mtune target: core2

というエラーが出ています。

Google検索したところ、イシューが挙がってました。

pCloud CLI for ARM · Issue #175 · pcloudcom/console-client · GitHub

-mtune=native に変更しましょう。nativeはコンパイラがビルドコンピュータの CPU を自動検出するモードです。

ちなみに、Raspberry Pi Zero 2 WのCPUは以下の通りでした。

pi@raspberrypi:~/console-client/pCloudCC/lib/pclsync $ uname -a
Linux raspberrypi 5.15.84-v7+ #1613 SMP Thu Jan 5 11:59:48 GMT 2023 armv7l GNU/Linux

Makefileを開き、

CFLAGS=-Wall -Wpointer-arith -O2 -g -fno-stack-protector -fomit-frame-pointer -mtune=core2 -I../sqlite -DP_ELECTRON -fPIC

となっていることころ

CFLAGS=-Wall -Wpointer-arith -O2 -g -fno-stack-protector -fomit-frame-pointer -mtune=native -I../sqlite -DP_ELECTRON -fPIC

に変更します。再度make fsしてみましょう。

pi@raspberrypi:~/console-client/pCloudCC/lib/pclsync $ make fs
<省略>
gcc -Wall -Wpointer-arith -O2 -g -fno-stack-protector -fomit-frame-pointer -mtune=native -I../sqlite -DP_ELECTRON -fPIC -DP_OS_LINUX -D_FILE_OFFSET_BITS=64 -DP_SSL_MBEDTLS -I../mbedtls/include   -c -o pcrc32c.o pcrc32c.c
gcc -Wall -Wpointer-arith -O2 -g -fno-stack-protector -fomit-frame-pointer -mtune=native -I../sqlite -DP_ELECTRON -fPIC -DP_OS_LINUX -D_FILE_OFFSET_BITS=64 -DP_SSL_MBEDTLS -I../mbedtls/include   -c -o pfsstatic.o pfsstatic.c
ar rcu psynclib.a pcompat.o psynclib.o plocks.o plibs.o pcallbacks.o pdiff.o pstatus.o papi.o ptimer.o pupload.o pdownload.o pfolder.o psyncer.o ptasks.o psettings.o pnetlibs.o pcache.o pscanner.o plist.o plocalscan.o plocalnotify.o pp2p.o pcrypto.o pssl.o pfileops.o ptree.o ppassword.o prunratelimit.o pmemlock.o pnotifications.o pexternalstatus.o publiclinks.o pbusinessaccount.o pcontacts.o poverlay.o poverlay_lin.o poverlay_mac.o poverlay_win.o pcompression.o pasyncnet.o ppathstatus.o pdevice_monitor.o ptools.o pssl-mbedtls.o pfs.o ppagecache.o pfsfolder.o pfstasks.o pfsupload.o pintervaltree.o pfsxattr.o pcloudcrypto.o pfscrypto.o pcrc32c.o pfsstatic.o plocks.o
ar: `u' modifier ignored since `D' is the default (see `U')
ranlib psynclib.a

他のモジュールもビルドしていきます。

pi@raspberrypi:~/console-client/pCloudCC/lib/pclsync $ cd ../mbedtls/
pi@raspberrypi:~/console-client/pCloudCC/lib/mbedtls $ cmake .
-- The C compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/console-client/pCloudCC/lib/mbedtls
pi@raspberrypi:~/console-client/pCloudCC/lib/mbedtls $ make clean
pi@raspberrypi:~/console-client/pCloudCC/lib/mbedtls $ make
Scanning dependencies of target mbedtls
[  1%] Building C object library/CMakeFiles/mbedtls.dir/aes.c.o
[  2%] Building C object library/CMakeFiles/mbedtls.dir/aesni.c.o
[  4%] Building C object library/CMakeFiles/mbedtls.dir/arc4.c.o
<省略>
[ 95%] Building C object library/CMakeFiles/mbedtls.dir/x509write_crt.c.o
[ 97%] Building C object library/CMakeFiles/mbedtls.dir/x509write_csr.c.o
[ 98%] Building C object library/CMakeFiles/mbedtls.dir/xtea.c.o
[100%] Linking C static library libmbedtls.a
[100%] Built target mbedtls

cmakeします。

pi@raspberrypi:~/console-client/pCloudCC/lib/mbedtls $ cd ../..
pi@raspberrypi:~/console-client/pCloudCC $ cmake .
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: /usr/lib/arm-linux-gnueabihf/cmake/Boost-1.74.0/BoostConfig.cmake (found version "1.74.0") found components: system program_options 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/console-client/pCloudCC
pi@raspberrypi:~/console-client/pCloudCC $ make
Scanning dependencies of target sqlite3
[ 10%] Building C object CMakeFiles/sqlite3.dir/lib/sqlite/sqlite3.c.o
<省略>
[100%] Linking CXX executable pcloudcc
[100%] Built target pcloudcc

うまくビルドできたようです。最後にインストールして完了です。

pi@raspberrypi:~/console-client/pCloudCC $ sudo make install
[ 20%] Built target sqlite3
[ 80%] Built target pcloudcc_lib
[100%] Built target pcloudcc
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/pcloudcc
-- Set runtime path of "/usr/local/bin/pcloudcc" to ""
-- Installing: /usr/local/lib/libpcloudcc_lib.so

認識させます。

pi@raspberrypi:~/console-client/pCloudCC $ sudo ldconfig

接続してみましょう。-sオプションを付けるとパスワードを保存します。以降はパスワード入力不要です。

pi@raspberrypi:~ $ pcloudcc -u username -p -s
pCloud console client v.2.0.1
Please, enter password
Down: Everything Downloaded| Up: Everything Uploaded, status is LOGIN_REQUIRED
logging in
Down: Everything Downloaded| Up: Everything Uploaded, status is CONNECTING
Down: Everything Downloaded| Up: Everything Uploaded, status is SCANNING
event1073741824
event1073741825
Down: Everything Downloaded| Up: Everything Uploaded, status is READY

おお、接続できました!!!

ラズパイでpCloudに接続出来るとは感動です!

マウント先を指定します。

mkdir -p /home/pi/mnt/pcloud

pcloudcc -u username -p -s -m /home/pi/mnt/pcloud

/home/pi/mnt/pcloudにマウントされます。このフォルダはネットワーク・ストレージです。ラズパイ上には存在せず、クラウドと連携しています。ここにファイルをコピーすると、CloudへUPされます。

クライアントを停止するには、-kでfinalizeコマンドを送ります。

pi@raspberrypi:/media/usb0 $ pcloudcc -u username -k
pCloud console client v.2.0.1
Supported commands are:
startcrypto <crypto pass>, stopcrypto, finalize, q, quit
> finalize

停止された時にまだUpされていないファイルがある場合、~/.pcloud/Cacheにファイルがある状態です。保留中の転送ファイルが残っている状態です。このフォルダの中身がcachedだけになると、すべてアップロードされた状態であることを意味しています。

pi@raspberrypi:~/.pcloud/Cache $ ls ~/.pcloud/Cache
52000000d  54000000d  56000000d  58000000d  5a000000d  5c000000d  5e000000d  60000000d  62000000d  64000000d  66000000d  68000000d  6a000000d  6c000000d
53000000d  55000000d  57000000d  59000000d  5b000000d  5d000000d  5f000000d  61000000d  63000000d  65000000d  67000000d  69000000d  6b000000d  cached

pCloudをマウントする|[無料公開]pCloudを使いディスクレスのNASを作成する

を参考に、起動時にマウントするようにサービス化しておきます。

/etc/systemd/system/pcloud.service を作成します。

sudo vim /etc/systemd/system/pcloud.service
[Unit]
Description=pCloud Command Line Client
After=network-online.target

[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/
ExecStart=/usr/local/bin/pcloudcc -u your_account_here
Restart=always

[Install]
WantedBy=multi-user.target

your_account_hereを、pCloudのアカウント(メールアドレス)に変更しておきます。

ユニットファイルを配置したらdaemon-reloadで反映し、pcloudサービスの起動・終了のテストを行い、pcloudサービスを自動起動するように設定しましょう。




pi@raspberrypi:~ $ sudo systemctl daemon-reload pi@raspberrypi:~ $ sudo systemctl start pcloud pi@raspberrypi:~ $ sudo systemctl status pcloud ● pcloud.service - pCloud Command Line Client Loaded: loaded (/etc/systemd/system/pcloud.service; disabled; vendor preset: enabled) Active: active (running) since Sat 2023-03-25 11:23:10 JST; 2s ago Main PID: 15516 (pcloudcc) Tasks: 13 (limit: 869) CPU: 1.185s CGroup: /system.slice/pcloud.service └─15516 pCloudDrive

Mar 25 11:23:10 raspberrypi systemd[1]: Started pCloud Command Line Client. Mar 25 11:23:10 raspberrypi pcloudcc[15516]: pCloud console client v.2.0.1

pi@raspberrypi:~ $ sudo systemctl stop pcloud pi@raspberrypi:~ $ sudo systemctl enable pcloud Created symlink /etc/systemd/system/multi-user.target.wants/pcloud.service → /etc/systemd/system/pcloud.service.

最後に、ラズパイを再起動してみて、自動マウントされることを確認しましょう。

### ドラレコ動画をpCloudにアップロードするプログラムを作成する。

プログラムの要件はざっと以下のような感じ。

* 動画ファイルのタイムスタンプを確認し、古いものからpCloudにアップロードしていく。
* USBが90%になったら古い動画から消していくため、古いファイル優先でクラウドにUp
* ファイルをpCloudのネットワーク・ストレージにコピーする。
* コピー処理は数十秒待たされることもあるので別スレッドで動かす。
* いくらかのファイルはpCloudのクライアントがキャッシュしてくれる。
* pCloudにアップロードしたファイルのタイムスタンプを覚えておき、次回はそのタイムスタンプよりも新しいファイルだけアップロードすることで、複数回アップロードしてしまわないように考慮する。
* タイムスタンプが新しいファイルは、まだ保存途中の動画ファイルかもしれないので、現在時間より2分以上(120秒以上)経過したファイルアップロード対象とする。

これを実現するためのcopy_cloud関数を作成。

最終的に、dashcamスクリプトは次のようになりました。

!/usr/bin/env python3

from usbVideoDevice import UsbVideoDevice # https://smartphone-zine.hatenablog.com/entry/2023/02/25/065957 import subprocess import psutil # フォルダ残量確認 import os # ファイル操作に使う import sys # プログラムを途中で終了させるのに使う from operator import itemgetter # イテラブルから任意の要素を抜き出す import signal # 非同期イベントにハンドラを設定する import threading import time # スリープ用 import shelve # 最後にクラウドへアップしたファイルの日時。これ以降のデータをpCloudへUpする import shutil # ファイルのコピー import datetime # 日時処理

config = shelve.open("dashcam") # 設定ファイル開く try: cloud_up_time = config["cloud_up_time"] except Exception as e: cloud_up_time = 0 print('Error: {0}'.format(e), file=sys.stderr)

print('\n------------[cloud_up_time]:' + str(datetime.datetime.fromtimestamp(cloud_up_time)))

pCloudの保存先フォルダ

pCloud = '/home/pi/mnt/pcloud/Dashcam/'

pCliudを使用するユーザ

pCloud_user = 1000

データを保存するフォルダ EX) folder = '/media/usb0/'

folder = '/media/usb0/'

保存形式

extension = ".avi"

デスク使用率がこの%を超えたら古いファイルを削除

dsk_usage_ratio = 90.0

前方カメラのUSBポート番号と画像サイズ

front_cam_port = 4 front_cam_size = '1920x1080'

後方カメラのUSBポート番号

rear_cam_port = 1 rear_cam_size = '1280x720'

video_front_p = None # 録画用のプロセスです video_rear_p = None # 録画用のプロセスです

カメラのVideoポート判定

usbVideoDevice = UsbVideoDevice() video_front = "/dev/video" + str(usbVideoDevice.getId(front_cam_port)) video_rear = "/dev/video" + str(usbVideoDevice.getId(rear_cam_port))

Ctrl+C or KILL で止められた時の処理

def sig_handler(signum, frame) -> None: print('\n\n\n------------sig_handler()\n\n\n') global video_front_p global video_rear_p

config.close()  # cloud_up_timeをディスクに永続化する。

if not video_front_p is None:
    # video_front_p.terminate()
    video_front_p.kill()

if not video_rear_p is None:
    # video_rear_p.terminate()
    video_rear_p.kill()

sys.exit(1)  # プログラムを途中で終了させる

録画処理

def record(): global video_front_p global video_rear_p video_front_p = subprocess.Popen( ['ffmpeg', '-loglevel', 'error', '-use_wallclock_as_timestamps', '1', '-rtbufsize', '300M', '-f', 'v4l2', '-input_format', 'h264', '-video_size', front_cam_size, '-framerate', '30', '-i', video_front, '-c:v', 'copy', '-f', 'segment', '-strftime', '1', '-segment_time', '60', '-segment_atclocktime', '1', '-reset_timestamps', '1', folder + '%Y-%m-%d%H-%M-%S_f' + extension]) video_rear_p = subprocess.Popen( ['ffmpeg', '-loglevel', 'error', '-use_wallclock_as_timestamps', '1', '-rtbufsize', '300M', '-itsoffset', '-4.80', '-f', 'alsa', '-ac', '2', '-ar', '8000', '-acodec', 'pcm_s32le', '-thread_queue_size', '256', '-i', 'dmic_sv', '-f', 'v4l2', '-input_format', 'h264', '-video_size', rear_cam_size, '-i', video_rear, '-c:v', 'copy', '-acodec', 'aac', '-ar', '8000', '-b:a', '128k', '-vol', '512', '-f', 'segment', '-strftime', '1', '-segment_time', '60', '-segment_atclocktime', '1', '-reset_timestamps', '1', folder + '%Y-%m-%d%H-%M-%S_r' + extension])

def diskfree(): file_list = [] # ディスク使用率を取得 dsk = psutil.disk_usage(folder) print('\n------------usage:' + str(dsk.percent)) if dsk.percent <= dsk_usage_ratio: return

# ファイルデータ取得
for file in os.listdir(folder):
    file_info = os.stat(folder + file)
    file_list.append([folder + file, file_info.st_mtime, int(file_info.st_size / 1024)])

# 古い順にソート
file_list.sort(key=itemgetter(1))

# ファイルの削除
for file in file_list:
    if os.path.isfile(file[0]):
        if dsk.percent > dsk_usage_ratio:
            print('\n------------[DELETE]' + file[0])
            os.remove(file[0])
            dsk = psutil.disk_usage(folder)
            print('\n------------usage:' + str(dsk.percent))
        else:
            break

pCloudへアップロードする。

最後にアップロードしたファイルのタイムスタンプをcloud_up_timeに覚えておき、それ以降に作成されたファイルのみUploadする。

無限ループ処理になっているので、別スレッドで呼び出す。

def copy_cloud(): global cloud_up_time

while True:
    # ファイルデータ取得
    file_list = []
    for file in os.listdir(folder):
        file_info = os.stat(folder + file)
        # UNIX時間(エポック秒)を入れてソートできるようにする。
        file_list.append([folder + file, file_info.st_mtime, int(file_info.st_size / 1024)])

    # 古い順にソート
    file_list.sort(key=itemgetter(1))

    # time.time()-120 # 2分前のUnixTimeを得る方法、(エポック秒)なので120秒を減算すればOK
    # 前回クラウドにUploadしたファイルの時間(cloud_up_time)以降、且つ、2分前以前のファイルをクラウドにUploadする。
    for file in file_list:
        if os.path.isfile(file[0]):
            if cloud_up_time <= file[1] <= time.time() - 120:
                # pCloudマウントディレクトリにコピー
                try:
                    shutil.copy(file[0], pCloud)
                    cloud_up_time = file[1]  # 前回クラウドUploadしたファイルの時間更新
                    print('\n------------[upload]:' + file[0] + " " + str(datetime.datetime.fromtimestamp(file[1])))
                except Exception as err:
                    print('Error: {0}'.format(err), file=sys.stderr)

            else:
                print('\n------------[skip]:' + file[0] + " " + str(datetime.datetime.fromtimestamp(file[1])))
    time.sleep(1)

def main(): # スクリプトが止められたらプロセスを停止する signal.signal(signal.SIGTERM, sig_handler) # KILLされたとき signal.signal(signal.SIGINT, sig_handler) # Ctrl+Cされたとき

# 録画開始
record()

# pCloudへアップロード。
thread = threading.Thread(target=copy_cloud)
thread.start()

while True:
    # ディスクが使用率を超えたら古いファイルを削除する
    thread = threading.Thread(target=diskfree)
    thread.start()

    # 暫く待つ
    time.sleep(60)

if name == 'main': main()

今日はここまでです。

【ドラレコ】Raspberry pi Zere2 W に繋いだ2個のカメラを安定させる【スマートバイク】

カメラ2個を安定させるにはセルフパワーのUSBハブにする

ラズパイでバイク用ドラレコを作ろうと試行錯誤しています。

これまでの調査で、前後2台のカメラでフルHD画像を保存することが出来るようになりました。

一日録画して安定性を見ているのですが、片方のカメラがエラーとなり撮影できない事が多いです。

Mar 23 11:07:42 raspberrypi dashcam[836]: [video4linux2,v4l2 @ 0x3be5310] ioctl(VIDIOC_DQBUF): No such device
Mar 23 11:07:42 raspberrypi dashcam[836]:     Last message repeated 1 times
Mar 23 11:07:42 raspberrypi dashcam[836]: /dev/video2: No such device

特に、USBケーブルを延長しているとよく発生するような気がします。

原因として考えられるのが、カメラの電力不足です。バスパワーのUSBハブ(青い方)を使っていたのですが、これをセルフパワーのUSBハブ(白い方)に変更してみます。これでカメラへの電力供給不足が解消され、カメラのエラーが発生しなくなれば、電力問題が原因だった事になりますね。

セルフパワーのUSBハブに変更してから、エラーはなくなりました!

USBケーブルを延長しているのは関係なく、単に電力不足だったようです。Raspberry PiでUSB機器を使う場合は電力供給が問題になりますね。

【ドラレコ】マイクを付ける【スマートバイク】

もしもの時には音も重要

小型のマイクを取り付けて、音も録音出来るようにしたいと思います。

SPH0645LM4H搭載 I2S MEMSマイクモジュール

このモジュールはモノラルですが、小さいためバイクに収めるのも楽そうです。ドラレコの音声としては事故発生時の記録として衝撃音などが録音されていれば十分と考えていますのでこういった安価で小さなマイクモジュールで十分かなと思います。

www.adafruit.com

ラズパイに配線しましょう。下記に配線とドライバインストール方法が詳しく記載されています。

learn.adafruit.com

ドライバのインストールのためカーネルのビルドが必要なようです。インストールスクリプトが用意されているのでそれに従ってインストールを実施します。

インストールが完了したら、後日アップデートしたときに標準カーネルへと戻ってしまわないように、

$ sudo apt-mark hold raspberrypi-kernel
$ sudo apt-mark hold firmware*

を実行して、勝手にカーネルがバージョンUPされないようにしておきます。

録画と録音を同時に行う

ffmpegで動画を撮影しつつ、録音する設定にしていきましょう。

このサイト、

I2S Mems microphone & FFMPEG RTP Settings [Solved] - Raspberry Pi Forums

が参考になりました。

最終的に、次のようなコマンドで録画と録音ができました。

ffmpeg \
-use_wallclock_as_timestamps 1 \
-rtbufsize 30M \
-itsoffset -2.01 \
-f alsa -ac 2 -ar 8000 -acodec pcm_s32le -thread_queue_size 256 -i dmic_sv \
-f v4l2 -input_format h264 -video_size 1920x1080 -framerate 30  -thread_queue_size 256  \
-i /dev/video0 -c:v copy \
-acodec aac -ar 8000 -b:a 128k -vol 512 \
-f segment -strftime 1 -segment_time 60 \
-reset_timestamps 1 \
/media/usb0/front_%Y-%m-%d_%H-%M-%S.avi

今までの録画設定にオーディオ関係のオプションを追加しています。

-ac 2 

チャンネルは2に設定します。 ボリュームを上げるため、また音声デバイス指定をdmic_svという文字列で行うために、

Raspberry Pi Wiring & Test | Adafruit I2S MEMS Microphone Breakout | Adafruit Learning System

を実施しています。これを実施するとモノラルでもチャンネル設定が2になります。

-vol <n>

ボリュームを設定します。nは256単位で設定します。元のボリュームが少し小さめだったので200%を指定しています。

-vol 256  = 100%
-vol 512  = 200%
-vol 768  = 300%
-vol 1024 = 400%
-vol 2048 = 800%
-f <alsa> 

音声入力をに設定します。

-ar <rate>

音声のサンプリングレートを指定します。音質を表します。

-acodec pcm_s32le

入力音声のコーディックを指定します。このマイクはS32LEですので、これを指定します。指定しないとエラーになってしまいます。

-b:a:音声のビットレート(bitrate:audio)

音声のビットレートを指定するコマンドです。音量を何段階で表すかを表します。一般的では-b:a 192k (192kbps)と指定します。

-i dmic_sv

音声デバイスを指定します。普通は、hw:0とか、hw:1という風に割り当てられている番号で指定するのですが、ディスプレイを繋いでいると、HDMIディスプレイは音声出力を持っているためhw:0が割り振られ、マイクモジュールがhw:1になります。ディスプレイを繋いでいないと、マイクモジュールにhw:0が割り振られます。このように、接続デバイス数によって番号が変化するので不便ですので、先の手順で.asoundrcファイル内で付けた名前である、dmic_svを使用して接続します。

なお、ユーザ設定の場合は~/.asoundrcファイルに、システム全体に反映させる場合は/etc/asound.confに設定します。

後方カメラに音声を追加することにしました。現在のスクリプトはこんな感じです。

#!/usr/bin/env python3

from usbVideoDevice import UsbVideoDevice  # https://smartphone-zine.hatenablog.com/entry/2023/02/25/065957
import subprocess
import psutil  # フォルダ残量確認
import os  # ファイル操作に使う
import sys  # プログラムを途中で終了させるのに使う
from operator import itemgetter  # イテラブルから任意の要素を抜き出す
import signal  # 非同期イベントにハンドラを設定する
import threading
import time  # スリープ用


# データを保存するフォルダ EX) folder = '/media/usb0/'
folder = '/media/usb0/'

# 保存形式
extension = ".avi"

# デスク使用率がこの%を超えたら古いファイルを削除
dsk_usage_ratio = 90.0

# 前方カメラのUSBポート番号と画像サイズ
front_cam_port = 1
front_cam_size = '1920x1080'

# 後方カメラのUSBポート番号
rear_cam_port = 4
rear_cam_size = '1280x720'

video_front_p = None  # 録画用のプロセスです
video_rear_p = None  # 録画用のプロセスです

# カメラのVideoポート判定
usbVideoDevice = UsbVideoDevice()
video_front = "/dev/video" + str(usbVideoDevice.getId(front_cam_port))
video_rear = "/dev/video" + str(usbVideoDevice.getId(rear_cam_port))


# Ctrl+C or KILL で止められた時の処理
def sig_handler(signum, frame) -> None:
    print('\n\n\n------------sig_handler()\n\n\n')
    global video_front_p
    global video_rear_p

    if not video_front_p is None:
        #video_front_p.terminate()
        video_front_p.kill()

    if not video_rear_p is None:
        #video_rear_p.terminate()
        video_rear_p.kill()

    sys.exit(1)  # プログラムを途中で終了させる


# 録画処理
def record():
    global video_front_p
    global video_rear_p
    video_front_p = subprocess.Popen(
        ['ffmpeg',
         '-use_wallclock_as_timestamps', '1',
         '-rtbufsize', '300M',
         '-f', 'v4l2', '-input_format', 'h264', '-video_size', front_cam_size, '-framerate', '30',
         '-i', video_front, '-c:v', 'copy',
         '-f', 'segment', '-strftime', '1', '-segment_time', '60',
         '-reset_timestamps', '1',
         folder + '%Y-%m-%d_%H-%M-%S_f' + extension])
    video_rear_p = subprocess.Popen(
        ['ffmpeg',
         '-use_wallclock_as_timestamps', '1',
         '-rtbufsize', '30M',
         '-itsoffset', '-1.90',
         '-f', 'alsa', '-ac', '2', '-ar', '8000', '-acodec', 'pcm_s32le', '-thread_queue_size', '256', '-i', 'dmic_sv',
         '-f', 'v4l2', '-input_format', 'h264', '-video_size', rear_cam_size, '-framerate', '30',
         '-i', video_rear, '-c:v', 'copy',
         '-acodec', 'aac', '-ar', '8000', '-b:a', '128k', '-vol', '512',
         '-f', 'segment', '-strftime', '1', '-segment_time', '60',
         '-reset_timestamps', '1',
         folder + '%Y-%m-%d_%H-%M-%S_r' + extension])

def diskfree():
    file_list = []
    # ディスク使用率を取得
    dsk = psutil.disk_usage(folder)
    print('\n------------usage:' + str(dsk.percent))
    if dsk.percent <= dsk_usage_ratio:
        return

    # ファイルデータ取得
    for file in os.listdir(folder):
        file_info = os.stat(folder + file)
        file_list.append([folder + file, file_info.st_mtime, int(file_info.st_size / 1024)])

    # 古い順にソート
    file_list.sort(key=itemgetter(1))

    # ファイルの削除
    for file in file_list:
        if dsk.percent > dsk_usage_ratio:
            print('\n------------[DELETE]' + file[0])
            os.remove(file[0])
            dsk = psutil.disk_usage(folder)
            print('\n------------usage:' + str(dsk.percent))
        else:
            break


def main():
    # スクリプトが止められたらプロセスを停止する
    signal.signal(signal.SIGTERM, sig_handler) # KILLされたとき
    signal.signal(signal.SIGINT, sig_handler) # Ctrl+Cされたとき

    # 録画開始、メインスレッド
    record()

    while True:
        # ディスクが使用率を超えたら古いファイルを削除する
        thread = threading.Thread(target=diskfree)
        thread.start()

        # 暫く待つ
        time.sleep(60)


if __name__ == '__main__':
    main()

今日はここまでです。

【ヤマハFZS25】GIVIじゃなくても十分!モトボワットBBアッパーラック付きを取り付けてみました!

バイクで困るのが荷物が載らないこと

バイクの積載量って本当に少ないですよね。

今までずっと車での移動だったのですがバイクでの移動に変わって何が不便かというとやはり荷物が運べない事が一番不便だなと思います。

私の場合はFZS25を普段の足としても使いたいので、バイクを購入する前からリアボックスは必須だと思ってました。

youtu.be

GIVIはちょっとお高い

ほしいなと思っていたのはやはり定番のGIVI。ちょっと大きめの47Lのタイプを狙っていました。

GIVI

公式サイトはこちら。

GIVI

定価で、52800円!ほしいけど高いんですよねー!(ちょうどこの記事を書いている今はアマゾンの特選タイムセールでちょっとお安くなってるみたいですね。)

安いリアボックスを発見!!

そこで安いものがないか見てたところ、「モトボワットリアボックス 47L」というのを見つけました!なんといっても安いです!定価で12,820円です!(ちょうど今はセール中で、8760円になってました!なんとGIVI V47NNの6分の1の値段で買えちゃいます!)

モトボワットBB バイク トップケース・リアボックス BB47ADV モトボワットリアボックス 47L

このモトボワットBBリアボックスが良さそう!!

Amazonレビューを見ても悪い評価は少ないので、まあ問題ないだろうということでこの製品に決定です!

アッパーラック付きのタイプも有りまして、結局こちらを購入しました。

このアッパーラックにはとても期待しています。小型なテントやシュラフならばネットを使って簡単に固定することができますね!47Lの大容量+このアッパーラックがあれば、宿泊ツーリングでも大活躍間違いなしです!

今はまだ寒いですが(取り付けたのは2月です)、もう少し暖かくなったらキャンプツーリングにも行きたいですね。

モトボワットBB バイク トップケース・リアボックス BB47ADV-XT モトボワットリアボックス 47L+アッパーラック

購入しました!

というわけでAmazonで購入し、無事届いたので早速取り付けてみたいとおもいます。

こうやってみるとやはり結構大きなサイズですね。

フルフェイスが2個まで問題無く収納できる大容量のリアボックスです。

開封の儀

早速開けてみましょう。

慎重にカッターで開封していきます。

中には、しっかりとした分厚い梱包材の下から、リアボック本体が現れました。

やっぱり47リットルはなかなか大きいですね。

鍵は左に回して解錠します。蓋を開けてみます。

うん、やっぱり内部も広々していて十分な広さです。

中には使用上の注意が入っていますが、これは説明書ではないです。注意事項が書いてあるだけです。

説明書はこれだけ。取り付け方とか一切ありません!いい感じに取り付けろってことでしょう。

あとは、黄色い反射ステッカーが付属します。でもいかにも反射材ですって色なのであまり気に入らないんですよね。

ベースプレートはこんな感じでいっぱい穴が空いてます。

内容物はこれですべてです。

これをバイクのリアキャリアに取り付けていくわけです。まずはどんな感じでつくのか、試してみましょう。

2箇所の爪を引っ掛けてから、カチッとはめ込むようです。

では、実際にキャリアに載せてみましょう。この沢山ある穴の中から、リアキャリアの形状にあわせて最適な穴を選択、

するんだと思います。たぶんこの波型の金具が、キャリアの下側に入って、 四角いプレートを、穴の中にはめ込んで、ナットとネジで固定していく、ようです。

ナットはちゃんとロックナットになっていますね、ナイロン製のインサートが入ったタイプです。

振動などによる緩みを大幅に軽減してくれるタイプですね。

モトボワットBB取り付けレビュー

さて試行錯誤しながら、位置を決めていきます。これば正解だという場所はないのでしょうが、しっかり固定できているなら問題ないと思います。

まずは仮止めです。とりあえず、2箇所は前後にずれないように考慮して位置決めしていきました。

それから残り2箇所は、左右にずれないように考慮して位置決めしていきます。

さて、ここから試行錯誤すること約20分。

パズルのようにああでもない、こうでもないと、取り付けては外し、外しては取り付けて、ガッチリ固定出来る場所を探っていきます。

最終的にはこの位置で落ち着きました。

下から見るとこうなっています。しっかり固定できているようです。

あとは、蓋を5本のネジで止めてしまえばOKです。ここはあまりキツく締めなくても大丈夫ですね。

最後に、リアボックを取り付けます。しっかりとはまっているか確認します。

開けると、こんな感じ、アッパーラックがシートにあたってちょうど良い感じに平行に蓋が開いています。荷物整理のときには蓋の部分に物をおけるので、積み込み作業が捗りそうですね。

完成!そして近所の公園まで初走行です!

というわけで、リアボックス装着しての初走行です!

ちなみに、付属していた、蛍光色のイエローの反射テープはこちら。

この蛍光色がちょっと好みではなかったので、蛍光色ではない普通の黄色の反射テープを購入、貼り付けています。車体のオレンジと違和感なくマッチしているので、この黄色のほうが好みです。

GIVIもデザイン的には流線型でスタイリッシュ、とてもかっこいいのでスポーツタイプに似合いそうです。でも荷物を載せるのにはちょっと不便ですね。「モトボワットBB」は無骨な四角いやつですが逆にストリートファイターのFZS25にはマッチしていて、ちょっとツアラーモデルっぽくなって気に入っています。四角いのでスペースを隅まで広々と使えて大ききなサイズの荷物も格納できるので、これから重宝しそうです。

以上、モトボワットリアボックス 47Lの取り付けレビューでした!