TCS34725接Arduino:颜色识别从接线到分拣实战

2026-10-24 20:49:51 62阅读

做分拣机器人、颜色循迹小车这类项目,绕不开一个问题:怎么让机器认出眼前的东西是什么颜色。上相机当然行,但要算力、要标定、要伺候光照,对一块 Arduino 来说太重了。其实有个轻得多的答案:TCS34725,一颗 I2C 接口的数字颜色传感器,十几块钱,四根线接上就能读 RGB。这篇我从接线、装库、跑代码一路讲到做分拣的实战要点,看完可以直接动手。

TCS34725 是个什么传感器

TCS34725 是 AMS(艾迈斯)出的 RGB 全彩颜色传感器。它不是一个简单的光敏元件,内部集成了红、绿、蓝三组带滤光的光电二极管,外加一个不带滤光的 Clear 通道,一次采样能同时给出 R、G、B、C 四路 16 位数据。

这颗芯片最值钱的地方有两个。一是片上带红外截止滤光片,把入射光里的红外成分挡掉——人眼看不见红外,红外混进来只会让颜色读数发飘,挡掉之后测出来的颜色才接近人眼的真实感知。二是动态范围高达 3,800,000:1,配合可调积分时间(2.4ms 到 614ms 多档)和可调增益(1X、4X、16X、60X),强光弱光下都能工作,甚至可以隔着深色玻璃测。

市售模块的参数也给你列齐(以 DFRobot 的 SEN0212 为例):工作电压 3.3V 到 5V,工作电流只有 65uA,I2C 地址固定 0x29,时钟频率 0 到 400kHz,建议检测距离 3 到 10mm,工作温度 -30℃ 到 +70℃,板子尺寸 18.5mm×23mm。模块上自带白色 LED 补光(Adafruit 版本是一颗 4150K 中性白 LED,DFRobot 版本是四颗高亮灯珠),环境光不足时照亮被测物体,读数才稳。接口一般同时提供 PH2.0 和 2.54mm 间距排针两种,面包板直插没问题。

TCS34725颜色传感器接Arduino检测橙子实拍

图里这套就是 Adafruit 的 TCS34725 分线板接 Arduino UNO 的实际效果:传感器贴着橙子,面包板上的 RGB 灯实时复现它读到的颜色。看完这篇你也能搭出来。

接线:四根线搞定

TCS34725 走 I2C,总共只需要四根线:UNO 的 5V 接模块 VIN(模块板载 3.3V 稳压,所以 3.3V 到 5V 供电都行),GND 接 GND,SDA 接 SDA,SCL 接 SCL。就这么多。

有几个老板子的坑要提前说:R3 之前的 UNO 没有独立的 SDA、SCL 排针,要用模拟口 A4 当 SDA、A5 当 SCL;R2 之前的 Mega 是 20 脚 SDA、21 脚 SCL;Leonardo 则是 2 脚 SDA、3 脚 SCL。Adafruit 的分线板在 I2C 脚上做了电平转换,3.3V 和 5V 逻辑都能直接用;但如果你买的是不带电平转换的裸板,主控又是 5V 逻辑,记得自己加转换,别把 3.3V 的芯片硬怼 5V。

TCS34725与主控板I2C接线图

板载补光 LED 的控制有三种玩法:LED 脚悬空或者接高电平,灯常亮,适合一直要补光的场景;直接接 GND,灯彻底关掉,测入射式环境光时用;接某个数字脚,代码里 digitalWrite 控制开关。Adafruit 的板子还有个进阶玩法,把 LED 脚接到 INT 脚,用库里的 setInterrupt() 函数联动控制,下面的官方例程 colorview 就是这么干的。

装库,先跑官方测试例程

打开 Arduino IDE 的库管理器(工具→管理库),搜索 Adafruit TCS34725,认准 Adafruit 出品,点安装。

Arduino库管理器安装Adafruit TCS34725

装完别急着写代码,先验证硬件通不通。打开 文件→示例→Adafruit TCS34725→tcs34725,上传,再打开串口监视器,波特率 9600。正常的话会先打印一行 Found sensor,然后 Color Temp(色温,单位 K)、Lux(光照度)、R、G、B、C 六列数据一直滚动。拿手遮挡、换个光源、贴个色块,数值会跟着明显变化。

TCS34725测试例程串口输出数据

如果卡在 No TCS34725 found,按顺序查:四根线有没有接对、SDA 和 SCL 有没有插反、地址是不是 0x29、模块底部红外遮光片上那层保护纸撕了没有。这个测试例程用的是 getRawData(),读的是 16 位原始值;后面主菜 colorview 用的是 getRGB(),读的是按 Clear 通道归一化到 0 到 255 的值,直接对应颜色深浅,做识别更顺手。

完整代码:让 RGB 灯复现它看到的颜色

硬件验证通过,上主菜。colorview 是库自带的第二个例程,思路很漂亮:先用板载 LED 照亮被测物体(反射式测量),等 60ms(给 50ms 积分时间留足余量),getRGB() 读出归一化的 R、G、B,过一张 gamma 表修正人眼对亮度的非线性感知,最后 PWM 驱动一颗共阳 RGB LED,把读到的颜色实时复现出来。你拿红纸给它看,灯变红;拿蓝纸,灯变蓝。

除了传感器本体,还需要一颗共阳 RGB LED 和三颗电阻(1K 一颗、560 欧两颗)。接线:LED 共阳长脚接 5V;红脚串 1K 接 UNO 的 3 脚;绿脚串 560 欧接 5 脚;蓝脚串 560 欧接 6 脚。RGB LED 四个脚的定义看下面这张图,别接错,最长那根是公共阳极。

共阳RGB LED引脚定义图

代码完整贴出(来自 Adafruit_TCS34725 库官方示例 colorview.ino;ESP32 主控也能用,代码里自带 ledcAttach 分支,UNO 走 pinMode 加 analogWrite)。有一处发布适配要说清楚:官方源码第一行是尖括号形式的 #include <Wire.h>,本站发布系统会吞掉尖括号里的内容,所以代码块里改用引号形式 #include "Wire.h"——对 Arduino 核心库来说这两种写法编译完全等价,复制即可编译,你改回尖括号也一样跑:

#include "Wire.h"
#include "Adafruit_TCS34725.h"

// Pick analog outputs, for the UNO these three work well
// use ~560  ohm resistor between Red & Blue, ~1K for green (its brighter)
#define redpin 3
#define greenpin 5
#define bluepin 6
// for a common anode LED, connect the common pin to +5V
// for common cathode, connect the common to ground

// set to false if using a common cathode LED
#define commonAnode true

// our RGB -> eye-recognized gamma color
byte gammatable[256];


Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);

void setup() {
  Serial.begin(9600);
  //Serial.println("Color View Test!");

  if (tcs.begin()) {
    //Serial.println("Found sensor");
  } else {
    Serial.println("No TCS34725 found ... check your connections");
    while (1); // halt!
  }

  // use these three pins to drive an LED
#if defined(ARDUINO_ARCH_ESP32)
  ledcAttach(redpin, 12000, 8);
  ledcAttach(greenpin, 12000, 8);
  ledcAttach(bluepin, 12000, 8);
#else
  pinMode(redpin, OUTPUT);
  pinMode(greenpin, OUTPUT);
  pinMode(bluepin, OUTPUT);
#endif

  // thanks PhilB for this gamma table!
  // it helps convert RGB colors to what humans see
  for (int i=0; i<256; i++) {
    float x = i;
    x /= 255;
    x = pow(x, 2.5);
    x *= 255;

    if (commonAnode) {
      gammatable[i] = 255 - x;
    } else {
      gammatable[i] = x;
    }
    //Serial.println(gammatable[i]);
  }
}

// The commented out code in loop is example of getRawData with clear value.
// Processing example colorview.pde can work with this kind of data too, but It requires manual conversion to 
// [0-255] RGB value. You can still uncomments parts of colorview.pde and play with clear value.
void loop() {
  float red, green, blue;
  
  tcs.setInterrupt(false);  // turn on LED

  delay(60);  // takes 50ms to read

  tcs.getRGB(&red, &green, &blue);
  
  tcs.setInterrupt(true);  // turn off LED

  Serial.print("R:\t"); Serial.print(int(red)); 
  Serial.print("\tG:\t"); Serial.print(int(green)); 
  Serial.print("\tB:\t"); Serial.print(int(blue));

//  Serial.print("\t");
//  Serial.print((int)red, HEX); Serial.print((int)green, HEX); Serial.print((int)blue, HEX);
  Serial.print("\n");

//  uint16_t red, green, blue, clear;
//  
//  tcs.setInterrupt(false);  // turn on LED
//
//  delay(60);  // takes 50ms to read
//
//  tcs.getRawData(&red, &green, &blue, &clear);
//  
//  tcs.setInterrupt(true);  // turn off LED
//
//  Serial.print("C:\t"); Serial.print(int(clear)); 
//  Serial.print("R:\t"); Serial.print(int(red)); 
//  Serial.print("\tG:\t"); Serial.print(int(green)); 
//  Serial.print("\tB:\t"); Serial.print(int(blue));
//  Serial.println();


#if defined(ARDUINO_ARCH_ESP32)
  ledcWrite(1, gammatable[(int)red]);
  ledcWrite(2, gammatable[(int)green]);
  ledcWrite(3, gammatable[(int)blue]);
#else
  analogWrite(redpin, gammatable[(int)red]);
  analogWrite(greenpin, gammatable[(int)green]);
  analogWrite(bluepin, gammatable[(int)blue]);
#endif
}

跑起来之后,串口 9600 会一直打印 R、G、B 三列 0 到 255 的值,RGB 灯的颜色跟着被测物体变。建议先找几张纯色卡纸试:红色的 R 值明显大于 G 和 B,绿色的 G 冒头,蓝色的 B 最高,规律非常直观。读数时传感器贴住纸面,效果最稳。

从认颜色到做分拣:实战要点

到这里硬件和代码都通了,但要真拿去做分拣机器人,还有几个坑得提前知道。Adafruit 官方文档说得很直白:识别特定颜色不是把传感器往色块前一指读个数就完事,距离、视场、环境光都会影响读数。结合实际使用经验,给你四条能直接用的建议。

第一,把检测距离固定死。这颗传感器的有效检测距离是 3 到 10mm,别用手举着测,做个结构件(3D 打印或者亚克力板)把传感器卡在离被测面 5mm 左右的位置,距离稳了读数才能稳。第二,管住环境光。分拣机构上最好给传感器加个遮光罩,让被测区域的光照只来自板载 LED,这样不管白天晚上、开不开灯,读数基准都一样——这也是 colorview 例程要在读数前手动点亮 LED 的原因。

第三,判别逻辑用归一化比值,别用绝对值。直接判 R 大于多少,容易翻车在亮度变化上;把 R、G、B 分别除以 Clear 通道(就像 DFRobot 例程里 r /= sum 那样),得到颜色占比,整体变亮变暗时占比基本不动,判别稳得多。更讲究一点可以做黑白校准:测一张白纸记下各通道基准,测全黑记下底噪,之后的读数映射到这个区间里。第四,积分时间和增益按场景调。默认 50ms 加 4X 增益适合室内常亮;环境暗就把积分时间拉长(最长 614ms 那档)或者增益拉满 60X,代价是采样变慢,分拣节拍要提前算好。

想做完整分拣项目的,推荐去看 Adafruit 论坛玩家 systembolaget 的 Colour Finder 项目:TCS34725 配一颗 HD-1900A 舵机做的颜色查找加分拣机,GitHub 上有全套代码和讲解,Adafruit 官方文档专门引用了它。DFRobot 论坛也有一篇手动白平衡的方法帖,校准细节写得挺细。

最后说句选型的大实话:老一辈的 TCS3200 也不是不能用,但它是频率输出、没有红外滤光片、读数受环境光影响大,调试成本高不少。做颜色分拣这种要稳定判别的活,TCS34725 贵不了几块钱,省下的调试时间远超差价。

小结

总结一下:TCS34725 四根 I2C 线接上 Arduino,装 Adafruit 的库,先跑测试例程验证硬件,再上 colorview 做反射式颜色识别;做分拣记住三件事——固定距离、遮环境光、用归一化比值。这是轻量级颜色识别性价比最高的方案之一。下次接着讲怎么把它装上小车做颜色循迹,以及配合舵机分拣臂的联动结构,感兴趣的关注更新。


作者:电机传感器师
链接:https://www.aiddithome.com/p/aa3f4d11a4e89.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
周五下班搞一搞
1楼 · 2026-10-24 20:49:58

TCS3200 换 TCS34725 的路过,IR 滤光片确实不是智商税,日光灯下读数稳太多了。这篇的增益调节部分讲得很实用。

调参到凌晨
2楼 · 2026-10-24 20:49:56

问下楼主,检测距离5mm是结构件卡死的吗?我想装在机械臂末端,物体高度不太一致,有没有什么容错办法。

胶佬憨憨
3楼 · 2026-10-24 20:49:54

正好在做颜色分拣的毕设,归一化比值这个思路救了我,之前直接用绝对值判别,中午和晚上判出来完全是两个东西。

电烙铁爱好者
4楼 · 2026-10-24 20:49:51

照着接线一次点亮,Found sensor 出来的时候还挺有成就感的。提醒下后来人,模块底下那张保护纸真别忘了撕,我卡在这步折腾了半小时。