mp3の再生

mpg321をインストールします

$ sudo apt-get install alsa-utils
$ sudo apt-get install mpg321

音声の出力先設定をします
アナログ出力の場合
$ amixer cset numid=3 1

HDMI出力の場合
$ amixer cset numid=3 2

自動起動アプリの設定

設定ファイルを編集します。ターミナルから下記コマンドを実行します

$ nano .config/lxsession/LXDE-pi/autostart

@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xscreensaver -no-splash
@sh ${HOME}/.config/lxsession/LXDE-pi/autokey.sh
@xset s off
@xset -dpms
@xset s noblank
@epiphany-browser http://yahoo.co.jp

ついでにスクリーンセーバーをオフにしています

デスクトップの日本語化

RaapberryPi をNoobsでOSを作成すると、起動時にデスクトップ(GUI)が立ち上がります。

日本語化するにはフォントをインストールします。

ターミナルから
$ sudo apt-get install fonts-vlgothic
フォントをインストールします。

言語、タイムゾーン、キーボードの設定はデスクトップ上部MenuからPreferences > Raspberry Pi Configuration を選択して設定してください。

温度センサーIC LM19を使う

ここでは温度センサーIC LM19(National Semiconductor)を使ってRaspberry piで温度監視を行う事例を紹介します。

LM19仕様

  • パッケージ:TO-92
  • 動作電源電圧:2.4V~5.5V
  • 使用温度範囲:-30℃~+130℃
  • 精度:±2.5(@30℃)

接続例

スクリーンショット 2014-01-21 4.24.02
LM19からの出力はアナログ電圧のためRaspberry piでは直接扱うことができません。そこで一旦I2Cインターフェイス基盤でアナログ電圧を読み取り、その結果をI2Cをとおして取得することにします。
ICのデータシートを参考に出力には抵抗とコンデンサをつないでいます。

Python script


import i2cinterface99
ii = i2cinterface99.i2cinterface99()
state,value = ii.analogRead(0) #read A0 Pin
if state == True:
 volt = value / 1023.0*3.3 #3.3V電圧でインターフェイス基盤を動作している場合のAD変換式
 temp = (1.8641 - volt)/0.0117 #ボルトから温度への変換の式
 print "%d deg/C" %(temp) #摂氏表示
else:
 print "I2C error"

温度への変換式はICのデータシートに記載されている−10℃〜65℃における推奨式を元にしています。
上記スクリプトをsudo python ファイル名.py で実行します。
温度センサーの値を読み取った結果がコンソールに表示されるはずです。
I2Cインターフェイス基盤にLCDを接続していれば、LCD上に温度の値が表示されるようにしてもよいでしょう。

今回行った実験では、LM19の測定値が温度湿度センサーDHT11による測定値とほぼ同じであることが確認できました。

Raspberry piを使った時報システム

I2Cインターフェイス基板とRaspberry piを使った時報システムを簡単に作ってみました。時報の音はI2Cインターフェイス基板上に実装されている圧電スピーカーを鳴らします。

python なら専用のライブラリーがあるので、音を出すための設定も楽々です。
こんな感じでプログラムを作ってみました


import time
import i2cinterface99
ii=i2cinterface99.i2cinterface99()
ii.setSound(16,2)
for var in range(0, 3):
 ii.sound(1)
 time.sleep(1)
ii.setSound(32,30)
ii.sound(1)

ライブラリi2cinterface99.pyと同じディレクトリに保存しておきます.
あとはLinuxのcrontabによって定時動作させるだけ

pi@raspberrypi ~ $ crontab -e

0 7-19 * * * python ~/alarm.py

この例では毎日7時から19時の間に毎正午時報を鳴らすことが出来ます。
piユーザーでもi2cデバイスを操作できるようにpiユーザーのサブグループにi2cグループを追加しておけばsudoから呼び出す必要はありません。

$ sudo usermod -a -G i2c pi

バックグランドプロセス(ジョブ)の停止

raspberry piでSSH接続で&オプションを付けてプロセスをバックグランドで起動することで、SSHが切断されたあともプロセスを継続することができます.常時動き続けるようなプロセス(プログラム)を走らせるのに有用です.

常時動作しているプロセスを保守などのために停止する際に、SSHから停止をさせます。再接続したSSHからは該当のプロセスを通常ユーザからは見ることができません。管理者になる必要があります.

pi@raspberrypi ~ $ sudo su

起動しているプロセス一覧を取得します
root@raspberrypi:/home/pi# ps x
PID TTY STAT TIME COMMAND
1 ? Ss 0:03 init [2]
2 ? S 0:00 [kthreadd]
3 ? S 0:01 [ksoftirqd/0]
5 ? S< 0:00 [kworker/0:0H] 6 ? S 0:06 [kworker/u:0] 7 ? S< 0:00 [kworker/u:0H] 8 ? S< 0:00 [khelper] 9 ? S 0:00 [kdevtmpfs] 10 ? S< 0:00 [netns] 12 ? S 0:00 [bdi-default] 13 ? S< 0:00 [kblockd] 14 ? S 0:00 [khubd] 15 ? S< 0:00 [rpciod] 16 ? S 0:00 [khungtaskd] 17 ? S 0:00 [kswapd0] 18 ? S 0:00 [fsnotify_mark] 19 ? S< 0:00 [nfsiod] 20 ? S< 0:00 [crypto] 27 ? S< 0:00 [kthrotld] 28 ? S< 0:00 [VCHIQ-0] 29 ? S< 0:00 [VCHIQr-0] 30 ? S< 0:00 [VCHIQs-0] 31 ? S< 0:00 [iscsi_eh] 32 ? S< 0:00 [dwc_otg] 33 ? S< 0:00 [DWC Notificatio] 35 ? S< 0:00 [deferwq] 36 ? S 0:00 [kworker/u:2] (中略) 32371 ? Ss 0:00 sshd: pi [priv]

停止したいプロセスのIDを見つけてkillコマンドでプロセスの停止を行います.

root@raspberrypi:/home/pi# kill -9 2875

プロセスの停止が出来たら管理者ユーザーからログアウトしておきましょう。

Raspberry piにshut downボタンを付ける

Raspberry piを停止する際はコンソールからshut downを行う必要が有ります.

pi@raspberrypi ~ $sudo halt

Raspberry piの仕様から端末に繋ぐことなくスタンドアロンで運用することも多いと思います.本体をちょっと移動したいとき電源を一時的に外さなくてはならないとき、いきなり電源をオフにしてしまえばSDメモリーカードの破損、破壊の恐れが出てきます.安全に電源を落とすためには確実にShut downを行わなければなりません。

そこでイーサネット越しにリモートログインしてshut downを行っても良いのですが、Raspberry pi単体でもShut down出来ないものかと。そこでここではGPIOの一つにshut downスイッチを設け、それを常に監視し、スイッチが押されたらShut Downシーケンスに入るものとします。

スイッチにaitendoで見つけたシートキーを使います.キーが4つ有りますのでシャットダウン以外にもそれぞれ機能を持たせる事ができます。
CIMG2384
Python用GPIOインストールしているものとして進めます.
インポートしているacm1602は外付けのLCDキャラクターディスプレイを制御するものです。
GPIOピンの22〜25にシートキーをプルダウン抵抗を介して接続しておきます。
いかサンプルコードを紹介します.


import time
import acm1602
import datetime
import subprocess
import RPi.GPIO as GPIO

def pushRedButtonLong():
        lcd.cls()
        lcd.putString("Shut Down?",0)
        lcd.putString("Y)Green,N)YellowL",1)
        while 1:
                if GPIO.input(pin_yellowBtnL) == 1 or GPIO.input(pin_yellowBtnR) == 1:
                        lcd.cls()
                        lcd.putString("Cancell",0)#LCDにshut downをキャンセルした事を表示
                        time.sleep(1)
                        return
                if GPIO.input(pin_greenBtn) == 1:
                        lcd.cls()
                        lcd.putString("sudo halt",0)#LCDにshut down処理を行っている事を表示
                        ret = subprocess.check_output(["sudo","halt"]);#システムにshut downを指示する
                        exit()
def pushRedButtonShort():
        lcd.cls()
        lcd.putString("Red Button",0)
        time.sleep(1)
def pushYellowButtonLeft():
        lcd.cls()
        lcd.putString("Yellow L Button",0)
        time.sleep(1)
def pushYellowButtonRight():
        lcd.cls()
        lcd.putString("Yellow R Button",0)
        time.sleep(1)
def pushGreenButton():
        lcd.cls()
        lcd.putString("Green Button",0)
        time.sleep(1)


print "start"
GPIO.setmode(GPIO.BCM)
pin_redBtn=25
GPIO.setup(pin_redBtn,GPIO.IN)
pin_yellowBtnL=24
GPIO.setup(pin_yellowBtnL,GPIO.IN)
pin_yellowBtnR=23
GPIO.setup(pin_yellowBtnR,GPIO.IN)
pin_greenBtn=22
GPIO.setup(pin_greenBtn,GPIO.IN)

lcd = acm1602.acm1602()
lcd.set_cursor('off')
try:
        redPushCount=0
        while 1:
                time.sleep(0.1)

               if GPIO.input(pin_redBtn) == 1:
                        redPushCount += 1
                        if redPushCount > 30:# 3秒長押し検出
                                pushRedButtonLong()
                                redPushCount = 0
                elif redPushCount > 0:
                        pushRedButtonShort() #短押しの場合
                        redPushCount = 0
                if GPIO.input(pin_yellowBtnL) == 1:
                        pushYellowButtonLeft()
                if GPIO.input(pin_yellowBtnR)==1:
                        pushYellowButtonRight()
                if GPIO.input(pin_greenBtn) == 1:
                        pushGreenButton()
except KeyboardInterrupt:
        print 'user terminated'
        GPIO.cleanup()

ここでは赤ボタンを長押ししたら、Shut downするかCancellするかどうかがLCDに表示されます.そこで緑ボタンを押せばShut down処理を始めます。
その他のキーの長押しはそのキーの名称をLCDに表示します.
ここまでで赤ボタン長押しし、そのあと緑ボタンを始めればShutDown処理に移行するようになりました。このようにユーザーの確認をワンクッション置く事で、間違ってShut downするのを防ぐことができます.
ここですぐに電源を抜いてしまうと、Shut down処理の途中ではSDメモリーカードにアクセスしていますので、アクセス中の電源断は運が悪ければSDカードの破損、再起動不能になってしまいます.
アクセスランプが消灯している事を確認してから電源を抜くようにしても良いのですが、筐体によってはボード上のLEDが見えない場合もあります。そこで接続してあるLCDにShut Down処理が完了したことを表示する事にします.

Raspberry pi(Raspbian)ではシャットダウン時に行うスクリプトを書くことができます.
/etc/default/halt
を編集してください.

# Default behaviour of shutdown -h / halt. Set to "halt" or "poweroff".
HALT=poweroff
/home/pi/shutDownLCD.py
/etc/default/halt

ここでは上のようにしました。ユーザーディレクトリに”shutDownLCD.py”というスクリプトを置いてます.これは単純にLCDに”Shut down”しましたよ〜という表示を行うだけのものです.LCDに表示する代わりに終了の音楽をならしても良いしLEDを明滅しても良いですし、ご自身の環境や趣味に合わせてスクリプトを用意してください.
厳密には電源を落としても大丈夫な状態になるのはここで指定したスクリプトが終わってからひと呼吸おいた後になるのですが、電源断のある程度の目安になる事でしょう.

今回は外部表示装置としてLCDキャラクターディスプレイACM1602を使いました。I2CインターフェイスをもつこのLCDはRaspberry piと接続したところ、ちょっと使いこなしが難しい点も幾つか見つかりました。(詳細は別記事にて)
I2Cインターフェイス基板LCD付きを使えばもっと簡単にLCDを制御できる事でしょう。

動体検出にPIRセンサーを

動体検出には幾つかの方法が有ります。まずカメラ画像の中から動いている物体を検出するものがあります。これは人でも車でもカメラが見ることのできる動いているものを検出します.カメラの性能にも依存しますので例えば暗い時のようにカメラの映像にノイズが入ってしまう場合にはご検出を頻繁に起こしてしまうでしょう。

赤外線の変化を検出して動体検出とするものが有り、これが焦電センサーまたはPIRセンサーで行うことができます。防犯ライトなどにも多く使われている一般的なセンサーです.人間や動物など熱を持つ物体は赤外線を放出しており、その赤外線をセンサーが検出します.赤外線の検出値に変化が有れば何らかの物体が動いたという事でセンサーからの出力を行います.カメラのように画像によることがありませんので暗闇でも検出することができます.一方風なども物体と捉える事が出来るため、風の強い日はその赤外線の変化さえも検出してしまいます.

ここでは安価に入手できるPIRセンサーを紹介します.
CIMG2383
PIR センサー A708-1H
AITENDOで購入
仕様概要:動作電圧0.8-8v、 出力電圧 h:3.3 l:0v、 検出距離5-7m
参考にRaspberry piで接続する場合の例を紹介します.
必要な回路部品はすべてセンサーモジュールに実装されています.接続はPIRの出力をRaspberry piのいずれかのGPIOにつなげるだけです.

スクリーンショット 2013-12-15 13.06.30
あえて書くまでもないかもしれませんが、一応サンプルコードを紹介します.
PythonのGPIOはインストールしている前提です.


#!/usr/bin/python3
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
io_pin=17
GPIO.setup(io_pin,GPIO.IN)
while True:
        gp17=GPIO.input(io_pin)
        if gp17 == 1:
                print ("Move!");
        else:
                print("No move");
        time.sleep(1)

電源電圧が3.3VであるRaspberry piはGPIOの入力電圧も電源電圧を超えないものとしなければなりません。このPIRセンサーの出力は3.3Vという事でそのまま接続できますので大変便利ですね。

IOError: [Errno 5] Input/output error

Raspberry piでデバイスとI2C通信をしている時に
IOError: [Errno 5] Input/output error
に出会う時が有ります.基本的な設定が済んでいるものとして、このようなエラーが出る場合はいくつかの原因が考えられます。

1)信号線が長い、ノイズの影響を受けているなどで、信号そのものの波形が劣化している場合

 この場合は具体的にはオシロスコープを使って波形を確認した方が良いでしょう。オシロスコープが無い場合は信号線を出来るだけ短くすること、プルアップ抵抗が適切なものが入っているか確認する事と通信スピードを落としてみるのも有効です。

2)相手が準備できていないのにコマンドを送っている、データをリクエストしている場合
 コマンドを送る前にWaitを入れることになります.デバイスによってはコマンドを受け付けた後にいくら処理に時間がかかってそのあとにリクエストを受け付けると言ったシーケンスを明記しているものも有ります。詳しくはそれぞれのデバイスのリファレンスを参照の上で最適化するようにします。

3)初期化シーケンスをコマンド送信ごとに送ってしまっている
 本来であればSPI通信を始める場合の初期化処理は一度で良いのですが、スクリプトになっていとそれを外から呼び出した時に何度も短い間隔で呼び出して気づかない事も有ります。初期化は誰がやっているか、どのタイミングでやっているか確認し、スクリプトの最適化を行います.