はじめに
いつか別の記事にしたいと思っていますが、最近ミニ四駆の改造をしています。
その一環としてカラーセンサーが必要になりました。
使用部品
- I2C対応カラーセンサー S13683-03DT
-
超薄型SOP10変換基板
・カラーセンサー用を取り付けるための基板 -
3mm砲弾型昼光色LED 6500K 1560mcd 70° OSW4YK3Z72A
・輝度の確保
・白色光をの反射光を計測することで、センサの色班別の再現性を担保 - 抵抗:2K2[Ω]×2、100[Ω]×1
回路図
カラーセンサー:
- センサのピン配置は、データシートを参考に、受光部の向きに注意して配線します。
- I2C通信はオープン・コレクタ方式なので、プルアップ抵抗が必要です。
センサ内部のトランジスタが接地$\rightarrow$"Low", オープン$\rightarrow$3.3Vで"High"になります。 - ArduinoはI2C用のピンが指定されています。SDAはA4、SCLはA5です。
- 中央の3本のピンはGNDにつながっているので、半田づけの際は短絡しないよう注意。
その他
- 白色LEDの反射光の色を検出するために、LEDは30度ほど傾けています。
- センサの裏側に抵抗を配置しています。
プログラム
AIに書かせたので全然わかっていないです。修正したほうがいいところがあれば教えてほしいです。
上手く動かなかくて修正した部分を挙げます。
-
const int S13683_ADDR = 0x2A;:
I2C通信ではマスタ(Arduino)からセンサーにスレーブと呼ばれる通信開始の合図を出します。アドレスはデバイスごとに異なります。特に今回のセンサのアドレスはレア(?)らしいので注意。データシートを確認しましょう。 - 色判定の補正係数は自分で修正する必要があります。
特に以下の二か所:
1.実データに乗算する補正係数2.色の閾値の設定float k_r = 1.0; float k_g = 0.7; float k_b = 1.0;r_final > g_final * 1.3 && r_final > b_final * 1.3b_final > g_final * 1.3 && b_final > r_final * 1.3 - その他、必要であれば積分時間など微調節してください。
コード全体
ColorSensor.ino
#include <Wire.h>
const int S13683_ADDR = 0x2A;
// --- 補正係数(適当な初期値。白路面で 'c' を送信すると自動更新される) ---
float k_r = 1.0;
float k_g = 0.7;
float k_b = 1.0;
void setup() {
Wire.begin();
Serial.begin(115200); // 高速通信のため115200bps推奨
delay(100);
// 1. ミニ四駆向けの高速応答設定(積分時間 1.4ms/ch)
writeReg(0x00, 0x89); // ADCリセット(Bit7=1) + High Gain + 1.4ms
delay(10);
writeReg(0x00, 0x09); // ADC動作開始(Bit7=0)
delay(10); // 初回のデータ更新を待つ
Serial.println("Mini4WD Color Sensor Ready.");
}
void loop() {
// --- キャリブレーション処理(シリアルモニタから 'c' を受信した時) ---
if (Serial.available() > 0) {
char cmd = Serial.read();
if (cmd == 'c' || cmd == 'C') {
calibrate();
}
}
// --- センサーからデータ読み出し ---
Wire.beginTransmission(S13683_ADDR);
Wire.write(0x03);
Wire.endTransmission(false);
Wire.requestFrom(S13683_ADDR, 8);
if (Wire.available() == 8) {
// Highバイト -> Lowバイトの順で結合
uint16_t r_raw = (Wire.read() << 8) | Wire.read();
uint16_t g_raw = (Wire.read() << 8) | Wire.read();
uint16_t b_raw = (Wire.read() << 8) | Wire.read();
uint16_t comp = (Wire.read() << 8) | Wire.read();
// 赤外・迷光成分の減算(マイナスになる場合は0に丸める)
int32_t r_c = (int32_t)r_raw - comp;
int32_t g_c = (int32_t)g_raw - comp;
int32_t b_c = (int32_t)b_raw - comp;
r_c = (r_c < 0) ? 0 : r_c;
g_c = (g_c < 0) ? 0 : g_c;
b_c = (b_c < 0) ? 0 : b_c;
// 係数を掛けて最終的なRGB値を算出
float r_final = r_c * k_r;
float g_final = g_c * k_g;
float b_final = b_c * k_b;
// --- 色の簡易判定ロジック ---
// 光量が少なすぎる場合はコース外(または影)と判定
float total_light = r_final + g_final + b_final;
String detected_color = "UNKNOWN";
if (total_light < 50) {
detected_color = "BLACK/OUT";
} else {
// RGBの中で一番強い成分を見る(白の場合はRGBがほぼ均等に高くなる)
if (r_final > g_final * 1.3 && r_final > b_final * 1.3) {
detected_color = "RED";
} else if (b_final > g_final * 1.3 && b_final > r_final * 1.3) {
detected_color = "BLUE";
} else {
detected_color = "WHITE (STRAIGHT)";
}
}
// --- 結果の出力 ---
Serial.print("R:"); Serial.print(r_final, 0);
Serial.print("\tG:"); Serial.print(g_final, 0);
Serial.print("\tB:"); Serial.print(b_final, 0);
Serial.print("\t-> "); Serial.println(detected_color);
}
// 1.4ms * 4ch = 5.6ms の更新周期に合わせて待機
delay(10);
}
// レジスタ書き込み用ヘルパー
void writeReg(byte reg, byte val) {
Wire.beginTransmission(S13683_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
// キャリブレーション実行用関数
void calibrate() {
Wire.beginTransmission(S13683_ADDR);
Wire.write(0x03);
Wire.endTransmission(false);
Wire.requestFrom(S13683_ADDR, 8);
if (Wire.available() == 8) {
uint16_t r_raw = (Wire.read() << 8) | Wire.read();
uint16_t g_raw = (Wire.read() << 8) | Wire.read();
uint16_t b_raw = (Wire.read() << 8) | Wire.read();
uint16_t comp = (Wire.read() << 8) | Wire.read();
int32_t r_c = max(0, (int32_t)r_raw - comp);
int32_t g_c = max(0, (int32_t)g_raw - comp);
int32_t b_c = max(0, (int32_t)b_raw - comp);
if (r_c > 0 && b_c > 0) {
k_r = (float)g_c / r_c;
k_b = (float)g_c / b_c;
Serial.println("\n*** CALIBRATION COMPLETED ***");
Serial.print("New k_r: "); Serial.println(k_r);
Serial.print("New k_b: "); Serial.println(k_b);
Serial.println("*****************************\n");
}
}
}
動作
動画の載せ方が分からないので、後日追記しておきます。
青い物体から赤色の物体にセンサをスライドさせたときのSerial Monitorの出力は以下のようになります。
色判定のアルゴリズムは使用環境に応じて調節する必要があります。
データシートに記載の通り、使用したLEDは青と緑の強度が高く、センサは赤と緑の感度が高いです。そのため、今回は色判定時の緑の重みを小さくしています。
Serial Monitor
R:48 G:85 B:114 -> BLUE
R:48 G:84 B:113 -> BLUE
R:48 G:84 B:112 -> BLUE
R:47 G:83 B:111 -> BLUE
R:47 G:82 B:110 -> BLUE
R:47 G:81 B:110 -> BLUE
R:47 G:81 B:108 -> BLUE
R:48 G:80 B:105 -> BLUE
R:48 G:80 B:104 -> BLUE
R:47 G:78 B:102 -> BLUE
R:46 G:76 B:98 -> WHITE (STRAIGHT)
R:48 G:75 B:96 -> WHITE (STRAIGHT)
R:49 G:73 B:92 -> WHITE (STRAIGHT)
R:48 G:71 B:87 -> WHITE (STRAIGHT)
R:47 G:67 B:81 -> WHITE (STRAIGHT)
R:48 G:64 B:77 -> WHITE (STRAIGHT)
R:48 G:62 B:72 -> WHITE (STRAIGHT)
R:50 G:61 B:68 -> WHITE (STRAIGHT)
R:0 G:0 B:0 -> BLACK/OUT
R:56 G:58 B:60 -> WHITE (STRAIGHT)
R:59 G:57 B:57 -> WHITE (STRAIGHT)
R:65 G:56 B:54 -> WHITE (STRAIGHT)
R:71 G:59 B:54 -> WHITE (STRAIGHT)
R:77 G:62 B:55 -> WHITE (STRAIGHT)
R:81 G:63 B:53 -> WHITE (STRAIGHT)
R:83 G:62 B:51 -> RED
R:84 G:61 B:50 -> RED
R:86 G:62 B:50 -> RED
R:86 G:61 B:48 -> RED
R:87 G:61 B:48 -> RED
R:86 G:60 B:47 -> RED
R:86 G:60 B:46 -> RED
R:86 G:60 B:47 -> RED
R:86 G:60 B:47 -> RED
R:85 G:58 B:46 -> RED
R:84 G:58 B:46 -> RED
R:83 G:57 B:46 -> RED
R:83 G:58 B:46 -> RED
R:82 G:57 B:45 -> RED
R:81 G:56 B:45 -> RED
R:81 G:57 B:46 -> RED
R:80 G:56 B:45 -> RED
R:81 G:57 B:46 -> RED
R:82 G:57 B:45 -> RED
