測距モジュール(GP2Y0E03)で物体の距離を測ってみます(2/2)

〔1/2〕   〔Arduinoの動かせ方入門に戻る〕



測距モジュール  前に測距モジュールのGP2Y0A21YKを動作させて見ました
 今度シャープから新型の測距モジュールGP2Y0E03が出たので
 Arduinoで動作させて見ます。
 尚、PICでGP2Y0E03の記事はこちらです。

 左写真の上がGP2Y0A21で、下がGP2Y0E03です、
 かなり小さくなっていますね。
 これならロボット等にも搭載しようかなって思えますね。
 が、取り付け穴ぐらいは欲しいような気がします....

 GP2Y0E03は秋月電子のこちらから購入しています。

 GP2Y0E03の測距範囲は4〜50cmです、出力はアナログ電圧出力I2C出力が有ります。
 GP2Y0E03のデータシート(アプリケーションノート)はこちらです。

下のグラフはデータシートからの抜粋ですが、出力電圧と距離の関係グラフです。
左がGP2Y0A21で、右がGP2Y0E03です。

電圧と距離の関係グラフ1  電圧と距離の関係グラフ2

GP2Y0A21では、電圧と距離の関係が一直線でなかった為に距離を割り出すのが大変で誤差が大きく
距離を測ると言うよりは物体を検知する的な使い方しか出来なかったです。

GP2Y0E03は、赤外線を使い三角法で距離を測定するらしくグラフが一直線ですねぇ、すばらしぃ、
ですので距離の割り出しも簡単で精度もかなり良いです、±1cm以内位でした。
ただ、三角法ゆえんかぁ、放射する光が垂直に物体に当たる様にする必要が有り、
ズレても±3°以内位で光を反射させなといけないです。
でないと距離がズレます、結構シビアかもね、この辺が若干なんだなぁ。

《配線図》

配線図 この配線の、GP2Y0E03からの出力は
アナログ出力(Vout)とI2C出力(SCL/SDA)の
両方を配線しています。
なので自分の利用する方のみ配線を
行えば良いでしょう。

GP2Y0E03は付属のコネクタケーブルで
接続します、7本線が出ています。

VDDは2.7-5.5Vですが、I/Oが1.8-3.3Vです
なので3.3Vで利用しましょう。

VIN
I/Oへの電圧供給端子Cです。
「I2C通信とGPIO1端子の入力電圧の
入力/出力電圧は、VIN(IO)端子の
入力電圧によって決定される。」
と書いて有ります。

GPIO1
アクティブ/スタンバイ切替端子Dです。
アクティブはHIGH(VINと同じ電圧)に接続
スタンバイはLOW(GND)に接続

アナログ出力
GP2Y0E03のAVoutとArduinoのA0端子を接続しています、上図の青色線です。
上のグラフでも解る様に大体、4〜50cm で 2.2V〜0.55V の出力電圧が得られます。

I2C出力
GP2Y0E03のESCL/FSDAとArduinoのA5(SCL)/A4(SDA)とをそれぞれ接続します、上図の黄色線です。
但しGP2Y0E03側は3.3V、Arduino側は5Vの電圧差が有るので電圧レベルを合わせる必要が有ります。

I2Cレベル変換モジュール  左の電圧レベル変換モジュール(PCA9306)を間に入れています、
 3.3Vマイコンを使う場合、変換は必要なく直接接続出来ますが
 I2C用プルアップ抵抗は必要になります。
 このモジュールは1KΩのプルアップ抵抗を内蔵しているので
 それを利用しています。

 外付けプルアップ抵抗を使う場合はモジュール裏のジャンパーパターンをカットすれば良いです。

 尚、VPU端子は外部から通信可能不可能の切り替えをする為の物ですが、今回利用していません。
 また、VREF2側に電圧の高い方を接続する様にしましょう。

 あ、それとぉ、Arduino UNOの場合はデジタル端子側の方にSCL/SDA専用端子が有ります、
 そちらに接続しても良いでしょう。

PS. *1)
こちらのモジュール(FXMA2102)も有ります、こちらはI2C用プルアップ抵抗は無しでOEピンが有るので
同じI2Cアドレスがダブってもモジュールを切り替える事も出来ますね、使い勝手がよさそう。

《スケッチ1》

スケッチ1はアナログ出力を利用する場合のサンプルプログラムです。
アナログ端子(A0)に接続したセンサーから、100回読込み単純平均化させた値から距離に変換し
表示させるだけのスケッチです。

@まずは、上記配線図の様に配線しましょう。
Aarduinoボード(Arduino UNO R3)はUSBケーブルで接続して、arduino IDE 1.0.1を起動させます。
BIDEに下記のスケッチプログラムをコピーペーストして貼り付けて下さい。
---------------------------------------------------------------------
void setup() {
     Serial.begin(9600) ;          // 9600bpsでシリアル通信のポートを開きます
 }
void loop() {
     int ans ;

     ans = IDMread(0)  ;           // アナログピン0番のセンサー値を読込む
     ans = map(ans,0,1023,0,500) ; // 読込んだ値から電圧値に変換する(0-5V)
     ans = map(ans,50,220,50,4) ;  // 電圧値から距離に変換する(0.5-2.2V -> 50-4cm)
     Serial.print(ans) ;           // シリアルモニターに表示させる
     Serial.println("cm") ;
     delay(500) ;                  // 500ms後に繰り返す
 }
// 赤外線測距モジュールから読み込む処理
int IDMread(int PinNo) {
     long ans ;
     int i ;

     ans = 0 ;
     for (i=0 ; i < 100 ; i++) {
          ans  = ans + analogRead(PinNo) ;   // 指定のアナログピンから読取ります
     }
     return ans/100 ;                        // 100回の平均値を返します
}
---------------------------------------------------------------------
CIDEツールバーの赤枠部分「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを
 行います。

upload


実行結果1  D正常終了後、ArduinoIDEのシリアルモニター(右側のアイコン)を
   起動して下さい、

 E赤外線距離センサーの前に反射物をかざしてみましょう、
   左図の様に値が変化するはずです。
  この値は10cm〜15cmの間で反射物を移動させた結果です。

 近場はかなり正確です、50cmに近づくと±1cmぐらいの誤差が
 出るような感じです。

 実際に電圧を測ったりしてmap( )関数の値を少し上下に変更すれば
 もう少し精度が出ると思いますが実験していません。


《スケッチ2》

スケッチ2ではI2Cで接続をする場合のサンプルプログラムです。

スケッチ1と入換えて実行して見て下さい、結果は上図と同じ様に表示されます。
また、I2C機能はArduinoの標準Wireライブラリを使っています、
詳しくはArduino 日本語リファレンスを参照下さい。
---------------------------------------------------------------------
#include <Wire.h>

#define SENSOR_ADRS   0x40              // GP2Y0E03のI2Cアドレス
#define DISTANCE_ADRS 0x5E              // Distance Value のデータアドレス

// 電源起動時とリセットの時だけのみ処理する関数
void setup()
{
     Serial.begin(9600) ;               // シリアル通信の初期化
     Wire.begin() ;                     // I2Cの初期化、マスターとする
     delay(1000) ;                      // 1秒後に開始
}
// 繰り返し実行されるメインの処理関数
void loop()
{
     int  ans  ;
     byte c[2] ;

     Wire.beginTransmission(SENSOR_ADRS) ;        // 通信の開始処理
     Wire.write(DISTANCE_ADRS) ;                  // 距離値を格納したテーブルのアドレスを指定する
     ans = Wire.endTransmission() ;               // データの送信と終了処理
     if (ans == 0) {
          ans = Wire.requestFrom(SENSOR_ADRS,2) ; // GP2Y0E03にデータ送信要求をだし、2バイト受信する
          c[0] = Wire.read()  ;                   // データの11-4ビット目を読み出す
          c[1] = Wire.read()  ;                   // データの 3-0ビット目を読み出す
          ans = ((c[0]*16+c[1]) / 16) / 4 ;       // 取り出した値から距離(cm)を計算する
          Serial.print(ans) ;                     // シリアルモニターに表示させる
          Serial.println("cm") ;
     } else {
          Serial.print("ERROR NO.=") ;            // GP2Y0E03と通信出来ない
          Serial.println(ans) ;
     }
     delay(500) ;                                 // 500ms後に繰り返す
}
---------------------------------------------------------------------
I2Cスレーブアドレスについて

アドレス設定  アドレスは7ビットで表します、左図の1〜7ビットです。
 0ビット目はR/Wでこれはスレーブに対する読書き指示ビットです。
 R/W=0 : 書き込み要求です(スレーブは受信モード)
 R/W=1 : 読み込み要求です(スレーブは送信モード)

今回のGP2Y0E03アドレスは、7ビット"1000000"(0x40)です。("1000000"+R/W)
データシートには、
R/W=0 : "1000000"+"0"で0x80
R/W=1 : "1000000"+"1"で0x81
と8ビットで記載されています注意しましょう。
よってここでは
#define SENSOR_ADRS 0x40 // GP2Y0E03のI2Cアドレス
となっています。

GP2Y0E03アドレスは変更する事が出来ます、GP2Y0E03内部の不揮発性メモリに書込まれています。
これを変更(E-Fuse Programming)すれば良いでしょうその方法はデータシートを参照して下さい。

距離計算について

GP2Y0E03の距離用データ格納先は、テーブルアドレスの0x5E,0x5Fに格納されています。
データは12ビットです、0x5Eに上位11-4ビットが格納され、0x5Fに下位3-0ビットが格納されています。
スケッチでは
ans = ((c[0]*16+c[1]) / 16) / 4 ;    // 取り出した値から距離(cm)を計算する
となっています。
 c[0] = 0x5E (11-4 Bit)
 c[1] = 0x5F ( 3-0 Bit)
    4 = 2^n    // n=Shift Bit(テーブルアドレス0x35の内容で0x01か0x02です、デフォルトは0x02)
よって実際は
ans = ((c[0]*16+c[1]) / 16) / pow(2,0x02) ;  // pow()はべき乗関数
なので、本当ならsetup( )内でテーブルアドレス0x35を読込んで置いてそれを計算に使うとした方が
良いです、が、0x35は自分で設定を行うデータで有りどんな値(デフォルトは0x02)が設定されているか
解っているはずです。
また、pow( )関数を使うとコンパイル後の使用メモリが1.5K程増えます、
だからスケッチは 2^2 = としました。

《その他》

実験の風景  左は実験風景の写真です。

 アナログ接続とI2C接続でお勧めは
 アナログ接続です、
 スケッチが簡単だしぃ、I2C接続は
 スケッチサイズが1.0K程増えるしぃ、
 でもぉ複数個使用するならI2C接続でしょう。

 反射物に光が垂直に当たる様にしないと
 距離が結構ずれるのが気にかかります
 移動する物(ロボット・車)に搭載して
 果たして上手く行くのか気になりますねぇ。

 こちらも有りますがアナログ出力のみ
 しかもお値段が大して変わらない。




記事一部追記(*1) 2019/01/27


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.