PCA9685 +RaspberryPi Zeroでサーボモータを動かす

準備

用意したもの

複数のサーボモータを動かせるように、サーボモータ制御ボード(PCA9685搭載)と小型サーボモータ(MG90S互換品)をAliexpressで購入しました。

RaspberryPiZeroW

品薄が続いているようで少し高いですが、それでも2500円程度なので一つ購入しました。

MG90S

まずは小型かつ安価にロボットを作りたいので、MG90を購入しました。

Aliexpressだと1個350円程度で互換品を購入することができます。
※安い分不良品が多少含まれてます....
https://ja.aliexpress.com/item/32840704368.html?spm=a2g0s.9042311.0.0.1b6c4c4dfkxLhk

  • PCA9685

こちらもサーボモータと一緒にAliexpressで100円くらいで購入しましたが、日本のアマゾンでも比較的安価で購入できます。


RaspberryPiの事前設定

raspi-configでI2C有効化

"sudo raspi-config"を実行して、I2Cを有効化する。

f:id:da-yamax:20200523194823p:plain:w300
raspi-configでi2c有効化

I2c通信速度設定

以下を実行して、I2C通信速度を設定する。

$ sudo su
$ echo "dtparam=i2c_baudrate=10000" >> /boot/config.txt
$ reboot 

ライブラリインストール

Adafruit Python PCA9685のサンプルを参考に進めます。
https://github.com/adafruit/Adafruit_Python_PCA9685

pipでのインストールがお手軽ですが、サンプルコードがインストールされないため下記手順でインストールしました。

$sudo apt-get install git build-essential python3-dev python3-pip
$cd ~
$git clone https://github.com/adafruit/Adafruit_Python_PCA9685.git
$cd Adafruit_Python_PCA9685
$sudo python3 setup.py install

PCA9685接続実施

接続構成

PCA9685をRaspberryPiのGPIOに接続します。
製品によってピン配置が微妙に違うので基板に記載されたピン配置の確認が必要です。

Raspbery PiのGPIOピン配置

GPIOのピン配置は以下の図の通りです。
RaspberyPiZeroも同じ配置ですので、以下に従ってPCA9685と接続します。
https://www.raspberrypi.org/documentation/usage/gpio/images/GPIO-Pinout-Diagram-2.png
https://www.raspberrypi.orgより引用

PCA9685の配線

以下のように接続します。
V+ 未接続
VCC ⇔ Pin2 (5V)
SDA ⇔ Pin3 (SDA)
SCL ⇔ Pin5 (SCL)
OE  未接続
GND ⇔ Pin6 (GND)

f:id:da-yamax:20200523193928p:plain
PCA9685とRaspberryPiの配線


接続確認

PCA9685接続後にi2c動作確認

$ 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 -- -- -- -- -- -- --

PCA9685での制御の基本

PCA9685でのPWM制御は以下の関数で実施する。

set_pwm_freq(周波数Hz)
set_pwm(チャンネル番号, パルスのスタート, パルスの終了)
  • チャンネル番号:PCA9685は複数のサーボモーターを接続できるため、動かしたいサーボモーターのチャンネルを指定します。
  • パルス:パルスは4096stepで周波数は24Hz-1526Hzの間でサーボモータの仕様に合わせて設定します。
    • MG90やSG90は"周波数50or60hz""パルス150~650"で設定するようです。
    • ※メーカーのデータシートを見てもなぜこの値なのか不明でした....

動作確認

以下のソースコードサーボモータを0~180度で動かします。

servo.py
import Adafruit_PCA9685
import time

#サーボモーターをコントロールするためのクラス
class servo:
    PULSE_MIN = 150     # パルス最小値(若干の個体差分あり)
    PULSE_MAX = 650     # パルス最大値(若干の個体差分あり)
    MAX_ANGLE = 180     # サーボモータの最大角度
    def __init__(self, Channel):
        self.Channel = Channel
        self.pwm = Adafruit_PCA9685.PCA9685(0x40)
        self.pwm.set_pwm_freq(60)

    def setPos(self,pos):
        # PLUSE_MIN~PULSE_MAXの値が 0 度 ~ MAX_ANGLE度に対応するため、
        # 指定した角度になるようにパルスを計算する
        pulse = int((self.PULSE_MAX - self.PULSE_MIN) / self.MAX_ANGLE * pos + self.PULSE_MIN)
        self.pwm.set_pwm(self.Channel, 0, pulse)

pos = 0
s = servo(0)
s.setPos(0)

while True:
    # 2秒間隔で0~90~180度を繰り返す
    # 設定した角度にならない場合は、PULSE_MIN、PLUSE_MAX、MAX_ANGLEが間違っている
    time.sleep(2)
    s.setPos(pos)
    pos += 90
    if (pos > 180):
        pos = 0
実行

コードを実行すると、サーボモータが1秒おきに動作する。

$sudo python3 servo.py

f:id:da-yamax:20200523200750g:plain

トラブルシューティング

問題:コード実行時に以下のエラーが発生して実行できなかった。
原因:VCCの配線が抜けていた。
PCA9685ボードの外部電源を接続していたが、それでもVCC接続は必要な模様

Traceback (most recent call last):
  File "servo.py", line 4, in <module>
    pwm = Adafruit_PCA9685.PCA9685()
  File "/usr/local/lib/python3.7/dist-packages/Adafruit_PCA9685-1.0.1-py3.7.egg/Adafruit_PCA9685/PCA9685.py", line 77, in __init__
  File "/usr/local/lib/python3.7/dist-packages/Adafruit_GPIO-1.0.4-py3.7.egg/Adafruit_GPIO/I2C.py", line 116, in write8
  File "/usr/local/lib/python3.7/dist-packages/Adafruit_PureIO-1.1.5-py3.7.egg/Adafruit_PureIO/smbus.py", line 322, in write_byte_data
OSError: [Errno 121] Remote I/O error

まとめ

PCA9685を使ってRaspberryPiでサーボモーターを動かしてみました。
Adeept DarkPowでもPCA9685を利用してロボットを動かしていましたが、ラッパーが定義されていたのでPCA9685の動きを理解して、複数のサーボモータをいい感じに動かす方法を考える必要がありそうです。