🚥

カラーセンサの使い方

2023/04/14に公開


右の色を読み取って左に反映する

部品

https://akizukidenshi.com/catalog/g/gK-08316/

データシート

https://akizukidenshi.com/download/ds/hamamatsu/s11059-02dt.pdf

配線

S11059-02DT 側 Arduino 側
SDA SDA (13)
SDL SDL (14)

とくに難しいところはない。また Wire.begin() のときに番号を渡す必要もない。

コード

#include <Wire.h>

#define I2C_ADDRESS 0x2A

struct RGBA {
  unsigned int r;
  unsigned int g;
  unsigned int b;
  unsigned int a;
};

void setup() {
  Serial.begin(9600);

  pinMode( 9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);

  Wire.begin();

  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(B10001011);
  Wire.endTransmission();

  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(B00001011);
  Wire.endTransmission();
}

void loop() {
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(0x03);
  Wire.endTransmission();

  Wire.requestFrom(I2C_ADDRESS, 8); // 8バイト要求する
  if (Wire.available()) {
    RGBA color1 = {
      raw_value_read(),
      raw_value_read(),
      raw_value_read(),
      raw_value_read(),
    };

    RGBA color2 = {
      constrain(map(color1.r, 184, 33000, 0, 255), 0, 255),
      constrain(map(color1.g, 118, 54800, 0, 255), 0, 255),
      constrain(map(color1.b,  91, 63000, 0, 255), 0, 255),
    };

    // シリアルモニタ用
    char str[128];
    sprintf(str, "RAW(%u %u %u) -> RGB(%u %u %u)",
      color1.r, color1.g, color1.b,
      color2.r, color2.g, color2.b);
    Serial.println(str);

    // 左のフルカラーLEDに反映する
    analogWrite( 9, color2.r);
    analogWrite(10, color2.g);
    analogWrite(11, color2.b);
  }
  Wire.endTransmission();

  delay(180);
}

uint16_t raw_value_read() {
  uint8_t h = Wire.read();
  uint8_t l = Wire.read();
  return h << 8 | l;
}
右側のLEDの点滅を繰り返す部分
class LedCycle {
 public:
  uint64_t count = 0;

  LedCycle() {
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
  }

  void call() {
    digitalWrite(2, ((count / 15) % 3) == 0);
    digitalWrite(3, ((count / 15) % 3) == 1);
    digitalWrite(4, ((count / 15) % 3) == 2);
    count++;
  }
};

LedCycle led_cycle = LedCycle();

// void loop() {
//   led_cycle.call()
// }

0x2A とは?

カラーセンサモジュールを特定する I2C アドレスのことでデータシートに書いてある。

最初の設定の意味は?

0 を送ってこれからコントロールを設定することを伝える。

Wire.write(0);

次に設定値を送る。

Wire.write(B10001011);

データシートの3枚目に次のように書いてあるので、

Bit 項目 設定値
7 ADCリセット 1:リセット 0: 動作開始
6 スリープ機能 1: 待機モード 0: 動作モード
5 スリープ機能 モニタ
4 -
3 ゲイン選択 1: Highゲイン 0: Lowゲイン
2 積分モード 1: マニュアル設定モード 0: 固定時間モード
1 積分時間設定
0 積分時間設定 (00)87.5 μs, (01)1.4 ms (10)22.4 ms, (11)179.2 ms

B10001011 は「ADCリセット」+「Highゲイン」+「積分時間設定 179.2 ms」になる。

0x03 とは?

Wire.write(0x03);

データシートによると「出力データバイトを指定」らしいがどういうことだ?

計測とマッピング

センサからは RGB の各値が符号なし 16 ビット整数で取れる。しかし、綺麗に 0〜65535 の範囲に分布しているわけではない。各要素の幅がばらばらなので各要素毎に最小最大をシリアルモニタで調べて 256 段階にマッピングする必要がある。

RGBA color2 = {
  map(color1.r, 184, 33000, 0, 255), // 184..33000 -> 0..255
  map(color1.g, 118, 54800, 0, 255),
  map(color1.b,  91, 63000, 0, 255),
};

このあたり、同じ色でも明るい部屋なのか暗い部屋なのかでもセンサ値が変わってくるので、誰かの測定値を真似るのではなく自分が使う環境に合わせて測定・調整した値を使うこと。

参考

https://qiita.com/Kakimoty_Field/items/cc0f2504da14be903bbf

https://numanohate.hateblo.jp/entry/2015/08/28/111202

Discussion