RaspberryPiを初めて触ってみたので、サーボモーターとPIRセンサーを動かしてみる

この記事は フリュー Advent Calendar 2022 の12日目の記事となります。
前日の11日目は@m_kazu_mさんの[Tableauを使ってドット絵を書いてみた](https://qiita.com/m_kazu_m/items/402034b728bc26a5f0f8)記事だったのですが、分析ツールで絵を描くというユニークな発想にとても面白いなと思いました。
ぜひそちらの記事もご覧になってくださると嬉しいです。

# 1.はじめに
フリュー株式会社でiOSアプリエンジニアをしている里形です。新卒1年目で、毎日学びが多いなぁと思いながらモバイルアプリ開発に携わっています。

普段はiOSのアプリ開発を行なっているため、「たまにはスマホと関係のないことを勉強したいなぁ」と思い、なんとなくRaspberryPiを触ってみることにしました。
組み込み系のことは学生時代の実験ぶりで何も覚えていなかったため、初歩的な実装を行なって実験しました。
この記事は**ラズパイをMacで操作する設定**と**PIRセンサーとサーボモーターを動かす方法**を紹介します。

### 成果物
PIRセンサーが動きを検知するとサーボモーターが動作します。
![IMG_2774.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989508/7d8b3a2d-f624-955b-0d15-d473b8dbb57b.gif)


### 本記事で使用しているもの
- RaspberryPI Zero 2W（GPIOピンを取り付ける必要があります）
- ミニスタジオ MiniS Servo RB90
- SparkFun PIRモーションセンサー


# 2.ラズパイをMacで動かしてみる
使用したラズパイは電源とHDMIケーブルとキーボード類を接続してあげることで、PCと独立した状態でGUIを使いながら開発してあげることができます。
しかし、いちいちモニターやキーボードなどを接続して立ち上げるのはそこそこ手間に感じます。（個人差があります）
なので、MacBookに接続して操作することができれば、かなり接続する手間が省けたり、モニターに縛られず自由な場所でGUIを使った実装をすることができるようになります。
ラズパイにはデフォルトでReal VNCというものが導入されており、これを使えばリモート接続して操作することができるようになります。

### VNCサーバーの設定
デフォルトのVNCサーバーの設定では、認証の問題でReal VNCを使ってMacとリモート接続することができないみたいです。
なので、まずはラズパイをモニターに繋げた状態で立ち上げて、Menu Barの右側にあるReal VNCを起動します。
起動したら、右上のハンバーガーメニューからoptionsを選択して設定画面に入ってください。
Seculityの項目のEncryptionをPreffer offに、AuthentificationをVNC passwordに変更してください。VNC passwordを選択すると、VNC passwordの設定画面が開くと思うので、任意のパスワードを設定してください。
もしパスワードの設定画面が開かなかった場合は、左のUsers & Permissionsの項目を選択して、接続したいユーザー名をダブルクリックしてパスワードを設定してください。
![スクリーンショット 2022-12-10 0.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989508/32b8e57d-fc3b-f4c5-65ae-b67da508492d.png)
全ての設定を適用したら準備完了です。
最後に、Real VNCの最初の画面のConnectivityの下に記載されているアドレスをメモしてください。（192.xxx.xx.xといった形式で表示されているもの）


### Mac側の操作
MacのFinderを開いてControl+kで接続するサーバーを選択できます。
接続先は”vnc:アドレス:5900”と入力してください。アドレスには先ほどメモしたアドレスを入れてください。末尾の":5900"はラズパイのIPアドレスの指定になります。
接続を選択すると、パスワードを入力するように求められるので、先ほど設定したパスワードを入力してください。
接続が成功したらMacの画面共有が起動してラズパイの画面が表示されます。
![スクリーンショット 2022-12-11 0.27.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989508/7bb681fa-40f2-354a-6bd4-a00c68dcec30.png)

# 3.サーボモーターを動かしてみる
使用しているサーボモーターには茶色・赤・黄色の3本のワイヤがあります。
それぞれの役割は`茶色->GND
赤->5V+
黄色->INPUT`になっています。
ラズパイへの配線は`茶色->6番（GND）
赤->2番（5V電源）
黄色->10番（GPIO 18）`に接続しています。
（接続先は[ラズパイ公式ドキュメント](https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header)のGPIOの配置を参照してください）
サーボモーターのINPUTをGPIO 18に接続している理由としては、制御にPWMを使うコードを用いているためです。（実験してみたらPWM非対応のGPIOでも一応動作はしていた）

次に、制御用のコードを記述します。
```
import pigpio
import time

SERVO_PIN = 18

pi = pigpiod.pi()

while True:
    pi.set_servo_pulsewidth(SERVO_PIN, 1500)
    time.sleep(1)

    pi.set_servo_pulsewidth(SERVO_PIN, 500)
    time.sleep(1)
```
まず最初にimportされているpigpioですが、これは入出力を制御できるようにする、ラズパイ用のライブラリです。これを用いることで、サーボモーターなどを手軽に制御できるようになります。これを導入するにはpigpiodというpigpioライブラリをデーモンとして起動するユーティリティを使用する必要があります。（使い方に関しては後ほど解説）
そのpigpiodのpi()というメソッドを変数piに割り当てています。
`pi.set_servo_pulsewidth(SERVO_PIN, 1500)`はSERVO_PINに割り当てられたGPIOピンに指定した数値の分だけサーボモーターを動かす信号を送ります。
サーボモーターを動かすメソッドを1500と500で2つ実装しているのは、数値の角度になるように信号を送っているようなので、片方だけの信号を送ると見た目上動作していないように見えるためです。
また、間に`time.sleep(5)`を置いているのは、連続して信号を送ると信号がつながってしまい、サーボモーターに意図しない信号が送られてうまく動作しなくなるためです。
最後の準備として、pigpioライブラリを使うために、ターミナルで`sudo pigpiod`を実行します。これを実行することで、pigpioライブラリを使用できるようになります。実行時にはメッセージ等表示されませんが、エラー表示がなければpigpiodを起動することはできています。


この制御用コードを実行すると、サーボモーターが右回りと左回りに交互に動作します。


# 4.PIRモーションセンサーを動かしてみる
PIRモーションセンサーとは、赤外線を用いたセンサーです。使用しているPIRモーションセンサーは、電源を入れて1,2秒後にものの配置を記憶して、赤外線で検知できるものが動くとアラーム信号を送ってくれます。
使用しているPIRセンサーには赤・白・黒の3本のワイヤがあります。
それぞれの役割は`赤->5V+
白->GND
黒->アラーム`になっています。
ラズパイへの配線は`赤->4番（5V電源）
白->14番（GND）
黒->32番（GPIO 12）`に接続しています。
次に、制御用のコードを記述します。
```
import time
import RPi.GPIO as GPIO

PIR_PIN = 12
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR_PIN, GPIO.IN)

cnt = 0

while True:
    if (GPIO.inpit(PIR_PIN) == GPIO.HIGH):
        print("きたでな")
        time.sleep(5)
    else:
        cnt+=1
        print("きてないでな" + str(cnt))
        time.sleep(1)
```
インポートしているRPi.GPIOはPythonでラズパイのGPIOを制御するためのライブラリです。
`GPIO.setmode(GPIO.BCM)`はGPIOのピンの指定方法のセットになります。GPIO.BCMはGPIOの数字で指定する設定になります。ここをGPIO.BOARDにすることで、ピン番号で指定することができます。
`GPIO.setup(PIR_PIN, GPIO.IN)`は指定したピンを入力に指定することができます。GPIO.OUTをパラメータにすることで、出力に指定することもできます。
`if (GPIO.inpit(PIR_PIN) == GPIO.HIGH):`では、指定したGPIO信号がHIGHになったときに処理を行うようにしています。つまり、PIRセンサーからアラート信号が来た時にif文の中身を実行します。
この制御コードを実行した結果のスクリーンショットは以下のものになります。
![スクリーンショット 2022-12-10 22.21.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989508/f212e021-72b1-e152-6902-3aef6e766cb0.png)
PIRセンサーからアラート信号が送られてくるとif文が実行され、`きたでな`をターミナルに出力します。また、信号が来ない間は`きてないでな[数字]`が出力されます。


# 5.PIRセンサーの入力を受け取ったらモーターを動かすようにしてみる
これまでのコードを組み合わせて、PIRセンサーで動作を検知したらサーボモーターを動かすようにしてみましょう。
```
import pigpio
import time
import RPi.GPIO as GPIO

SERVO_PIN = 18
PIR_PIN = 12

pi = pigpiod.pi()

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR_PIN, GPIO.IN)

cnt = 0

while True:
    if (GPIO.inpit(PIR_PIN) == GPIO.HIGH):
        print("きたでな")
        pi.set_servo_pulsewidth(SERVO_PIN, 1500)
        time.sleep(1)
        pi.set_servo_pulsewidth(SERVO_PIN, 500)
        time.sleep(5)
    else:
        cnt += 1
        print("きてないでな" + str(cnt))
        time.sleep(1)
```
こちらの制御コードでは、PIRセンサーから信号が送られるとコンソールに`きたでな`を表示し、サーボモーターを2回動かすコードになっています。また、信号が来ない間はコンソールに`きてないでな[数字]`を表示します。


# 6.この実験を通して起こった問題と解決策
### サーボモーターに送る信号が1つだけだとサーボモーターがうまく動かない
3の項目でも説明しましたが、サーボモーターは入力された信号の位置（角度）に動くようになるようです。最初は指定した数値の分だけ回転するものだと思っていため、一度モーターが動いた後は動作音はしていても回転しなかったため、非常に悩みました。
サーボモーターを一定の場所に何度も動かす動作をさせる場合は、元の位置に戻すような処理を挟んであげる必要があります。

### モーターを動かすとラズパイが落ちる
最初はMacからラズパイに給電をして実験をしていたのですが、モーターが一度動くとラズパイが落ちてしまいました。
原因としてはラズパイとモーターを同時に動かすだけの給電がMacからはできないようで、5V2Aのモバイルバッテリーを電源として接続してあげることで解決しました。（しかし、これがまた別の問題を起こしました）

### PIRセンサーがうまく動作しない
モバイルバッテリーで給電した状態でPIRセンサーを動作させたところ、ごく稀にしか検知信号を送って来ませんでした。センサーを撫でるような動きをしてやっとたまに動くレベルで、安定的な動作をしませんでした。
原因としては、モバイルバッテリーを電源として用いたことが原因と考えられます。ラズパイに付属の電源は5.1V3Aのもので、使用したモバイルバッテリーはV数A数ともに若干足りてません（このレベルで動作に影響が出るのかはわかりませんが...）。ラズパイ付属の電源ケーブルを接続することでいくらか検知動作はマシになりました。（完全解決はしなかった）

### [未解決]PIRセンサーの検知精度が悪い
PIRセンサーの動作は比較的安定したものの、動いている時に検知しなかったり、動いていない時に検知をするなど、実用的ではない動作をしています。
これに関しては、今回は解決することができませんでした。
PIRセンサーの販売ページなどでは、`起動から1秒から2秒で物体の位置を記憶します`と書かれていることや、他の記事によると`PIRセンサーの性質として、通電から50秒から60秒程度の時間を置かないと動作が安定しない`などの環境的な要因があるようです。
これらの条件を満たした状態で制御コードを実装してみると、満たしていない状態よりも安定したように見えますが、やはり実用的なレベルでの動作はできませんでした。

# 7.最後に
見切り発車でラズパイを触ってみたのですが、Macでラズパイを使って実験をすることができました。
もし少しでもラズパイに興味を持っていただけたら、これらの制御コードなどを参考にサーボモーターやセンサーなどを動かしてみてください。


-------------

おまけの宣伝ですが、先日SPAJAM2022にてチーム日本列島のメンバーとして本選に参加させていただきました。引っ込み思案な性格なので、これまでなかなか技術的なイベントに参加することができなかったのですが、会社全体としてハッカソンやアドベントカレンダーへの参加に協力的にサポートしてくださるので、（楽しいなぁ）と思いながら参加できるようになりました。
こういったイベントに参加すると、知見が広まったり新しい交流が生まれたりするので非常に楽しい経験ができるなと思っています。
参加したいけどなかなか参加できないなと思っている方がいらっしゃったら、ぜひ参加してみると案外楽しいことがあるかもしれません。もしそういった機会にお会いすることがあったらよろしくお願いします。