サーボモーターを動かす
ここからは、データの向きを逆にして、ブラウザからM5Stackにコマンドを送ります。 スライダーでアームの関節の角度を指定し、関節ごとにどこまで動かしてよいか(可動範囲)を確かめます。 ここで確かめた可動範囲は、ハンズオン④で声からアームを動かすときに使います。
サーボモーターの仕組み
サーボモーターは、指示された角度まで回って、その角度を保つモーターです。 ハンズオンで使うマイクロサーボ(SG90など)は、約20ミリ秒ごとに届くパルスの幅で角度を受け取ります。 パルス幅が約0.5ミリ秒なら0度、約2.4ミリ秒なら180度で、そのあいだは幅に比例した角度になります1。
このパルスを作るのが、サーボドライバーに載っているPCA9685です。
ブリッジはservo 0 90のようなコマンドを受け取ると、角度をパルス幅に換算し、I2CでPCA9685に書き込みます。
以後はPCA9685がパルスを出し続けるので、ブリッジが次のコマンドを送るまでサーボモーターは同じ角度を保ちます。
サンプル
可動範囲を確かめる
アームの関節は、構造上、0度から180度まで回り切れるとは限りません。 グリッパーなら、爪が閉じ切った位置より先には進めません。 その先の角度を指示すると、サーボモーターは届かない角度に向かって力を出し続け、「ジー」という音を立てて発熱します。 この状態が続くと、サーボモーターやアームの部品が壊れることがあります。
そこで、実際に動かしながら、関節ごとに安全に動かせる範囲を記録します。
- サーボモーターの電源を入れてから、「接続」を押してM5Stackを選びます。接続すると、両方の関節が初期位置の90度に動きます。
- 関節1のスライダーを、左右に少しずつ動かします。音が変わったり、それ以上動かなくなったりした角度を見つけたら、そこから5度から10度戻した値を記録します。
- 値を大きくしたときにアームがどちらを向くかも記録します。
- 関節2(グリッパー)についても、同じように開き切った角度と閉じ切った角度を記録します。
- 記録が済んだら「脱力させる」を押します。
| 関節 | 最小の角度 | 最大の角度 | 値を大きくしたときの動き |
|---|---|---|---|
| 関節1(旋回、チャンネル0) | 例:左を向く | ||
| 関節2(グリッパー、チャンネル1) | 例:閉じる |
「脱力させる」は、ブリッジにreleaseコマンドを送り、PCA9685のパルスを止めます。
パルスが止まるとサーボモーターは角度を保たなくなり、手でアームを動かせるようになります。
アームを使い終えたときや、サーボモーターから異音がしたときは、脱力させてから原因を調べます。
コードを読む
関節の設定を1か所にまとめる
関節ごとのチャンネルと可動範囲は、script.jsの先頭のJOINTSにまとめています。
const JOINTS = [
{ channel: 0, label: "関節1(旋回)", min: 0, max: 180, home: 90 },
{ channel: 1, label: "関節2(グリッパー)", min: 0, max: 180, home: 90 },
];
スライダーはJOINTSをもとに作っているので、minとmaxを記録した値に書き換えると、スライダーもその範囲でしか動かなくなります。
ブリッジの側でも0度から180度の範囲外の値は拒否しますが、アームごとの可動範囲まではブリッジは知りません。
アームに合わせた範囲の制限は、ブラウザの側で行います。
送信の回数を減らす
スライダーを動かしている間、inputイベントは1秒間に数十回発生します。
しかし、そのたびにコマンドを送っても、サーボモーターの動きは細かくなりません。
マイクロサーボが60度回るには0.1秒ほどかかり、数ミリ秒ごとに角度を指示しても、回り切る前に次の指示で上書きされるだけだからです。
サンプルでは、50ミリ秒のあいだに変わった値をまとめて、1行のコマンドで送っています。
const pending = new Map();
let timer;
function queueServo(channel, angle) {
pending.set(channel, angle);
timer ??= setTimeout(() => {
sendLine(`servo ${[...pending].flat().join(" ")}`);
pending.clear();
timer = undefined;
}, 50);
}
pendingは、チャンネルをキー、角度を値とするMapです。
50ミリ秒のあいだに同じチャンネルの値が何度変わっても、最後の値だけが残ります。
2つの関節の値が変わっていれば、servo 0 120 1 45のように、複数のチャンネルを1行にまとめて送ります。
ブリッジのコマンドを複数チャンネル対応にしてあるのは、この使い方のためです。
試してみよう
JOINTSのminとmaxを、記録した可動範囲に書き換えてみましょう。- 「初期位置に戻す」を押したとき、関節が一度に動くのではなく、1度ずつゆっくり戻るようにしてみましょう。
- ハンズオン②のサンプルと組み合わせて、M5Stackを傾けた向きにアームを旋回させてみましょう。
-
0度と180度に対応するパルス幅は、サーボモーターの製品ごとに少しずつ異なります。ブリッジのプログラムでは
SERVO_MIN_USとSERVO_MAX_USで設定しています。 ↩