PCA9685で複数サーボモーターをコントロール

#はじめに
ロボットアーム的なものを自作してみたかったのでサーボドライバーPCA9685を使って作ってみました。試作も試作なのでスーパー荒削りかつ生産終了のサーボモーターを使用しているため参考にならない気もします。
<img width="240" alt="arm.png" src="https://qiita-image-store.s3.amazonaws.com/0/236295/1255617d-1621-5991-bab1-6ff949a2f777.png">


#もろもろの構成
1.Raspbianが入ったRaspberryPi3

2.サーボモーター×4(VIGOR VS-2)
メルカリで4個セット1500円で手に入りました

3.PCA9685
サーボモーターを最大16個まで動かせるドライバーです。amazonだと680円ですぐに購入できます。
[HiLetgo PCA9685 16チャンネル 12-ビット](https://www.amazon.co.jp/HiLetgo-PCA9685-16%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB-12-%E3%83%93%E3%83%83%E3%83%88-Arduino%E3%81%AB%E5%AF%BE%E5%BF%9C/dp/B01D1D0CX2/ref=sr_1_1?ie=UTF8&qid=1533394503&sr=8-1&keywords=pca9685)

4.外部電源
PCA9685の外部電源として充電池(1.2v)を直列に4つなので4.8vを入れてます。RaspberryPiからの5Vだけでも良いのですが、念の為です。

5.ジャンパーワイヤー
これは工作するときには必須ですね。たくさんあるといいと思います。
[HiLetgo® 6個セット 2*120本 3種類 オスーオス メスーメス オス ーメス](https://www.amazon.co.jp/gp/product/B074DWCDNG/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)

6.サーボ同士をつけるための土台
これは3Dプリンターで作成しました。

#配線①〜③
①RaspberryPi側
左から黒(GND)・一個飛ばして緑(GPIO:SCL)・白（GPIO:SDA)・赤(3.3V)
<img width="320" alt="raspberrypi.png" src="https://qiita-image-store.s3.amazonaws.com/0/236295/b783a55e-32a1-fb41-922b-087f5a9cde70.png">

②PCA9685側
黒(GND)・一個飛ばして緑(SCL)・白（SDA)・赤(Vcc)に挿してください。
サーボモーターのピンをチャンネル0~2並べて挿してください。
※メルカリで4個買ったのですが1個ギアが壊れていたものがあったので修理するまでは3個です。
<img width="200" alt="PCA9685_1.png" src="https://qiita-image-store.s3.amazonaws.com/0/236295/a9a6931a-01df-7cea-e3dc-2164f344d2a7.png">

③外部電源
<img width="240" alt="battery.png" src="https://qiita-image-store.s3.amazonaws.com/0/236295/6e49b80c-2a38-f538-f6f2-92bfbd09ee20.png">

配線は以上です。

#RaspberryPiとドライバーのセットアップ
この方がわかりやすく記事を書いてくれているのでこちらを参考にコマンドで動作確認まで行ってください。
[Raspberry Pi 3でPCA9685を使う](https://qiita.com/ttyokoyama/items/935b51128d2d5bb26f15)

```bash:コマンド
pi@raspberry:~ $sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: 70 -- -- -- -- -- -- -- 
```
0の行に40とか70みたいに表示されていれば大丈夫です。
されていない場合は配線ミスの可能性があります。

#pythonで各々のサーボモーターを制御
以下のコードで簡単に動かしてみます。
こちらはこの方のコードを参考にさせてもらっています。
[Hobby robot laboratory](https://sites.google.com/site/memorandumjavaandalgorithm/raspberry-pi-jiang-zuo9-pwmkontorora-pca9685)
できるだけ初心者でも分かるように注釈過多ぎみです。

```python:servo_test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Adafruit_PCA9685
import time

#サーボモーターをコントロールするためのクラス
class servo_Class:
    #ChannelはPCA9685のサーボモーターを繋いだチャンネル
    #ZeroOffsetはサーボモーターの基準の位置を調節するためのパラメーターです
    def __init__(self, Channel, ZeroOffset):
        self.Channel = Channel
        self.ZeroOffset = ZeroOffset

        #Adafruit_PCA9685の初期化
        self.pwm = Adafruit_PCA9685.PCA9685(address=0x40)
        self.pwm.set_pwm_freq(60)

    """角度を設定する関数です"""
    def SetPos(self,pos):
        #pulse = 150～650 : 0 ～ 180度
        #PCA9685はパルスで角度を制御しているため0~180のように角度を指定しても思った角度にはなりません
        #そこで角度の値からパルスの値へと変換します。PCA9685ではパルス150~650が角度の0~180に対応しているみたいです
        #下の式の(650-150)/180は1度あたりのパルスを表しています
        #それにpos(制御したい角度)を掛けた後、150を足すことでことで角度をパルスに直しています。
        #最後にZeroOffsetを足すことで基準にしたい位置に補正します
        pulse = (650-150)/180*pos+150+self.ZeroOffset
        self.pwm.set_pwm(self.Channel, 0, pulse)


"""制御を行うメインの部分です"""
if __name__ == '__main__':
    #今回はサーボモーターが3つあります
    Servo0 = servo_Class(Channel=0, ZeroOffset=-5)
    Servo1 = servo_Class(Channel=1, ZeroOffset=-5)
    Servo2 = servo_Class(Channel=2, ZeroOffset=-5)

    try:
        #テストでそれぞれのサーボモーターを45度,90度と繰り返し動かしてみます。
        while True:
            print '45'
            Servo0.SetPos(45)
            time.sleep(2)
            Servo1.SetPos(45)
            time.sleep(2)
            Servo2.SetPos(45)
            time.sleep(2)

            print '90'
            Servo0.SetPos(90)
            time.sleep(2)
            Servo1.SetPos(90)
            time.sleep(2)
            Servo2.SetPos(90)
            time.sleep(2)

    except KeyboardInterrupt  :         #Ctl+Cが押されたらループを終了
        print("\nCtl+C")
    except Exception as e:
        print(str(e))
```
スクリプトを好きなところに保存し、保存したディレクトリで以下のコマンドを実行

```bash:コマンド
pi@raspberry:~ $python servo_test.py
45
90
45
90
45
90
#Ctl+cを押すと止まります
```
#終わりに
ここまででPCA9685の簡単な使い方を紹介してきました。
気が向いたらもう少し応用的なプログラムを載せたいと思います。

#参考サイト
・https://qiita.com/ttyokoyama/items/935b51128d2d5bb26f15
・https://sites.google.com/site/memorandumjavaandalgorithm/raspberry-pi-jiang-zuo9-pwmkontorora-pca9685
・https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf