M5StackGrayでレーザー距離センサの動作テスト
2021.5.26 Coskx Lab
1 はじめに
M5Stack Grayにレーザー距離センサVL53L1X(STMicroelectronics)を接続して周囲の対象物までの距離を測定します。
VL53L1Xは,赤外線レーザにより4m程度までの距離を測定することができ,M5StackにはI2Cでデータを転送します。
VL53L1Xを基板上に取り付けた製品は多数ありますが,ここでは秋月電子で販売されているAE-VL53L1Xを使用します。
2 使用環境
- Windows 10 64-bit
- Arduino IDE 1.8.13
- M5Stack Gray ESP32-D0WDQ6-V3 (revision 3)
MPU6886 + BMM150 16MB 40MHz
- AE-VL53L1X
3 接続
マニュアルのピンアサインを見てそのままつなげるだけです。
XSHUTとGPIOはAE-VL53L1X内部でプルアップされているので何もつながないことにします。
名称 | 機能 | 配線色 | M5Stack配線先 |
V+ | 3.3~5V 入力 | 赤 | 3.3V |
GND | GND | 黒 | GND |
SDA | データ線 | 黄 | SDA (21) |
SCL | クロック線 | 緑 | SCL (22) |
XSHUT | シャットダウン入力端子 | 青 | 接続しない |
GPIO | GPIO(2.8Vレベル) | 紫 | 接続しない |
注意1 モータなどのノイズ発生機器と同時にレーザ距離センサを使う場合,使用していないXSHUT(青)とGPIO(紫)の2本もケーブルは,コネクタから外してください。ノイズの影響でレーザ距離センサが誤動作する場合があります。
注意2 AE-VL53L1XのV+には「3.3~5V 入力」と書いてありますが,これは3.3Vのシステムでも5Vのシステムでも使えますということを表しています。
AE-VL53L1Xはよくできていて,AE-VL53L1Xの電源に3.3Vを与えると3.3VでI2C通信し,5Vを与えると5VでI2C通信します。
M5Stackで使うとき,M5Stackの信号レベルは3.3Vであるため,3.3Vで通信したいのでAE-VL53L1Xの電源には3.3Vを与えます。
信号レベルが5Vのマイコンにつなげるときは,5Vで通信したいので5Vを与えます。
参考 M5Stackの裏側に書いてあるピンの名称
注意 SDA,SCLはI2C用に用途の定まったピンなので,他のピンを利用することはできません。
実際の様子 未使用の配線が処理されていないので汚いです。
4 準備
VL53L1XはI2CでCPUとデータをやり取りしますが,そのためのライブラリが必要です。
Arduino IDEにて,「ツール」メニューから,「ライブラリを管理」を選び,「ライブラリマネージャ」を開きます。
上部にある「タイプ すべて」,「トピック すべて」の右側の長いボックスが検索欄なので,
そこに「VL53L1X」と書き込むと検索されます。複数の「VL53L1X」が見つかりますが,
「by PoLolu」と書いてあるものを選んでインストールします。
5 テストプログラム
https://github.com/pololu/vl53l1x-arduino
を参考にさせていただきました。
実行時に,測定距離4m以上の場合でも何らかの数値が得られます。
しかしstatusを表示させてみると,計測に成功しているかどうかがわかります。
・range valid (statNum = 0) 正常測定値が得られています。
・signal fail (statNum = 2) それらしい値が得られていますが,測定時の信号レベルが低いとき,および測定限界以遠のとき
・wrap target fail (statNum = 7) 測定失敗です
今のところこれ以外の表示は出てきません。
・statNum = 0 なら信頼
・statNum = 2 なら信頼度は低いが一応測定値は使う。(ただし,測定限界以遠の時には測定値は全く使えないので,測定限界以内であることが確実である場合のみ)
・statNum = 7 なら測定値は使えない
といったところでしょうか。
動作テスト用プログラム本体(センサは常時稼働)
//DistanceSenSor_VL53l1xTest03.ino//
#include <M5Stack.h>
#include <Wire.h>
#include <VL53L1X.h>
VL53L1X sensor;
const int SDApin = 21; //SDAピン番号
const int SCLpin = 22; //SCLピン番号
void setup()
{
M5.begin();
M5.Power.begin();
Wire.begin(SDApin,SCLpin); //ここをGray用に設定しないと通信に失敗する
Wire.setClock(400000); // use 400 kHz I2C
M5.Lcd.setTextSize(2); //高さ16 26文字/行
sensor.setTimeout(500); //[msec]
if (!sensor.init())
{
M5.Lcd.println("Failed to detect and initialize sensor!");
while (1);
}
sensor.setDistanceMode(VL53L1X::Long);
sensor.setMeasurementTimingBudget(50000); //測定タイミングバジェット(1回の距離測定)に許容される時間[micros]
sensor.startContinuous(50); //連続測定モードの測定間隔[msec] 0を指定すると可能な限り最速になる
M5.Lcd.println("VL53L1X Started");
}
void loop()
{
static int result = 0;
//result = (result*8 + sensor.read()*2)/10;
result = sensor.read();
if (sensor.timeoutOccurred()) {
M5.Lcd.setCursor(0, 80);
M5.Lcd.print("TIMEOUT");
} else {
M5.Lcd.setCursor(0, 80);
M5.Lcd.print(" ");
}
M5.Lcd.setCursor(0, 30);
M5.Lcd.print("
");
M5.Lcd.setCursor(0, 30);
M5.Lcd.printf("status: %s\n",VL53L1X::rangeStatusToString(sensor.ranging_data.range_status));
M5.Lcd.printf("statNum: %5d \n",sensor.ranging_data.range_status);
M5.Lcd.printf("result[mm]: %5d \n",result);
M5.Lcd.printf("range: %5d \n",sensor.ranging_data.range_mm);
M5.Lcd.printf("peakSignal: %8.3f \n",sensor.ranging_data.peak_signal_count_rate_MCPS);
M5.Lcd.printf("ambient: %8.3f ",sensor.ranging_data.ambient_count_rate_MCPS);
delay(500);//[msec]
}
常時センサを動かす必要はないので,必要な時だけセンサを動かして,センサがデータを取得出来たら(データの準備ができたら)読み込むようにします。
「センサへにデータを取得しなさい」は readSingle(false)
「データがデータの準備ができているのチェック」はdataReady()
「センサからのデータ取得」は read(false)
で行います。
sensor.readSingle(false);
while (!sensor.dataReady());
int result = sensor.read(false);
の3行だけでも良いのですが,whileで待っている間CPUは何も仕事をしない状態になってしまいます。
そのため,状態を示す変数を用いて,状態が変化したときだけ必要な作業を行うようなテストプログラムにしています。
動作テスト用プログラム本体(センサは必要な時だけ稼働)
//DistanceSenSor_VL53l1xTest04.ino//
#include <M5Stack.h>
#include <Wire.h>
#include <VL53L1X.h>
//https://www.arduino.cc/reference/en/libraries/vl53l1x/
//SingleMode (not ContinuousMode)
//必要なときに1回だけ測距
VL53L1X sensor;
int measurementstatus = 0; //0:何もしていない 1:リクエスト中
const int SDApin = 21; //SDAピン番号
const int SCLpin = 22; //SCLピン番号
void setup()
{
M5.begin();
M5.Power.begin();
Wire.begin(SDApin,SCLpin); //ここをGray用に設定しないと通信に失敗する
Wire.setClock(400000); // use 400 kHz I2C
M5.Lcd.setTextSize(2); //高さ16 26文字/行
sensor.setTimeout(500); //[msec]
if (!sensor.init())
{
M5.Lcd.println("Failed to detect and initialize sensor!");
while (1);
}
sensor.setDistanceMode(VL53L1X::Long);
sensor.setMeasurementTimingBudget(50000); //測定タイミングバジェット(1回の距離測定)に許容される時間[micros]
//sensor.startContinuous(50); //連続測定モードの測定間隔[msec] 0を指定すると可能な限り最速になる
M5.Lcd.println("VL53L1X Started");
}
void loop()
{
if (measurementstatus == 0) {
sensor.readSingle(false); //start the measurement
measurementstatus = 1;
} else if (measurementstatus == 1) {
if (sensor.dataReady()){ //センサデータ取得完了だったら
measurementstatus = 0;
int result = 0;
result = sensor.read(false);
if (sensor.timeoutOccurred()) {
M5.Lcd.setCursor(0, 80);
M5.Lcd.print("TIMEOUT");
} else {
M5.Lcd.setCursor(0, 80);
M5.Lcd.print(" ");
}
M5.Lcd.setCursor(0, 30);
M5.Lcd.print(" ");
M5.Lcd.setCursor(0, 30);
M5.Lcd.printf("status: %s\n",VL53L1X::rangeStatusToString(sensor.ranging_data.range_status));
M5.Lcd.printf("statNum: %5d \n",sensor.ranging_data.range_status);
M5.Lcd.printf("result[mm]: %5d \n",result);
M5.Lcd.printf("range: %5d \n",sensor.ranging_data.range_mm);
M5.Lcd.printf("peakSignal: %8.3f \n",sensor.ranging_data.peak_signal_count_rate_MCPS);
M5.Lcd.printf("ambient: %8.3f ",sensor.ranging_data.ambient_count_rate_MCPS);
delay(1000);//[msec]
}
}
//M5.Lcd.setCursor(0, 130);
//M5.Lcd.printf("measurementstatus = %d", measurementstatus);
}
6 赤外線レーザ光の観察
赤外線の照射を見るのには,デジタルカメラやスマホのカメラがよいと思っていたのですが,近年は赤外線カットフィルタが入っているので,見ることが出来ません。
古いデジカメで観察したところ,観察ができました。思った以上にレーザ赤外線は指向性が悪く,広がっています。
そうすると距離測定では,床面や,周囲の障害物の影響を受けてしまうことが考えられます。
センサの直前に白い箱をおいたところ,かすかに,ピンク色の円が写りました。
センサを20cmくらい離すとピンクの円は写らなくなります。
7 トラブルシューティング
動作が不安定,時折初期化を失敗するとき,モータを含むシステムで使って誤動作するとき
(1)センサケーブルが細くて耐ノイズ性に問題があります。ケーブルはきれいに束ねない方がよいようです。
(2)使用していないセンサのケーブル(例えばGPIOの紫ケーブル)はノイズの原因になりますので取り外した方が良いでしょう。(下の画像は紫ケーブルを外したところ。細いピンなどで詰めを持ち上げれば簡単に外れます。)
(3)XSHUTを使っている場合,センサ内部でプルアップされているので,マイコン側はオープンドレインに設定するのがセオリですが,ノイズに弱くなるので,単なる出力設定にすると改善されることがあります。
pinMode(〇〇〇〇, OUTPUT_OPEN_DRAIN);
ではなく
pinMode(〇〇〇〇, OUTPUT);
8 まとめ
センサを手にもって,周囲に向けたところ,4m程度までの距離測定ができました。
古いデジカメで観察したところ,思った以上にレーザ赤外線は放射指向性が悪く,広がっています。
そのため,床面や,周囲の障害物の影響を受けています。
フローリングの床面から高さ40mmのセンサでは3mくらいが正常測定限度でした。
また,凹凸のある側面壁から180mmの位置でフローリングの床面から高さ40mmのセンサでは2mくらいが正常測定限度でした。
どのような場合でも距離測定値は得られてしまうものの,statusを見るとその値を信用してよいかどうかわかります。