目次

3. I2C の使い方

概要

CHIRIMEN for Raspberry Pi(以下 「CHIRIMEN Raspi」) を使ったプログラミングを通じて、Web I2C API の使い方を学びます。

前回 は温度センサを使いながら Web I2C API の基本的な利用方法を学びました。今回は温度センサ以外のI2Cセンサの使い方を見ていきましょう。

ここでは例として光センサ、距離センサ、加速度センサの 3 つについて詳しく説明しますが、最後に「他の I2C モジュールも使ってみる」として紹介しているように、CHIRIMEN ではそれ以外にも多くの I2C デバイス (あるいは I2C の ADC を使って様々なアナログセンサ類) が簡単に扱えるようになっており、 examples ページ (オンライン版) に回路図とサンプルコードが用意されています。各自興味のあるセンサを順に試していってください。

前回までのおさらい

本チュートリアルを進める前に前回までのチュートリアルを進めておいてください。

前回までのチュートリアルで学んだことは下記のとおりです。

1.準備

用意するもの

上記に加え今回紹介するセンサが必要となりますが、センサについては各センサの説明のパートに記載します。

2. 光センサを使ってみる

光の強度 (明るさ) に反応するセンサを使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

Raspberry Piとの接続方法については、下記回路図を参照ください。

/home/pi/Desktop/gc/contrib/examples/i2c-BH1750/BH1750schematic.png

回路図

b. 接続確認とexampleの実行

i2cdetect で接続を確認しておきましょう。ターミナルで次のコマンドを実行します。

$ i2cdetect -y -r 1

WebI2C 版 /home/pi/Desktop/gc/i2c/i2c-detect/index.html でも確認できますが、I2C 接続をこちらを使う場合は確認後に必ずタブを閉じて

SlaveAddress 0x23 が見つかれば接続OKです。次に example を動かします。

https://r.chirimen.org/examples/#I2C-BH1750

画面左上の LIGHT[lx] :に表示されてる数値が明るさです。センサに当たる光を遮断してみてください。数値が小さくなるはずです。逆にセンサに LED の光を直接当てると数値が大きくなることが確認できるでしょう。

c. コード解説

example のコードから、光センサに関係する部分を見ていきます。今回はドライバーライブラリの中までは深入りせずに、アプリケーションの流れを追ってみましょう。ADT7410 の時とほとんど同じであることがわかるはずです。

c-1. index.html

下記がindex.htmlの中から主要な部分を抜き出したコードです。

index.html

    : 
    <script src="node_modules/@chirimen-raspi/polyfill/polyfill.js"></script>
    <script src="node_modules/@chirimen-raspi/chirimen-driver-i2c-bh1750/BH1750.js"></script>
    <script src="./main.js" defer></script>
    :
  <body>
    :
    <table>
      <tr>
        <td>LIGHT[lx] : </td>
        <td id="light"></td>
      </tr>
    </table>
  </body>

HTML は ADT7410 の時とほとんど同じです。ドライバーライブラリは、BH1750.js に変わりました。

c-2. main.js

次に、main.jsを見てみましょう。(重要な部分以外は削っています)

main.js

  var light = document.getElementById("light");
  var i2cAccess = await navigator.requestI2CAccess();
  var port = i2cAccess.ports.get(1);
  var bh1750 = new BH1750(port, 0x23);
  await bh1750.init();
  await bh1750.set_sensitivity(128);
  
  while (1) {
    var val = await bh1750.measure_high_res();
    light.innerHTML = val;
    await sleep(300);

main.js も温度センサとほとんど同じです。最初に I2C デバイスを操作するため I2CAccess、Port と順に取得したら SlaveAddress と一緒にドライバに渡して初期化し、あとはセンサーの値を読みたいときに read() の代わりに measure_high_res() します。詳しく見てみましょう。

var light = new BH1750(port, 0x23)

ここで光センサ用の ドライバーライブラリのインスタンス生成 を行なっています。

ライブラリ名が変わっただけで ADT7410 と同様に、port オブジェクトと、SlaveAddress をパラメータで渡しています。

bh1750.init()

init()I2C ポートを開いてセンサーを初期化 します。

内部ではインスタンス生成時に指定したportオブジェクトと slaveAddress(0x23) を用いて I2CPort.open() を行ない、返却される I2CSlaveDevice を保存後に resolve() で呼び出し元に処理を返しています。

bh1750.measure_high_res()

BH1750 の仕様に基づく データ読み出し処理 をここで実施しています。

3. 測距センサを使ってみる

モノまでの距離を測定する測距センサ (I2C-VL53L0X) を使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

raspi との接続方法については、こちらの回路図を参照ください。

回路図

このセンサモジュールは 4 本のピンヘッダ経由で接続します。あらかじめピンヘッダをハンダ付けしておいてください。また、製品によってはチップ表面に黄色の保護フィルムがついているものがあります。剥して使用してください。

ピンの加工例 (保護フィルムが残っている状態)

加工例

b. 接続確認と example の実行

i2cdetect で接続を確認しておきましょう。

$ i2cdetect -y -r 1

SlaveAddress 0x52 が見つかれば接続OKです。次にexampleを動かします。

/home/pi/Desktop/gc/i2c/i2c-VL53L0X/VL53L0X.html

センサの前面 (VIN、GND、SCL、SDA等の文字が書いてある方) に手を近づけたり離したりしてみてください。距離の値が変化するはずです。

VL53L0X が計測できる距離は およそ 3〜200 cm (30-2000 mm) までです。

c.コード解説

example のコードから、測距センサに関係する部分を見ていきます。

c-1. index.html

下記がVL53L0X.htmlの中から主要な部分を抜き出したコードです。

VL53L0X.html

    :
    <script src="node_modules/@chirimen-raspi/polyfill/polyfill.js"></script>
    <script src="node_modules/@chirimen-raspi/chirimen-driver-i2c-vl53l0x/VL53L0X.js"></script>
    <script src="./main.js" defer></script>
    :
  <body>
    :
    <tr><td>Distance [mm]</td>
    <td id="dist"></td></tr>
    :
  </body>

HTML は ADT7410 の時とほとんど同じです。ドライバーライブラリは VL53L0X.js に変わりました。リモート版の URL は https://r.chirimen.org/vl53l0x.js です。

c-2. main.js

次に、main.js を見てみましょう。(重要な部分以外は削っています)

main.js

  var dist = document.getElementById("dist");
  var i2cAccess = await navigator.requestI2CAccess();
  var port = i2cAccess.ports.get(1);
  var vl = new VL53L0X(port, 0x29);
  await vl.init(); // for Long Range Mode (<2m) : await vl.init(true);
  for (;;) {
    var distance = await vl.getRange();
    dist.innerHTML=distance;
    await sleep(200);
  }

main.js も温度センサとほとんど同じです。

var vl = new VL53L0X(port, 0x29)

ドライバーライブラリのインスタンス生成処理です。

vl.init()

こちらも、内部で I2CSlaveDevice インタフェースを取得する処理で、他のセンサと同様です。

vl.read()

測距センサ VL53L0X の仕様に基づくデータ読み出し処理をここで実施しています。計測範囲内に遮蔽物がない場合には値が数値で得られないことに注意してください。

4. 加速度、角加速度センサを使ってみる

傾きなどに反応するセンサを使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

raspi との接続方法については、下記回路図を参照ください。

回路図

b. 接続確認とexampleの実行

i2cdetect で接続を確認しておきましょう。

$ i2cdetect -y -r 1

SlaveAddress 0x68 が見つかれば接続OKです。次に example を動かします。

https://r.chirimen.org/examples/#I2C-MPU6050

画面の左上に表示されている Gx Gy Gz が加速度センサの値、Rx Ry Rz が角加速度を表しています。センサを動かすと数値が変化するはずです。

c. コード解説

exampleのコードを見てみましょう。

c-1. index.html

下記がindex.htmlの中から主要な部分を抜き出したコードです。

index.html

    :
    <script src="node_modules/@chirimen-raspi/polyfill/polyfill.js"></script>
    <script src="node_modules/@chirimen-raspi/chirimen-driver-i2c-mpu6050/MPU6050.js"></script>
    <script src="./main.js" defer></script>
    :
  <body>
    :
    <table>
      <tr>
          :
        <td>Gx</td>
        <td id="gx"></td>
          :
        <td>Gy</td>
        <td id="gy"></td>
          :          :
        <td>Rz</td>
        <td id="rz"></td>
      </tr>
    </table>
  </body>

今回のドライバーライブラリは、MPU6050.js です。オンラインから読み込む場合は https://r.chirimen.org/examples/i2c-MPU6050/main.js です。そして出力が Gx Gy Gz Rx Ry Rz と6つの値を表示するため要素が6つに変わりましたが、それ以外はこれまでとほとんど同じです。

c-2. main.js

次に、main.js を見てみましょう。(重要な部分以外は削っています)

main.js

    var gx = document.getElementById("gx");
    var gy = document.getElementById("gy");
    var gz = document.getElementById("gz");
    var rx = document.getElementById("rx");
    var ry = document.getElementById("ry");
    var rz = document.getElementById("rz");
    var i2cAccess = await navigator.requestI2CAccess();
    var port = i2cAccess.ports.get(1);
    var mpu6050 = new MPU6050(port, 0x68);
    await mpu6050.init();
    while (1) {
      var val = await mpu6050.readAll();
      // console.log('value:', value);
      temp.innerHTML = val.temperature;
      gx.innerHTML = val.gx;
      gy.innerHTML = val.gy;
      gz.innerHTML = val.gz;
      rx.innerHTML = val.rx;
      ry.innerHTML = val.ry;
      rz.innerHTML = val.rz;
      await sleep(1000);
    }

main.js もこれまでの他のセンサーとほとんど同じです。

var mpu6050 = new MPU6050(port, 0x68);

ここで加速度センサ用のドライバーライブラリのインスタンス生成を行なっています。

mpu6050.init()

これまでのドライバーライブラリ同様に init() では、インスタンス生成時に指定した port オブジェクトと slaveAddress(0x68) を用いて I2CPort.open() を行ない、返却される I2CSlaveDevice を保存後にresolve()で呼び出し元に処理を返しています。

mpu6050.readAll()

readAll() では、Gx Gy Gz Rx Ry Rz の値が一度に返却されます。

5. 演習: 複数のセンサを組み合わせて使ってみよう

下記のような組み合わせで2つのセンサを繋いで動かしてみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

b. モジュールを複数接続する

I2C モジュールを複数利用するのは一見難しそうに見えるかもしれませんが、実際には I2C モジュールの各ピン (VDD GND SDA SCL) を並列に接続すれば問題なく動作します。

b-1. I2C モジュール側の準備をする

ブレッドボードに挿せるよう、 I2C モジュールの各ピンにジャンパ線を接続します。

b-2. ブレッドボードにジャンパ線を接続する

接続例

補足:接続を簡単に行える Grove という規格のデバイスを用いれば、 Grove Hub というパーツで簡単に複数のデバイスを接続することが可能です。長所短所ともにありますので、詳しくは Grove 編チュートリアルをご覧ください。

c. コードを編集する

実際に2つのモジュールからデータを取得するコードを書いてみましょう。

c-0. 利用するモジュール各々のコードを用意する

Examples 等を参考にして、それぞれのモジュール用のコードを用意します。

自分で一からコーディングする場合には不要です。

c-1. HTML を書く

c-2. JavaScript(main.js) を書く

6. 他の I2C モジュールも使ってみる

前回からこれまでに 4 つの I2C センサを使ってみました。

CHIRIMEN Raspi には、他にも /home/pi/Desktop/gc/i2c/ 配下に例えば下記のような I2C モジュールの examples が含まれています。それぞれの回路図、デイバスドライバ、サンプルコードもあるので、お手持ちのデバイスを使ってみてください。

また、CHIRIMEN Raspi のイメージ内に同梱されている example 以外にも、CHIIRMEN examples ページのオンライン版 にはこれらに加えてコミュニティによって順次いろいろなデバイス利用例が Advanced Examples として追加されています (ドライバーなどが cotrib ディレクトリ内にあるので注意)。作りたいもの、試したいものを考えながら試してみてください。

I2C デバイスを複数使う場合の注意事項

I2Cデバイスを同時に接続して使用するとき、重要な注意事項があります。それは I2C アドレスの衝突です。チュートリアル2-2 の図に書かれているように I2C デバイスは個々のアドレスを持っています。このアドレスは I2C デバイスの製品ごとに固有のアドレスが設定されていますが、偶然同じアドレスを持ったデバイスを手にすることもあります。

アドレスが衝突しているデバイスは同時に接続できません。 このチュートリアルで使ったデバイスのアドレスを以下の表に掲載します。NativeAddr がそのデバイスのオリジナルの状態のアドレスです。すでに衝突しているものがいくつかあるのがわかると思います。

一方、I2C デバイスのによってはこのアドレスを変更でき、アドレスの衝突を回避できる場合があります。但しアドレスの変更は JavaScript から行うのではなく、デバイスの基板上でハードウェア的(電気的)に設定するジャンパによって設定します。(ジャンパはピンヘッダとして用意され、ジャンパ線などで設定できるものもありますが、多くの場合は半田を盛ってジャンパとするタイプです。詳しくは各デバイスを購入すると付属しているデータシートを参照してください。)

下表の ChangedAddr はアドレス変更可能なデバイスでジャンパーを設定し、他のデバイスのアドレスと衝突しないようにする例です。

Device NativeAddr ChangedAddr
ADT7410 0x48 => 0x49
ADS1015 0x48
VEML6070 0x38, 0x39
S11059 0x2a
PCA9685 0x40 => 0x41
grove-touch 0x5a
grove-oledDisplay 0x3c
grove-gesture 0x73
grove-light 0x29
grove-accelerometer 0x53

まとめ

このチュートリアルでは 下記について学びました。

このチュートリアルで扱ったコードは以下のページで参照できます:

次のCHIRIMEN for Raspberry Pi チュートリアルでは、『Web GPIO APIとWeb I2C APIを組み合わせたプログラミング』に挑戦します!