2015年08月12日

Raspberry piのファイルシステム破損による起動失敗とリカバリ方法

それまでは問題なく利用していたRaspberry piが、突然起動しなくなってしまいました。
どうやらファイルシステムが破損してしまいrootをマウントできていない模様。

具体的には、コンソールの最終行に「end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,6)」と出力されて停止している状態でした。

SDカードリーダが搭載されているWindowsノートPCでリカバリができましたので、手順をまとめておきます。
(NOOBSでRaspbianを入れた環境です)

また、以下の工程では、オペミス等でリカバリに失敗して完全にデータが失われてしまう可能性もあるため、事前にWin32DiskImager等でディスクイメージ毎バックアップを取っておくことをお勧めいたします。
(ファイルシステムが破損する前にバックアップを取得しておけばよいわけですが…)


SDカードを認識してfsckコマンドを実行できる環境の準備

結局はこの副題が全てなわけですが、該当するようなLinuxマシンが手元になかったため、WindowsのノートPC上に仮想環境を構築しました。

VirtualBoxとVMware Playerの両方で試してみましたが、個人的にはVMware Playerの方がSDカードの認識部分においてわかりやすかったです。

VMware Playerは個人用途ならば無償で利用できるため、適時ダウンロードして導入してください。

OSはFedoraをお勧めします。

当初は使い慣れていて既に環境構築済みのCentOSでやったのですが、カードの認識がうまくいかなかったりドライバが足りなかったりと、最終的に成功したとはいえ、色々と面倒でした。

で、Fedoraならば新し目の要素も対応しているかなと思い試してみた結果、追加で何も設定しない素の状態でSDカードを認識して、リカバリまで持っていけました。


デバイスを接続してfsckを実行

VMware Playerでは親機に接続されている機器を仮想マシンに認識させることが可能ですので、ノートPCに搭載されているSDカードリーダにカードを差し込みます。

この時、初めからカードを差し込んだ状態で、仮想マシンを後から起動しても問題ありませんが、複数のデバイスが選択可能な場合、どれがSDカードリーダなのか案外わかりにくかったりします。

仮想マシンを起動後にカードを差し込みますと、新規の取り外し可能デバイスとして、以下のようなウィンドウがポップアップされますのでわかりやすいかと思います。

sd.png


その後、実際に仮想マシンに認識させる際は、VMware Playerのメニューを「Player」→「取り外し可能デバイス」→「SDカードリーダ名」→「接続(ホストから切断)」の順番で選択します。

うまく認識してくれると、/dev配下にデバイスが追加されます。

筆者の環境の場合では、以下のようにデバイスが追加されました。
(CentOSでやった際は/dev/sdb〜として認識されましたので、必ずしも下記の限りではありません)

mmcblk0
mmcblk0p1
mmcblk0p2
mmcblk0p3
mmcblk0p5
mmcblk0p6

で、とりあえず一通りのデバイスにfsckを打ち込んでみましたが、mmcblk0p6にエラーがあったようで、結構な数のエラーが出力されました。

出力されるエラーに対しては、基本的にyで修復を了承していくだけで問題ありません。

修復が完了後は、Raspberry Piに戻して起動できるか確認しましょう。
(ファイルの救出が目的の場合は、Raspberry Piに戻さず、仮想環境から直接マウントしてファイルを取得することも可能です)

タグ:Raspberry Pi
posted by hahasoha at 00:00| Comment(0) | TrackBack(0) | Raspberry Pi

2015年08月08日

Raspberry Pi A+のモバイルバッテリ連続運転テスト

日本Raspberry Pi ユーザーグループ代表の太田さんが書かれているRaspberry Piの今という記事に、以下のような記載があります。

Ebenからは汎用としてのRaspberry Pi 2と組み込み機器などの利用で省電力性の高いRaspberry Pi A+が主力製品になるだろうとの話を受けています。

私も少々Raspberry Piを扱わせて頂く機会があって、色々な使い道を模索しているのですが…

確かに、Raspberry PiをRaspberry Piらしく使うのであれば、「Pi 2 Model B」より、「Pi 1 Model A+」の方が適しているケースも多いのではないかと思います。

A+が2Bより優れている点は、「価格」「消費電力」「大きさ」「重さ」でしょう。

価格は日本国内ではAmazonで購入すると以下のような価格です。




その他の項目についてはWikipediaの記事をご覧頂いた方が早いかとは思いますが、前述の4項目の中で、A+が2Bより最も優れているのは「消費電力」です。

2Bが900 mAなのに対し、A+は単体で僅か200 mAです。
(A+のCPUが700MHz1コアなのに対し、2Bは900MHz4コアですから当然の差とも言えますが)
(知識不足のため、「電力」「電流」等の用語の使用の誤謬があるかもしれません)

この消費電力の少なさを最大限に生かそうと考えると、モバイルでの用途が思いつきます。

モバイルでの利用について、既に先人の方々が記事を挙げられていますが、自身の調査結果も記事にまとめておきたいと思います。


調査対象モバイルバッテリ

Raspberry PiはマイクロUSBから給電をしますので、スマホ用のモバイルバッテリからも給電が可能です。

ということで、価格.comで最安値となっていた以下の商品を購入してみました。




記事執筆時点では、送料無料で680円で購入できました。
モバイルバッテリってこんなに安いものもあるんですね…

ちなみに、Amazonのリンク先の説明には「USB出力:DC5V1A」とあるのですが、これはウソです。

Panasonicの同商品の詳細仕様には「USB出力 DC5V 0.5A」と明記されています。
本体の裏面にも定格出力0.5A(MAX)と印字されています。

0.5Aとは500 mAのことですので、つまり、A+は動作しても2Bは起動すらできないことになります。

本製品に限らず、出力可能な電圧電流は極めて重要ですので、なるべく正確な情報を確認してから購入するようにご注意ください。

ちなみにこの商品は、Panasonicのサイトに掲載されている写真をご覧頂ければわかりますが、出力用のマイクロUSBが本体に一体化していて、かつ重さが約58gしかありません。

A+の重さは23gですので、合わせても余裕で100g未満ということになります。

容量は1430mAhで、出力時間の目安は満充電した状態で500 mA出力で約1.3時間とのことです。

また、バッテリ残量をランプの色で確認可能で、残り約60%以上までは緑、残り約30%以上までは橙、残り約30%以下で赤く点灯します。


連続運転テスト条件

このモバイルバッテリーで、A+がどれだけ動作できるか連続運転テストを行いたいと思います。

が、何の機器も接続していない状態のA+なぞ全く実用的ではありませんので、Wifiと気温センサを実装させます。

Raspberry Piは素のままではWifiは利用できませんので、アダプタを追加する必要があります。
で、Amazonで安そうなものを見繕うと以下のような商品が出てきますが、ここでも消費電力が重要な要素となります。




これらの商品は大体同じような価格・スペックに見えますが、それぞれの商品の製品仕様を確認すると、白い方のGW-USNano2の最大消費電力は最大約1.3Wで、黒い方のWLI-UC-GNMは最大約2.5Wと、2倍近くも差があります。

これらの値は、mAに換算するとGW-USNano2は260 mA、WLI-UC-GNMは500 mAとなりますので、前述のモバイルバッテリでは、WLI-UC-GNMを利用していると電圧不足で動作不良を起こす可能性が高いです。

なので、今回は消費電力の低いGW-USNano2を採用します。
(Raspberry Piでの利用実績も多いようで、色々なサイトで報告例を見かけます)

モバイルバッテリの出力が500 mAで、A+単体で200 mA、Wifiで260mA消費しますので…
一応の計算上は、センサに残り40 mA使えることになります。
(実際は余裕を持たせるべきでしょうが)

で、気温センサは以下の書籍を参考に、秋月電子でいくつか商品を購入して自作しました。




非常に丁寧に書かれた書籍ですので、Pythonやら組み込み系やらが全くの未経験の方にもお勧めできます。
気温センサ等の消費電流は125 μA等と、単位がマイクロですので、残り40 mAでもまだ余裕がありそうです。

これらを組み合わせて「気温センサから値を毎秒取得し、その都度HTTPのGETパラメータでサーバに情報を送信し続ける」という条件でテストを行いました。

※ランプが消灯するまで使い続けるとデータ破損が発生する可能性が高いため、実際には、バッテリの限界まで利用すべきではありません


テスト結果

結論から書いてしまえば、約5時間連続して動作しました。

センサから情報を取得し続けて毎秒HTTPGETするという、それなりに実用的かつ負荷がかかるであろう条件でしたが、思いの外、長時間動作しました。
(電圧・電流チェッカは後日購入しようかと思います)

また、10秒毎に写真を撮影し続けるという簡易スクリプトを別のRaspberry Piで動作させ、モバイルバッテリのランプ色の変化も合わせて調査しました。

経過時間ランプ色残電量
開始時点100%
開始から146分経過橙に変化60%
更に101分経過赤に変化30%
更に51分経過消灯0%

赤に変化するまでは大体10%を30分ペースで消費していましたが、ランプが赤になってから消灯するまでの時間は急激に短くなっています。

ただ、ランプが消灯して電力が供給されなくなる直前まではRaspberry Piは正常に動作をし続け、以下のように、取得した温度センサの値にも異常は見られませんでした。

temp.png

エアコンの温度設定を色々と調整して確認しましたが、大体想定通りの値が出ています。
※ちなみに、19時あたりに急激に温度が下がっているのは、温度センサにあずきバーを接近させたためです。

前述のように、今回利用したモバイルバッテリの容量は1430mAhしかありませんが、それでも数時間も動作するのであれば、電源を確保できないような環境でも、お手軽に様々な用途に利用できるのではないかと思います。


安価かつ軽量であることを利用して、GPSやジャイロセンサと組み合わせるのも面白いかと思いますので、また別途調査したいと思います。

タグ:Raspberry Pi
posted by hahasoha at 00:00| Comment(0) | TrackBack(0) | Raspberry Pi

2014年12月16日

PostgreSQLパズル?

これはPostgreSQL Advent Calendar 2014の12月16日分の記事です。

昨日はmoomindaniさんの記事でした。







数あるデータベースの中からPostgreSQL……というより、RDBMSを採用する理由の一つとして、複雑なクエリが実行できることが挙げられます。


スケールアウト等を考えると、重たい処理をDBで実行させるのはあまり褒められた話ではないとも思いますが、趣味でやっているWebサービスレベルであれば、そもそもマシンが1台しかないなら、なるべくDB内で処理を完結させた方が効率的なこともあります。


で、先日、とある処理をDB内で完結させようとした結果、思いのほかドツボに嵌まり、個人的には相当カオスなSQLが生まれてしまいましたので、ここで紹介したいと思います。

(と申しますか、もっと美しいSQLがある筈……)


現在、Microsoft Office Wordの自動索引登録機能を補助することに特化したサイトを趣味で作っているのですが、wordファイル中から索引候補を抽出する処理でtextsearch_jaのja_analyzeを利用させて頂いています。


例えば、PostgreSQLの公式ドキュメントの一部をja_analyzeにかけると以下のような結果が取得できます。


=>SELECT word,type,ruby FROM
ja_analyze('PostgreSQLの統計情報コレクタはサーバの活動状況に
関する情報を収集し、報告するサブシステムです。');

word | type | ruby
--------------+--------+--------------
PostgreSQL | 名詞 | PostgreSQL
の | 助詞 | ノ
統計 | 名詞 | トウケイ
情報 | 名詞 | ジョウホウ
コレクタ | 名詞 | コレクタ
は | 助詞 | ハ
サーバ | 名詞 | サーバ
の | 助詞 | ノ
活動 | 名詞 | カツドウ
状況 | 名詞 | ジョウキョウ
に | 助詞 | ニ
関する | 動詞 | カンスル
情報 | 名詞 | ジョウホウ
を | 助詞 | ヲ
収集 | 名詞 | シュウシュウ
し | 動詞 | シ
、 | 記号 | 、
報告 | 名詞 | ホウコク
する | 動詞 | スル
サブシステム | 名詞 | サブシステム
です | 助動詞 | デス
。 | 記号 | 。
(22 rows)

一見すると問題なさそうですが、索引候補とするには、名詞が細かく分割され過ぎています。

索引候補としては「統計情報コレクタ」で一つの語句として抽出したいわけです。


どういった条件で一つの語句とするかは色々な考え方があるのでしょうが、今回は「名詞が連続している部分を抽出する」ことを条件としたいと思います。


つまり、以下のような結果を取得するためには、どのようなSQLを書いたら良いか、ということです。


word | ruby
------------------+----------------------------
統計情報コレクタ | トウケイジョウホウコレクタ
活動状況 | カツドウジョウキョウ
(2 rows)

まず、「連続している名詞」を抽出しなければならないわけですが、これは先日の記事でも紹介したWindow関数で抽出できます。

後の処理のために、row_numberも取得しておきます。



=>SELECT row_number () OVER (),
lag (type) OVER (),
lead (type) OVER (),
word,type,ruby FROM
ja_analyze('PostgreSQLの統計情報コレクタはサーバの活動状況に
関する情報を収集し、報告するサブシステムです。');

row_number | lag | lead | word | type | ruby
------------+--------+--------+--------------+--------+--------------
1 | | 助詞 | PostgreSQL | 名詞 | PostgreSQL
2 | 名詞 | 名詞 | の | 助詞 | ノ
3 | 助詞 | 名詞 | 統計 | 名詞 | トウケイ
4 | 名詞 | 名詞 | 情報 | 名詞 | ジョウホウ
5 | 名詞 | 助詞 | コレクタ | 名詞 | コレクタ
6 | 名詞 | 名詞 | は | 助詞 | ハ
7 | 助詞 | 助詞 | サーバ | 名詞 | サーバ
8 | 名詞 | 名詞 | の | 助詞 | ノ
9 | 助詞 | 名詞 | 活動 | 名詞 | カツドウ
10 | 名詞 | 助詞 | 状況 | 名詞 | ジョウキョウ
11 | 名詞 | 動詞 | に | 助詞 | ニ
12 | 助詞 | 名詞 | 関する | 動詞 | カンスル
13 | 動詞 | 助詞 | 情報 | 名詞 | ジョウホウ
14 | 名詞 | 名詞 | を | 助詞 | ヲ
15 | 助詞 | 動詞 | 収集 | 名詞 | シュウシュウ
16 | 名詞 | 記号 | し | 動詞 | シ
17 | 動詞 | 名詞 | 、 | 記号 | 、
18 | 記号 | 動詞 | 報告 | 名詞 | ホウコク
19 | 名詞 | 名詞 | する | 動詞 | スル
20 | 動詞 | 助動詞 | サブシステム | 名詞 | サブシステム
21 | 名詞 | 記号 | です | 助動詞 | デス
22 | 助動詞 | | 。 | 記号 | 。
(22 rows)

lagに1行前の、leadに1行後のtypeが表示されます。

ウィンドウ演算が行われた結果に対してフィルタ処理を掛ける場合は副問い合わせを利用します。

また、この後の処理のために、row_numberに対してCASE文を打ちます。


=>SELECT CASE
WHEN lag = '名詞' THEN 1
ELSE row_number
END num,
row_number,word,ruby
FROM
(
SELECT row_number () OVER (),
lag (type) OVER (),
lead (type) OVER (),
word,type,basic,ruby FROM
ja_analyze('PostgreSQLの統計情報コレクタはサーバの活動状況に
関する情報を収集し、報告するサブシステムです。')
) foo1
WHERE (lead = '名詞' AND type = '名詞')
OR ( lag = '名詞' AND type = '名詞');

num | row_number | word | ruby
-----+------------+----------+--------------
3 | 3 | 統計 | トウケイ
1 | 4 | 情報 | ジョウホウ
1 | 5 | コレクタ | コレクタ
9 | 9 | 活動 | カツドウ
1 | 10 | 状況 | ジョウキョウ
(5 rows)

lagを利用し、1行前が名詞だったら1、そうでなければrow_numberを表示させます。

これにより、連続している名詞の切れ目でnum列に最大値が現れることになります


次は、この結果に対して更にWindow関数を用いて副問い合わせします。


=>SELECT max(num) OVER (ORDER BY row_number),word,ruby FROM
(
SELECT CASE
WHEN lag = '名詞' THEN 1
ELSE row_number
END num,
row_number,word,ruby
FROM
(
SELECT row_number () OVER (),
lag (type) OVER (),
lead (type) OVER (),
word,type,basic,ruby FROM
ja_analyze('PostgreSQLの統計情報コレクタはサーバの活動状況に
関する情報を収集し、報告するサブシステムです。')
) foo1
WHERE (lead = '名詞' AND type = '名詞')
OR ( lag = '名詞' AND type = '名詞')
) foo2;

max | word | ruby
-----+----------+--------------
3 | 統計 | トウケイ
3 | 情報 | ジョウホウ
3 | コレクタ | コレクタ
9 | 活動 | カツドウ
9 | 状況 | ジョウキョウ
(5 rows)

上から順に各行時点でのnumの最大値を表示するmax列を生成することで、連続している名詞がmax列の値でグループ化されます。(個人的にはここの処理で一番悩みました)


ここまで持ってくればあと一息です。


異なる行の値を連結するために、array_agg関数array_to_string関数を使います。

array_agg関数は引数を配列に変換する集約関数で、array_to_string関数は引数の配列を文字列に結合する関数です。


よって、上記の結果を更に副問い合わせし、max列で集約すれば完成です。



=>SELECT
array_to_string (array_agg (word), '') word,
array_to_string (array_agg (ruby), '') ruby FROM
(
SELECT max(num) OVER (ORDER BY row_number),word,ruby FROM
(
SELECT CASE
WHEN lag = '名詞' THEN 1
ELSE row_number
END num,
row_number,word,ruby
FROM
(
SELECT row_number () OVER (),
lag (type) OVER (),
lead (type) OVER (),
word,type,basic,ruby FROM
ja_analyze('PostgreSQLの統計情報コレクタはサーバの活動状況に
関する情報を収集し、報告するサブシステムです。')
) foo1
WHERE (lead = '名詞' AND type = '名詞')
OR ( lag = '名詞' AND type = '名詞')
) foo2
) foo3 GROUP BY max;

word | ruby
------------------+----------------------------
統計情報コレクタ | トウケイジョウホウコレクタ
活動状況 | カツドウジョウキョウ
(2 rows)


如何でしたでしょうか。


……SQLでやらなければforループとかで遥かにシンプルに実装できそうなことはわかってはおりますが、そこはPostgreSQL Advent Calendarの記事だからということで目をつむって頂ければと思います。


SQLに限った話ではないですが、結局、各種機能を「知っているか知らないか」だけで生産性が大幅に変わることになります。


SQLによる他の方法で同結果を得る方法を思いつく方は、是非ご教示ください。

タグ:PostgreSQL
posted by hahasoha at 18:00| Comment(2) | PostgreSQL