測距モジュール(VL53L0X)のI2Cスレーブ アドレスの変更プログラム

VL53L0X外観
VL53L0X測距センサー

この測距モジュールは、I2Cインターフェイスを通してデータを取得できる取り扱いやすいセンサーです。ただ、複数のモジュールを使う場合には、それぞれのモジュールのI2Cのスレーブ アドレスを変更する必要があり(デフォールト アドレスは0x29)、その変更はプログラムで行います。GitHubにVL53L0Xライブラリがあり、このセンサーをRaspberry piで使うためのモジュールや、複数のセンサーを使うサンプルプログラムも用意されています。しかし、そのサンプルプログラムを使うとエラーになり機能しなかったので、複数のセンサーを使う手順を見直して、実際に使えるようになったので、その手順とプログラム事例を記録として残します。
<VL53L0Xの主な仕様>
・インターフェイス:I2C
・電源電圧(VDD):3.3~5.0V
・測距範囲:3~200cm

1.センサーモジュールVL53L0XのRaspberry piへの接続

センサーモジュールの端子からは6本のケーブルが出ていて、その内、電源(①VDD、②GND)、I2C信号(③SDA、④SCL)をRaspberry piへ接続する以外に、⑤XSHUT端子を使います。⑥GPIO1端子は、割り込み用の信号ですが、今回は使いません。
今回の例では、2つのVL53L0Xを使いますが、1つ目のセンサーの⑤XSHUTをGPIO20に、2つ目のセンサーの⑤XSHUTをGPIO21に接続しました。

VL53L0X配線
6本のケーブル

※モジュールのピン配列は、秋月電子通商で販売されているものと、ストロベリー・リナックスで販売されているもので異なっています。秋月電子通商製のセンサーモジュールのXSHUTは10kΩでプルアップされています。ここでは、秋月電子通商で販売されているセンサーモジュール(\1,080)を使っています。

2.Python用APIモジュールのインストール

このセンサーを使うためのAPIモジュールはいろいろなサイトで用意されているが、ここでは次gitHubから入手した。
pip3 install git+https://github.com/naisy/VL53L0X_rasp_python.git
sudo apt-get install build-essential python-dev・・・最新でない場合
mkdir gitTemp
cd gitTemp
git clone https://github.com/naisy/VL53L0X_rasp_python.git
cd VL53L0X_rasp_python
make

このセンサーを使う場合には、このインストール後にできる次の2つのファイルが必要です。
VL53L0X.py
/bin/vl53l0x_python.so

3.スレーブ アドレスを変更するプログラムの説明

測距センサーVL53L0XのI2Cスレーブ アドレスの初期値は0x29となっているので、複数のセンサーを接続すると干渉してしまいます。そこで、通信するセンサーの⑤XSHUT信号だけを「HIGH」にして、アドレス変更し、2つのセンサーのスレーブ アドレスを異なるアドレスにすれば、それぞれ独立してセンサー機能を使うことができます。

(1)全てのセンサーの⑤XSHUT信号を「LOW」にして「スタンバイ」モードにする。

この時、I2Cデバイスの接続アドレスをi2cdetectで確認すると、何も見えない。

pi@pi3B:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --      
(2)1番目のセンサーの⑤XSHUT信号を「HIGH」にして「アクティブ(BOOT)」モードにする

I2C接続デバイスとして、1番目のセンサーの0x29が見える。

pi@pi3B:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- 29 -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --    
(3)1番目のセンサーのアドレスを変更する

1番目の初期アドレスを使って、VL53L0Xのインスタンスを作り、ライブラリに用意されているアドレス変更関数(change_address)を使って、新しいアドレス0x2Bに変更する。接続デバイスのリストから0x29が無くなり、新しい0x2Bが見える。

pi@pi3B:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- 2b -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --      
(4)2番目のセンサーについても、上記の(1)~(3)の操作を行う。

2番目のセンサーのアドレスも0x29から0x2Dに変更される。その結果、1番目のアドレス0x2B、2番目のアドレス0x2Dを用いて、それぞれセンサーから距離データを得ることができる。この変更アドレスは、⑤XSHUTを「LOW」にして、「スタンバイ」モードにすると、初期アドレス0x29に戻ります。

pi@pi3B:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- 29 -- 2b -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --               

2番目のセンサーのアドレスを変更し、2つが異なるアドレスとなる。

pi@pi3B:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- 2b -- 2d -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --          

4.アドレスを変更して2つのセンサーから距離データを得るプログラム例

2つのVL53L0Xを用いて、それぞれ0x2B、0x2Dにアドレス変更して、2つのセンサーから100回データを取得するプログラム事例です。

# -*- coding: utf-8 -*-
import time
import VL53L0X
import RPi.GPIO as GPIO

VL53_1_XSHUT = 20    # GPIO for XSHUT PIN of VL53L0X No.1
VL53_2_XSHUT = 21    # GPIO for XSHUT PIN of VL53L0X No.2

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

# HW Standby mode (XSHUT PIN is Active Low)
GPIO.setup(VL53_1_XSHUT, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(VL53_2_XSHUT, GPIO.OUT, initial=GPIO.LOW)
time.sleep(0.5)

# No.1のVL53L0XをBOOTして、初期i2cアドレス(0x29)で、i2cアドレスを変更する
GPIO.output(VL53_1_XSHUT, GPIO.HIGH) # VL53L0X No.1 BOOT
time.sleep(0.1)
sensor1 = VL53L0X.VL53L0X(i2c_bus=1,i2c_address=0x29)
sensor1.change_address(0x2B)    #No.1のVL53L0Xのi2cアドレスを0x2Bに変更

# No.2のVL53L0XをBOOTして、初期i2cアドレス(0x29)で、i2cアドレスを変更する
GPIO.output(VL53_2_XSHUT, GPIO.HIGH) # VL53L0X No.2 BOOT
time.sleep(0.1)
sensor2 = VL53L0X.VL53L0X(i2c_bus=1,i2c_address=0x29)
sensor2.change_address(0x2D)    #No.2のVL53L0Xのi2cアドレスを0x2Dに変更

# センサーの測距精度を設定して、測定開始する
sensor1.open()
sensor1.start_ranging(VL53L0X.Vl53l0xAccuracyMode.BETTER)
sensor2.open()
sensor2.start_ranging(VL53L0X.Vl53l0xAccuracyMode.BETTER)

timing = sensor1.get_timing()
if timing < 20000:
    timing = 20000
print("Read Timing = ", timing/1000, " (msec)")

for rpt in range(100):
    distance1 = sensor1.get_distance()
    distance2 = sensor2.get_distance()
    print("{:5d} mm, {:5d} mm".format(distance1, distance2))
    time.sleep(timing/1000000.00)   # micro sec. -> sec.
    
sensor1.stop_ranging()
sensor1.close()
GPIO.output(VL53_1_XSHUT, GPIO.LOW) # i2cアドレスを初期アドレスに戻す
sensor2.stop_ranging()
sensor2.close()
GPIO.output(VL53_2_XSHUT, GPIO.LOW) # i2cアドレスを初期アドレスに戻す
GPIO.cleanup()