Tag Archives: Raspberry Pi

VNC自動起動 Raspberry Pi2 Raspbian8 systemd

諸事情からRaspberry PiでVNCを使いたくなったのですが、VNCの自動起動に躓いたのでメモしておきます。

Raspberry Pi2に入れたRaspbian8なのですがDebian8がベースなのでinit.d方式でなくてsystemd方式で起動プロセスが走ります。

古いRaspberry Piの記事だとRaspbian7のinit.d形式で自動起動のスクリプトが書かれていたりします。。。
しかし本来、systemdでも/etc/init.d内の起動スクリプトも実行されるはずなのですが、うまく実行されませんでした。

取りあえず、”郷に入れば郷に従え”の教えに従い、systemd方式で設定ファイルを作成したら正常に起動しました。

$ sudo su –

# apt-get install tightvncserver

# vncserver :1
※ 初回起動時はパスワードを聞かれると思いますので設定してください

# vi /etc/systemd/system/vncserver@.service

[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=forking
User=pi
PAMName=login
PIDFile=/home/pi/.vnc/%H:%i.pid
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 :%i
ExecStop=/usr/bin/vncserver -kill :%i

[Install]
WantedBy=multi-user.target

# systemctl daemon-reload
# systemctl enable vncserver@1.service

これで自動起動するはずです。。。

参考サイト
Raspberry Pi • View topic – VNC server in Jessie (using a systemd service)

Raspberry Piを使ってスマホ・音声で家電を制御するシステムを作ってみた

最近、スマホ制御や音声制御できる家電が話題になっているで低価格かつ比較的簡単に構築できるか試してみました。

iRemoconなど便利な製品も出ているのに何故自作かといいますと。。。
失礼ながらこの製品がお高いのと、将来的な機能拡張を考えると圧倒的に自作に分があると考えたからです。

簡単な解説動画を制作してみました

達成目標

  • スマホ等からリモートで操作できること
  • 音声だけで何も触れずに操作できること
  • なるべく低価格で構築すること
  • なるべく単純なスクリプトで実装すること
  • 自宅サーバを構築しているような感覚で構築できること

ハードウエア

  1. Raspberry Pi Type B
  2. USB接続 赤外線リモコンキット
  3. GW-USValue-EZ(無線LAN子機)
  4. TEMPer V23.5(温度計)
  5. MM-MCUSB21BK(マイク)
  6. MS-UP201BK(スピーカー)
  7. U2H-EG4SWH(セルフパワーのUSBハブ)
  8. その他、USB延長コードなど

※ USB接続 赤外線リモコンキットを使用するのは、事前の実験にてLIRCではエアコンなどの長い命令を送る家電の制御が出来ないことがあると判明したためです。

簡単な仕組みについての図
学習リモコン
※ 図ではマイクがハブへの接続になってますが、ノイズが酷い場合はRaspberry Piへ直挿しの方がいいです。

Raspberry Piの初期設定

Raspberry PiのOSインストールに関しては以前まとめたものがありますのでこちらを御覧ください。

有線LANでも構築できますが、どうしても無線LANを使用したい場合、設定はネットに多くの情報が出ておりますので各自で調べるようお願いします。

USB接続された機器の制御で必要となるパッケージのインストール
$ sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev libusb-dev

USB接続 赤外線リモコンキット制御用コマンドのインストール
$ git clone https://github.com/kjmkznr/bto_ir_cmd.git
$ cd bto_ir_cmd/
$ make
$ sudo mv bto_ir_cmd /usr/local/bin/

信号を受信する場合は次のように実行します。
$ sudo bto_ir_cmd -e -r

信号を送信する場合は次のように実行します。
$ sudo bto_ir_cmd -e -t 0000000000000000000000000000000000000000000000000000000000000000000000
※ 00000….の部分は受信した時に表示されたものを使用します。

TEMPer V23.5制御用コマンドのインストール
$ git clone https://github.com/bitplane/temper.git
$ cd temper/
$ vi temper.c

                /* 44行目付近の行で日付がグリニッジ標準時となってるので修正 */
                //utc = gmtime(&t);
                utc = localtime(&t);

                /* 47行目付近の行で日付のフォーマットが欧米仕様となってるので修正 */
                //strftime(dt, 80, "%d-%b-%Y %H:%M", utc);
                strftime(dt, 80, "%Y-%m-%d %H:%M:%S", utc);

$ make
$ sudo make install

温度を取得する場合は次のように実行します。
$ sudo temper

WEBリモコン機能の実装

ネットワーク図
性質上、直接外部に公開すると明らかに色々と問題があるシステムなので公開しないで運用出来るようにしました。
ネットワーク図
※ 図ではルータのVPN機能を使用していますが、Raspberry PiにVPNを構築して接続するのも良いかもしれません。

Mojoliciousの導入
Mojoliciousをインストールします。
$ sudo cpan Mojolicious

Mojoliciousをデーモンとして稼働させるためstarmanもインストールします。
$ sudo cpan Starman

WEBリモコン機能をスクリプトで作成
$ vi web_remocon

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use Mojolicious::Lite;

# GETメソッドで「/」にアクセスしたときに行う処理を書く
get '/' => sub {
  my $self = shift;

  # 描画
  $self->render();
} => 'index';

get '/light_on' => sub {
  my $self = shift;

  system("sudo bto_ir_cmd -e -t 022000E70C976800000000000000000000000000000000000000000000000000000000");

  $self->flash(message => '【送信完了】シーリングライト 全光');
  $self->redirect_to('/');
} => 'light_on';

get '/light_night' => sub {
  my $self = shift;

  system("sudo bto_ir_cmd -e -t 022000E70C8F7000000000000000000000000000000000000000000000000000000000");

  $self->flash(message => '【送信完了】シーリングライト 常夜灯');
  $self->redirect_to('/');
} => 'light_night';

get '/light_off' => sub {
  my $self = shift;

  system("sudo bto_ir_cmd -e -t 022000E70C8B7400000000000000000000000000000000000000000000000000000000");

  $self->flash(message => '【送信完了】シーリングライト 消灯');
  $self->redirect_to('/');
} => 'light_off';

get '/aircon_on' => sub {
  my $self = shift;

  system("sudo bto_ir_cmd -e -t 0188004000148043422EDE230068000001000055000000000000000000000000000000");

  $self->flash(message => '【送信完了】エアコン 稼働');
  $self->redirect_to('/');
} => 'aircon_on';

get '/aircon_off' => sub {
  my $self = shift;

  system("sudo bto_ir_cmd -e -t 0188004000148043412EDE030068000001000052000000000000000000000000000000");

  $self->flash(message => '【送信完了】エアコン 停止');
  $self->redirect_to('/');
} => 'aircon_off';

# アプリ起動
app->start;

# 以下テンプレート(Mojo::Template)
__DATA__

@@ index.html.ep
<html>
  <head>
    <meta name="viewport" content="width=320, height=480, initial-scale=1.0, minimum-scale=1.0, maximum-scale=2.0, user-scalable=yes" />
    <title>室内リモコン</title>
  </head>
  <body>
    <h1>室内リモコン</h1>
    <%= flash 'message' %>

    <h2>シーリングライト</h2>
    <input type="button" value="全光" onClick="location.href='<%= url_for('light_on') %>'">
    <input type="button" value="常夜灯" onClick="location.href='<%= url_for('light_night') %>'">
    <input type="button" value="消灯" onClick="location.href='<%= url_for('light_off') %>'">

    <h2>エアコン</h2>
    <input type="button" value="稼働" onClick="location.href='<%= url_for('aircon_on') %>'">
    <input type="button" value="停止" onClick="location.href='<%= url_for('aircon_off') %>'">
  </body>
</html>

※ 各自、環境に合わせたスクリプトを書いてください。TEMPerを使って温度を表示しても良いかもしれません。

スクリプトに実行権限を与えてコマンドとして実行できるようにします。
$ chmod +x web_remocon
$ sudo mv web_remocon /usr/local/bin/

スクリプトが正常に実行され、WEBブラウザからアクセスできる事を確認します。
$ web_remocon

Raspberry Pi起動時に自動でスクリプトが実行されるように以下の行を追記します。
$ sudo vi /etc/rc.local

# WEB_REMOCON SERVER
su - pi -c 'starman --port=3000 --daemonize --pid=/tmp/web_remocon.pid /usr/local/bin/web_remocon'

これで、WEBリモコン機能の実装は完了です。

音声リモコン機能の実装

音声リモコン 制御プロトコルについての図
音声制御プロトコル図
※ 合言葉のもう一つ利点として、1つの部屋に複数の音声リモコン(ハードウエア)を設置しても合言葉を識別子として使用できるというのが上げられます。

Juliusで使用するサウンドデバイスの指定
USBマイクがサウンドデバイスとして認識されているか確認します。
$ sudo cat /proc/asound/modules

 0 snd_bcm2835
 1 snd_usb_audio

※ 各自、環境に合わせて読み替えて下さい。

USBマイクを接続するとJuliusが標準で使用されるデバイスファイル(/dev/dsp)とは異なるため環境変数で指定します。
$ sudo vi /etc/profile

export AUDIODEV=/dev/dsp1

Juliusの導入
必要なファイルをダウンロードしてきます。
$ wget -O julius-4.3.1.tar.gz \
> ‘http://sourceforge.jp/frs/redir.php?m=osdn&f=%2Fjulius%2F60273%2Fjulius-4.3.1.tar.gz’
$ wget -O dictation-kit-v4.3.1-linux.tgz \
> ‘http://sourceforge.jp/frs/redir.php?m=jaist&f=%2Fjulius%2F60416%2Fdictation-kit-v4.3.1-linux.tgz’
※ コマンドが長いため折り返してあります。最新版が必要な場合はバージョンを調べてインストールしてください。

設定ファイルや辞書ファイルを設置するディレクトリを作成します。
$ sudo mkdir /etc/julius/
$ sudo mkdir /var/lib/julius/

Juliusをビルドしてインストールします。
$ tar zxvf julius-4.3.1.tar.gz
$ cd julius-4.3.1/
$ ./configure
$ make
$ make install

dictation-kitに含まれているファイルをコピーします。
$ tar zxvf dictation-kit-v4.3.1-linux.tgz
$ cd dictation-kit-v4.3.1-linux/
$ sudo cp model/lang_m/bccwj.60k.htkdic /var/lib/julius/
$ sudo cp model/phone_m/jnas-tri-3k16-gid.binhmm /var/lib/julius/
$ sudo cp model/phone_m/logicalTri /var/lib/julius/

単語辞書を作成します。
辞書ファイルを記述するとき、文字コードはUTF-8ではなくEUC-JPを使用します。文字コード切り替えは(:e ++enc=euc-jp)
$ vi /var/lib/julius/word.list

<sil>           []              silB
<sil>           []              silE
<sp>            []              sp
スタンバイ      [スタンバイ]    s u t a N b a i
ニュートラル    [ニュートラル]  n u t o r a r u
照明起動        [照明起動]      sh o u m e i k i d o u
ライト点ける    [照明起動]      r a i t o t u k e r u
照明停止        [照明停止]      sh o u m e i t e i sh i
ライト消す      [照明停止]      r a i t o k e s u
暖房起動        [暖房起動]      d a N b o u k i d o u
暖房点ける      [暖房起動]      d a N b o u t u k e r u
暖房停止        [暖房停止]      d a N b o u t e i sh i
暖房消す        [暖房停止]      d a N b o u k e s u
冷房起動        [冷房起動]      r e i b o u k i d o u
冷房点ける      [冷房起動]      r e i b o u t u k e r u
冷房停止        [冷房停止]      r e i b o u t e i sh i
冷房消す        [冷房停止]      r e i b o u k e s u

※ 各自、環境に合わせて単語辞書を書いてください。

Juliusの設定ファイル(テスト稼働用)を作成して記述します。
$ vi /etc/julius/julius_debug.conf

-w /var/lib/julius/word.list
-v /var/lib/julius/bccwj.60k.htkdic
-h /var/lib/julius/jnas-tri-3k16-gid.binhmm
-hlist /var/lib/julius/logicalTri
-n 5
-output 1
-input mic
-input oss
-rejectshort 600
-charconv euc-jp utf8
-lv 1500

※ 各自、自分に合わせて設定を書いてください。

Juliusの設定ファイル(本稼働用)を作成して記述します。
$ vi /etc/julius/julius.conf

-w /var/lib/julius/word.list
-v /var/lib/julius/bccwj.60k.htkdic
-h /var/lib/julius/jnas-tri-3k16-gid.binhmm
-hlist /var/lib/julius/logicalTri
-n 5
-output 1
-input mic
-input oss
-module
-rejectshort 600
-charconv euc-jp utf8
-lv 1500

※ 各自、自分に合わせて設定を書いてください。

Juliusをテスト稼働し音声コマンドを正常に認識できるか動作確認をします。
$ julius -C /etc/julius/julius_debug.conf

Raspberry Pi起動時に自動でjuliusが実行されるように以下の行を追記します。
$ sudo vi /etc/rc.local

su - pi -c 'nohup julius -C /etc/julius/julius.conf > /dev/null 2>&1 & echo $! > /tmp/julius.pid'

Open JTalkの導入
Open JTalkとその他必要なパッケージをインストールします。
$ sudo apt-get install open-jtalk open-jtalk-mecab-naist-jdic \
> htsengine libhtsengine-dev hts-voice-nitech-jp-atr503-m001
※ コマンドが長いため折り返してあります。

デフォルトは男性の音声ですが女性の音声を追加することもできるようです。
$ wget http://downloads.sourceforge.net/project/mmdagent/\
> MMDAgent_Example/MMDAgent_Example-1.4/MMDAgent_Example-1.4.zip
※ コマンドが長いため折り返してあります。
$ unzip MMDAgent_Example-1.4.zip
$ sudo cp -R MMDAgent_Example-1.4/Voice/* /usr/share/hts-voice/

Open JTalkを手軽に使用するスクリプトの記述
$ vi jsay

#!/bin/bash
WAV_FILE=/tmp/jsay_${RANDOM}.wav
#cd /usr/share/hts-voice/nitech-jp-atr503-m001
#cd /usr/share/hts-voice/mei_happy
cd /usr/share/hts-voice/mei_normal
echo "$1" | open_jtalk \
-td tree-dur.inf \
-tf tree-lf0.inf \
-tm tree-mgc.inf \
-md dur.pdf \
-mf lf0.pdf \
-mm mgc.pdf \
-dm mgc.win1 \
-dm mgc.win2 \
-dm mgc.win3 \
-df lf0.win1 \
-df lf0.win2 \
-df lf0.win3 \
-dl lpf.win1 \
-ef tree-gv-lf0.inf \
-em tree-gv-mgc.inf \
-cf gv-lf0.pdf \
-cm gv-mgc.pdf \
-k gv-switch.inf \
-s 16000 \
-a 0.05 \
-u 0.0 \
-jm 1.0 \
-jf 1.0 \
-jl 1.0 \
-x /var/lib/mecab/dic/open-jtalk/naist-jdic \
-ow $WAV_FILE && \
aplay --quiet $WAV_FILE
rm -f $WAV_FILE

スクリプトに実行権限を与えてコマンドとして実行できるようにします。
$ chmod +x jsay
$ sudo mv jsay /usr/local/bin/

音声合成ができる事を確認します。
$ jsay 月が綺麗ですね

音声リモコン機能をスクリプトで作成
$ vi voice_remocon

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;

use 5.10.0;

use Encode;
use IO::Socket;

# 接続先情報にJuliusサーバを指定する
my $socket = IO::Socket::INET->new(
    PeerAddr => 'localhost',  # 接続先
    PeerPort => 10500,        # Port 番号
    Proto    => 'tcp',        # Protocol
    TimeOut  => 5             # タイムアウト時間
);

die("Could not create socket: $!") unless($socket);

# 待機モードのループ
while(1){
    my $msg = $socket->getline();
    my ($word, $cm) = &get_parameter($msg);

    # 誤認識による誤作動防止のための合言葉を判定
    # 認識の信憑性もCM値で確認する
    if($word eq "スタンバイ" && $cm >= 0.8){
        system("sudo jsay アクティブモードを開始します");

        eval{
            local $SIG{ALRM} = sub { die "timeout" };

            # タイムアウトする時間(秒)の設定
            my $timer = 30;

            # タイムアウト処理-開始-
            alarm($timer);

            # 音声コマンドの受付のループ
            while(1){
                my $msg = $socket->getline();
                my ($word, $cm) = &get_parameter($msg);

                # 認識の信憑性が一定である場合はコマンドを識別し実行する
                if($cm >= 0.8){
                    given($word){
                        when("ニュートラル"){
                            system("sudo jsay アクティブモードを終了します");
                            last;
                        }
                        when("照明起動"){
                            system("sudo jsay 照明を起動します");
                            system("sudo bto_ir_cmd -e -t 022000E70C976800000000000000000000000000000000000000000000000000000000");
                        }
                        when("照明停止"){
                            system("sudo jsay 照明を停止します");
                            system("sudo bto_ir_cmd -e -t 022000E70C8B7400000000000000000000000000000000000000000000000000000000");
                        }
                        when("暖房起動"){
                            system("sudo jsay 暖房を起動します");
                            system("sudo bto_ir_cmd -e -t 0188004000148043422EDE230068000001000055000000000000000000000000000000");
                        }
                        when("暖房停止"){
                            system("sudo jsay 暖房を停止します");
                            system("sudo bto_ir_cmd -e -t 0188004000148043412EDE030068000001000052000000000000000000000000000000");
                        }
                    }
                }
            }

            # タイムアウト処理-終了-
            alarm(0);
        };

        if($@){
            print $@ . "\n";
            system("sudo jsay ディアクテブモードになります");
        }
    }
}

# 渡されたXMLにUTF-8フラグを付けてWORDとCMを取得する関数
sub get_parameter(){
    my $msg = shift;

    my $text = decode_utf8($msg);

    if($text =~ /.+WORD="(\S+)".+CM="(\S+)"/){
        return ($1, $2);
    }else{
        return ("",  0);
    }
}

※ 各自、環境に合わせたスクリプトを書いてください。音声合成時には音声識別を停止しても良いかもしれません。

スクリプトに実行権限を与えてコマンドとして実行できるようにします。
$ chmod +x voice_remocon
$ sudo mv voice_remocon /usr/local/bin/

スクリプトが正常に実行され、音声コマンドにて制御できる事を確認します。
$ voice_remocon

Raspberry Pi起動時に自動でスクリプトが実行されるように以下の行を追記します。
$ sudo vi /etc/rc.local

su - pi -c 'sleep 30 && nohup voice_remocon > /dev/null 2>&1 & echo $! > /tmp/voice_remocon.pid'

これで、音声リモコン機能の実装は完了です。

将来性・拡張性について

今回は家電制御に重点を置いていますが、スクリプトをちょっと書き換えたり追加することにより、現在時刻や室内温度、天気予報、干満時刻、新着メール、ニュースヘッドライン、Twitterのタイムラインなどを音声コマンドだけで読み上げてくれるシステムを作成出来るでしょう。家電制御の面だけでも、ルンバの起動や、温度監視を行いエアコンを制御して室温を自動調整したり、リモコン式のOAタップと組み合わせることで赤外線リモコンに対応していない他の家電を制御することも可能になるかもしれませんので拡張性は大いにあるかと思います。

その他・補足について

マイクを取り付けている以上、Raspberry Piに侵入された場合、日常生活を盗聴される危険性があります。また、音声で家電を制御するということは当然ながらスピーカーを取り付けたパソコン越しからでも動作する事が実験でも分かっております。今のところ実害は無いと思いますが通話中など、パソコン越しや電話越しに家電を乗っ取られる可能性も十分に考えられますのでご注意ください。

参考サイト
株式会社 ビット・トレード・ワン | USB接続 赤外線リモコンキット
kjmkznr/bto_ir_cmd
Mojolicious::Liteでウェブツールを作ろう – Perl Advent Calendar Japan 2011 Casual Track
Devel/電子工作/RaspberryPi/日本語音声認識 – cubic9.com
Raspberry Pi で音声認識 – 猫ぱーんち!
Raspberry Pi でミクにしゃべらせよう | ぱわふる
橋本商会 » Raspberry Piに喋らせる
いつか、そのとき、あの場所で。 | [システム監視][Temper][Zabbix] Raspberry Piで、USB温度計を使って室温を計測する方法。

Raspberry Pi Wifi GW-USValue-EZ 安定させる ハードウエアを改造する前に要確認

Rapsberry Piに無線LANアダプタ(GW-USValue-EZ)を接続して使用していたところ、非常に不安定で作業中に度々切断されることから対策してみた。

これまでに、セルフ給電式のUSBハブの導入や、Raspberry Piのコンデンサ交換などを試みたが一向に解消する兆しがなかった。
それらのことから、無線LANアダプタについて調べたところ使用されているチップセットの省エネモードが原因であることがわかった。

ちなみに、PLANEX(GW-USValue-EZ)以外の無線LANでもチップセットがRealtekのRTL8192CUである場合は同様に対策できる。

結果が1であった場合、省エネモードで動いている
$ sudo cat /sys/module/8192cu/parameters/rtw_power_mgnt

設定ファイルを作成し下記の行を記述する
$ sudo vi /etc/modprobe.d/8192cu.conf

# Disable power management
options 8192cu rtw_power_mgnt=0

再起動して設定を適用する
# sudo reboot

参考サイト
Raspbian で Wi-Fi がスリープするのを防ぐ – CO’s Home ~ Boiling Water River & Morning Forever
linux – How do I disable suspend mode? – Raspberry Pi Stack Exchange

Raspberry Pi 自分の用途に合わせたディスクイメージを作成する Debian 最小構成

RaspbianはRaspberry Piに適した素晴らしいLinuxですがGUIが不要な用途だったりすると
不要なパッケージがあまりにも多く含まれていると感じたり
ほかのデスクトップ環境のディスクイメージを作りたいと考える人もいるかと思います
そこで、自分の用途に合わせたディスクイメージの作り方をメモしておきます

必要な物
・Raspberry Pi
・Raspbianの入ったSDカード
・空のSDカード
・カードリーダライタ

Raspbianの入ったSDカードで起動し
空のSDカードにディスクイメージとなる環境を作ります

SDのパーティション削除とジオメトリの設定
$ sudo fdisk /dev/sda

Command (m for help): p

Disk /dev/sda: 1990 MB, 1990197248 bytes
241 heads, 63 sectors/track, 256 cylinders, total 3887104 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *          63     3886847     1943392+   b  W95 FAT32

Command (m for help): d
Selected partition 1

Command (m for help): x

Expert command (m for help): h
Number of heads (1-256, default 241): 255

Expert command (m for help): s
Number of sectors (1-63, default 63): 63

Expert command (m for help): c
Number of cylinders (1-1048576, default 256): 各自計算したシリンダ数

Expert command (m for help): r

Command (m for help): p

Disk /dev/sda: 1990 MB, 1990197248 bytes
255 heads, 63 sectors/track, 241 cylinders, total 3887104 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

シリンダ数の計算
SDカードの容量 / 255 / 63 / 512 = シリンダ数
例) 1990197248 / 255 / 63 / 512 = 241
割り切れない数値は切り捨てます

Windowsパーティション’/boot’の作成 (64MB)
$ sudo fdisk /dev/sda

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p):
Using default response p
Partition number (1-4, default 1):
Using default value 1
First sector (2048-3887103, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-3887103, default 3887103): +64M

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))

Command (m for help): a
Partition number (1-4): 1

Command (m for help): p

Disk /dev/sda: 1990 MB, 1990197248 bytes
62 heads, 62 sectors/track, 1011 cylinders, total 3887104 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      133119       65536    c  W95 FAT32 (LBA)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
information.
Syncing disks.

Linuxパーティション”/”の作成 (残りの容量全部)
$ sudo fdisk /dev/sda

Command (m for help): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p):
Using default response p
Partition number (1-4, default 2):
Using default value 2
First sector (133120-3887103, default 133120):
Using default value 133120
Last sector, +sectors or +size{K,M,G} (133120-3887103, default 3887103):
Using default value 3887103

Command (m for help): p

Disk /dev/sda: 1990 MB, 1990197248 bytes
40 heads, 6 sectors/track, 16196 cylinders, total 3887104 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      133119       65536    c  W95 FAT32 (LBA)
/dev/sda2          133120     3887103     1876992   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

必要なパッケージのインストール
$ sudo apt-get install dosfstools debootstrap git-core ca-certificates

フォーマット
$ sudo mkfs -t vfat -v -c -F 32 /dev/sda1
$ sudo mke2fs -t ext4 /dev/sda2 -m 1

SDカードに作成したパーティション/を/mntにマウントしてdebootstrapを使いDebianをインストール
$ sudo mount -o defaults,noatime /dev/sda2 /mnt/
$ sudo debootstrap –exclude=ed,nano –foreign –arch armel wheezy /mnt http://ftp.jp.debian.org/debian

必要なファイルをコピー
$ sudo cp /etc/inittab /mnt/etc/inittab
$ sudo cp /etc/hosts /mnt/etc/hosts
$ sudo cp /etc/fstab /mnt/etc/fstab
$ sudo cp /etc/network/interfaces /mnt/etc/network/interfaces

rootユーザで/mntをchrootし疑似的にLinuxを触る
chrootするとsudoコマンドは使えないためrootユーザになっておく必要があります
作業中は一応、ヒストリーに履歴が残ってしまうようなので残らないようにしておきます
debootstrapを実行させるとマウントしていた/procがアンマウントされるようなので再度マウントします
$ sudo su –
# export HISTSIZE=0 HISTFILESIZE=0
# chroot /mnt
# mount -n /proc
# export PATH=/bin:/sbin:/usr/bin:/usr/sbin
# /debootstrap/debootstrap –second-stage –no-resolve-deps
# mount -n /proc

リポジトリの追加
これは標準のDevianのリポジトリを追加していますが面倒ならRaspbian側のファイルをコピーしても問題ありません
# vi /etc/apt/sources.list

# See sources.list(5) for more information, especialy
# Remember that you can only use http, ftp or file URIs
# CDROMs are managed through the apt-cdrom tool.
deb http://http.us.debian.org/debian stable main contrib non-free
deb http://non-us.debian.org/debian-non-US stable/non-US main contrib non-free
deb http://security.debian.org stable/updates main contrib non-free

# Uncomment if you want the apt-get source function to work
#deb-src http://http.us.debian.org/debian stable main contrib non-free
#deb-src http://non-us.debian.org/debian-non-US stable/non-US main contrib non-free

アップデートとアップグレードの実行とその他、各自必要なパッケージのインストール
ここで好きなパッケージをインストールしておくことで用途に合わせたディスクイメージを作成することができます
# apt-get update
# apt-get upgrade
# apt-get install console-common console-setup console-data console-tools \
keyboard-configuration locales ntpdate ntp lua5.1 vim ssh sudo syslog-ng usbutils

ユーザの作成とsudoグループへの追加
この時にpasswdコマンドを使用しrootユーザのパスワードを設定することもできます
# adduser pi
# gpasswd -a pi sudo

chrootでの作業とrootでの作業の終了
# exit
# exit

起動時にeth0を有効化させる設定
$ sudo vi /mnt/etc/network/interfaces

auto lo eth0

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

/bootとモジュールのコピー
$ sudo mount /dev/sda1 /mnt/boot
$ sudo cp -rp /boot/* /mnt/boot
$ sudo cp -rp /lib/modules/* /mnt/lib/modules

カーネルとモジュールのアップデート
$ sudo wget http://goo.gl/1BOfJ -O /usr/bin/rpi-update
$ sudo chmod +x /usr/bin/rpi-update
$ sudo ROOT_PATH=/mnt BOOT_PATH=/mnt/boot rpi-update

SDカードをアンマウント
$ sudo umount -l /mnt

シャットダウン
$ sudo shutdown -h now

SDカードを引き抜き、SDカードのイメージを作成すればオリジナルディスクイメージの完成です。
イメージ作成はWin32 Disk Imagerなどを使用すると簡単かもしれません

最後に作成したSDカードをRaspberry Piに接続し電源を入れ、正常に起動するするかを確認してみてください。

参考URL
覚書的な何か » Blog Archive » Raspberry PiでまっさらなDebianのインストール
Debian Linux for Raspberry Pi – GreenLeaf
Raspberry piにDebian squeezeをインストールする – もぐてっく
fdiskでフォーマットする – Android on Beagle

1万円で放射線量を計測して自動でTwitterに投稿する装置を作ろう!

一昔前はこういう装置を作成するのに結構な費用が必要となっておりましたが最近は非常に低価格かつ簡単に実現することができます。そして計測結果は高い精度を期待できます。
今回は難しいハンダ付けやプログラミングをほとんど行わなくても作成できる事を目標とします。

利用するパーツ

Linux組み込みボード Raspberry Pi 3,500円
組み込み用線量計 ポケットガイガー Type 5 6,450円
ジャンパーワイヤー ジャンパーワイヤ オス⇔メス(10本セット) 400円
ジャンパーワイヤー ジャンパーワイヤ オス⇔オス(70本セット) 400円
ブレッドボード ブレッドボード EIC-801 250円
プルアップ抵抗 【CF1/4-22kΩJ】1/4Wカーボン抵抗 22kΩ 赤赤橙金(100本入) 283円
ピンソケット ピンヘッダ(オスL型) 1×40 (40P) 50円
SDカード ADATA ASDH4GCL4-R SDHCカード Class4 4GB 452円
合計 11,785円

※ 状況によっては価格は変動します。
※ 上記の他に、Windows OSをインストールしたパソコン、モニタ、HDMIケーブル、キーボード、マウス、ネット環境、MicroUSBケーブル、半田ゴテ、ハンダ線、こて台、Twitterアカウントが必要となります。

Twitterのディベロッパー登録

こちらのサイトを元にアプリケーションの登録を済ませておいてください。
下記の内容が必要となります。メモしておいてください。
CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET
bot開発物語 その2―アプリケーション登録―
※ 必ずAPI側でRead and Writeの権限を与えておいてください。

Raspberry PiへのOSインストール

以前の記事を参考にしてください。
Raspberry PiでRaspbianを日本語環境で動かそう!

ピンヘッダのハンダ付け

ピンヘッダの列から5本分を折り取りポケットガイガー Type5に差し込んでハンダ付けします。
IMG_1589[1]

Raspberry Piとポケットガイガー Type5の接続

ブレッドボードとジャンパーワイヤーを使用しRaspberry Piとポケットガイガー Type5の接続を行います。

ワイヤーの色とピンの対応表

ジャンパーワイヤー ポケガ RasPi
赤色 VCC 3v3
黒色 GND GND
青色 SIG GPIO 17
黄色 NS GPIO 27

ポケットガイガー Type5とプルアップ用抵抗をブレッドボードに設置しジャンパーワイヤー(オス⇔オス)で接続します。

IMG_1620[1]

IMG_1621[1]

IMG_1622[1]

ブレッドボードとRaspberry Piをジャンパーワイヤー(オス⇔メス)で接続すます。

IMG_1623[1]

IMG_1625[1]

※ 私のRaspberry PiはP5の位置にピンヘッダがハンダ付けされておりますが気にする必要はありません。

Raspberry Piのピン配置はこのようになっております。
Raspberry_Pi_GPIO

全体的に見るとこういう感じになります。
IMG_1627[1]

Raspberry Piへのプログラムインストール

起動とログイン

Raspberry Piとポケットガイガー Type5を接続した状態でRaspberry Piを起動します。
ログイン後コンソールに下記のコマンドを入力してデスクトップを起動してください。
$ sudo startx
※ こうすることにより管理者権限でGUIな操作を行うことができるようになります。
※ Linux初心者向けにGUIで解説しますがコンソールのみで操作できる方はX Windowを起動する必要ありません。

ターミナルの起動

左下メニュー”アクセサリ”→”LXTerminal”を起動してください。
snapshot1

起動に成功すると真っ黒な画面が出てきます。
snapshot2

真っ黒な画面の中に必要なコマンドを入力していきます。
snapshot3

gitコマンドのインストール

“LXTerminal”内に下記のコマンドを1行ずつ実行してください。
※ #以降の文字列を入力してください。
※ 依存パッケージのインストールを求められる事があります。その場合は”Enter”を押してください。
※ 場合によっては非常に時間が掛かる事があります。気長にお待ちください。
# apt-get update
# apt-get upgrade
# apt-get install git

wiringPiライブラリのインストール

“LXTerminal”内に下記のコマンドを1行ずつ実行してください。
# git clone git://git.drogon.net/wiringPi
# cd wiringPi
# git pull origin
# ./build
# cd ../

Rasdiationのインストール

“LXTerminal”内に下記のコマンドを1行ずつ実行してください。
# git clone git://github.com/orsp/Pocket_Rasdiation_Counter.git
# cd Pocket_Rasdiation_Counter
# make
# make install
# cd ../

Rasdiationの動作テスト

“LXTerminal”内に下記のコマンドを実行してください。
# rasdiation -s 17 -n 27 -b -m

下記の様にCPMやuSv/hの値がカウントされた状態で表示されていれば接続とインストールに成功しています。
snapshot4

Raspberry Pi起動時に連動したRasdiationの自動実行の設定

タスクバー左側アイコンより”ファイルマネージャ”を起動します。
snapshot5

ディレクトリパスに”/etc”と指定しその中の”inittab”をダブルクリックします。
snapshot6

ファイルの最後に下記の行を追記し上書き保存します。
alog:2000:respawn:/usr/local/bin/rasdiation -s 17 -n 27 -o /var/lib/rasdiation/rasdiation.fifo
snapshot7

python-tweepyライブラリのインストール

“LXTerminal”を起動してください。
“LXTerminal”内に下記のコマンドを実行してください。
※ 依存パッケージのインストールを求められる事があります。その場合は”Enter”を押してください。
# apt-get install python-tweepy
# easy_install tweepy
※ apt-getのpython-tweepyは古いようなのでこちらから新しいバージョンのpython-tweepyをインストールします。

Twitter自動投稿スクリプトの設置

“LXTerminal”内に下記のコマンドを1行ずつ実行してください。
# mkdir -p /GEIGERCOUNTER/Twitter
# cp Pocket_Rasdiation_Counter/example/twitter_post.py /GEIGERCOUNTER/Twitter/
# chmod 755 /GEIGERCOUNTER/Twitter/twitter_post.py

Twitter自動投稿スクリプトの設定

タスクバー左側アイコンより”ファイルマネージャ”を起動します。
ディレクトリパスに”/GEIGERCOUNTER/Twitter”と指定します。
“twitter_post.py”をダブルクリックで開きます。
snapshot13

“Twitterのディベロッパー登録”で得たパラメータを記述し上書き保存します。
snapshot14

Twitter自動投稿スクリプトの動作テスト

“LXTerminal”を起動してください。
“LXTerminal”内に下記のコマンドを実行してください。
# python /GEIGERCOUNTER/Twitter/twitter_post.py

設定したTwitterアカウントで下記のような内容がツイートされている事を確認してください。
※ 実際の投稿内容の日付や数値は変化します。
2013年03月24日(日) 11時35分 現在の放射線量は CPM:2.964 uSv/h:0.05589(誤差 0.00833) でした。

Twitter自動投稿スクリプトの定期実行の設定

タスクバー左側アイコンより”ファイルマネージャ”を起動します。
ディレクトリパスに”/etc/cron.d”と指定します。
snapshot8

中に空ファイル”twitter_post”を新規作成します。
snapshot9

作成した”twitter_post”をダブルクリックします。
snapshot10

下記の行を記述し上書き保存します。
※ この設定は30分毎に”twitter_post.py”を実行するという意味です。必要に応じて変更してください。
*/30 * * * * root python /GEIGERCOUNTER/Twitter/twitter_post.py
snapshot15

最終動作確認

正常に30分毎に投稿されるかを確認できましたら放射線量自動投稿機の完成です。
正しく設定されていればRaspberry Piを再起動しても自動で放射線量を計測し投稿いたします。

今回、ブレッドボードを使用しましたがユニバーサル基板を使い回路を作成しても良いかもしれません。
必要があればPythonのスクリプトを改造し自分の好みの投稿内容にするのも楽しいでしょうね。

Raspberry PiでRaspbianを日本語環境で動かそう!

Raspberry PiのOSインストール

こちらからRaspberry PiにインストールするDebian系Linux OS “Raspbian”をダウンロードしてきます。
こちらからRaspbianをSDカードにインストールするためのプログラム”Win32DiskImager”をダウンロードします。

ダウンロードした双方の圧縮ファイルを展開します。

SDカードをパソコンに接続し展開したフォルダーから”Win32DiskImager.exe”を起動します。
※ “Win32DiskImager”の使用は書き込み先を間違うとデータ損失の危険性があります。慎重に行なってください。

ダウンロードした”Raspbian”のイメージファイルを選択し、書き込み先のSDカードを選択します。
準備ができたら”Write”ボタンを押してください。
WS000003

警告ダイアログが出てきます。問題がなければ”Yes”を押してください。
WS000004

書き込みが完了すると下記のダイアログが出ます。”OK”を押し、”Win32DiskImager.exe”を終了してください。
WS000007

Raspberry Piの初回起動

Raspberry PiにOSの入ったSDカードを接続し、キーボード、マウス、モニタ、LANケーブルを接続します。
準備ができたことを確認し最後にMicroUSBケーブルを接続します。
※ Raspberry Piには電源ボタンがありません。MicroUSBケーブルを接続した瞬間起動し始めます。
IMG_1610

起動中に下記のような初回設定画面が表示されます。
WS000008
※ 画像ではインストール後、SSHによる遠隔操作にて再現を行なっております。
※ ここでは、最低限の設定を紹介いたします。各自、必要に応じて設定を行なってください。

SDカードの容量全部を使用するようにします。

“expand_rootfs”を選択しTabキーを押し”Select”を選択し”Enter”を押します。
※ 以降、カーソルの移動に仕方につては省略して解説します。
WS000009

そのまま”Ok”を押して設定項目が並んでいる画面に戻ってください。
WS000014

画面をフルスクリーンで表示する設定を行います。

“overscan”を選択します。
WS000011

“Enable”を選択し設定項目が並んでいる画面に戻ってください。
WS000012

キーボードレイアウトを設定します。

“configure_keyboard”を選択します。
WS000013

“Generic 105-key (Intl) PC”を選択します。
WS000015

“Other”を選択します。
WS000016

“Japanese”を選択します。
WS000017

“Japanese”を選択します。
WS000018

“The default for the keyboard layout”を選択します。
WS000019

“No compose key”を選択します。
WS000020

そのまま”No”を押して設定項目が並んでいる画面に戻ってください。
WS000021

ローケルを設定します。

“change_locale”を選択します。
WS000022

“ja_JP.UTF-8 UTF-8″にSpaceキーでチェックを入れ、”Ok”押してください。
WS000023

“ja_JP.UTF-8″を選択し設定項目が並んでいる画面に戻ってください。
WS000024

タイムゾーンを設定します

“change_timezone”を選択します。
WS000025

“Asia”を選択します。
WS000026

“Tokyo”を選択し設定項目が並んでいる画面に戻ってください。
WS000027

OSをアップデートします

“update”を選択します。
※ アップデートにはインターネット環境が必要です。
※ 結構時間がかかります。気長に待ってください。
WS000028

設定を終了します

“Finish”を選択してください。
WS000029

日本語環境をインストール

コンソール画面に切り替わりましたら下記のコマンドを入力してください。
※ インストールにはインターネット環境が必要です。
※ 結構時間がかかります。気長に待ってください。
$ sudo apt-get install task-japanese task-japanese-desktop
WS000031

依存関係にあるパッケージのインストール求められるので”Enter”を押します。
WS000033

Raspberry Piを再起動します

日本語環境のインストールが完了しましたら下記のコマンドを入力してください。
※ 今回は若干エラーを吐いているパッケージもありますが気にしないことにします。
※ どうしてもエラーが気になる場合は$ sudo apt-get -f installと実行してください。
$ sudo reboot
WS000034

Raspberry Piのログイン

正常に起動すると下記のような文字列が表示されます。
下記のようにアカウント情報を入力してください。

My IP address is ***.***.***.***

Debian GNU/Linux 7.0 raspberrypi tty1

raspberrypi login: pi       ← ユーザ名
Password: raspberry         ← パスワード(入力中の文字列は表示されません)

デスクトップの起動

ログインするとコンソールが表示されます。
下記の様にコマンドを入力してデスクトップを起動してください。

$ startx
snapshot1

以上でインストール完了となります。

Raspbianでスクリーンショットを撮る

Raspbianでスクリーンショットを撮ろうと思ったらパッケージが入っていなかったようなのでインストールしてみました。

$ sudo apt-get install ksnapshot

左下メニューの”グラフィックス”→”KSnapshot”から起動出来ます。

snapshot2

Raspberry PiでC言語を使い2つのスレッドを200ミリ秒と2秒ごとに処理させる

Arduinoだとタイマー割り込みを使って処理したいところですが残念ながら私の調べた限りRaspberry Piでは無さそうなのでC言語とスレッドを利用し近い処理をさせることにしました。

$ vi thread_test.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *thread_function1( void *ptr );
void *thread_function2( void *ptr );

int main(void){
     pthread_t thread1, thread2;
     useconds_t tick1 = 200000;
     useconds_t tick2 = 2000000;

     pthread_create( &thread1, NULL, thread_function1, (void *) &tick1);
     pthread_create( &thread2, NULL, thread_function2, (void *) &tick2);

     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL);

     return 0;
}

void *thread_function1(void *ptr){
    useconds_t tick = *( int * )ptr;

    while(1){
        printf("function1\n");
        usleep(tick);
    }
}

void *thread_function2(void *ptr){
    useconds_t tick = *( int * )ptr;

    while(1){
        printf("function2\n");
        usleep(tick);
    }
}

コンパイルします
$ gcc thread_test.c -pthread

実行
$ ./a.out

しかし、これでは共有資源を利用したプログラムを書いた場合取り合いになり下手をするとデータが失われたりする場合があるため排他制御するようにします。

$ vi thread_test.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *thread_function1( void *ptr );
void *thread_function2( void *ptr );

pthread_mutex_t mutex;
pthread_cond_t cond;
int count = 0;

useconds_t tick1 = 200000;
useconds_t tick2 = 2000000;

int main(void){
     pthread_t thread1, thread2;

     pthread_mutex_init(&mutex, NULL);

     pthread_create( &thread1, NULL, thread_function1, (void *) &tick1);
     pthread_create( &thread2, NULL, thread_function2, (void *) &tick2);

     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL);

     pthread_mutex_destroy(&mutex);

     return 0;
}

void *thread_function1(void *ptr){
    useconds_t tick = *( int * )ptr;

    while(1){
        pthread_mutex_lock(&mutex);

        printf("function1 %d\n",count++);
        pthread_mutex_unlock(&mutex);
        usleep(tick);
    }
}

void *thread_function2(void *ptr){
    useconds_t tick = *( int * )ptr;

    while(1){
        pthread_mutex_lock(&mutex);

        printf("function2 %d\n",count++);
        pthread_mutex_unlock(&mutex);
        usleep(tick);
    }
}

コンパイルします
$ gcc thread_test.c -pthread

実行
$ ./a.out
function2 0
function1 1
function1 2
function1 3
function1 4
function1 5
function1 6
function1 7
function1 8
function1 9
function1 10
function2 11
function1 12
function1 13
function1 14
function1 15
function1 16
function1 17
function1 18

Raspberry PiでAdafruit製LCD(カラーバックライト+ボタン付きシールド)を利用する

Raspberry PiでAdafruit RGB Negative 16×2 LCD+Keypad Kit for Raspberry Pi – を使ったプログラムをAdafruitの公式ライブラリを使い書いてみました。

シールドの組立、ライブラリのインストールや使い方は公式の方をご覧ください。

下記のソースコードはRasbperry Piの時間とインターフェイス毎のIPアドレスをLCDに表示します。

インターフェイス毎のローカルIPアドレスを取得するために”netifaces”ライブラリを使用しております。
$ apt-get install python-netifaces

/LCDディレクトリを作成し公式ライブラリを入れておきます。
$ sudo mkdir /LCD

$ sudo vi /LCD/MENU_LCD.py

#!/usr/bin/env python
from netifaces import interfaces, ifaddresses, AF_INET

from time import sleep
from Adafruit_I2C import Adafruit_I2C
from Adafruit_MCP230xx import Adafruit_MCP230XX
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate

from IPaddr_LCD import IPaddr_LCD
from DateTime_LCD import DateTime_LCD

import smbus

lcd = Adafruit_CharLCDPlate(busnum = 1)

class MENU_LCD():
    def get_const_list(self):
        const_list   = []

        ip   = IPaddr_LCD()
        time = DateTime_LCD()

        const_list.append(ip)
        const_list.append(time)

        return const_list

    def print_progress(self, sleep_time, message):
        lcd.clear()
        lcd.message(message)
        sleep(sleep_time)
        self.print_lcd()

    def print_lcd(self):
        pointer_id = 0
        push_flag  = 0

        lcd.clear()
        lcd.message("Please Push\nRite/Left Button")

        const_list = self.get_const_list()
        const_list_size = len(const_list) - 1

        while 1:
            if (lcd.buttonPressed(lcd.RIGHT) or lcd.buttonPressed(lcd.LEFT)):
                if (lcd.buttonPressed(lcd.RIGHT)):
                    if (pointer_id < const_list_size):
                        pointer_id += 1
                    else:
                        pointer_id = 0

                if (lcd.buttonPressed(lcd.LEFT)):
                    if (pointer_id > 0):
                        pointer_id -= 1
                    else:
                        pointer_id = const_list_size

                push_flag  = 1
                const_list[pointer_id].title()

            if (push_flag > 0 and lcd.buttonPressed(lcd.SELECT)):
                const_list[pointer_id].print_lcd()
                break

            if (push_flag > 0 and lcd.buttonPressed(lcd.UP)):
                break

            if (push_flag > 0 and lcd.buttonPressed(lcd.DOWN)):
                break

            sleep(.2)
        return self.print_progress(1, "Reinitializeing\nPlease wate....")

if __name__ == '__main__':
    try:
        menu = MENU_LCD()
        menu.print_progress(3, "Initializeing\nPlease wate....")
        menu.print_lcd()
    except KeyboardInterrupt:
        print("Exit\n")

$ sudo vi /LCD/DateTime_LCD.py

#!/usr/bin/env python
import datetime
import locale

from time import sleep
from Adafruit_I2C import Adafruit_I2C
from Adafruit_MCP230xx import Adafruit_MCP230XX
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate

import smbus

lcd = Adafruit_CharLCDPlate(busnum = 1)

class DateTime_LCD():
    def title(self):
        lcd.clear()
        lcd.message("Raspberry Pi\nDate Time")
        return

    def print_lcd(self):

        while 1:
            d = datetime.datetime.today()
            time = d.strftime("Date %Y/%m/%d\nTime  %H:%M:%S")

            lcd.clear()
            lcd.message(time)

            if (lcd.buttonPressed(lcd.RIGHT)):
                break

            if (lcd.buttonPressed(lcd.LEFT)):
                break

            sleep(.2)
        return


if __name__ == '__main__':
    try:
        time = DateTime_LCD()
        time.print_lcd()
    except KeyboardInterrupt:
        print("Exit\n")

$ sudo vi /LCD/IPaddr_LCD.py

#!/usr/bin/env python
from netifaces import interfaces, ifaddresses, AF_INET

from time import sleep
from Adafruit_I2C import Adafruit_I2C
from Adafruit_MCP230xx import Adafruit_MCP230XX
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate

import smbus

lcd = Adafruit_CharLCDPlate(busnum = 1)

class IPaddr_LCD():
    def title(self):
        lcd.clear()
        lcd.message("Raspberry Pi\nIP Address")
        return

    def get_ip_list(self):
        ipaddr_list   = []
        for ifaceName in interfaces():
            nic_ip_list = []
            addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
            nic = '%s' % (ifaceName)
            ip  = '%s' % (', '.join(addresses))
            nic_ip_list.append(nic)
            nic_ip_list.append(ip)
            ipaddr_list.append(nic_ip_list)
        return ipaddr_list

    def print_lcd(self):
        pointer_id = 0

        lcd.clear()
        lcd.message("Please Push\nUp/Down Button")

        while 1:
            if (lcd.buttonPressed(lcd.UP) or lcd.buttonPressed(lcd.DOWN)):
                ipaddr_list = self.get_ip_list()
                ipaddr_list_size = len(ipaddr_list) - 1

                if (lcd.buttonPressed(lcd.UP)):
                    if (pointer_id < ipaddr_list_size):
                        pointer_id += 1
                    else:
                        pointer_id = 0

                if (lcd.buttonPressed(lcd.DOWN)):
                    if (pointer_id > 0):
                        pointer_id -= 1
                    else:
                        pointer_id = ipaddr_list_size

                lcd.clear()
                lcd.message(ipaddr_list[pointer_id][0] + "\n" + ipaddr_list[pointer_id][1])

            if (lcd.buttonPressed(lcd.RIGHT)):
                break

            if (lcd.buttonPressed(lcd.LEFT)):
                break

            sleep(.2)
        return

if __name__ == '__main__':
    try:
        ip = IPaddr_LCD()
        ip.print_lcd()
    except KeyboardInterrupt:
        print("Exit\n")

コマンド用の実行ファイルを作成しておきます
$ sudo vi /LCD/LCD_PRINTER

#!/usr/bin/env python
from MENU_LCD import MENU_LCD

if __name__ == '__main__':
    try:
        menu = MENU_LCD()
        menu.print_progress(3, "Initializeing\nPlease wate....")
        menu.print_lcd()
    except KeyboardInterrupt:
        print("Exit\n")

実行権限を与えどこからでもパスが通るように”/usr/bin/”の中にシンボリックを貼っておきます。
$ sudo chmod 700 /LCD/LCD_PRINTER
$ sudo ln -s /LCD/LCD_PRINTER /usr/bin/LCD_PRINTER

せっかくなので起動スクリプトも書いてみました。
$ sudo mkdir /LCD/init.d/
$ sudo vi /LCD/init.d/lcd_printer

#!/bin/sh
### BEGIN INIT INFO
# Provides:          LCD_PRINTER
# chkconfig:         2345 91 91
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       LCD_PRINTER daemon script.
### END INIT INFO

. /lib/lsb/init-functions

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/LCD_PRINTER
DAEMON_NAME=`basename $DAEMON`
PIDFILE="/var/run/lcd_printer.pid"

set -e

start() {
  log_daemon_msg "Starting $DAEMON_NAME"
  if ! start-stop-daemon --stop --quiet --pidfile ${PIDFILE} --signal 0; then
    start-stop-daemon --start --pidfile ${PIDFILE} --make-pidfile --quiet --background --exec ${DAEMON}
    log_end_msg $?
  else
    echo -n " already running."
    log_end_msg 1
  fi
}

stop() {
  log_daemon_msg "Stopping $DAEMON_NAME"
  start-stop-daemon --stop --pidfile ${PIDFILE}
  log_end_msg $?
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    start
    ;;
  status)
    status_of_proc -p $PIDFILE $DAEMON $DAEMON_NAME && exit 0 || exit $?
    ;;
  *)
    echo $"Usage: $DAEMONNAME {start|stop|restart|status}" >&2
    exit 1
    ;;
esac
exit 0

実行権限を与え、起動スクリプトとして”/etc/init.d/”の中にシンボリックを貼っておきます。
$ sudo chmod 755 /LCD/init.d/lcd_printer
$ sudo ln -s /LCD/init.d/lcd_printer /etc/init.d/lcd_printer

起動するか確認してみます。
$ sudo service lcd_printer start

自動起動するように設定します。
$ sudo update-rc.d lcd_printer defaults

自動起動するか確認します。完全に電源を落とすためrebootではなくシャットダウンして電源を入れます。
$ sudo shutdown -h now

余談ですがRedHat系はchkconfigで設定するのですがDebian系は違うのですね・・・勉強になりました。

Raspberry PiでGPIOを使った割り込み処理を行う

どうしてもポーリングではなく割り込み処理にてGPIOを監視したかったので調べていたら最近wiringPi.hwiringPiISRと呼ばれる頼もしい関数が追加されたようなので試してみました。
下記のサンプルコードではRaspberry Piにポケットガイガー Type5をGPIO 2にシグナル、GPIO 3にノイズを接続して100マイクロ秒で送られてくるパルスを検知します。

#include <wiringPi.h>
#include <stdlib.h>
#include <stdio.h>

void signal(void){
        printf("Signal\n");
}

void noise(void){
        printf("Noise\n");
}

int main(void){
        int setup = 0;
        setup = wiringPiSetupSys();
        while(setup != -1){
                wiringPiISR( 30, INT_EDGE_FALLING, signal );
                wiringPiISR( 31, INT_EDGE_RISING,  noise  );
                sleep(10000);
        }
        return 0;
}

コンパイル
$ sudo gcc Interrupt.c -lwiringPi

実行結果(最初ポケットガイガー Type5をつついてノイズを発生させてみました)
$ ./a.out
Noise
Signal
Noise
Signal
Noise
Noise
Noise
Signal
Signal
Noise
Noise
Signal
Signal
Noise
Signal
Signal
Signal
Signal
Signal
Signal

他にもwaitForInterruptという関数もあるようですがwiringPiISRの方が便利かもしれません。

当たり前ですがこれをポーリングで書くとsleepがほとんど使えない状態になるのでCPU使用率が偉いことになりますw

組み込みLinuxの世界も楽しいものですね。

追記
プログラムに下記のように記述しておりましたのを修正しました。
wiringPiISR( 2, INT_EDGE_BOTH, signal );
wiringPiISR( 3, INT_EDGE_BOTH, noise );

ポケットガイガーのシグナルは通常はHighで検知されるとlowとなります。ノイズは通常lowで信号が検知されるとhighとなります。ここで”INT_EDGE_BOTH”を指定すると、信号が来て割り込みが発生し、通常の状態に戻ったときも割り込みが発生します。つまり一回の検知で2回割り込みが発生してしまうということになります。
そのため、個別できちんと指定する必要が有るようです。