hotch-potch, Note to self

いろいろ作業記録

Nerves開発環境の準備・VM+Ubuntu環境でErlang & Elixirをパッケージインストール

■はじめに

7月に開催された「Nervesトレーニング in福岡」を受講してきました。
fukuokaex.connpass.com
事前に指示のあった環境構築での不備で色々詰まってしまい、ハンズオン前半の時間を浪費してしまったので、ハマリどころと回避策をまとめました。

ここでの説明概要

以下の手順を紹介しています。

  • Erlang & Elixirを、コンパイルでは無くパッケージからインストールする方法
  • VirtualBoxでNervesデバイスを認識できない場合に、RaspberryPiから書き込む方法
  • Nervesデバイスに書き込みが出来なくなったときに、ファームを丸ごと初期化する方法
続きを読む

dpkg: unrecoverable fatal error, aborting の処置

はじめに

現場で半年ほど使用していたRaspberryPiで、久しぶりにアップデートしてみたところ、
下記のようなエラーが出てしまいました。
単体のパッケージを入れようとしても、入れられない状態になってしまいました。

pi@raspibp:~ $ sudo apt upgrade -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  tzdata
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/273 kB of archives.
After this operation, 2048 B of additional disk space will be used.
apt-listchanges: Reading changelogs...
Preconfiguring packages ...
dpkg: warning: files list file for package 'openssh-sftp-server' missing; assuming package has no files currently installed
dpkg: unrecoverable fatal error, aborting:
 files list file for package 'iputils-ping' is missing final newline
E: Sub-process /usr/bin/dpkg returned an error code (2)

結論

iputils-pingは、aptのパッケージ情報が壊れていて、
openssh-sftp-serverは、インストール済のはずのファイルが一致してないようです

横着して、swapの無効化や、/varへのログ出力の抑制をしていなかったので、
SDカードが壊れ始めているのかもしれません。

iputils-pingのパッケージ情報ファイルを一旦避けて、
それぞれのパッケージを改めてインストールしました。

復旧までの流れ

まずは「iputils-ping」の処置

pi@raspibp:~ $ cd /var/lib/dpkg/info
pi@raspibp:/var/lib/dpkg/info $ sudo mv iputils-ping.* /var/lib/dpkg/info/old

多分壊れているファイルを逃がしてから、iputils-pingを強制再インストール。

pi@raspibp:/var/lib/dpkg/info $ sudo apt-get install iputils-ping --reinstall
Reading package lists... Done
Building dependency tree
Reading state information... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 1 not upgraded.
Need to get 0 B/54.1 kB of archives.
After this operation, 0 B of additional disk space will be used.
dpkg: warning: files list file for package 'iputils-ping' missing; assuming package has no files currently installed
dpkg: warning: files list file for package 'openssh-sftp-server' missing; assuming package has no files currently installed
dpkg: unrecoverable fatal error, aborting:
 files list file for package 'iptables' is missing final newline
E: Sub-process /usr/bin/dpkg returned an error code (2)

こんどは、「iptables」もダメだ・・・

続いて「iptables」の処置

pi@raspibp:/var/lib/dpkg/info $ sudo mv iptables.* /var/lib/dpkg/info/old

多分壊れているファイルを逃がしてから、iputils-pingと、iptablesを強制再インストール。

pi@raspibp:/var/lib/dpkg/info $ sudo apt-get install iputils-ping --reinstall
Reading package lists... Done
Building dependency tree
Reading state information... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 1 not upgraded.
Need to get 0 B/54.1 kB of archives.
After this operation, 0 B of additional disk space will be used.
dpkg: warning: files list file for package 'iputils-ping' missing; assuming package has no files currently installed
dpkg: warning: files list file for package 'openssh-sftp-server' missing; assuming package has no files currently installed
dpkg: warning: files list file for package 'iptables' missing; assuming package has no files currently installed
(Reading database ... 38376 files and directories currently installed.)
Preparing to unpack .../iputils-ping_3%3a20161105-1_armhf.deb ...
Unpacking iputils-ping (3:20161105-1) over (3:20161105-1) ...
Setting up iputils-ping (3:20161105-1) ...
Processing triggers for man-db (2.7.6.1-2) ...

pi@raspibp:/var/lib/dpkg/info $ sudo apt-get install iptables --reinstall
Reading package lists... Done
Building dependency tree
Reading state information... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 1 not upgraded.
Need to get 259 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://ftp.jaist.ac.jp/raspbian stretch/main armhf iptables armhf 1.6.0+snapshot20161117-6 [259 kB]
Fetched 259 kB in 0s (878 kB/s)
dpkg: warning: files list file for package 'openssh-sftp-server' missing; assuming package has no files currently installed
dpkg: warning: files list file for package 'iptables' missing; assuming package has no files currently installed
(Reading database ... 38388 files and directories currently installed.)
Preparing to unpack .../iptables_1.6.0+snapshot20161117-6_armhf.deb ...
Unpacking iptables (1.6.0+snapshot20161117-6) over (1.6.0+snapshot20161117-6) ...
Setting up iptables (1.6.0+snapshot20161117-6) ...
Processing triggers for man-db (2.7.6.1-2) ...
pi@raspibp:/var/lib/dpkg/info $

最後に「openssh-sftp-server」の処置

pi@raspibp:/var/lib/dpkg/info $ sudo apt-get install openssh-sftp-server --reinstall
Reading package lists... Done
Building dependency tree
Reading state information... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 1 not upgraded.
Need to get 0 B/32.9 kB of archives.
After this operation, 0 B of additional disk space will be used.
dpkg: warning: files list file for package 'openssh-sftp-server' missing; assuming package has no files currently installed
(Reading database ... 38529 files and directories currently installed.)
Preparing to unpack .../openssh-sftp-server_1%3a7.4p1-10+deb9u6_armhf.deb ...
Unpacking openssh-sftp-server (1:7.4p1-10+deb9u6) over (1:7.4p1-10+deb9u6) ...
Setting up openssh-sftp-server (1:7.4p1-10+deb9u6) ...
Processing triggers for man-db (2.7.6.1-2) ...
pi@raspibp:/var/lib/dpkg/info $

まとめ

ひとまずこれで、apt install他が正常に動くようになりました。

参考

こちらをもとに作業しました。
qiita.com

RaspberryPiにOpenCV 4を入れてみる

はじめに

RaspberryPi3+にOpenCV 4.xを入れる手順について、
下記参考ページのうち、
所々詰まったところがあるので、補足しています。

参考ページ

qiita.com

環境

~ $ uname -a
Linux raspi3 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.9 (stretch)
Release:        9.9
Codename:       stretch

下準備

参考ページに従い、下記の項目を予め実行する。

  1. OS環境の最新化
  2. インストール
    1. CMake環境
    2. イメージファイル用ライブラリ
    3. ビデオストリーム用ライブラリ
    4. 画像表示用ライブラリ
    5. 演算用ライブラリ
    6. Python3開発用ヘッダ
  3. NumPy

コンパイル

作業フォルダを準備

~ $ mkdir gitwork
~ $ cd gitwork
~/gitwork $

Githubからクローン

本体とcontribの二つを準備します。
ここでは、Ver.4.1.0をcheckoutしています。

~/gitwork $ git clone https://github.com/opencv/opencv.git
~/gitwork $ git clone https://github.com/opencv/opencv_contrib.git
~/gitwork $ cd opencv_contrib
~/gitwork/opencv_contrib $ git checkout [TAB KEY]
3.0.0           3.2.0           3.3.1           3.4.2           3.4.6           4.0.0-rc        master
3.0.0-beta      3.2.0-rc        3.4             3.4.3           4.0.0           4.0.1           origin/3.4
3.0.0-rc1       3.3.0           3.4.0           3.4.4           4.0.0-alpha     4.1.0           origin/HEAD
3.1.0           3.3.0-rc        3.4.1           3.4.5           4.0.0-beta      HEAD            origin/master
~/gitwork/opencv_contrib $ git checkout 4.1.0
~/gitwork/opencv_contrib $ cd ..
~/gitwork $ cd opencv
~/gitwork/opencv $ checkout
~/gitwork/opencv $ git checkout [TAB KEY]
・・・(略)
2.4.10                 2.4.2                  2.4.8                  3.3.1                  4.0.0-rc
2.4.10.1               2.4.3                  2.4.8.1                3.3.1-cvsdk            4.0.1
2.4.10.2               2.4.3.1                2.4.8.2                3.4                    4.0.1-openvino
2.4.10.3               2.4.3.2                2.4.8.3                3.4.0                  4.1.0
2.4.10.4               2.4.3-rc               2.4.9                  3.4.0-rc               4.1.0-openvino
2.4.11                 2.4.4                  2.4.9.1                3.4.1                  HEAD
2.4.12                 2.4.4-beta             3.0.0                  3.4.1-cvsdk            master
・・・(略)
~/gitwork/opencv $ git checkout 4.1.0
~/gitwork/opencv $ mkdir build
~/gitwork/opencv $ cd build

コンパイル

cmakeのオプションは、参考ページを参照。
ここだけ書き換えしてください。

-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules

コンパイルの実行

~/gitwork/opencv/build $ cmake <OPTIONS>
~/gitwork/opencv/build $ make -j4

インストール

いつも通り、パッケージ管理ツールporgを使用。*1
パッケージ名は「OpenCV410」とします。
porg -aで、インストールできているか確認します。

~/gitwork/opencv/build $ sudo porg -lp OpenCV410 make install
~/gitwork/opencv/build $ porg -a
...
opencv410
...
~/gitwork/opencv/build $ sudo ldconfig

動作確認

~ $ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.1.0'
>>> exit()
~ $

外部信号でシャットダウン

はじめに

RaspberryPiの端子に信号が入力されると、シャットダウンする機能です。
いろいろなサンプルが公開されていますが、ここでは、systemdからスクリプトを起動して、定期的に監視する方法を説明します。

環境

  • Raspbian(2018-11-13-raspbian-stretch-lite)

スクリプト

GPIOの監視

「定数」の所は、環境に合わせて修正してください。

定数 意味
SET_WATCH_PORT GPIOピンにシャットダウン信号を入れる番号を指定
SET_TRIGGER 信号の立ち上がり・立ち下がりどちらで反応するかを設定
SET_WATCH_INTERVAL 指定した秒数ごとに、シャットダウン信号の状態を監視

ソース中の所々の[INSTALL DIR]は、お使いの環境に合わせて書き換えてください。

#!/bin/bash
#--------------------------------------------------------------------
#UPSの信号監視とシャットダウン
#--------------------------------------------------------------------
#
#install:
# $ sudo ln -s /home/pi/[INSTALL DIR]/setPowerWatcher.service /etc/systemd/system
# $ sudo systemctl enable setPowerWatcher.service
# $ sudo systemctl start setPowerWatcher.service
#--------------------------------------------------------------------
#ref:
#
# ※必ずbashを使うこと。shは関数の宣言でエラーが出ます
#   https://yatta47.hateblo.jp/entry/2014/04/20/222707
#

#----------------------------------
#定数
#----------------------------------

#監視するポート
SET_WATCH_PORT=2

#監視モード
# 1:ダウンパルス、0:アップパルス
SET_TRIGGER=1

#監視ループの間隔(sec)
SET_WATCH_INTERVAL=1


#----------------------------------
#関数
#----------------------------------

#シャットダウンの開始処理
function ShutdownGoProc ( ) {
    #シャットダウン信号を検出したメッセージを表示
    echo "  ! Shutdown signal detected. ${MESSAGE}"

    #シャットダウン処理を開始
    if [ ! "$MODE_TEST" = 1 ]; then
        #瞬停防止のため1秒だけshutdownを待つ
        /sbin/shutdown -P now
    fi
}

#シャットダウンの停止処理
function ShutdownStopProc ( ) {
    #シャットダウン信号を検出したメッセージを表示
    echo "  + Shutdown signal disappeared. ${MESSAGE}"

    #シャットダウン処理を中止
    if [ ! "$MODE_TEST" = 1 ]; then
        /sbin/shutdown -c
    fi

    #すぐにループ処理に戻らないよう、ウェイト
    sleep 1
}


#----------------------------------
#メイン処理
#----------------------------------

#実行中ユーザをチェック
if [ `/usr/bin/id -u` != "0" ]; then
    #rootでなければ異常終了
    echo " ! Please run as root."
    exit 1
fi

#主要コマンドの存在をチェック
if [ ! -x /usr/bin/gpio ]; then
    #見つからなければ異常終了
    echo " ! No 'gpio' Command."
    exit 1
fi

#自身のコマンド名を変数に入れる。usage用
CMDNAME=`basename $0`

#引数のチェックと動作フラグの生成
#https://shellscript.sunone.me/parameter.html
while getopts vt OPT
do
    case $OPT in
        "v" )
            #verboseモード
            MODE_VERBOSE=1 ;;
        "t" )
            #テストモード(シャットダウンはしない)
            MODE_TEST=1 ;;
        * )
            #それ以外の指定は、usageを表示
            echo "Usage: $CMDNAME [-v] [-t]" 1>&2
            exit 1 ;;
    esac
done

#動作モードのメッセージ
if [ ${SET_TRIGGER} -eq 1 ]; then
MESSAGE="(MODE: Down trigger)"
else
MESSAGE="(MODE: Up trigger)"
fi

#起動メッセージ
if [ "$MODE_VERBOSE" = 1 ]; then

  #メッセージ
  echo " * Monitor the GPIO signal and shutdown * ${MESSAGE}"

  #テストモードのメッセージ表示
  if [ "$MODE_TEST" = 1 ]; then
    echo '  - test mode (no shutdown)'
  fi
fi

#ポートの初期化
`/usr/bin/gpio -g mode ${SET_WATCH_PORT} in`

#監視ポートの状態変数の初期化と問い合わせ
STAT_PORT_PREV=`/usr/bin/gpio -g read ${SET_WATCH_PORT}`

#監視ループ
while :
do
    #監視ポートの状態を問い合わせ
    STAT_PORT_NOW=`/usr/bin/gpio -g read ${SET_WATCH_PORT}`

    if [ ${SET_TRIGGER} -eq 1 -a ${STAT_PORT_PREV} = "1"  -a  ${STAT_PORT_NOW} = "0" ]; then
        #ダウントリガで検知
        ShutdownGoProc
    elif [ ${SET_TRIGGER} -eq 0 -a ${STAT_PORT_PREV} = "0"  -a  ${STAT_PORT_NOW} = "1" ]; then
        #アップトリガで検知
        ShutdownGoProc 

    elif [ ${SET_TRIGGER} -eq 1 -a ${STAT_PORT_PREV} = "0"  -a  ${STAT_PORT_NOW} = "1" ]; then
        #アップトリガで検知
        ShutdownStopProc
    elif [ ${SET_TRIGGER} -eq 0 -a ${STAT_PORT_PREV} = "1"  -a  ${STAT_PORT_NOW} = "0" ]; then
        #ダウントリガで検知
        ShutdownStopProc 
    fi

    #監視ポートの状態変数に、現在の状態を代入
    STAT_PORT_PREV=${STAT_PORT_NOW}

    #ウェイト
    sleep ${SET_WATCH_INTERVAL}
done

exit 0

systemdに登録するserviceファイル

[Unit]
Description=Monitor the GPIO signal and shutdown
After=local-fs.target
ConditionPathExists=/home/pi/[INSTALL DIR]

[Service]
ExecStart=/home/pi/[INSTALL DIR]/setPowerWatcher.sh
ExecStop=/bin/kill ${MAINPID}
Restart=on-failure
StartLimitInterval=60
StartLimitBurst=3
KillMode=mixed
Type=simple
User=root
Group=root

[Install]
WantedBy=multi-user.target

インストール手順

systemdへ登録

systemdに登録して、サービスを起動します。

$ sudo ln -s /home/pi/[INSTALL DIR]/setPowerWatcher.service /etc/systemd/system
$ sudo systemctl enable /home/pi/[INSTALL DIR]/setPowerWatcher.service

serviceファイルを修正した時

下記のように都度、リロードします。

$ sudo systemctl daemon-reload

状態を確認

systemctl statusコマンドで、状態を確認します。
まだ起動していません

$ systemctl status setPowerWatcher.service
● setPowerWatcher.service - Monitor the GPIO signal and shutdown
   Loaded: loaded (/home/pi/[INSTALL DIR]/setPowerWatcher.service; linked; vendor preset: enabled)
   Active: inactive (dead)

起動

$ sudo systemctl start setPowerWatcher.service

状態を確認

下記のようになっていて、左上の●が緑色になっていれば、正常に起動しています。

$ systemctl status setPowerWatcher.service
● setPowerWatcher.service - Monitor the GPIO signal and shutdown
   Loaded: loaded (/home/pi/[INSTALL DIR]/setPowerWatcher.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2019-03-09 15:47:22 JST; 9s ago
 Main PID: 537 (setPowerWatcher)
   CGroup: /system.slice/setPowerWatcher.service
           tq537 /bin/bash /home/pi/[INSTALL DIR]/setPowerWatcher.sh
           mq564 sleep 1

Mar 09 15:47:22 raspizwh systemd[1]: Started Monitor the GPIO signal and shutdown.

動作確認

GPIOに信号を入れると、間もなくシャットダウンします
その際syslogには、下記のメッセージが残ります。

Mar  9 15:58:13 raspizwh setPowerWatcher.sh[537]:   ! Shutdown signal detected. (MODE: Down trigger)