5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (32) 距離センサ3 I2C VCNL4010

測定誤差を少なくする工夫がいっぱい

 10~150mmが測れる近距離用測距センサです。スイッチサイエンスから VCNL4010搭載 小型測距/環境光センサ として入手しました。Adafruitのモジュールなので、サンプル・プログラムがあり、参考になります。

 赤外線LEDで前方に照射し、フォト・ダイオードで反射光を受光し距離を測ります。赤外線は約390kHzで変調されているので、日光などに含まれる赤外線の影響を少なくできます。反射する面の状態などで、測定値が大きく変わる可能性があります。環境に合わせて測定回数のレートや平均化の回数を設定するレジスタが用意されています。

VCNL4010のスペック

  • 電源電圧 2.5~3.6V
  • 測定距離範囲 1~200mm
  • 測定光度範囲:10~16000lux
  • 環境光受光素子の中心波長 約540nm
  • 100/120Hz誘導ノイズ除去
  • 赤外線LEDデバイス電圧 2.5~5V
  • 赤外線LEDパルス電流 10~200mA
  • スレーブ・アドレス 0x13(7ビット表記)
  • インターフェース I2C(最大転送速度3.4MHz)

VCNL4010モジュール

 モジュールの回路図が見つかりません。VCNL4010の回路部分のVddは3.3Vですが赤外線LEDは5Vまでの電圧をかけられます。I2Cのインターフェースは、Highレベルが1.7~5Vと変則的ですが、3.3/5Vのどちらでも使えるようです。写真から、電源レギュレータが入っているように見えます。したがって、Vinが5V入力で3voが3.3V電圧出力だと思われます。INTは設定した距離カウントもしくは明るさカウントのスレッショルドを上回ったり下回ったときに発生する割り込み信号です。

 赤外線LEDを明るく点灯するには、5VをVinに入れます。

 モジュールには、SDA/SCLのI2C信号線に10kΩのプルアップ抵抗が入っています。ラズパイは本体にプルアップ抵抗は入っているので、取り去ります。

接続

VL6180X ラズパイ
SCL 5番ピン
SDA 3番ピン
GND 6番ピン
Vin 2番ピン 5V
3vo -
INT -

 i2cdetect -y 1 で接続を確認しました。スレーブ・アドレスは0x13です。

レジスタ

設定関連

コマンド・レジスタ(アドレス0x80

b7 b6 b5 b4 b3 b2 b1 b0
config_
lock
als_data_rdy prox_data_rdy als_od prox_od als_en prox_en selftimed_en

config_lock 読み出しのみ。値=1

als_data_rdy 読み出しのみ。環境光のデータが用意できたら1。

prox_data_rdy 読み出しのみ。距離測定のデータが用意できたら1 。

als_od 読み/書き。環境光のオンデマンド(要求があったら)測定を1回開始する。平均化が有効な場合、一連の読み取りを開始し、平均化された結果を保存する。 結果は変換の最後にレジスタ#5(HB)と#6(LB)を読む。

prox_od 読み/書き。距離のオンデマンド(要求があったら)測定を1回開始する。平均化が有効な場合、一連の読み取りを開始し、平均化された結果を保存する。 結果は変換の最後にレジスタ#7(HB)と#8(LB)を読む。

als_en 読み/書き。環境光の定期的な測定を可能にする。

prox_en 読み/書き。距離の定期的な測定を可能にする。

selftimed_en 読み/書き。状態変数とLP発振器がそれらのタイミングで計測を可能にする。 対応するビットがセットされるまで測定は行われない。

PRODUCT IDとレビジョンIDレジスタ(アドレス0x81)

 省略

距離測定レート・レジスタ(アドレス0x82

b7 b6 b5 b4 b3 b2 b1 b0
- - - - - 読み書きビット。1秒間の測定回数
000 : 1.95  (デフォルト)
001 : 3.90625 
010 : 7.8125
011 : 16.625 
100 : 31.25 
101 : 62.5 
110 : 125 
111 : 250 

赤外線LEDの電流設定レジスタ(アドレス0x83

b7 b6 b5 b4 b3 b2 b1 b0
Fuse prog ID 赤外線LEDの電流。読み書きビット。0~20の10進値。
0:0mA、1:10mA、2:20mA...20:200mA

環境光設定レジスタ(アドレス0x84

b7 b6 b5 b4 b3 b2 b1 b0

連続変換モード

読み書き。
1:イネーブル、0:ディセーブル(デフォルト)

環境光の測定レート。読み書き。1秒間の回数

000 : 1 
001 : 2(デフォルト)
010 : 3 
011 : 4 
100 : 5 
101 : 6 
110 : 8 
111 : 10 

自動オフセットの補償

読み書き。
1:イネーブル(デフォルト)、0:ディセーブル

平均化ファンクション

読み書き。1回の測定サイクル中に実行される変換回数を設定する。 測定の平均値が得られる。
変換回数=2^N。
N=0は1回、N=1は2回、N=2は4回...N=7は128回。
デフォルトは101:32回

読み出し関連

環境光データ収納レジスタ(アドレス0x85が上位バイト、0x86が下位バイト)

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。環境光の上位バイト

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。環境光の下位バイト

距離データ収納レジスタ(アドレス0x87が上位バイト、0x88が下位バイト)

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の上位バイト

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の下位バイト

割り込み関連

割り込み制御レジスタ(アドレス0x89)

b7 b6 b5 b4 b3 b2 b1 b0

読み書き。

割り込みカウント設定値。

000 : 1(デフォルト)
001 : 2
010 : 4
011 : 8
100 :16
101 : 32
110 : 64
111 : 128

-

読み書き。

距離データが用意されたたらイネーブル

読み書き。

環境光データが用意されたたらイネーブル

読み書き。

スレッショルドを超えたらイネーブル

読み書き。

どちらのスレッショルドか。

1:距離、0:環境光

Lowスレッショルド・レジスタ(アドレス0x8Aが上位バイト、0x8Bが下位バイト)

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の上位バイト

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の下位バイト

Highスレッショルド・レジスタ(アドレス0x8Cが上位バイト、0x8Dが下位バイト)

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の上位バイト

b7 b6 b5 b4 b3 b2 b1 b0
読み出しのみ。距離の下位バイト

割り込みステータス・レジスタ(アドレス0x8E)

b7 b6 b5 b4 b3 b2 b1 b0
-

読み書き。

距離割り込みレディ

読み書き。

環境光割り込みレディ

読み書き。

Lowスレッショルドを超えた

読み書き。

Highスレッショルドを超えた

距離測定変調タイミング調整レジスタ(アドレス0x8F)

b7 b6 b5 b4 b3 b2 b1 b0

変調遅延時間。

読み書き。

赤外線LED信号発光と赤外線受光の遅延時間。
デフォルト0

距離周波数。

読み書き。

00 : 390.625 kHz(デフォルト)
01 : 781.25 kHz
10 : 1.5625 MHz
11 : 3.125 MHz

変調デッド・タイム。

読み書き。

外乱の影響を低減するために、赤外線信号のスロープを評価する時間。デフォルト1。信号レベルを低下させるので注意

プログラム

 ライブラリsmbusではI2Cの転送速度を記述できません。/boot/config.txtに記述します。デフォルトは100kHzで、そのままでも利用できます。

 高速で利用したいときは、下記のようにターミナルのエディタでconfig.txtを修正し、リブートします。単位はHzです。3400000Hzは規格上もっとも高速なHigh-speed (Hs-mode)です。

sudo nano /boot/config.txt

 エディタを立ち上げて、カーソル・キーで最下行付近に移動し、下記のように追加します。

dtparam=i2c_baudrate=3400000

 Ctrl+o、リターンで保存し、Ctrl+xでエディタを終了します。rebootで再起動します。ラズパイ・ゼロでは、3.4MHzと1MHzの通信はエラーになりました。400kHz、100kHzは正常でした。

 このデバイスは、I2Cのデータのやり取りはとてもオーソドックスです。最初に、コマンド・レジスタ0x80の測定イネーブル・ビットを'1'にします。1秒間の測定回数を指定する距離測定レート・レジスタ0x82はデフォルトの0です。測定回数のレートを上げると、測定データの信頼性が上がると思われます。次に、赤外線LEDの電流を100mAに設定します。200mAだと0x14です。最後に環境光の設定です。連続変換モードをイネーブルにした以外はデフォルト値です。

 コマンド・レジスタ0x80のフラグを見て、'1'だったら読み出します。距離のデータはすぐに読み出せますが、環境光データは相当回数リトライします。ブロック読み出し関数で2バイトを読み、16ビットのデータに直します。

#!/usr/bin/python
import time
import smbus
addr = 0x13
bus = smbus.SMBus(1)

#init
bus.write_byte_data(addr, 0x80, 0x07) # Set Command Register 0 0 0 0 0 1 1 1
bus.write_byte_data(addr, 0x82, 0x00) # Proximity Rate Register
bus.write_byte_data(addr, 0x83, 0x0a) # IR LED Current 100mA
bus.write_byte_data(addr, 0x84, 0x8d) # Ambient Light Parameter Register 1 000 1 101
#bus.write_byte_data(addr, 0x8f, 0x01) # Proximity mod 000 00 001

#main
while (bus.read_byte_data(addr, 0x80) & 0x20 ) == 0 : #prox_data_rdy
continue
dataP = bus.read_i2c_block_data(addr, 0x87, 2)
Proximity = dataP[0]<<8 | dataP[1]
print (Proximity)

while (bus.read_byte_data(addr, 0x80) & 0x40 ) == 0 : #als_data_rdy
continue
dataL = bus.read_i2c_block_data(addr, 0x85, 2)
Light = dataL[0]<<8 | dataL[1]
print (Light*0.25,'lux')

 距離の読み取り値Proximityはカウント数で、センサに近いほど高い値になります。環境光Lightのカウント数はデータシートのグラフから、約1/4するとluxに近似できるようです。

 距離はカタログ上では200mmですが、センサとの距離が離れるほど値は変化しなくなります。100mm付近までを目安に使うのがよさそうです。

 実測しました。[cm]がセンサとの距離です。検出する壁はアルミ・ブロックを使いました。アプリケーション・ノートに書かれている値に近いです。

[cm] 5 10 20 30 40 50 60 70 80 90
LED 電流100mA 32827 11601 5799 4366 3891 3665 3554 3448 3443 3412
LED 電流200mA 33447 21209  9445  6628   5696 5263  5020  4933  4826  4763 

つづき。

100 110 120 130 140 150 160 170 180 190
 3414 3383   3387 3392   3382 3375   3375  3366  3366 3357
 4752 4729   4732 4724  4717  4702  4697  4683  4677  4675 

※執筆時点;2017-11-29版をダウンロードし、sudo apt-get update と sudo apt-get upgrade -y および sudo rpi-update で更新し、カーネルは、uname -a で確認。4.9.66でした。

※プログラムを仮にvcnl4010.pyと/home/piに保存すると、sudo chmod 755 vcnl4010.py で実行権を付け、ターミナルから、python vcnl4010.pyで実行します。I2CやSPIのグループにpiユーザが属しているので、sudoは不要です。
 プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、リターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで改行してください。

※I2Cの有効化は、この説明を参照ください。1-Wireと同じく、I2CやSPIもEnableにチェックを入れています。