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

サーボモーターを動かす

ここからは、データの向きを逆にして、ブラウザからM5Stackにコマンドを送ります。 スライダーでアームの関節の角度を指定し、関節ごとにどこまで動かしてよいか(可動範囲)を確かめます。 ここで確かめた可動範囲は、ハンズオン④で声からアームを動かすときに使います。

サーボモーターの仕組み

サーボモーターは、指示された角度まで回って、その角度を保つモーターです。 ハンズオンで使うマイクロサーボ(SG90など)は、約20ミリ秒ごとに届くパルスの幅で角度を受け取ります。 パルス幅が約0.5ミリ秒なら0度、約2.4ミリ秒なら180度で、そのあいだは幅に比例した角度になります1。

このパルスを作るのが、サーボドライバーに載っているPCA9685です。 ブリッジはservo 0 90のようなコマンドを受け取ると、角度をパルス幅に換算し、I2CでPCA9685に書き込みます。 以後はPCA9685がパルスを出し続けるので、ブリッジが次のコマンドを送るまでサーボモーターは同じ角度を保ちます。

サンプル

View on GitHub Open in LiveCodes Open in StackBlitz

可動範囲を確かめる

アームの関節は、構造上、0度から180度まで回り切れるとは限りません。 グリッパーなら、爪が閉じ切った位置より先には進めません。 その先の角度を指示すると、サーボモーターは届かない角度に向かって力を出し続け、「ジー」という音を立てて発熱します。 この状態が続くと、サーボモーターやアームの部品が壊れることがあります。

そこで、実際に動かしながら、関節ごとに安全に動かせる範囲を記録します。

  1. サーボモーターの電源を入れてから、「接続」を押してM5Stackを選びます。接続すると、両方の関節が初期位置の90度に動きます。
  2. 関節1のスライダーを、左右に少しずつ動かします。音が変わったり、それ以上動かなくなったりした角度を見つけたら、そこから5度から10度戻した値を記録します。
  3. 値を大きくしたときにアームがどちらを向くかも記録します。
  4. 関節2(グリッパー)についても、同じように開き切った角度と閉じ切った角度を記録します。
  5. 記録が済んだら「脱力させる」を押します。
関節最小の角度最大の角度値を大きくしたときの動き
関節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を傾けた向きにアームを旋回させてみましょう。

  1. 0度と180度に対応するパルス幅は、サーボモーターの製品ごとに少しずつ異なります。ブリッジのプログラムではSERVO_MIN_USとSERVO_MAX_USで設定しています。 ↩