Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Pi Servo HATの使い方

SparkFun Pi Servo HATを使うと、Raspberry PiはI2C接続を介して最大16台のサーボモーターを制御できるようになる。 これによりGPIOを節約でき、オンボードのGPIOを他の用途に使えるようになる。 さらに、Pi Servo Shieldにはシリアルターミナル接続も追加されており、モニタやキーボードを接続しなくてもRaspberry Piを起動できる。

必要な部品

このチュートリアルを進めるには、次のものが必要になる。 NOOBS対応のカードにはPi Zero Wに対応するだけの新しいOSが入っていないことがあるため、NOOBS対応カードではなく、まっさらなmicroSDカードを購入することを推奨する。

  • 絶縁GPIOヘッダー(メス、PTH、0.1インチ、2×20ピン)
  • ストレートヘッダー(オス、PTH、0.1インチ、40ピン)
  • Raspberry Pi Zero W
  • ACアダプタ電源(5.1V、2.5A、USB Micro-B)
  • microSDカード(アダプタ付き)
  • SparkFun Pi Servo HAT

さらに、セットアップをテストするための何らかのサーボモーターが必要になる。 このチュートリアルの後半で紹介する例は、まず汎用サブマイクロサーボで試してみるとよい。

必要な道具

この製品の組み立てに特別な道具は必要ない。 はんだごて、はんだ、一般的なはんだ付け用アクセサリーが必要になる。

参考になるチュートリアル

このチュートリアルに取り組む前に、次のチュートリアルも確認しておくとよい。

ハードウェア概要

この基板は使いやすさを最優先に設計されたHATであるため、注目すべき部分はごくわずかである。

USB Micro Bコネクタ — このコネクタは、サーボモーターだけに給電するためにも、サーボモーターとHATに接続されたPiの両方に給電するためにも使える。 また、Piのセットアップにモニタやキーボードを使わずに済むよう、シリアルポート接続経由でPiに接続するのにも使える。

電源絶縁ジャンパー — このジャンパーを(デフォルトでは閉じているが)切断すると、サーボ用の電源レールをPiの5V電源レールから絶縁できる。 なぜそうしたいのかというと、複数のサーボや、重い負荷のかかった大型サーボを使う場合、サーボモーターが電源レールに乗せるノイズによってPiの動作に望ましくない影響が出ることがあり、完全なリセットやシャットダウンに至ることさえあるためである。 なお、このジャンパーの状態にかかわらず、Piに電源が入っている限りシリアルインターフェースは動作し続ける。

サーボモーター用ピンヘッダー — これらのヘッダーは、サーボモーターを取り付けやすいよう間隔を空けて配置されている。 ほとんどのホビー用サーボモーターのコネクタに対応する正しい順序でピンが割り当てられている。

ハードウェアの組み立て

オスヘッダーはPi Zero Wにはんだ付けすることを推奨する。

このような作業でよく使う筆者お気に入りのコツは、まず1本のピンをはんだ付けし、右手に持ったこてでそのピンのはんだを溶かしながら、左手でヘッダーが下の写真のように平らに収まるよう調整するというものである。 ヘッダーの短い側ではんだ付けし、長い方のピンが部品側にくるようにすること。 1本のピンを仮止めしたら、残りのピンをすべてPi Zero Wにはんだ付けする。

メスヘッダーとPi Servo Hatについても同じ手順を繰り返す。

短いピンを基板の下側から挿入し、部品側にはんだを盛ることで、Pi Servo HatをPi Zero Wのオスヘッダーピンの上に積み重ねられるようにすること。 すべてのピンをはんだ付けする前に、ヘッダーが水平になっていることも確認する必要がある。

ヘッダーのはんだ付けが終わったら、Pi Servo HatをPi Zero Wに重ねる。 続いて、使用するサーボに応じて、チャンネル「0」にホビーサーボを接続する。 ホビーサーボのデータシートを確認するか、このチュートリアルに掲載されている標準的なサーボコネクタのピン配置を参考にしてほしい。 十分な容量の5V ACアダプタを使い、Pi Zero Wに給電できる。 ACアダプタをコンセントに差し込み、Pi Zero Wの「PWR IN」とラベル付けされたmicro-Bコネクタに接続する。

ソフトウェア - Python

ここでは、PythonでPi Servo Hatにアクセスし、使う方法を詳しく説明する。 完全なサンプルコードは、製品のGitHubリポジトリで公開されている。

注意: このチュートリアルは、サーボモーターを200HzのPWMで制御する前提で書かれている。「大きな」ブザー音が聞こえる場合や、サーボモーターの制御がうまくいかない場合は、周波数を下げるとよいかもしれない。50Hz用のサンプル一式を確認してみてほしい。

SMBusリソースへのアクセスを準備する

まず一つ目のポイントとして、OSレベルのやり取りのほとんどでは、I2CバスはSMBusと呼ばれる。 というわけで、最初のコードは次のようになる。 これはsmbusモジュールをインポートし、SMBus型のオブジェクトを作成して、Piの各種SMBusのうちバス「1」に接続する。

import smbus
bus = smbus.SMBus(1)

プログラムに部品のアドレスを教える必要がある。 デフォルトでは0x40なので、後で使うために変数にこの値を設定しておく。

addr = 0x40

続いて、PWMチップを有効にし、書き込み後にアドレスを自動的にインクリメントするよう指示する必要がある(これにより、1回の操作で複数バイトの書き込みができるようになる)。

bus.write_byte_data(addr, 0, 0x20)
bus.write_byte_data(addr, 0xfe, 0x1e)

PWMレジスタに値を書き込む

必要な準備はこれですべてである。 ここから先は、PWMチップにデータを書き込めば、それに応じた反応が得られるはずである。次に例を示す。

bus.write_word_data(addr, 0x06, 0)
bus.write_word_data(addr, 0x08, 1250)

最初の書き込みは、チャンネル0の「開始時間」レジスタに対するものである。 デフォルトでは、このチップのPWM周波数は200Hz、つまり5msごとに1回パルスが発生する。 開始時間レジスタは、5msのサイクルの中でパルスがいつハイになるかを決定する。 すべてのチャンネルはこのサイクルに同期している。 一般に、ここには0を書き込む。

2つ目の書き込みは「停止時間」レジスタに対するもので、パルスがいつローになるかを制御する。 この値の範囲は0から4095までで、各カウントはその5msの期間の1コマ分(5ms/4095、約1.2µs)を表す。 つまり、上で書き込んだ1250という値は、5msの期間のうちおよそ1.5msがハイであることを表している。

サーボモーターは、このパルス幅から制御信号を受け取る。 一般に、1.5msのパルス幅はモーターの可動範囲の両端のちょうど中間にあたる「中立」位置になる。 1.0msはおよそ中央から-90度、2.0msはおよそ中央から+90度に相当する。 実際にはこれらの値は90度より多少大きかったり小さかったりすることがあり、モーターがどちらの方向にも90度よりわずかに多く、あるいは少なく動作できることもある。

他のチャンネルにアクセスするには、上記の2つのレジスタのアドレスに単純に4ずつ加算していけばよい。 つまり、チャンネル1の開始時間は0x0A、チャンネル2は0x0E、チャンネル3は0x12というように続き、チャンネル1の停止時間のアドレスは0x0C、チャンネル2は0x10、チャンネル3は0x14というように続く。下の表を参照してほしい。

チャンネル番号開始アドレス停止アドレス
Ch 00x060x08
Ch 10x0A0x0C
Ch 20x0E0x10
Ch 30x120x14
Ch 40x160x18
Ch 50x1A0x1C
Ch 60x1E0x20
Ch 70x220x24
Ch 80x260x28
Ch 90x2A0x2C
Ch 100x2E0x30
Ch 110x320x34
Ch 120x360x38
Ch 130x3A0x3C
Ch 140x3E0x40
Ch 150x420x44

開始アドレスに0を書き込んだ場合、90度からの角度のずれ1度ごとに、停止アドレスへの書き込み値が4.6カウント分変化する。 つまり、中立位置からずらしたい角度の数に4.6を掛け、動かしたい方向に応じてその結果を1250に加算または減算すればよい。 たとえば、中央から45度ずらしたい場合、動かしたい方向に応じて1250より207(45×4.6)カウント多いか少ない値になる。

ソフトウェア - C++

ここでは、C++でPi Servo Hatにアクセスし、使う方法を詳しく説明する。 Pythonよりもかなり難しいので、これを機にPythonを学ぶのもよいかもしれない。 完全なサンプルコードは、製品のGitHubリポジトリで公開されている。

注意: このチュートリアルは、サーボモーターを200Hz PWMで制御する前提で書かれている。「大きな」ブザー音が聞こえる場合や、サーボモーターの制御がうまくいかない場合は、周波数を50Hzに下げるとよいかもしれない。50Hz用のPythonサンプル一式や、C++のコードを50Hz用に調整する際に必要なI2Cレジスタと設定についてはPCA9685のデータシートを確認してみてほしい。

必要なファイルをインクルードする

まず、インクルードする必要のあるファイルから見ていく。

#include <unistd.h> // required for I2C device access
#include <fcntl.h>  // required for I2C device configuration
#include <sys/ioctl.h> // required for I2C device usage
#include <linux/i2c-dev.h> // required for constant definitions
#include <stdio.h>  // required for printf statements

I2Cデバイスファイルを開く

まず、/dev内のi2c-1ファイルを読み書き用に開く。

char *filename = (char*)"/dev/i2c-1"; // Define the filename
int file_i2c = open(filename, O_RDWR); // open file for R/W

open()関数の戻り値を確認し、ファイルが正常に開けたかどうかを確認するとよい。 ファイルが正常に開けた場合は正の整数が返り、そうでない場合は負の値になる。

if (file_i2c < 0)
{
  printf("Failed to open file!");
  return -1;
}

書き込み用にスレーブアドレスを設定する

Python(やArduino)ではトランザクションごとにスレーブアドレスを設定するのに対し、ここでは「次に変更するまで」有効なアドレスを設定する。 これにはioctl()関数を使う。

int addr = 0x40;    // PCA9685 address
ioctl(file_i2c, I2C_SLAVE, addr); // Set the I2C address for upcoming
                                  //  transactions

ioctl()はI2Cに限定されない汎用の関数である。

PCA9685チップを正しく動作するよう設定する

PCA9685チップのデフォルト設定は、そのままでは今回の用途に適していない。 正しく動作させるには、チップ上のいくつかのレジスタに書き込む必要がある。

まず、チップを有効にしてPWM出力をオンにする必要がある。 これは、レジスタ0に値0x20を書き込むことで行える。

buffer[0] = 0;    // target register
buffer[1] = 0x20; // desired value
length = 2;       // number of bytes, including address
write(file_i2c, buffer, length); // initiate write

続いて、複数バイト書き込みを有効にする必要がある。後でPWM値を設定する際に、一度に2バイトずつ書き込むことになるためである。 今回はlength変数はすでに正しく設定されているため、変更する必要はない。

buffer[0] = 0xfe;
buffer[1] = 0x1e;
write(file_i2c, buffer, length);

PWMレジスタに値を書き込む

必要な準備はこれですべてである。 ここから先は、PWMチップにデータを書き込めば、それに応じた反応が得られるはずである。次に例を示す。

buffer[0] = 0x06;  // "start time" reg for channel 0
buffer[1] = 0;     // We want the pulse to start at time t=0
buffer[2] = 0;
length = 3;        // 3 bytes total written
write(file_i2c, buffer, length); // initiate the write

buffer[0] = 0x08;   // "stop time" reg for channel 0
buffer[1] = 1250 & 0xff; // The "low" byte comes first...
buffer[2] = (1250>>8) & 0xff; // followed by the high byte.
write(file_i2c, buffer, length); // Initiate the write.

最初の書き込みは、チャンネル0の「開始時間」レジスタに対するものである。 デフォルトでは、このチップのPWM周波数は200Hz、つまり5msごとに1回パルスが発生する。 開始時間レジスタは、5msのサイクルの中でパルスがいつハイになるかを決定する。 すべてのチャンネルはこのサイクルに同期している。 一般に、ここには0を書き込む。

2つ目の書き込みは「停止時間」レジスタに対するもので、パルスがいつローになるかを制御する。 この値の範囲は0から4095までで、各カウントはその5msの期間の1コマ分(5ms/4095、約1.2µs)を表す。 つまり、上で書き込んだ1250という値は、5msの期間のうちおよそ1.5msがハイであることを表している。

サーボモーターは、このパルス幅から制御信号を受け取る。 一般に、1.5msのパルス幅はモーターの可動範囲の両端のちょうど中間にあたる「中立」位置になる。 1.0msはおよそ中央から-90度、2.0msはおよそ中央から+90度に相当する。 実際にはこれらの値は90度より多少大きかったり小さかったりすることがあり、モーターがどちらの方向にも90度よりわずかに多く、あるいは少なく動作できることもある。

他のチャンネルにアクセスするには、上記の2つのレジスタのアドレスに単純に4ずつ加算していけばよい。 つまり、チャンネル1の開始時間は0x0A、チャンネル2は0x0E、チャンネル3は0x12というように続き、チャンネル1の停止時間のアドレスは0x0C、チャンネル2は0x10、チャンネル3は0x14というように続く。下の表を参照してほしい。

チャンネル番号開始アドレス停止アドレス
Ch 00x060x08
Ch 10x0A0x0C
Ch 20x0E0x10
Ch 30x120x14
Ch 40x160x18
Ch 50x1A0x1C
Ch 60x1E0x20
Ch 70x220x24
Ch 80x260x28
Ch 90x2A0x2C
Ch 100x2E0x30
Ch 110x320x34
Ch 120x360x38
Ch 130x3A0x3C
Ch 140x3E0x40
Ch 150x420x44

開始アドレスに0を書き込んだ場合、90度からの角度のずれ1度ごとに、停止アドレスへの書き込み値が4.6カウント分変化する。 つまり、中立位置からずらしたい角度の数に4.6を掛け、動かしたい方向に応じてその結果を1250に加算または減算すればよい。 たとえば、中央から45度ずらしたい場合、動かしたい方向に応じて1250より207(45×4.6)カウント多いか少ない値になる。

まとめ・参考資料

SparkFun Pi Servo Hatを無事に動かせたら、次は自分のプロジェクトに組み込む番である。

より詳しい情報は、以下の資料を参照してほしい。

PCA9685を使った他のソフトウェアの例については、同じハードウェアを使いコンセプトも非常によく似ている、SparkFun Blocks for Intel Edison - PWMのHookup Guideも参考になる。 あるいは、Pi Servo Hatを使ったパン・チルトカメラの例も確認してみてほしい。

次のプロジェクトのヒントとして、次のような関連チュートリアルも参考になる。

タグ: Hookup、モーション、モーター、Raspberry Pi


出典:Pi Servo Hat Hookup Guide(SparkFun Learn)を日本語に翻訳し、再構成した。 原文は CC BY-SA 4.0 ライセンスで公開されており、本ページも同ライセンスの下で提供する。