Raspiで使ったセンサ/アクチュエータと制御プログラムのまとめ 

約１年前に買って放置していたRaspberryPiで遊んだので、使ったセンサ/アクチュエータと制御プログラムをまとめます。

使用したコードはgithubに登録しています。
https://github.com/aratakokubun/RaspiBot.git
実装はpythonと一部shellで書いています。

## Raspiでのプログラム概要

Twitterから操作を送信し、外部からセンサ情報を取得・アクチュエータを駆動するプログラを実装しています。
機能は以下の通り

- カメラキャプチャ
- カメラの首振り
- エアコンのON/OFF
- パソコンに設置した超音波測距センサの現在・ログのグラフ取得(基本的には自分とパソコン画面との距離)
- 湿温度センサの現在・ログのグラフ取得

## サーボモータ

### アクチュエータ概要
- GWS S03T
- 指定した角度に回転する、ごく普通のサーボモータ
- 値段 ¥1200 (秋月購入)
- 5V, GND, 制御端子の３端子

### 用途
Twitterから角度を指定して指令を送り、搭載したwebカメラの角度を変える

### 実装
RaspberryPiのピン入出力制御ライブラリのRPi.GPIOを使用しています。
参考文献1のページを参考に実装しました。
以下処理の抜粋

- 初期化

```py3
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
# サーボのGPIOピン番号を23に設定
SERVO_GPIO = 23
GPIO.setup(SERVO_GPIO, GPIO.OUT)
# 動作周波数は50Hz
HZ = 50
servo = GPIO.PWM(SERVO_GPIO, HZ)
servo.start(0.0)
```


- 角度を指定して制御

`ChangeDutyCycle`メソッドで制御するが、動作範囲は`2.0 - 12.0`で`0° - 180°`に対応する。

```py3
dc = 2.0 + 10.0 * float(angle/180)
servo.ChangeDutyCycle(dc)
# Wait while finishing servo
time.sleep(0.5)
```


- プログラム終了

GPIOをcleanupしてから終了します。

```py3
GPIO.cleanup(SERVO_GPIO)
```

## 赤外線LED(送信・受信)

### センサ・アクチュエータ概要

受信モジュール

- 赤外線リモコン受信モジュール　ＧＰ１ＵＸＣ４１ＱＳ
- 値段 ? (元から持ってた)
- 5V, GND, 制御端子の３端子で回路は単純

送信モジュール

- 赤外線ＬＥＤ　ＯＳＩ５ＦＵ５１１１
- 値段 ? (元から持ってた)
- GND, 制御端子の2端子

### 用途
リモコンの信号を取得し、同じ信号を赤外線LEDで送信

### 実装
Linux用の赤外線モジュール制御のライブラリであるlircを使用しました。
参考文献2のページを参考に実装しました。

- lircでのリモコンの信号取得と発信する信号の設定
lircの設定方法は参考文献2を参照してください。ここでは割愛します。
簡単には以下の設定を行います。(全てroot権限が必要)
    1. `/etc/lirc/hardware.conf`の設定を変更する。
    2. `/boot/config.txt`の設定を変更し、起動時にLIRCを有効にする。
    3. `mode2 -d /dev/lirc0(hardware.confに設定した名称)`コマンドでlircを起動し、リモコンの信号を赤外線受信モジュールに送信した際にデータが取れることを確認する。
    4. 3のコマンドで取得したデータをデータ送信用のコマンド定義と共に`/etc/lirc/lircd.conf`に追記する。
    5. `/etc/init.d/lirc start`でlircを起動
    6. `irsend SEND_ONCE <コマンド>`でデータが送信できることを確認

- 初期化
初期化用のshellを用意しておき、pythonから初期化時に呼び出します。

```shell-session:initLirc.sh
sudo /etc/init.d/lirc stop
sudo /etc/init.d/lirc start
```
```py3
from subprocess import call
INIT_CMD = "sudo bash ./src/initLirc.sh"
call(INIT_CMD.strip().split(" "))
```


- エアコン制御<br>

```py3
from subprocess import call
ON_CMD = "sudo irsend SEND_ONCE aircon cooler_on"
OFF_CMD = "sudo irsend SEND_ONCE aircon cooler_on"

call(ON_CMD.strip().split(" "))
call(OFF_CMD.strip().split(" "))
```

- プログラム終了<br>

```shell-session:stopLirc.sh
sudo /etc/init.d/lirc stop
```
```py3
from subprocess import call
STOP_CMD = "sudo bash ./src/stopLirc.sh"
call(STOP_CMD.strip().split(" "))
```


## 測距センサ

### センサ概要
- HC-SR04
- 超音の反射時間を利用して非接触で測距するセンサモジュール
- 2-180cmまで測距可能
- 値段 ¥400 (秋月購入)
- 5V, GND, ECHO, TRIGGERの4端子

### 用途
パソコンに設置し、自分がパソコンに向き合ってる時の距離を測定

### 実装
こちらもRaspberryPiのピン入出力制御ライブラリのRPi.GPIOを使用しています。

- 初期化

```py3
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
# TRIGGERのGPIOを17, ECHOのGPIOを27に設定
TRIG_GPIO = 17
ECHO_GPIO = 27
# TRIGGERは出力ピン、ECHOは入力ピンに設定
GPIO.setup(TRIG_GPIO, GPIO.OUT)
GPIO.setup(ECHO_GPIO, GPIO.IN)
# TRIGGERを0Vに設定
GPIO.output(TRIG_GPIO, GPIO.LOW)
```


- 測定

```py3
GPIO.output(TRIG_GPIO, True)
time.sleep(0.00001)
GPIO.output(TRIG_GPIO, False)

while GPIO.input(ECHO_GPIO) == 0:
  signaloff = time.time()
while GPIO.input(ECHO_GPIO) == 1:
  signalon = time.time()
return (signalon - signal off) * 17000
```


- プログラム終了

GPIOをcleanupしてから終了します。

```py3
GPIO.cleanup(TRIG_GPIO)
GPIO.cleanup(ECHO_GPIO)
```


## 湿温度センサ

### センサ概要

- DHT11
- 温度を1度単位・湿度を1%単位で計測可能
- 温度精度±2度・湿度精度±5%と精度は微妙
- 取得に失敗することもあり、動作も不安定
- 値段 ¥490 (amazon購入)
- 5V, GND, 入出力の4端子

### 用途
部屋の湿温度の現在値とログを取得

### 実装
RaspberryPiからDHT11の温度／湿度を取得する為のプログラムがgithubに公開されていたので、これを利用
https://github.com/adafruit/Adafruit_Python_DHT

- 初期化

```py3
import Adafruit_DHT
# DHTのGPIOを18番に設定
DHT_GPIO = 18
# センサを指定
sensor = Adafruit_DHT.DHT11
```


- 測定
1回だと失敗する可能性があるので、3回リトライしています。

```py3
MAX_TRIAL = 3
for _ in range(self.MAX_TRIAL):
  humidity, temperature =  Adafruit_DHT.read_retry(sensor, DHT_GPIO)
  if humidity is None and temperature is None:
    continue
  return [humidity, temperature]
```


- プログラム終了

特に終了時に処理をする必要はなさそうです。


## その他

- Twitterでのコマンド送受信
TwitterStreamingAPIを使用し、特定のメッセージを監視しています。

- 各センサの終了時の処理
atexitパッケージで終了処理のハンドラを登録していますが、クラスの__del__メソッドでもいい気がします・・・


## 参考文献
1. RaspberryPiでのサーボ制御<br> http://windvoice.hatenablog.jp/entry/2015/05/04/180110
2. Raspberry Pi 2 でエアコン操作（赤外線リモコン編）<br>
http://kaiware007.hatenablog.jp/entry/2015/08/28/020356
3. Raspberry Piに超音波距離計”HC-SR04”つけてみた<br>
http://arkouji.cocolog-nifty.com/blog/2014/05/raspberry-pihc-.html
4. 温湿度センサDHT11をRaspberryPiに接続しグラフ表示<br>
http://blog.bnikka.com/raspberrypi/dht11-raspberrypi.html