こんばんは、Reveです。技術のほうです。
ここ最近はホーチミンのマンガフェスティバルを記事にしていましたが、久しぶりに技術的なネタを投稿しようかと。
というわけで、今日はジャイロセンサーです。
【ジャイロセンサーとは】
物体の角速度を検知するためのセンサー。
小型ビデオ・カメラの手ブレ補正、ゲーム等のモーションセンシング、ロボットの姿勢制御などに使用されます。
【その前に角速度って何?】
え、角速度をご存じない。まあ、加速度と比べたらマイナーな気もする。
とりあえず角速度の説明をしましょう。
角速度とは、物体が回転する速さを表します。単位は通常ラジアン(rad/s)を使用します。
(ラジアンは、円の半径に等しい長さの弧の中心に対する角度、と定義しますが詳細はいつもの通り割愛)。
端的に言えば、物体の回る早さと思ってもらえれば大丈夫です。
この角速度を測れるセンサーが、タイトルにあるジャイロセンサーです。
センサーは回転の速さを計測するほかに、物体の回転角を測定するのにも使用されます。
以前、加速度センサーでも物体の傾斜角を計測する方法を紹介しましたが、物体が動いている場合は余計な力がかかってしまうため、正確な計測ができません。
そこで、このセンサーを使用すれば物体が運動している最中でも、物体の角度を計測することができます。
【サンプル】
今回は、L3GD20というジャイロセンサーを利用したサンプルを紹介します。
このデバイスは、I2CまたはSPI通信で3軸の角速度を計測できるもので、秋月電子で750円で購入できます。
一つ注意点として、このデバイス動作電圧が2.4V~3.6Vの範囲でしかないため、基本的に5Vの電源が必要なArduino(Unoなど)と接続することはできません。そのため、3.3Vで動作するArduino(Pro Mini 3.3Vなど)を用意しましょう。
今回は、I2C通信で値を取得するサンプルを作っていきます(ちなみに、I2C通信についてはこちら)。
ここではArduino ProMini(3.3V)を使用する想定で進めています。
まず、回路を制作するために、以下のようにピンを接続します。
Arduino | ジャイロセンサー | 備考 |
3.3V | 1(VDD), 5(CS) | CSピンでI2Cを選択 |
GND | 8(GND), 4(SD0) | アドレスの選択用 |
A4 | 3(SDA) | 要4.7kΩのプルアップ抵抗 |
A5 | 2(SCL) | 要4.7kΩのプルアップ抵抗 |
回路を作る際は、備考にも書いてある通り、センサー側のSDA、SCLピンそれぞれに4.7kΩの抵抗をプルアップで接続します。
Arduinoとセンサーを接続したら、次はプログラムを見てみましょう。プログラムは、Arduinoのススメ内のL3GD20のページを参考にさせていただきました(というか、ほとんど同じorz)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
; title="L3GD20_I2C.ino"]#include <Wire.h> // Connect L3GD20 with SDA (A4), SCL (A5) const byte L3GD20_ADDR = B1101010; // SA0 = GND //const byte L3GD20_ADDR = B1101011;// SA0 = VDD_IO const byte L3GD20_WHOAMI = 0x0f; const byte L3GD20_CTRL1 = 0x20; const byte L3GD20_CTRL2 = 0x21; const byte L3GD20_CTRL3 = 0x22; const byte L3GD20_CTRL4 = 0x23; const byte L3GD20_CTRL5 = 0x24; const byte L3GD20_X_L = 0x28; const byte L3GD20_X_H = 0x29; const byte L3GD20_Y_L = 0x2A; const byte L3GD20_Y_H = 0x2B; const byte L3GD20_Z_L = 0x2C; const byte L3GD20_Z_H = 0x2D; void L3GD20_write(byte reg, byte val) { Wire.beginTransmission(L3GD20_ADDR); Wire.write(reg); Wire.write(val); Wire.endTransmission(); } byte L3GD20_read(byte reg) { byte ret = 0; // request the registor Wire.beginTransmission(L3GD20_ADDR); Wire.write(reg); Wire.endTransmission(); // read Wire.requestFrom((unsigned int)L3GD20_ADDR, 1); while (Wire.available()) { ret = Wire.read(); } return ret; } void setup() { Serial.begin(9600); while (!Serial) {} Wire.begin(); Serial.println(L3GD20_read(L3GD20_WHOAMI), HEX); // should show D4 L3GD20_write(L3GD20_CTRL1, B00001111); // |||||||+ X axis enable // ||||||+- Y axis enable // |||||+-- Z axis enable // ||||+--- PD: 0: power down, 1: active // ||++---- BW1-BW0: cut off 12.5[Hz] // ++------ DR1-DR0: ODR 95[HZ] } void loop() { short X, Y, Z; float x, y, z; static float xt, yt, zt; X = L3GD20_read(L3GD20_X_H); x = X = (X << 8) | L3GD20_read(L3GD20_X_L); Y = L3GD20_read(L3GD20_Y_H); y = Y = (Y << 8) | L3GD20_read(L3GD20_Y_L); Z = L3GD20_read(L3GD20_Z_H); z = Z = (Z << 8) | L3GD20_read(L3GD20_Z_L); x *= 0.00875; // +-250dps xt += x; //x *= 0.0175;// +-500dps //x *= 0.07; // +-2000dps y *= 0.00875; // +-250dps yt += y; z *= 0.00875; // +-250dps zt += z; Serial.print(X); // X axis (reading) Serial.print("\t"); Serial.print(Y); // Y axis (reading) Serial.print("\t"); Serial.print(Z); // Z axis (reading) Serial.print("\t"); Serial.print(x); // X axis (deg/sec) Serial.print("\t"); Serial.print(y); // Y axis (deg/sec) Serial.print("\t"); Serial.println(z); // Z axis (deg/sec) Serial.print(xt); // X axis (deg) Serial.print("\t"); Serial.print(yt); // Y axis (deg) Serial.print("\t"); Serial.println(zt); // Z axis (deg) delay(10); } |
コメントアウトで少し長くなっていますが、基本的な流れは以下の通りです。
[初期化関数: setup() 内で処理]
1. I2C通信とシリアル通信の有効化
2. センサーの基本的な設定を行う
[メインループ: loop() 内で処理]
1. センサーの計測値を取得
2. 実際の物理量に変換
3. シリアル通信で計測した角速度を送信
全ての解説は例のごとく省略しますが、いくつか詳しく見ていきたいと思います。
まず、センサーの中ではアドレスとアドレスというものが設定されています。
ここでいうアドレスとは、センサーのプログラム内での名前みたいなもので、センサーを特定するために使用します。
また、レジスタとはセンサー内の設定、あるいは計測した値を記憶している場所を表します。プログラムではレジスタを指定してから、値を書き込んでセンサーの設定、あるいは値の取得して物理量の測定を行います(C言語のポインタに似てるかも)。
では、アドレスを指定しての読み書きはどう行うか。
それを定義した関数が以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
//センサーの設定を書き込む関数 void L3GD20_write(byte reg, byte val) { //アドレスを指定し、書き込みスタート Wire.beginTransmission(L3GD20_ADDR); //書き込み先のレジスタを指定 Wire.write(reg); //任意の値(1バイト)を書き込む Wire.write(val); //書き込み終了 Wire.endTransmission(); } //センサー値(1バイト)を読み取る関数 byte L3GD20_read(byte reg) { byte ret = 0; //センサー値の格納をする変数 //値を取得するセンサー(アドレス)を指定 Wire.beginTransmission(L3GD20_ADDR); //読み取り先のレジスタを指定 Wire.write(reg); //読み取り先の指定を終える Wire.endTransmission(); //センサー値の読み取り Wire.requestFrom((unsigned int)L3GD20_ADDR, 1); while (Wire.available()) { ret = Wire.read(); } return ret; } |
基本的にはArduinoのライブラリを利用していますが、そのまま書くと長くなってしまうため、関数にまとめています。
なお、センサー値は2バイトの値で取得できるのですが、この関数では1バイトずつしか読み取れないため、上位8ビットと下位8ビットを別々に読み取ってから合成しています(レジスタが別々のため)。
あとは、いつも通りプログラムをArduinoに書き込み、シリアル通信で値が表示されれば成功です。
デバイスを回転させると、回転の向きによっていろいろと値が変わると思います。
これを応用して、加速度センサーやデジタルコンパスと組み合わせれば、ロボットの姿勢や移動の軌跡なども測定することができるようになります。
余力がある方は、ぜひ挑戦してみてください。
次回はそのあたりをやってみようかなぁ
【お勧めのデバイス】
ちなみに、加速度センサとジャイロセンサが一体になったセンサーがAmazonで売られてます。
450円と値段も安いのでお勧めです(使ったことないけどw)。
コメント