ロボットに「まっすぐ進め」と命じるには、いま自分がどこを向いているかを知る必要があります。それを担うのがジャイロセンサーです。ところがジャイロは、向きそのものを測っていません。
ジャイロセンサーが測っているのは角速度、つまり「いま1秒あたり何度の速さで回っているか」です。単位は度/秒。
角度が欲しいなら、自分で計算します。角速度に時間をかけて足していく。これを積分といいます。
そして、この「足していく」という仕組みが、ジャイロの長所と、いちばん大きな弱点を生みます。
どこで使われているか
ジャイロは身のまわりに数多く入っています。
| 使われている場所 | 何をしているか |
|---|---|
| スマートフォン | 縦横の持ちかえを検知する。カメラの手ぶれ補正で、揺れと逆向きにレンズを動かす |
| ドローン | 傾きを毎秒数百回測り、4つのプロペラの回転数を変えて水平を保つ |
| 自動車 | 横滑り防止装置。ハンドルの切れ角と実際の回転量を比べ、ずれていればブレーキを片輪だけかける |
| カーナビ | トンネルでGPSが届かない間、ジャイロと車速から位置を推測して走り続ける |
| ゲーム機のコントローラー | 傾けて操作する。振って操作する |
| ロボット掃除機 | まっすぐ進んでいるか、何度曲がったかを把握する。部屋の地図づくりを助ける |
共通点があります。どれも「変化」を知るために使っていて、「絶対の向き」を知るためには使っていません。カーナビがジャイロだけで走れるのはトンネルの数分間だけで、外に出ればGPSで位置を直します。
どの向きの回転を測るのか ― ヨー・ピッチ・ロール
ジャイロは3つの軸それぞれについて、回る速さを測ります。呼び名は飛行機のものをそのまま使います。
サッカーロボットが使うのは、ヨーだけです。平らな床を走るので、知りたいのは「正面からどれだけ向きがずれたか」だけ。あとで出てくるプログラムの ev.orientation.x が、このヨーにあたります。
だからセンサーは水平に取り付けます。傾けて付けると、ロボットが段差で傾いただけで「向きが変わった」ことになってしまいます。多くの基板には X / Y / Z の軸が印刷されているので、Z を真上に向けます。この記事の最初の写真にも、その印が写っています。
ピッチをつかう競技もあります。レスキューには坂があるので、坂を登り始めたことをピッチで知るという使い方が考えられます。坂に入ったら速さを変える、といった判断です。ピッチは重力が基準なので、ヨーと違ってずれが積み上がりません。
ジャイロは、外付けの部品だけではありません。SPIKE プライムには、ハブの中にジャイロが入っています。部品を足さなくても、ヨー・ピッチ・ロールを読めます。
加速度・地磁気との役割分担
ロボットでよく使う「9軸センサー」は、3種類のセンサーを1つにまとめたものです。それぞれ3方向ぶんあるので、合計9軸です。
| センサー | 測るもの | 得意 | 苦手 |
|---|---|---|---|
| ジャイロ | 角速度 | 速い動きに正確。磁気に乱されない | 足し算なので、時間とともにずれる |
| 加速度 | 加速度(重力を含む) | 重力の向きから前後左右の傾きがわかる。ずれが積み上がらない | 振動に弱い。水平方向の回転はわからない |
| 地磁気 | 磁界の向き | 絶対の北がわかる。ずれが積み上がらない | 鉄・モーター・電流で簡単に狂う |
加速度センサーが返すのは「重力がどの軸に、どれだけ乗っているか」です。傾けると配られ方が変わるので、傾きが計算できます。けれど水平に回しても重力は真下のままで、数が1つも変わりません。ロールとピッチは重力から読めるが、ヨーだけは読めない。だからヨーはジャイロと地磁気が受けもちます。
そこで3つを組み合わせます。短い時間の変化はジャイロが受けもち、長い時間のずれを加速度と地磁気が直す。これをセンサーフュージョンといいます。BNO055 のようなセンサーは、この計算をセンサー自身の中で行い、「向き」の答えだけを返してくれます。
つなぐ ― BNO055 の配線
つなぐのは4本だけです。
Wire.begin() が既定で使うピン。SDA と SCL が何をしているのかは I2C通信の記事に、Arduino IDE と Pico の準備は Pico を Arduino IDE で使うにあります。
プログラムの基本 ― 向きを読む
ジャイロが返すのは「いま何度/秒で回っているか」です。角度にするには、これに経過時間をかけて足していきます。
BNO055 では、この足し算がセンサーの中で済んでいます。だからプログラムは、できあがった角度を読むだけです。
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
// アドレスは基板によって違う。2つ用意して、見つかったほうを使う
Adafruit_BNO055 bno29(55, 0x29, &Wire);
Adafruit_BNO055 bno28(55, 0x28, &Wire);
Adafruit_BNO055* bno = nullptr;
void setup() {
Serial.begin(115200);
Wire.begin();
delay(2000);
if (bno29.begin(OPERATION_MODE_IMUPLUS)) bno = &bno29; // 磁気を使わないモード
else if (bno28.begin(OPERATION_MODE_IMUPLUS)) bno = &bno28;
// 見つからないときは、黙らずに言い続ける
if (bno == nullptr) {
while (true) {
Serial.println("BNO055 not found. check 3V3 / GND / SDA / SCL");
delay(1000);
}
}
delay(1000); // 計算が始まるまで待つ
}
void loop() {
sensors_event_t ev;
bno->getEvent(&ev);
Serial.println(ev.orientation.x, 2); // 向き 0〜360度
delay(20);
}
sensors_event_t ev; で読んだ値を入れる箱を用意し、bno->getEvent(&ev); でそこへ書き込んでもらいます。向きは ev.orientation.x に入っています。この書き方そのものは、別の記事であらためて扱います。
OPERATION_MODE_IMUPLUS は、加速度とジャイロだけを使い、地磁気を使わないモードです。モーターのそばで使うセンサーでは、こちらを選ぶ場面が多くなります。地磁気がモーターの磁気に乱されるからです(「ずれへの対応」の項)。
アドレスは基板によって違います。0x28 と 0x29 の2種類があるので、上のプログラムは両方を試しています。
動かないときに見るところ ― 症状から原因を引く
この表の症状は、ひととおり実際に出たものです。
| 症状 | 原因 | 対処 |
|---|---|---|
| 何も出てこない | アドレスが 0x28 ではなく 0x29 | 2つ試す書き方にする(プログラムの項) |
| 何も出てこない | begin() が失敗し、while (true) {} で黙っている | 止まるなら理由を言わせる |
| 書き込みもできなくなった | while (true) {} が、書き込みの合図を受け取れない | BOOTSEL を押しながら USB を挿す |
数字は出るが 0.00 のまま | 動かしていないだけ。BNO055 の静止中のずれは、ごく小さい | 基板を回して、数字が動くか見る。値が変わらないことだけでは故障と判断できない |
| 途中で数字が止まった | SDA か SCL が一瞬外れ、返事を待ったまま停止している | 基板と線をテープで留める。手で回すと線がねじれる |
| 回す向きと符号が逆 | 取り付けの向き。計算では決まらない | 読んだ角度の符号を入れ替える |
起動した直後だけ大きくずれる、mag が 0 のまま、といった校正にかかわる症状は、キャリブレーションの記事にまとめてあります。
ここまでで、向きが読めるようになりました。けれども、読めた角度は少しずつずれていきます。その理由と対応は ずれを差し引く ― BNO055 のキャリブレーション にまとめました。
BNO055 の公式の資料です。117ページあり、モードの一覧・レジスタの詳細・軸の向きの定義まで載っています。なお資料の中では、記事で使った IMUPLUS が IMU という名前で書かれています。IMUPLUS は Adafruit のライブラリでの呼び方です。
ロボカップジュニア2027 に向けて、レスキュー(災害救助)とサッカーの2種目に取り組みます。プログラミングと電子工作の経験は問いません。