RaspberryPi を安定運用させる (original) (raw)

はじめに

しまねソフト研究開発センター(略称 ITOC)にいます、東です。

教育用ワンボードマイコンとして販売されている Raspberry Pi (以下ラズパイ)は、教育用のみならず実験用、産業用とさまざまな分野で使われつつあります。一方、マイクロSDカードをメインストレージに使用している事や、OSがクライアントPCよりの設定にしてある事などから、長期安定運用には向かない面も存在します。
このレポートでは、OSや稼働させるソフトウェアの設定など、できるだけ簡易に再現可能な方法により、可能な限りラズパイを安定して長期運用させることを狙います。また、その題材として、デジタルサイネージ(*)を作ってみます。

私は、2000年ごろからフラッシュメモリを使ったFA機器の開発を皮切りに、10年ほど前からは民生用フラッシュメモリ(CF,SD,USBメモリ)を起動デバイスとした機器を開発・運用していました。
私のスタンスとしては、産業用途にラズパイの利用を推奨するわけではありません。しかし、そういった用途にラズパイを使う事になった場合、このレポートに述べる程度の考慮は自分たちで行う必要がありそうだ、ということです。

(*) 題材としたサイネージの作成は、2018年にパシフィコ横浜で開催された「Embedded Technology 2018/IoT Technology 2018(ET2018)」にブース出展を行った際に、展示用にラズパイで作成したミニサイネージを、最新のハードウェア、ソフトウェアを使って再構築したものとなります。
https://monoist.itmedia.co.jp/mn/articles/1811/22/news050.html
(記事中、2つめの写真の右側に少しだけ写っているもの)


フラッシュメモリ(SDカード)について

SDカードに使われているNAND型フラッシュメモリには以下の特性があります。

書き込み回数に制限がある

フラッシュメモリは、絶縁膜により浮かせたフローティングゲートに電荷を貯めることでデータを記録する半導体素子です。
FlashMemory1.png
絶縁膜は極めて薄いことから、書き込みを繰り返すと絶縁膜が劣化し、十分な絶縁性を保つことが難しくなります。そのため、フラッシュメモリには書き込み回数に制限があり、TLCタイプのメモリデバイス単体では、おおよそ1000回程度と言われています。
また、書き込みや消去動作には高い電圧が必要になることから、近隣のセルにも影響が及ぶ場合があり、ビット化けの原因となります。(Program Disturb)
後述する理由により、書き込み動作自体を無くすことは不可能ですが、長寿命を狙うためには可能な限り書き込みを行わない事は必要な条件となります。

時間がたつと内容が消える事がある

フラッシュメモリの絶縁膜は、絶縁とは言えど抵抗値は無限大ではないので、フローティングゲートに蓄えられた電荷は徐々に漏れ出します。電荷の減少がセンスアンプの閾値を超えると、0から1方向へのビット化けが生じます。
以下の図は、代表的なデータ保持期間のグラフです。
データ保持期間.png
(桑野雅彦「メモリICの種類と使い方」 インターフェース別冊付録より引用)

また、多数のメモリセルを直列接続して構成している構造から、あるセルの読み込み動作が直列接続された他のセルへ影響を及ぼします。これは一般に電荷が溜まる方向に影響し、1から0方向へのビット化けが生じます。(Read Disturb)
その他にも、微細化、多値化の影響により、直接は接続されていないセルであっても近隣のセルの読み書きが発生すると、相互インダクタンスや浮遊キャパシタンスが影響して値が変化する場合があります。

こういった特性を補償するため、SDカードなど製品としてのフラッシュメモリには、エラー訂正の機能があります。訂正が効かないほどビットが化けてしまった場合でも、ほとんどの場合エラー検出はできます。この場合、SDカードのファームウェアによりセクタリードエラーとしてレポートされる思われます。

以下のキャプチャは、内部でビット化けが発生したと思われる USBフラッシュメモリを、dd コマンドを使って読み込んだ場合の動画です。実際に組込機器で起動デバイスとして使用していたもので、出荷から 10年を待たずして故障となりました。

このUSBメモリは、88624 * 64k バイト目からのセクタが、2回リードを試みて2回ともリードエラーになります。ところが、同セクタをゼロで上書きすることで、今度はリードが成功するようになります。

次に別のUSBメモリの例を示します。

このUSBメモリのファームウェアは、少し面白い動作をします。キャプチャを見てもらうと分かるとおり、エラーで停止後再度読み込みを行うと、同じセクタ位置ではリードエラーにならず、次は少し進んだ位置でエラー停止します。あくまでも外部から観測できる現象からの内部動作の類推ですが、このUSBメモリのファームウェアは以下の動作を行っているようです。

  1. リードエラーが発生するとホストマシンにエラーを報告する。
  2. 内部ではエラー訂正によって同セクタの書き戻しが行われる。
  3. リード2回目以降は同じセクタではエラーにならない。

書き込み途中での電源断

書き込み処理中に電源が切れると、フラッシュメモリへの書き込み内部シーケンスが中途半端となりデータの保証ができない状態になります。想定する最も悪いシナリオがこれです。書き込み途中のブロックがどういう状態になるのかはSDカードのファームウェアの作りにより変わります。
OSのファイルシステムレイヤーで考えた場合、Linuxはジャーナルファイルシステムを利用しているので、ある程度整合性を持ってリカバリが可能です。しかし運悪く電源断のあとセクタが読めない状態(ビットエラー訂正不可など)になってしまった場合、SDカードのファームウェアはOSへセクタリードエラーとしてレポートするでしょうから、そのセクタをファイルシステムが利用していた場合には、OSはディスク異常として認識するでしょう。

書き込みを完全に無くすことは不可能

SDカードのファームウェアに依存するのですが、SDカードの中ではフラッシュのビットエラー発生による書き戻しや、速度を維持するためのガーベージコレクションなど内部的なフラッシュメモリへの書き込みが行われます。
これらは、OSやアプリケーションの動作とは別に暗黙的に行われるため、ユーザーが知らない間にフラッシュメモリに書き込みが行われていることになります。


フラッシュメモリに対し、ユーザ側でできること

生のデバイス特性は上記の通りですが、ラズパイで使用する SDカードや USBメモリなどでは、ユーザーに見える部分はコントローラやそのファームウェアを通した状態でしかないため、ユーザ側でできることは限られます。ここでは、以下の2点について考察します。

  1. 書き込みを行わない
  2. 定期的に全ファイルの読み込みをする

書き込みを行わない

通常のOSでは、ログファイルやテンポラリファイルの書き込みが常時発生し、それに伴うファイルシステム管理領域も頻繁に書き換えが行われます。
OSの設定をカスタマイズし、書き込みを行わないようにすることで、こういった書き込み動作を抑制することができます。具体的にLinuxでは以下の方法があります。

  1. オーバーレイファイルシステムで、ルートディレクトリを覆う
  2. リードオンリーモードでマウントし、書き込みが必要な箇所にメモリファイルシステムをマウントする

現在の RaspberryPi OS では、raspi-config コマンドから、OverlayFileSystem の設定が選択できるので、1の方法が最も簡単と思われます。

定期的に全ファイルの読み込みをする

フラッシュメモリの内容は、時間とともに次第に劣化(信頼できない状態)していくので、エラー訂正が効く間に定期的に読み込み動作を行い、内部的にエラーが検出された場合にはファームウェアによる正しいデータの書き戻しを期待する戦略です。あくまでも「期待」ですし、前項の通り読み込み行為自体が別のセルのエラーを誘発するので頻度には気をつける必要がありますが、何もしないよりははるかに良いと考えられます。
読み込み確認の方法ですが、全領域を読む方法が簡単(ddコマンド)ですが、実際には使用している領域のみで十分で、空き領域の読み込みは害になり得ます。また、読み込み確認中は I/O 負荷が大きく跳ね上がり、他のプロセスの I/O操作を遅くしてしまうため、読み込み速度を適度に制限するほうが望ましいです。

産業用をうたったSDカード

以上の2点を工夫することで、経験上かなり安定して運用させることは可能だと思います。しかしながら、先に述べた理由により内部的な書き込みを完全に無くすことはできません。これら内部処理での書き込み中に電源断されうることは、さすがにどのファームウェアでも想定して設計されていると信じたいですが、内部動作の仕様や状況を外部から(OSやアプリケーションから)知ることは不可能ですので、ここはユーザー側で工夫のしようがありません。
産業用をうたったSDカードの中には、電源断対策がされていることを明示しているSDカードがあります。そのほかウェアレベリングや、先の戦略で述べたとおりの「定期的に全領域を読み込みしてエラーがあれば訂正したデータを書き戻す」事をファームウェアレベルで実装しているものもあります。
予算がゆるすのであれば、そういったSDカードを採用すればより安心できます。

SDカードの相性問題

SDカードの物理的・ソフトウェア的な仕様は、規格により定められ互換性が保たれています。しかしながら、まれに相性問題と言わざるを得ない現象に遭遇することがあります。

物理的相性

SDカードとラズパイ本体は、SDカードスロット内の機械的接点により接続されます。これは単純な接触によるものですので、接触不良が発生する場合があります。SDカードの接点は、その色から金フラッシュ処理のものと電解メッキのものがありそうだと想像できますが、どちらにせよ膜厚が非常に薄い(1μm以下)ため長期間の性能維持はあまり期待できません。
接点は、汚れ、または振動や熱サイクルによる摺動によって摩耗が生じ、摩耗粉が蓄積、酸化することで接触抵抗が増加します。

接点の摩耗例

次の例は、SDカードの接点ではなくHDMI端子の接点ですが、参考になると思うので掲載しておきます。

マイクロスコープ(光学)による観察

04-1.jpg

この写真は、車載に使用した機器(ラズパイではありません)が、数年間の使用により接触不良で故障したものです。写真の丸囲みで示した箇所は、対になる接点が接触していた部分が摩耗してへこみが生じ、奥側に摩耗粉が黒く蓄積している様子が観察できます。

SEM(走査電子顕微鏡)による観察と元素分析

SEM全体.jpg
コンタクト全体

SEM拡大.jpg
コンタクト拡大

SEMを使い、コンタクト部の観察と、各部位の元素分析を行いました。SEMの画像では、擦痕や摩耗粉がより鮮明に確認できます。

元素分析

金メッキ部(擦痕なし) 質量% 原子%
Ni 79.42 87.01
Cu 6.70 6.78
Zn 2.56 2.51
Au 11.31 3.70
擦痕部 質量% 原子%
Ni 78.75 82.59
Cu 11.39 11.04
Zn 5.22 4.92
Au 4.64 1.45
摩耗粉 質量% 原子%
Ni 47.84 50.57
Cu 49.02 47.88
Sn 2.68 1.41
Au 0.46 0.14

※ C,O 等の有機物由来と思われる元素を排除した結果です。

金メッキ部は、Au が 11.3質量% ほど検出されていますが、擦痕部は 4.6% へ低下しており、メッキが剥がれてしまっている事が確認できます。また、どちらも Ni が支配的になっており、Au膜厚が非常に薄いため、下層の Ni メッキが検出されているものと考えられます。
摩耗粉からは、Cu が 49.0% 検出されています。相手側コンタクトは、点接触をさせるために鋭い形状になっていて、より摩耗が進みやすいと思われます。基材の Cu まで摩耗が進んだ結果、この摩耗粉となったのかもしれません。

ソフトウェア的相性

ハードウェア的には問題ないようでも、ソフトウェア的に不具合が発生していると思われるケースもあります。
私が相談を受けた事例では、以下のような例がありました。

  1. 同一メーカーの同一シリーズのSDカードを何枚か購入しているが、連続稼働できるものと数日で停止してしまうものがある。
  2. OSカーネルの起動はするが、ルートファイルシステムのマウントに失敗、もしくは長い時間を要する。

1の事例は、詳しく調べてみるとSDカード側のファームウェアリビジョンが違っていたそうです。
2の事例は、私も1度経験しました。このときはOSのバージョンアップを行ったら再現しなくなってしまったので、それ以上原因を追えていません。カーネルのロードはラズパイのブートローダにより行われ、ルートファイルシステムのマウントはLinuxのデバイスドライバにより行われているため、ソフトウェア的相性がわかりやすい事例かと思います。

ラズパイのSDカードに関して、使用情報をまとめているサイトがありますので、紹介しておきます。

RPi SD cards
https://elinux.org/RPi_SD_cards


電源

ラズパイの電源は、Type-B micro USB コネクタもしくは、Type-C コネクタ経由で給電します。多くの場合、ACアダプタが使われますが、ラズパイ専用のACアダプタというのはラズベリーパイ財団からは販売されておらず、汎用のものから選んで使います。
USB コネクタでの給電は、USB PD 等の規格化されたプロトコルを除けば 5V 500mA が最大値ですが、ラズパイは単純にUSBコネクタを給電としてしか使用していません。利用するACアダプタの容量は、公式には 5Vの 2.5A 以上を推奨しています。

コネクタの定格

ラズパイの MicroUSB コネクタが何を使っているかは不明ですが、一応代表的な Type-B MicroUSBコネクタの電流定格を調べてみます。

メーカ 型番 定格電流 参照
レセプタクル アンフェノール 10118193-0001LF 1.8A https://www.amphenol-cs.com/micro-usb-101181930001lf.html
プラグ ヒロセ ZX64-B-5S-UNIT(31) 1.8A https://www.hirose.com/ja/product/p/CL0242-0009-3-31

ざっと調べたところ、なかには3Aを定格とするものもあるようですが、代表的には 1A〜1.8A 程度のようです。

電流値の確認

実際にはどの程度の電流が流れているか測定します。

ACアダプタとラズパイ本体の間にシャント抵抗を挟み、オシロスコープを使って電流波形を観測しました。併せてラズパイのテストポイント PP7-PP3間の電圧(レギュレータの入力電圧)も観測します。
ラズパイに負荷をかけるためには、UNIX BENCH の dhrystone ベンチマークを使い、4コア全てを使ってフルパワーで計算させて観測しました。

IMG_2844.jpeg
IMG_2843.jpeg

結果

scope_5.png

上が電圧波形、下が電流波形です。アイドル時約 800mA の電流値が、ベンチマーク実行時に 1900mA 程度まで上昇、伴って 300mV程度の電圧降下が認められます。ただしこの電圧降下は、シャント抵抗による電圧降下分(計算値約 190mV)も含んでいます。

ACアダプタの影響

ACアダプタを4種類用意し、それぞれで違いがあるかを確認します。

  1. KSY 0525USB-RASPI 5.2V 2.5A
  2. I.T.E Power SUPPLY F5V-2.3C-1U 5V 2.3A
  3. SANWA Supply ACA-IP38BK 5V 2.4A
  4. テラインターナショナル G208 5V 2.1A

IMG_2851.jpeg

結果

scope_24.png
アダプタ1

scope_21.png
アダプタ2

scope_25.png
アダプタ3

scope_36.png
アダプタ4

アダプタ 無負荷時 (V) 負荷時 (V) 電圧降下 (V)
1 5.19 4.93 0.26
2 5.01 4.78 0.23
3 4.96 4.67 0.29
4 4.81 4.57 0.24

電圧降下は、4種類とも 0.2-0.3V程度と、大幅な違いは見られませんでした。
アダプタ1は、もとより出力電圧が 5.2Vと、USB規格よりも 0.2V 高めに設定されていることもあり、負荷時でも 4.93V と最も高い値で安定しているように見えます。
アダプタ4は、テスト実行時ラズパイのコンソールに Under voltage detected! と表示されてしまいました。電圧波形を見ると、大きな電圧低下の直後にラズパイ側で速度制限がかかり、電圧低下が軽減する様子と、約3秒後に速度制限が外れて再び大きく電圧低下発生を繰り返す様子が確認できます。

電源ケーブルの影響

ACアダプタ側は通常 USB Type A コネクタ、ラズパイは USB micro B コネクタが使われているので、必然的にType A - micro B の汎用ケーブルで接続することになります。この電源ケーブルの影響を調査します。

  1. ケーブル1(白色) 1m
  2. ケーブル2(黒色) 1m

IMG_2848.jpeg

いずれも 何らかの機器に付属等で入手したものとなり、残念ながらケーブル単体の型番などは不明です。ケーブル2には、AWG28 が 2ペアで構成されていると印字があります。
以降 ACアダプタは、アダプタ1(KSY製 5.2V)を使います。

結果

scope_14.png
ケーブル1

scope_16.png
ケーブル2

ケーブル 電圧降下 (V) ベンチマークスコア
1 0.25 1757
2 0.53 798

ケーブル2は、大きく電圧降下が発生し、ラズパイのコンソールに Under voltage detected! と表示されました。速度制限のため、ベンチマークスコアも大きく下げてしまいました。

ケーブル2は、AWG28 が使われていることから代表的なケーブル抵抗値を計算することができ、ケーブルだけで約 0.426Ω あることが推定できます。実際にはこれに加えてコネクタの接触抵抗も含まれますので、大きな電圧降下が発生したものと推測されます。

電源コンデンサの追加

コンデンサの追加によって、ACアダプタの過渡応答改善、(ごく短時間の)電圧降下抑制ができるか試してみます。ラズパイの回路図上は、47μFのコンデンサが入っていますので、約10(*)倍 680μF の電源用電解コンデンサを追加します。

(*) あまり大きなコンデンサを使うと、電源アダプタの突入電流抑制が働いたりなど、良くない現象が発生することがあります。680μF は少々大きめだとは思いますが、流す電流量からいえばある程度妥当かなとも思います。

IMG_2846.jpeg
追加コンデンサ ニチコン UHE1C681MPD6

接続箇所は、ピンヘッダ 4pin - 6pin 間です。本来はもっとコネクタに近い箇所であるべきですが、容易に接続できることを重要視します。

結果

scope_13.png
Cなし(テストポイント PP7)

scope_10.png
680μF 追加(上段がテストポイント PP7、下段は追加したコンデンサの端子部)

観測波形は、ベンチマークプログラム起動直後に観測された小さな電圧降下部分を使いました。
コンデンサ追加後の結果は、波形を見る限りでは細かなサグが減っており、ある程度は効果があるように思われます。より高い安定度を求めるならば、コンデンサを追加する手段もありそうです。

GPIO 端子からの電源供給

ケーブルや接点の影響を少なくするために、GPIO端子部から給電することも一つのアイデアです。GPIO端子に使われている MIL コネクタは、通常一本のピンが2点接触するため、1点接触の USB コネクタよりも信頼性が期待できます。

コンタクト.png
ヒロセ電機 HIF3Aシリーズデータシートより引用(拡大図は筆者)

試験方法

一般のUSBケーブルの片方にピンソケットを接続する追加工を行います。GPIO端子の2,4番端子をVcc、6,14番端子をGNDに接続し、それぞれ2本ずつ接続します。

IMG_2853.jpeg IMG_2854.jpeg

結果

scope_31.png
MicroUSBコネクタ接続

scope_35.png
GPIOコネクタ接続

接続方法 アイドル時(V) 負荷時(V) 電圧降下(V)
MicroUSB 5.24 5.05 0.19
GPIO 5.28 5.16 0.12

GPIO入力の方がアイドル時、負荷時とも電圧値が高い結果となり、電圧降下も少ない結果となりました。
電圧入力位置とレギュレータがPCBレイアウト上離れた位置になってしまうのが気になったため、この間で電圧降下があるかをテスターで測っておきました。

入力電圧とレギュレータの電圧差(アイドル時)

測定ポイント 電位差 (mV)
GPIO pin 4 to PP7 (Vcc) 4.80
GPIO pin 6 to PP3 (GND) 0.11

考察

電源入力位置がレギュレータと離れていることは、一般的には不利に働くはずです。それでも電位差が 5mV 程度であったことやコンデンサ追加の試験結果が多少の改善を示したように、GPIO端子からの電源供給は一定の効果が見込めると思われます。
コネクタの傾きに関して言えば、USBコネクタは傾きによって容易に接触不良を起こす場合が散見されますが、MILコネクタは傾きに対しても強固です。


振動試験 高低温試験

少々古いデータですが、以前振動試験と高低温試験を行った事があるので、参考のために公開します。これは個別機器に対する試験であり、ラズパイ全般に対しての保証ではないことに注意が必要です。

試験環境

試験機.jpg

振動試験

試験条件

試験条件
振動周波数 5Hz~150Hz
最大変位振幅 0.35mm(片振幅) (59.55Hzの時5G到達)
最大加速度 5G (49m/s^2)
掃印時間 1 OCT/min (5Hz~150Hzで約5分)
振動方向 3方向 (X, Y, Z)
振動時間 各方向90分

振動条件.png
片振幅 0.35mm 最大 5G の振動条件

加振方向.png
加振方向

結果

X軸試験時に異常停止が発生しましたが、電源OFFし再度ONすることで復帰しました。Y軸及びZ軸の試験中は正常に動作しました。

振動試験時系列表

時刻
11:15 Z軸加振開始
12:45 Z軸加振終了
13:00 X軸加振開始
14:28 動作停止。電源OFF、ONにより復帰
14:30 X軸加振終了
14:45 Y軸加振開始
16:05 Y軸加振終了

温度試験

試験条件(温度プロファイル)

試験条件
試験温度 40℃, 60℃, -10℃, -20℃
試験方法 各10回、電源ON-OFFによって正常な起動と5分以上の動作を確認する。

温度プロファイル.png
温度プロファイル

結果

いずれの温度帯においても、正常に起動、動作を確認できました。

温度試験時系列

時刻
11:00 常温動作確認、加温開始
11:15 40℃到達 (DUT温度44.8℃) 起動試験実施
11:23 60℃加温開始
11:35 60℃到達 (DUT温度66.3℃) 起動試験実施
13:35 -10℃冷却開始
13:55 -10℃到達 (DUT温度 動作時-2.7℃ 非動作時-6.5℃) 起動試験実施
14:05 -20℃冷却開始
14:11 -20℃到達 (DUT温度 動作時-12.6℃ 非動作時-16.4℃) 起動試験実施
16:15 試験終了

ソフトウェア(OS)の設定

この項では、前述の通りフラッシュメモリへ書き込みを行わず、定期的な読み込み動作を組み込んだOSの設定を説明します。

ラズパイの標準的なOSである「Raspberry Pi OS (https://www.raspberrypi.com/software/ )」は、Linux カーネルを採用し、クライアント PC 寄りの設定がなされたOSです。そのため、定期的にインターネット上のリソースを使ってアップグレードを行ったり、電源を切る際にはシャットダウン操作を必要とするなど、組込機器としては望ましくない設定もあります。ここでは、OSの設定変更や不要なサービスの停止を行い、より組込機器に適した設定にします。

このレポートは OSのインストール手順を説明する事が目的ではないこと、Raspberr Pi OSのデフォルト設定もわりと頻繁に変わることから、各手順は簡易的に(慣れた人向けに)説明します。
Raspberry Pi OS のバージョンは、今日現在の最新版(Release date: May 3rd 2023 System: 32-bit)での方法です。

OSインストール

オフィスソフトやCADソフトなどは通常は不要であり、フラッシュメモリの寿命を考えても使用容量は少ないにこしたことはありません。よって Lite版を使用し、最小限の環境から始めます。

基本的な設定は、初回起動時インタラクティブに設定します。

追加の設定のため、raspi-config コマンドを実行し、以下の通り設定します。

5 Localization Options

時刻同期サーバを変更

nict が提供する NTPサーバを利用するように変更します。

/etc/systemd/timesyncd.conf

SWAPを使わない

フラッシュメモリへの書き込みを減らすため、SWAPファイルの使用を停止します。

systemctl stop dphys-swapfile.service
systemctl disable dphys-swapfile.service
rm /var/swap

avahi 使用しない

ネットワークから見える必要はありません。

apt remove --purge avahi-*

hciuartを使用しない

Bluetooth を使用しなければ、関連サービスを停止できます。

sudo systemctl disable hciuart

不要なタイマータスクを停止

systemd タイマーを確認すると、標準で7つのタスクが登録されていることがわかります。

systemctl list-timers
NEXT                        LEFT       LAST                        PASSED              UNIT                         ACTIVATES
Sat 2023-06-03 15:17:48 JST 9min left  n/a                         n/a                 systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Sat 2023-06-03 15:33:50 JST 25min left Wed 2023-05-03 09:25:55 JST 1 months 0 days ago fstrim.timer                 fstrim.service
Sat 2023-06-03 15:48:13 JST 39min left Wed 2023-05-03 09:25:55 JST 1 months 0 days ago apt-daily.timer              apt-daily.service
Sun 2023-06-04 00:00:00 JST 8h left    Sat 2023-06-03 14:06:36 JST 1h 1min ago         logrotate.timer              logrotate.service
Sun 2023-06-04 00:00:00 JST 8h left    Sat 2023-06-03 14:06:36 JST 1h 1min ago         man-db.timer                 man-db.service
Sun 2023-06-04 03:10:43 JST 12h left   Sat 2023-06-03 14:07:08 JST 1h 1min ago         e2scrub_all.timer            e2scrub_all.service
Sun 2023-06-04 06:45:06 JST 15h left   Sat 2023-06-03 15:04:29 JST 4min 5s ago         apt-daily-upgrade.timer      apt-daily-upgrade.service

7 timers listed.

自動アップグレード関連と、man-db を止めます。

systemctl stop apt-daily.timer
systemctl disable apt-daily.timer
systemctl stop apt-daily-upgrade.timer
systemctl disable apt-daily-upgrade.timer
systemctl stop man-db.timer
systemctl disable man-db.timer

e2scrub は、動作を追ってみましたが、おそらく有効に動いていないように思います。また、fstrim に関しては、trim 機能がある SDカードは、聞いたことがありません。おそらく SD コマンドもまだ用意されていないように思います。従って止めても良いと思いますが、大きな害もないので今回はそのままにしてあります。

トータルサイズの縮小

不要なツールを削除しトータルサイズを減らしておくと、SDカードのデュプリケート時間も短縮でき、セキュリティー的にも良いです。

不要なツール類の削除

gccやPythonなどの言語類、manpages、*-dev系などを必要に応じて消すと、全体容量を減らすことができます。どのツールが必要か不必要かは、動かすアプリケーションにより一概には決められないので、パッケージリストを見ながら都度決めます。

例 gccの削除

apt remove --purge gcc-10 make gdb locales
apt remove --purge gcc-7-base gcc-8-base gcc-9-base
apt autoremove

私の例では、初期 1.4Gだったものが、1Gを少し切る程度まで削減しました。

空きセクタのクリア

SDカードをPCへバックアップするとき、dumpやe2image で行う場合は関係ないですが、dd で全セクタコピーをする場合は、不要なセクタをクリアしておくと圧縮が良く効きます。
これは、マウントした状態ではできないので、別なLinuxマシンから行うのが簡単です。

zerofree -v -f255 /dev/sda1

-f255 が良いか、-f0 が良いかは、意見が分かれるところかと思います。

定期的な全ファイル読み込みの設定

Confirm SD service のインストール

https://github.com/HirohitoHigashi/RasPi_ConfirmSdService
より、定期的に全ファイルの読み込み確認をする仕組みをインストールします。

仕組み

systemd のタイマーで、定期的(起動15分後、その後1ヶ月ごと)に、SDカードの全使用セクタをリードします。その際、10kB読むごとに 50ms停止することで、I/O負荷が不必要に高くなるのを防いでいます。(shell scriptによる簡易な方法なので、数値はかなりアバウトです)

電源 OFF 対応

ラズパイを含む Linux マシンでは、稼働終了時にオペレータによるシャットダウン操作を必要とします。一方、組込機器は家電のようなオペレーションが求められることがあり、停電の発生も想定しなければなりません。
電源OFF時に特別の操作を必要とせず、中間スイッチやスイッチ付きテーブルタップで機器の ON/OFF を可能にしておけば、オペレーションコストの低減にもつながり停電対策にもなります。

File override service インストール

単純にオーバレイファイルシステムを有効化するだけだと個別のカスタマイズが面倒なので、以下のサービスを使います。
https://github.com/HirohitoHigashi/RasPi_FileOverrideService

仕組み

オーバレイファイルシステムの有効化は、raspi-config コマンドを使います。

オーバレイが有効になった状態で、起動の最初期に /boot パーティションにある /boot/my/overlays ディレクトリツリーの内容を、rsync を使いそっくりルートディレクトリへ上書きすることで、ある程度のカスタマイズがLinuxマシン無しで行えるようになります。
たとえば、WiFi の SSID 設定を設置場所により変更しなければならないケースを考えてみます。

  1. 標準的な方法で SDカードを作成、そのコピーを現場に持って行きます。
  2. 現場で SSID 情報を確認します。
  3. SDカードを Windowsマシンに挿入し、メモ帳などで /boot/my/overlays/etc/wpa_supplicant/wpa_supplicant.conf ファイルを作り(書き換え)ます。
  4. SDカードをラズパイに挿入し、起動します。

これなら、Windowsしか扱えない技術者でもアサインが可能です。

以上で、ベースとなるシステムができました。


デジタルサイネージとしての設定を付加

方針

今回作ったシステムのテスト題材として、デジタルサイネージを想定しました。可能な限りありもののツールで目的を達成するために、以下の設計方針で構成しています。

なお、OSインストールの項で設定したオーバレイファイルシステムは一旦無効化してから設定を行い、全て終わってから再度オーバレイを有効化します。

ツールの追加

画面表示のために、ウェブブラウザを使います。今回は chromium を選択しました。併せてXも導入します。

apt install xserver-xorg xinit x11-xserver-utils matchbox-window-manager
apt install chromium-browser fonts-ipafont

当初ウインドウマネージャは使わない想定をしており、実際にウインドウマネージャを使わなくても chromium の起動ができましたが、この環境では chromium の全画面表示ができませんでした。詳しく追いかけてはいませんが、chromium は画面サイズなどに関してウインドウマネージャの機能を利用しているものと思われたため、こういった場合の定番である MATCHBOX(https://www.yoctoproject.org/software-item/matchbox/) の、さらにウインドウマネージャモジュールのみを利用します。

pi ユーザで自動ログイン

経験上 ttyがないと面倒なことが起きやすいので、通常通りのログインからX起動、chromium 起動の流れを作りたいと思います。ただしその後の変更管理が面倒になるので、このタイミングで、別途管理ユーザを作っておくのも良いと思います。

まずは、piユーザーで自動ログインするように設定します。raspi-config にその項目が増えているので、そこで設定してみると以下のファイルが作成される事が確認できました。raspi-configを使わなくても、同ファイルを設置するだけでも良いです。

/etc/systemd/system/getty@tty1.service.d/autologin.conf

[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin pi --noclear %I $TERM

セキュリティー対策強化

pi ユーザーは、完全にサイネージ表示専用としますので、セキュリティーを若干でも向上させるために、sudo 権限を消しパスワードを無効化するのも良いと思います。

rm /etc/sudoers.d/010_pi-nopasswd
vipw -s

表示されるユーザリストから、pi ユーザのパスワードを * に書き換えます。

ブラウザ自動起動

.profileで Xを起動、.xinitrc で chromium を起動の流れを作ります。また、デジタルサイネージにはマウスカーソルは不要ですので、表示させないようにします。

/home/pi/.profile

while :; do
    xinit -- -nocursor >/dev/null 2>&1
done

/home/pi/.xinitrc

# dot xinitrc

if [ -e /boot/URL.txt ]; then
    . /boot/URL.txt
fi

BROWSER=chromium-browser
BROWSER_OPT="--disk-cache-size=100000000 --kiosk"
URL=${URL:-https://www.yahoo.co.jp}

check_ipv4_address() {
    ipv4_adrs=`ifconfig -a | grep "inet " | grep -v "inet 127.0.0.1"`
    test -n "$ipv4_adrs"
}

check_time_sync() {
    timedatectl show | grep -q 'NTPSynchronized=yes'
}

wait_for() {
    chkcmd=$1
    msg=${2:-"Waiting for something."}
    timeout=${3:-60}

    if $chkcmd; then
        return 0
    fi

    zenity --info --width=300 --text="$msg" &
    pid_dialog=$!

    i=0
    while ! $chkcmd; do
        i=$((i + 1))
        if [ <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>−</mo><mi>g</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">i -gt </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">t</span></span></span></span>timeout ]; then
            logger "TIMEOUT: $msg"
            break
        fi
        sleep 1
    done

    kill $pid_dialog
    test <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>−</mo><mi>l</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">i -le </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span></span></span></span>timeout
}

start_browser() {
    while :; do
        if [ -e ~/URL.txt ]; then
            . ~/URL.txt
        fi
        <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>R</mi><mi>O</mi><mi>W</mi><mi>S</mi><mi>E</mi><mi>R</mi></mrow><annotation encoding="application/x-tex">{BROWSER} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">BRO</span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mord mathnormal" style="margin-right:0.00773em;">SER</span></span></span></span></span>{BROWSER_OPT} ${URL}
    done
}

xset s off -dpms
wait_for check_ipv4_address "Waiting for IPv4 address assignment."
wait_for check_time_sync "Waiting for time synchronization."

start_browser &
exec matchbox-window-manager -use_cursor no

仕組み

X 起動スクリプトは、以下の処理を行っています。

  1. IP自動取得前にブラウザが起動してしまうのを防ぐために、IPv4アドレスが付与されるまで待ちます。
  2. 時刻が同期されるのを待ちます。
  3. ブラウザを起動します。
  4. ウインドウマネージャを起動します。

初期表示 URL は、/boot/URL.txt に以下のように指定します。

/boot/URL.txt

URL="https://www.example.jp"

TLS 接続では証明書の有効期間があり、その確認のためにはラズパイの時刻が合っていることが必要です。しかし、ラズパイは標準でRTCを搭載していないので、ネットワークから時刻を取得する必要があります。時刻が大幅にずれた状態でブラウザが起動してしまうと、https 接続が失敗し画面が表示されないでしょう。そのため、ブラウザ起動前に時刻が同期されるのを待つようにします。

このスクリプトでは、ブラウザ起動をバックグラウンドタスクで依頼してからウインドウマネージャを起動しています。前述の全画面表示の事象を考えると、これではレースコンディションがあるように思いますが、逆順にするとプロセスツリーの構造が通常と異なってしまったため、この問題には目をつむることにしました。


テスト

起動の様子

上記手順でデジタルサイネージとして設定したものと、Raspberry Pi OS Desktop版を使ってブラウザを自動起動するように設定しただけのものを使って、起動画面を比較します。

DUT1

IMG_2816.jpeg

起動後、一瞬ですが、IPアドレスの取得を待つ旨のダイアログが表示されているのが確認できます。

DUT2

DUT2では、目的のページが表示されるまでに X のウインドウマネージャが表示されたり、まだネット接続が不安定なタイミングでブラウザが起動してしまう様子がわかります。

電源 ON/OFF 繰り返しテスト

ネット上でラズパイ運用の問題点を探してみると、やはり突然の電源OFFによってSDカードの内容が壊れてしまい、起動しなくなるといった記事が多いようです。そこで、ITOCでも電源ON/OFFを繰り返すテストを行いました。

試験方法

試験結果

DUT1

DUT2

考察

DUT1の方は、想定通り何も異常は起こりませんでした。

何の工夫もしていないDUT2の方も、予想に反して起動しなくなるという事象は発生しませんでした。SDカードはいわゆる民生品と思われるものでしたが、なんらかの電源OFF対策などが行われているファームウェアを搭載していたのかもしれません。

長期的な安定性については現時点では評価不能ですが、カードとの接触不良が起こらなければ恐らく問題ないレベルだと考えています。

運用テスト

ITOC でのテスト

ITOC 事務所前の縦型ディスプレイに当システムを設置しました。コンテンツは、ITOCのホームページを表示しています。運用方法は、朝に電源ON、夕方電源OFFを、職員がコンセントの抜き差しによって行う方法です。2023/6/12より開始し、9/5現在、故障すること無く稼働しています。
DSC06253.JPG

フィールドでのテスト

有限会社あうるネット様にフィールドテストの場を提供頂き、デジタルサイネージを設置しました。
こちらは、設置写真など入手次第、追記します。


参考文献