概要
Raspberry Pi4、Ubuntu22.04LTS、PCA9685、Python、ROS2 Humbleでサーボモーターを廻したい。
※ChatGPTで、「優秀なロボティクス講師」としてロールプレイして頂いた記録。
PCA9685とは
16チャンネルのPWM(パルス幅変調)信号を生成できるI2Cベースのチップ。
このチップは、複数のサーボモーターやLEDを制御するのに非常に便利で、1つのI2Cバスに最大62個の
PCA9685を接続することで最大992個のPWM信号を制御できる。
PWM(パルス幅)とは?
- 電気信号のオン/オフを繰り返す方法。このオン/オフの割合(パルス幅)を変えることで、
出力される電力やモーターの速度、LEDの明るさなどを調整することができる。 - 例えるなら、蛇口の開け閉め。
水を完全に出す(オン)、完全に止める(オフ)を繰り返し、その割合を変えることで、
平均的に流れる水の量を調整するイメージ。
16チャンネルのPWMとは?
PCA9685は、このPWM信号を16個同時に制御できるチップ。
- 16チャンネル = 16個の制御できる「蛇口」があると考えることができる。
- 各チャンネル(蛇口)にサーボモーターやLDEを接続し、それぞれの「蛇口」を独立して開け閉めできるのが
16チャンネルPWMの特徴。
具体的な使い方
例えば、ロボットを作っているとして、複数のサーボモーターを使って関節を動かす場合、
PCA9685を使うことで16個のサーボモーターを1つのチップで同時に制御できる。
- 1チャンネル目:左腕のサーボモーター
- 2チャンネル目:右腕のサーボモーター
- 3チャンネル目:足のサーボモーター
- …
- 16チャンネル目:頭のサーボモーター
各サーボモーターの角度を別々に設定できるので、複雑な動きも可能になる。
⇒ たくさんの部品を一度に個別に効率的に動かせる!
I2C(アイツーシー)バスとは?
「Inter-Integrated Circuit」の略。
2本のワイヤーだけで複数のデバイス(センサーやモーターなど)を一緒に接続し、通信するためのバス。
⇒少ない配線で複数のデバイスを効率的に通信させるためのシンプルなシステム。
複数のデバイスを1つのバス(道)でやり取りさせたいときに便利。
I2Cの特徴
- 2本のワイヤーだけで通信
- 1本目:SCL(シリアルクロック)
- 時計の役割を果たし、デバイス間で信号のタイミングを合わせる。
- 2本目:SDA(シリアルデータ)
- 実際にデータのやり取りをするワイヤー。
- 1本目:SCL(シリアルクロック)
- 複数のデバイスを接続可能
- 1つのI2Cバスに複数のデバイスを接続できる。
- 各デバイスには固有のアドレスがあり、アドレスを使って通信するデバイスを指定する。
例:Raspberry Piとセンサーを接続
Raspberry PiにI2Cデバイス(PCA9685や温度センサーなど)を接続すると、2本のI2Cバスのワイヤーだけで、
Raspberry Piとこれらのデバイス間でデータをやり取りできます。各デバイスには個別のアドレスが設定されているので、どのデバイスに話しかけているかを簡単に区別できる。
PCA9685をRaspberry Pi4で使用するには
- I2Cツールのインストール:
sudo apt install i2c-tools
UbuntuでI2Cインターフェースを有効化する。
- I2Cモジュールをロード:
/etc/modules
ファイルに必要なモジュール名を追加する。
sudo vi /etc/modules
ファイルの末尾に以下の2行を追加する:
i2c_bcm2708
i2c_dev
- ブート設定の修正:
/boot/firmware/config.txt
を編集し、I2Cの設定を有効化する。
sudo vi /boot/firmware/config.txt
以下の行を追加する:
dtparam=i2c_arm=on
- ユーザーを
dialout
グループに追加する:
I2Cデバイスへのアクセス権をえるため、現在のユーザーをdialout
グループに追加する。
sudo usermod -aG dialout $USER
- 再起動:
設定を反省させるため、システムを再起動する。
sudo reboot
- アクセス権限の確認
再起動後、もう一度以下のコマンドでユーザの所属グループを確認。
groups
dialout
グループに所属していることを確認する。
dialout
グループは、シリアルデバイス(シリアルポートやI2C、SPIデバイスなど)にアクセスするための特権を持つユーザグループ
役割
dialout
グループに所属しているユーザは、システム上のシリアルデバイスにアクセスできる権限を持つ。これにより、例えばシリアル通信デバイスやI2C、SPIバス、USB経由で接続されたデバイスに対して、ユーザが特別な権限を持つ必要がなくなるため、アクセスや制御が可能になる。- 通常、デバイスファイル(例:
/dev/ttyUSB0
や/dev/i2c-1
)の所有者はroot
だが、グループがdialout
に設定されているため、このグループに所属するユーザであれば、シリアルデバイスにアクセスできるようになる。
典型的な利用場面
- マイクロコントローラとの通信::ArduinoやRaspberry Piなどのシリアルポートを利用する
デバイスとの通信を行う場合に、dialout
グループの権限が必要。 - I2Cデバイスの制御:Raspberry PiのI2Cバス (
/dev/i2c-1
) にアクセスするためにも、dialout
グループが関連する場合がある。
dialout
グループに所属するメリット
sudo
コマンドを使わずにシリアルポートやI2Cデバイスにアクセスできるため、
権限の問題を回避でき、スクリプトやアプリケーションを実行する際にスムーズに動作する。
ユーザが dialout
グループに追加されていれば、これらのデバイスに対して権限エラーが発生せずにアクセスできるようになる(なった)。
PCA9685を制御するためのPythonライブラリをインストールする。
- 必要なパッケージのインストール:
I2CツールやPython用のPCA9685ライブラリをインストール。
sudo apt update
sudo apt install -y python3-pip i2c-tools
sudo pip3 install adafruit-circuitpython-pca9685
※これだけでは足りないので下記も参照
- I2Cデバイスが正しく認識されているか確認:
I2Cが正しく機能しているか確認するため、デバイスを検出してみる。
sudo i2cdetect -y 1
PCA9685は通常、アドレス0x40
で表示されます。
sudo i2cdetect -y 1
コマンドを使用するとRaspberry Piや他のI2Cをサポートするデバイスで、
I2Cバスに接続されているデバイスのアドレスを一覧表示することができる。
- 12Cアドレスとは:
I2Cに接続される各デバイスには、固有のアドレスが割り当てられている。
このアドレスは、マスター(Raspberry Piなど)がどのデバイスに命令を送るかを指定するために
使用される。 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: -- -- -- -- -- -- -- --
- アドレス0x40について
PCA9685は、I2Cバス上でのデフォルトアドレスが0x40に設定されている。
このアドレスは、I2C通信でこのデバイスを特定するために使われる。- 表示された表の中で、0x40の位置に「40」と表示されている場合、
PCA9685が接続されて正しく認識されていることを示してる。
「–」 は、特定のアドレスにデバイスが存在しないことを意味する。
- 表示された表の中で、0x40の位置に「40」と表示されている場合、
以下の簡単なPythonコードを実行して、PCA9685を初期化し、1つのサーボを制御する。
- Pythonコード例:
import board
import busio
from adafruit_pca9685 import PCA9685
from adafruit_motor import servo
# I2Cバスの初期化
i2c = busio.I2C(board.SCL, board.SDA)
# PCA9685の初期化
pca = PCA9685(i2c)
pca.frequency = 50 # サーボモーターのために50Hzに設定
# サーボモーターのチャンネルを設定
servo_motor = servo.Servo(pca.channels[0])
# サーボモーターの角度を制御
servo_motor.angle = 90 # 90度に設定
- コードの説明:
- I2Cバスの初期化:busio.I2C()を使って、I2C通信を初期化する。
- PCA9685の初期化:PCA9685クラスを使って、PCA9685を初期化する。
- サーボモーターの制御:PCA9685の0番目のチャンネルにサーボモーターを接続し、角度を90度に設定
コード詳細
- ライブラリのインポート:
import board
import busio
from adafruit_pca9685 import PCA9685
from adafruit_motor import servo
- board:Raspberry PiのI2Cピンを指定するために使用。
SCL
とSDA
ピン(I2Cのクロックとデータライン)を指定。 - busio:I2C通信を初期化・制御するためのモジュール。
- adafruit_pca9685:PCA9685 PWMコントローラを扱うためのライブラリ。
これにより複数のPWM信号を生成し、モーターやLEDを制御できる。 - adafruit_motor.servo:サーボモーターを簡単に制御するためのライブラリ。
- I2Cバスの初期化
i2c = busio.I2C(board.SCL, board.SDA)
- Raspberry PiのI2Cバスを初期化。
board.SCL
とboard.SDA
は、それぞれクロックラインと
データラインのピンを示している。 - Raspberry PiのI2Cバスが動作するために、適切に設定されていることが前提。
(i2c-tools
での確認やraspi-config
での有効化)。
- PCA9685の初期化
pca = PCA9685(i2c)
pca.frequency = 50 # サーボモーターのために50Hzに設定
- PCA9685(i2c) :I2C経由でPCA9685を初期化。
PCA9685は、I2Cアドレス0x40を持つ16チャンネルのPWMコントローラ。 - pca.frequency = 50 :PWMの周波数を50Hzに設定。
サーボモーターは通常50HzのPWM信号で動作するため、この設定が必要。
- サーボモーターのチャンネル設定
servo_motor = servo.Servo(pca.channels[0])
- pca.channels[0] :PCA9685の最初のチャンネル(0番目のチャンネル)を指す。
このチャンネルに接続されているサーボモーターを制御するために、servo.Servo
クラスを
使用して初期化している。 - これにより、サーボモーターの角度や動きを制御できるオブジェクト
servo_motor
が
作成される。
- サーボモーターの角度制御
servo_motor.angle = 90 # 90度に設定
- servo_motor.angle = 90:サーボモーターの角度を90度に設定します。
- サーボモーターは通常、0度から180度までの範囲で回転でき、
この角度設定により、モーターが指定された角度まで回転する。
このコードを実行することで、Raspberry PiとPCA9685を使って、サーボモーターを指定の角度に回転させることができる。
0x40
に40
が表示されない場合
PCA9685がI2Cバスに正しく接続されていない可能性あり。
以下に、問題のトラブルシューティング手順を示します。※そもそもラズパイとPCA9685を繋いでなかった!
- 配線の確認
物理的な配線を確認する。
I2Cバスは以下の4本のワイヤーで接続されるが、これが正しく行われているか確認する。- VCC(電源):Raspberry Piの3.3Vピンに接続
- GND(グランド):Raspberry PiのGNDピンに接続
- SDA(データ):Raspberry PiのSDAピン(GPIO2、ピン番号3)に接続
- SCL(クロック):Raspberry PiのSCLピン(GPIO3、ピン番号5)に接続
配線が間違っていると、デバイスが認識されない。また、PCA9685が3.3Vで動作していることを確認する
(5V電源を使ってしまうと壊れる可能性がある)
- I2Cが有効になっているか確認
Ubuntu上でI2Cが有効になっていない場合、デバイスは認識されない。以下の手順で確認する。i2c-dev
モジュールがロードされているか確認
lsmod | grep i2c
このコマンドでi2c_bcm2835
やi2c_dev
がリストに含まれているか確認する。
含まれていない場合は手動でロードする必要がある。
- I2Cの有効化:
I2Cが有効になっているか確認し、必要に応じて/boot/firmware/config.txt
で設定を確認します。
sudo vi /boot/firmware/config.txt
dtparam=i2c_arm=on
が含まれていることを確認し、設定されていなければ追加する。
- デバイスが壊れていないか確認
他のデバイス(例えば温度センサーなど)でI2C通信ができるか試してみる。
もし他のI2Cデバイスも認識されない場合は、Raspberry PiやUbuntu側のI2C設定に問題がある可能性がある。
もし他のデバイスが正しく動作する場合は、PCA9685自体に問題があるかもしれない。 - 別のI2Cアドレスを確認
PCA9685には、アドレスが変更可能なジャンパピンが付いていることがある。
このジャンパピンが誤って設定されていると、デフォルトの0x40
ではなく他のアドレスに設定されている
可能性がある。
ジャンパの設定を確認し、必要に応じて調整する。 - 再起動
最後に、設定を変更した後、念のためシステムを再起動してから再度i2cdetect
を試してみる。 - I2Cバスの指定
Raspberry Pi 4では、I2Cバスが複数あるため、i2cdetect
で異なるバスを試してみる。
デフォルトは1
だが、他のバスも確認してみる。※試していない。。。
sudo i2cdetect -y 0
sudo i2cdetect -y 1
sudo i2cdetect -y 2
エラー
上記のPythonコードを実行すると下記エラーになる。
Traceback (most recent call last):
File "/home/masanori/servomotor_test1.py", line 1, in <module>
import board
File "/usr/local/lib/python3.10/dist-packages/board.py", line 51, in <module>
from adafruit_blinka.board.raspberrypi.raspi_4b import *
File "/usr/local/lib/python3.10/dist-packages/adafruit_blinka/board/raspberrypi/raspi_4b.py", line 6, in <module>
from adafruit_blinka.microcontroller.bcm2711 import pin
File "/usr/local/lib/python3.10/dist-packages/adafruit_blinka/microcontroller/bcm2711/pin.py", line 5, in <module>
from RPi import GPIO
ModuleNotFoundError: No module named 'RPi'
このエラーは、RPi.GPIO
モジュールがインストールされていないために発生している。
このモジュールは、Raspberry PiのGPIOピンを制御するために必要なライブラリ。
解決方法RPi.GPIO
モジュールをインストールする
RPi.GPIO
ライブラリのインストール:
ターミナルを開き、次のコマンドを実行してRPi.GPIO
ライブラリをインストールする。
sudo apt-get update
sudo apt-get install python3-rpi.gpio
または、pip3
を使ってインストールすることもできる。
sudo pip3 install RPi.GPIO
- コードの再実行:
ライブラリがインストールされたら、再度Pythonスクリプトを実行して
エラーが解消されているか確認する。
python3 /home/********/servomotor_test1.py
- Blinka環境の確認:
adafruit_blinka
は、Raspberry PiなどのSBC(シングルボードコンピュータ)でAdafruitのCircuitPythonライブラリを動かすための互換レイヤー。
このライブラリが正しく機能するためには、GPIOピンにアクセスできるようにする必要がある。
もし他に依存関係が不足している場合、以下のコマンドでBlinkaの依存関係を再インストール・更新することをおすすめされた。
pip3 install adafruit-blinka
今回はインストールが必要だった!
sudo pip3 install --upgrade adafruit-blinka
※インストール直後なのでアップデートは不要。
上記のPythonコードを実行するとまだ下記エラーになる。
Traceback (most recent call last):
File "/home/masanori/servomotor_test1.py", line 4, in <module>
from adafruit_motor import servo
ModuleNotFoundError: No module named 'adafruit_motor'
このエラーは、adafruit_motor
ライブラリがインストールされていないために発生している。
このライブラリは、サーボモーターなどのモーター制御を行うためのモジュール。
解決方法adafruit_motor
ライブラリをインストールする
adafruit_motor
ライブラリのインストール:
ターミナルを開き、pip3を使ってadafruit_motor
ライブラリをインストールする。
sudo pip3 install adafruit-circuitpython-motor
このコマンドにより、adafruit_motor
ライブラリがインストールされる。
- コードの再実行:
ライブラリがインストールされたら、再度Pythonスクリプトを実行して
エラーが解消されているか確認する。
python3 /home/********/servomotor_test1.py
サーボモーターを廻すことができた!!
(実際は「dialoutグループにuserを追加」にたどり着くまで結構かかった)
インストールしたソフトウェア、モジュール、ライブラリ
CircuitPythonライブラリ:
電子工作を簡単にするためのPythonベースのライブラリ。
特に、センサーやモーターなどのハードウェアを制御するために使われる。
- 初心者向け:シンプルでわかりやすいコードで電子部品を動かせます。
- Python言語:Pythonでハードウェアを制御できるため、学習しやすく手軽。
- 互換性:Adafruit製のマイクロコントローラーやRaspberry Piなど、多くのデバイスで動作します。
CircuitPythonライブラリを使うと、少ないコードでセンサーやLED、モーターなどのハードウェアを簡単にプログラムできるのが特徴です。
adafruit_blinka:
Raspberry Piのようなシングルボードコンピュータ(SBC)でAdafruitが提供する CircuitPython ライブラリを使うための「橋渡し」をするソフトウェア。
通常、CircuitPythonはマイクロコントローラー(Arduinoのような小型のコンピュータ)で動くものだが、Raspberry PiのようなLinuxが動くコンピュータでも、Pythonコードを使って簡単にハードウェアを制御できるようにするのが adafruit_blinka
の役割。
これがうまく動作するためには、GPIOピン というRaspberry Piのピンにアクセスできるように設定が必要。GPIOピンは、モーターやセンサーなどの電子部品と直接やり取りするための「入り口」のようなもの。
adafruit_blinka
はRaspberry Piで CircuitPython ライブラリを使うためのソフト。- これにより、Pythonを使ってモーターやセンサーなどを簡単に制御できる。
- ただし、Raspberry Piのピン(GPIOピン)にアクセスできるようにする設定が必要。
この設定がうまくいけば、Raspberry Piで様々な電子工作をPythonを使って簡単に行えるようになる。
コメント