みなさん,こんにちは
おかしょです.
この記事ではセンサとI2C通信をする方法を解説します.
使用するセンサは加速度センサ,ジャイロセンサ,地磁気センサが一つにまとまっている9軸センサを使います.
なぜこのセンサを使うのかというと,このブログでは倒立振子ロボットを作ることを目標に電子工作を行ってきました.倒立振子ロボットを自律させるためには振子の角度を知る必要があります.角度の情報だけでよければ地磁気センサは必要ないのですが,ついでです.地磁気センサもしっかり使いたいと思います.
この記事を読むと以下のようなことがわかる・できるようになります.
- I2C通信とはどのような通信方式か
- I2C通信の電子回路
- I2C通信を行うプログラムの書き方
この記事を読む前に
この記事内では,センサーの他にブレッドボードなどの電子部品を使用します.
ブレッドボードを使用したことがない方は以下で使用方法などを解説しているので,先に読むようにしてください.
今回使用するもの
今回使用したのは以下になります.
- センサ (LSM9DS1)
- ブレッドボード
- ジャンパー線×4本
- Arduino Uno
- USBケーブル(書き込み&電源用)
一番上に書いてあるLSM9DS1というのが,I2C通信を行う加速度・ジャイロ・地磁気センサーになります.
I2C通信とは
今回はセンサとI2C通信をすると言いましたが,そもそもI2C通信とは何なのでしょうか.
センサからデータを取得するには,マイコンと通信をさせるしかありません.この通信方式はI2C通信,SPI通信,USART通信など,さまざまなものがあります.
今回行うI2C通信は アイ・スクエアード・シー通信と読むのですが,よくアイ・ツー・シー通信と呼ばれます.この通信方式は信号線が2本だけでできるのが特徴です.
Arduinoを使って通信する場合は,センサと通信して,データ処理までしてくれるライブラリがたくさん用意されています.なので,全く通信のことはわからなくても使うことができます.
しかし,ライブラリに頼ってしまうと,プログラムの中身がよくわからずに使っているため,ロボットに合わせた設定ができなくなってしまいます.もちろん,中身を理解したうえでライブラリを使うのであれば,そのようなことにも対応できるとは思いますが,自分でちゃんと書いた方が自分好みに設定がしやすいため,自力でプログラムを書いた方が良いです.
それではI2C通信とはどのような通信方式なのか見ていきます.
この説明はI2C通信を用いるほとんどのセンサのデータシートに書かれています.
I2C通信はmasterとslaveという役割をそれぞれに与えて通信をします.センサなどからデータを取得したい場合は取得する側のマイコンをmaster,センサなどのデータを与える側をslaveとします.slaveというのは奴隷という意味があり,マイコンとセンサが主従関係のようになることからこのように割り振られています.今回の場合はmasterがArduino,slaveが9軸センサのLSM9DS1ということになります.
SlaveにはI2C addressというものが割り振られています.I2C addressはslave addressとも呼ばれます.複数のセンサと通信したい場合,このI2C addressによってそれぞれのセンサを区別します.つまり, I2C adressはセンサの名前のようなものです.
そして,さらにそのセンサの中に各機能ごとにaddressが割り振られています.このaddressをregister addressと呼びます.今回使用するセンサの場合は,加速度のデータが格納されているaddressや地磁気のデータが格納されているaddressがあります.
このregister addressを指定することによって,データを読み込んだり,設定を書き換えたりすることができます.
センサと通信する場合は,まずmasterであるArduinoからデータを送信します.この時にまず最初に I2C addressを送信して,センサを指定します.これはセンサを一つしか使わない場合でも,必ず行います.そして,そのセンサのアクセスするregister addressを指定します.
slave側のセンサはそのデータを受けっとたことをmasterに知らせます.master側はslaveがaddressを受け取ったことを確認したら,データを読み出したり,書き込む処理を行います.この時,一度に書き込みと読み出しをすることはできないので注意が必要です.また,書き込んではいけないところに,数値を書き込んでしまうとセンサが壊れて使えなくなることがあるので注意してください.書き込んではいけないaddressなどはデータシートに記載されているので,しっかり読んで確認するようにしてください.
このようにしてデータの書き込みや読み込みができたら,通信終了となります.
I2C通信手順
- MasterがI2C addressを送信
- 指定されたSlaveは返事をする
- Masterがregister addressを送信
- Slaveは返事をする(はい!)
- マスターはセンサーに書き込む場合はデータを送る
データを取得する場合は受信を待つ - スレーブはデータが送られてきたら書き込む
データを送る場合はデータを送信する - マスターは通信終了を知らせる
配線方法
次に,今回使用するセンサのLSM9DS1の配線方法を紹介します.
I2C通信で使うピンは,電源を供給するピンとGND,シリアルデータを伝送するピン(SDA),シリアルクロックを伝送するピン(SCL)の4本です.このように通信のために使用する線はSDAとSCLの2本だけで十分です.
このSDAやSCLというのは,SDAはデータを送るためにに使う線のことで,SCLというのはマイコンとセンサ間でデータの送るタイミングを合わせるために用いる線です.SDAがないと,そもそもデータが送れないので絶対に必要です.SCLもないとマイコンとセンサで時間の同期ができないので,マイコンがいつデータを要求してくるのか,センサがいつデータを送れるのかが全く分からなくなってしまい通信が行えません.だから,どちらも決して欠けてはいけません.
こちらでarduinoのバージョンごとのSDA, SCLピンの配置が記載されています.
私が使用しているのはArduino Unoなので,その場合はA4がSDA,A5がSCLピンになります.
次に,センサに供給する電源について説明します.
Arduinoでは5vか3.3vが供給できるのですが,センサによっては5vでは壊れてしまう場合や3.3vだと動かない場合があります.確実に動かすために,センサのデータシートを確認する必要があります.今回使用するLSM9DS1はデータシートにVdd (supply voltage)が1.9vから3.6vと記載されています.なので,電源を供給するのは3.3vのピンと接続します.
あとはGNDを接続すれば,センサを使うための配線は完了となります.
I2C通信を行うプログラムの書き方
それでは,実際にセンサとI2C通信を行ってみましょう.
まず,今回作成したプログラムを以下に示します.
#include <Wire.h>
uint8_t who_ag, who_m;
void setup() {
Serial.begin(115200);
Wire.begin();
Wire.beginTransmission(0x6B);
Wire.write(0x0F);
Wire.endTransmission(false);
Wire.requestFrom(0x6B, (uint8_t) 1);
who_ag = Wire.read();
Wire.beginTransmission(0x1E);
Wire.write(0x0F);
Wire.endTransmission(false);
Wire.requestFrom(0x1E, (uint8_t) 1);
who_m = Wire.read();
Serial.print("LSM9DS1 AccelGyro is ");
Serial.println(who_ag, HEX);
Serial.print("LSM9DS1 Mag is ");
Serial.println(who_m, HEX);
}
void loop() {
}
このプログラムではセンサとI2C通信を行い,しっかり通信ができているのかを確認しています.
どのようなセンサでもWHO_AM_Iというregister addressが用意されていて,通信の確認によく使用されます.上記のプログラムでも,このregister addressにアクセスして通信の確認をしています.
また,今回使用したLSM9DS1は加速度・ジャイロセンサと地磁気センサでI2C addressが別々に用意されています.そのため,二つのWHO_AM_I registerにアクセスしています.
それでは順番に解説していきます.
#include <Wire.h>
まず,一番最初にWireヘッダーファイルをincludeします.これをincludeすることによって,コマンドを入力するだけでI2C通信を簡単に行うことができるようになります.
uint8_t who_ag, who_m;
次に,各I2C addressのWHO_AM_I registerから読み込んだ値を格納するための変数をuint8_t型(符号なしの8 bit整数型)で定義します.
Serial.begin(115200);
setup関数内では,まずシリアル通信を行うためにシリアル通信のレートを設定します.
Wire.begin();
ここで,I2C通信の初期化を行います.I2C通信をする場合は,まず最初にこの初期化をしなければなりません.
これでI2C通信をする準備が整いました.以下からが,センサとのI2C通信を行うプログラムになります.
Wire.beginTransmission(0x6B);
まず,センサのI2C addressを指定します.今回使用するセンサの場合は0x6B1が加速度.ジャイロセンサのI2C addressになります.
Wire.write(0x0F);
次に,register addressを指定します.今回は0x0FがWHO_AM_Iのregister addressとして設定されていました.
Wire.endTransmission(false);
register addressまで送信したら,slave側が受け取ったことを確認して,さらにデータを送ることをslave側に伝えます.
Wire.requestFrom(0x6B, (uint8_t) 1);
ここで,もう一度I2C addressを指定し,欲しいデータのサイズを指定します.WHO_AM_I addressの場合は1 byte分のデータでいいので,上のようなプログラムになります.
who_ag = Wire.read();
最後に,センサからデータを読み込んで,用意していた変数に代入したら通信官僚になります.地磁気センサに関しても同様の流れでWHO_AM_I registerを読み取ることができます.
このプログラムを書きこんで,実行するとシリアルモニタに
LSM9DS1 Mag is 3D
と表示されれば,センサとのI2C通信ができたことになります.
まとめ
この記事ではI2C通信とはどのような通信方式か,どうやって通信をするのかを解説しました.
今回私が使用したLSM9DS1を皆さんも使っているのであれば,上記のプログラムで正常に動作すると思います.もし,正常に動作しない場合は,基板のはんだ不良が考えられるので見直してみてください.
また,別のセンサを使用している場合は,データシートをよく読んで,addressを確認してからプログラムを実行するようにしてください.間違ったプログラムのまま実行すると,センサが破損する恐れがあるので気を付けてください.
続けて読む
この記事で書いてあることができたら,センサを使用する準備ができました.
通信ができることが確認できたら,センサーを使用環境に合わせて設定を行い,データを取り出します.
その方法については以下の記事で解説しています.
Twitter(@okasho_emgineer)もやっているので,フォローしていただけると嬉しいです.
それでは最後まで読んでいただきありがとうございました.
コメント
[…] この確認は[電子工作] センサとI2C通信を行うでも行ったレジスターにアクセスして確認します.実際に確認するプログラムは以下になります. […]
センサデータを5分程度まとめて(TWELITEotMONOSTICK)→PCモニタ(TeraTerm?)出力のようなソフト例はありませんか?
コメントありがとうございます.
センサーのデータを表示するソフトをお探しということですが,当ブログではArduinoを使っているため,Arduino IDEにあるシリアルモニタを利用しています.
それ以外のソフトだと,私は研究ではSeristerを使って表示しています.
他にも定番のTera Termを使用している人もいます.
シリアルモニタとして私が知っているのは以上の3つになります.
それ以外の方法ではProcessingを用いて,シリアルモニタのようなものを作ることも可能です.
Processingを使用した方法は,このブログでも紹介していく予定ですが,他のブログでも多くの方が利用しているので調べていただいた方が早いかと思います.
早々のコメントありがとうございます。ハード関係は沢山知人がいるのですがソフトはC#、++,モニタ関連含めゼロでTeraTermが
入り易いかと思い問合せをさせて頂きました。Processingは探してみます。ありがとうございました。