IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP32 & Cảm biến: Bài 22 – Đọc cảm biến TCS34725: đo màu sắc RGB & theo dõi realtime

Sau khi đã quen với I2C ở Level 2 và bắt đầu tư duy “hệ thống” ở Level 3, chúng ta đến một cảm biến rất thú vị: TCS34725 – cảm biến đo màu cho ra dữ liệu RGB (và Clear), phù hợp cho các ứng dụng như:

  • Nhận diện màu vật thể
  • Phân loại sản phẩm (DIY conveyor mini)
  • Robot line-following nâng cao
  • Học xử lý tín hiệu & hiệu chuẩn màu

Bài này gồm 2 phần code:

  1. Đọc màu RGB local (Serial)
  2. Gửi dữ liệu RGB realtime lên IoTLabs Cloud MQTT

1. TCS34725 là gì?

TCS34725 là cảm biến màu có:

  • Giao tiếp: I2C
  • Dữ liệu: Red / Green / Blue + Clear (độ sáng tổng)
  • Có tích hợp IR filter (giúp đo màu ổn định hơn)
  • Thường đi kèm LED ánh sáng trắng trên module (hỗ trợ chiếu sáng vật thể)

📌 Địa chỉ I2C phổ biến: 0x29

2. Khi đo màu RGB, bạn cần lưu ý điều gì?

Đo màu “đúng” phụ thuộc nhiều vào môi trường:

  • Ánh sáng phòng thay đổi → RGB thay đổi
  • Khoảng cách sensor ↔ vật thể thay đổi → RGB thay đổi
  • Bề mặt bóng/nhám khác nhau → RGB khác nhau

Vì vậy tư duy đúng khi làm IoT đo màu là:

  • Dùng nguồn sáng ổn định (LED trên module)
  • Giữ khoảng cách cố định
  • Chuẩn hoá dữ liệu (scale hoặc normalize)

3. Chuẩn bị phần cứng & nối dây

Thiết bị

  • ESP32-C3 SuperMini
  • TCS34725 module (I2C)

Kết nối I2C (chuẩn series)

TCS34725ESP32-C3
VIN / VCC3.3V
GNDGND
SDAGPIO8
SCLGPIO9

4. Kiểm tra I2C address

Bạn có thể dùng đoạn scan I2C (đã dùng ở Level 2).
Kỳ vọng sẽ thấy: 0x29.

5. Ví dụ 1: Đọc RGB local (Serial)

Thư viện

  • Adafruit TCS34725
#include <Wire.h>
#include "Adafruit_TCS34725.h"

Adafruit_TCS34725 tcs = Adafruit_TCS34725(
  TCS34725_INTEGRATIONTIME_50MS,
  TCS34725_GAIN_4X
);

void setup() {
  Serial.begin(115200);
  Wire.begin(8, 9);

  if (!tcs.begin()) {
    Serial.println("TCS34725 not found");
    while (1) delay(10);
  }
  Serial.println("TCS34725 ready");
}

void loop() {
  uint16_t r, g, b, c;
  tcs.getRawData(&r, &g, &b, &c);

  Serial.print("R: "); Serial.print(r);
  Serial.print(" | G: "); Serial.print(g);
  Serial.print(" | B: "); Serial.print(b);
  Serial.print(" | C: "); Serial.println(c);

  delay(500);
}

📌 c (Clear) là tổng độ sáng, rất hữu ích để normalize.

6. Chuẩn hoá dữ liệu màu (RGB normalize)

Để dữ liệu ít phụ thuộc độ sáng, bạn có thể normalize:

  • rn = r / c
  • gn = g / c
  • bn = b / c

Ví dụ:

{
  "ts": 1760000000,
  "metrics": {
    "r": 1234,
    "g": 980,
    "b": 650,
    "c": 3120,
    "rn": 0.39,
    "gn": 0.31,
    "bn": 0.21
  }
}

👉 Khi hiển thị trên dashboard, bạn có thể vẽ:

  • Raw RGB
  • Hoặc normalized RGB (ổn định hơn)

7. Ví dụ 2: Gửi RGB realtime lên IoTLabs Cloud MQTT

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "Adafruit_TCS34725.h"

Adafruit_TCS34725 tcs = Adafruit_TCS34725(
  TCS34725_INTEGRATIONTIME_50MS,
  TCS34725_GAIN_4X
);

// ===== CONFIG =====
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";

const char* MQTT_HOST = "mqtt.iotlabs.vn";
const int MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_MQTT_USER";
const char* MQTT_PASS = "YOUR_MQTT_PASS";

const char* MQTT_TOPIC =
  "iotlabs/<orgId>/devices/<deviceId>/telemetry";

WiFiClientSecure net;
PubSubClient mqtt(net);

unsigned long lastSend = 0;

void connectWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void connectMQTT() {
  net.setInsecure();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  while (!mqtt.connected()) {
    mqtt.connect("esp32c3-tcs34725", MQTT_USER, MQTT_PASS);
    delay(1000);
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(8, 9);

  if (!tcs.begin()) {
    Serial.println("TCS34725 not found");
    while (1) delay(10);
  }

  connectWiFi();
  connectMQTT();
}

void loop() {
  if (!mqtt.connected()) connectMQTT();
  mqtt.loop();

  if (millis() - lastSend > 1000) {
    lastSend = millis();

    uint16_t r, g, b, c;
    tcs.getRawData(&r, &g, &b, &c);
    if (c == 0) return;

    float rn = (float)r / (float)c;
    float gn = (float)g / (float)c;
    float bn = (float)b / (float)c;

    long ts = millis() / 1000;

    String payload = "{";
    payload += "\"ts\":" + String(ts) + ",";
    payload += "\"metrics\":{";
    payload += "\"r\":" + String(r) + ",";
    payload += "\"g\":" + String(g) + ",";
    payload += "\"b\":" + String(b) + ",";
    payload += "\"c\":" + String(c) + ",";
    payload += "\"rn\":" + String(rn, 3) + ",";
    payload += "\"gn\":" + String(gn, 3) + ",";
    payload += "\"bn\":" + String(bn, 3);
    payload += "}}";

    mqtt.publish(MQTT_TOPIC, payload.c_str());
    Serial.println(payload);
  }
}

8. Kinh nghiệm thực tế để đo màu ổn định

  • Dùng LED chiếu sáng cố định (nếu module có)
  • Giữ khoảng cách sensor ↔ vật thể ổn định (5–15mm)
  • Đặt hộp che sáng (mini enclosure) để tránh ánh sáng môi trường
  • Dùng rn/gn/bn thay vì raw để ổn định dashboard

9. Gợi ý dashboard realtime cho RGB

Gợi ý hiển thị:

  • 3 card: R, G, B
  • 1 card: C (brightness)
  • 1 chart: rn/gn/bn theo thời gian

👉 Bạn sẽ thấy ngay khi đưa vật có màu khác nhau vào.

10. Tổng kết Bài 22

Sau bài này, bạn đã:

  • Đọc cảm biến màu TCS34725 qua I2C
  • Làm quen dữ liệu multi-metric RGB
  • Biết cách normalize màu theo độ sáng
  • Gửi dữ liệu realtime lên IoTLabs Cloud MQTT