2024年寒假练-用搭配带屏12指神探的传感器扩展板实现颜色识别
该项目使用了搭配带屏12指神探的传感器扩展板,实现了驱动颜色传感器-LTR-381RGB识别颜色的设计,它的主要功能为:通过I2C驱动颜色传感器-LTR-381RGB,进行颜色识别。。
标签
嵌入式系统
测试
显示
2024年“寒假在家一起练”
aramy
更新2024-03-29
209

硬件介绍:

12指神探是一款基于树莓派基金会推出的微控制器RP2040制作的多功能硬件调试助手,它有12根引脚,提供了5V和3.3V的电压,其中有9根GPIO,功能灵活,通过搭配不同程序可以做成各种调试器。RP2040芯片具有双Arm Cortex M0+内核,默认运行的125MHz时钟超频到200MHz也可稳定运行,搭载的PIO功能使其可以生成各种常用或者自定义的协议,开发语言可以选择MicroPython或C/C++并且官方文档例程丰富,适用于初学者快速入门应用的同时也可开发出芯片极致性能。

12指神探的传感器扩展板,接口完全适配,正确方向插入后即可使用。扩展板搭载了几款常见传感器和功能模块,麦克风、蜂鸣器、、红外收发、霍尔效应开关、加热电阻,为进阶操作准备的温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。其中温湿度传感器、六轴传感器、接近传感器、颜色传感器可拆卸为单个模块,通过杜邦线等连接线延伸其使用的空间范围。

任务选择:

我选择的是任务3:颜色识别及校准功能。任务要求:可识别至少五种颜色;可在LCD上显示基本信息如当前识别颜色;可在LCD上用色块显示识别的颜色并大致接近。

编程语言使用Arduino。开发工具使用 Vscode+platformio。

任务实现:

任务整体不复杂,就是从颜色传感器中获得环境中的颜色,然后在屏幕上进行还原即可。

第一步:读取传感器。这次颜色传感器是LTR-381RGB-WA。也许是因为太新的缘故吧,在网上没有找到这个传感器的驱动库。于是只能手搓驱动文件了。在网上找到个类似的产品LTR390的光线传感器,以此传感器驱动文件作为基础,进行修改。IIC初始化部分大体相同,留意启动时写入命令字有所区别。读取数据部分区别在于LTR381多了几个数据。

由手册可以得知,LTR381的数据有4组,分别是IR、green、red、blue,存放在寄存器0X0A~0X15中。IR猜测是红外数据,这里没有使用。只需要读取R/G/B三色数据即可。

#define LTR381_ADDR 0x53 // default address

// LTR381 register addresses
#define LTR381_CONTR 0x00
#define LTR381_MEAS_RATE 0x04
#define LTR381_ALS_GAIN 0x05
#define LTR381_PART_ID 0x06
#define LTR381_STATUS 0x07
#define LTR381_DATA_IR_0 0x0A
#define LTR381_DATA_IR_1 0x0B
#define LTR381_DATA_IR_2 0x0C
#define LTR381_DATA_GREEN_0 0x0D
#define LTR381_DATA_GREEN_1 0x0E
#define LTR381_DATA_GREEN_2 0x0F
#define LTR381_DATA_RED_0 0x10
#define LTR381_DATA_RED_1 0x11
#define LTR381_DATA_RED_2 0x12
#define LTR381_DATA_BLUE_0 0x13
#define LTR381_DATA_BLUE_1 0x14
#define LTR381_DATA_BLUE_2 0x15
#define LTR381_INTERRUPT 0x19
#define LTR381_INTR_PERS 0x1A
#define LTR381_THRES_UP_0 0x21
#define LTR381_THRES_UP_1 0x22
#define LTR381_THRES_UP_2 0x23
#define LTR381_THRES_LOW_0 0x24
#define LTR381_THRES_LOW_1 0x25
#define LTR381_THRES_LOW_2 0x26

enum COLOR
{
    IR = 0,
    GREEN,
    RED,
    BLUE
};

boolean LTR381::getColorData(enum COLOR color, unsigned long &data)
{
    switch (color)
    {
    case IR:
        return (readLongInt(LTR381_DATA_IR_0, data));
        break;
    case RED:
        return (readLongInt(LTR381_DATA_RED_0, data));
        break;
    case GREEN:
        return (readLongInt(LTR381_DATA_GREEN_0, data));
        break;
    case BLUE:
        return (readLongInt(LTR381_DATA_BLUE_0, data));
        break;
    }
    return false;
}

boolean LTR381::readLongInt(uint8_t address, unsigned long &value)
{
    // Reads an unsigned integer (16 bits) from a LTR381 address (low byte first)
    // Address: LTR381 address (0 to 15), low byte first
    // Value will be set to stored unsigned integer
    // Returns true (1) if successful, false (0) if there was an I2C error
    // (Also see getError() above)

    uint8_t high, med, low;

    // Check if sensor present for read
    Wire.beginTransmission(_i2c_address);
    Wire.write(address);
    _error = Wire.endTransmission();

    // Read two bytes (low and high)
    if (_error == 0)
    {
        Wire.requestFrom(_i2c_address, 3);
        if (Wire.available() == 3)
        {
            low = Wire.read();
            med = Wire.read();
            high = Wire.read();
            // Combine bytes into unsigned int
            value = ((long)(high & 0x0F)) << 16;
            value |= ((long)med) << 8;
            value |= (long)low;
            return (true);
        }
    }
    return (false);
}

另外还需要修改I2C默认的管脚,这里12指神探使用的管脚为SDA(20),SCL(21)。

第二步:合成颜色。驱动起LTR381后,可以读取到4个长整形数据。其中第一个数据应该是红外数据,使用空调遥控器对着传感器按,数据会有较大的变化,但是这个数据对此项目无效,故此舍弃。

读取LTR381官方文档,文档中有使用传感器数据合成亮度数据的方法。这里看的不是很明白,为啥亮度和红外数据和绿光相关,为啥和红光、蓝光无关呢?感觉还是自己英文不好,没能理解文档的意思。

如果简单地按照读取到传感器R、G、B三色数据的比例,混合出颜色来,经过测试颜色严重失真,混合后的颜色与实际颜色风马牛不相及。

在合成颜色这块卡了很久,找了蛮多文章,都没能很好地解决这个问题。使用手机屏幕给出纯色(红、绿、蓝),从传感器读取到的数据,在(R,G,B)三个分量上依然是都有值,这样一合成,颜色就偏离纯色了。然后我就改变思路,既然无法准确模拟出环境的颜色,那么就预设几种颜色,去猜测环境中的颜色是这预设的那个颜色即可。这样至少预设的几种颜色能够完全模拟出来。就像一块停了的手表,一天能有两次时间是准确的。

先采集各类纯色时,传感器收集到的R、G、B的值,然后用统计方法求均值。将(R,G,B)作为全集,计算在纯色时,每个分量占比全集的比例值。这样获得了7种颜色在三原色中的坐标信息。

白色 0.2622  0.4890  0.2488
红色 0.5926  0.3118  0.0955
绿色 0.1300  0.6446  0.2255
蓝色 0.1244  0.2746  0.6010
黄色 0.3734  0.5131  0.1135
pink 0.3949  0.2279  0.3772
绿蓝 0.0983  0.5042  0.3975

然后当传感器获得数据后,通过获得的(R,G,B)数据计算距离以上7种颜色的几何距离,取距离最近的颜色作为模拟颜色。

//计算距离指定颜色的距离
float distinctColor(float *in_c, float *targetedcolor)
{
  return sqrt((in_c[0] - targetedcolor[0]) * (in_c[0] - targetedcolor[0]) + (in_c[1] - targetedcolor[1]) * (in_c[1] - targetedcolor[1]) + (in_c[2] - targetedcolor[2]) * (in_c[2] - targetedcolor[2]));
}
//寻找最小值
int findMinVal(float *inval)
{
  int offset = 0;
  float diffval = inval[0];
  for (int i = 1; i < 7; i++)
  {
    if (inval[i] < diffval)
    {
      diffval = inval[i];
      offset = i;
    }
  }
  return offset;
}
// 用传感器计算获得的颜色,简化了程序,仅仅还原 RGB 饱和色的混合
// 方法是 计算到已知颜色的距离,取最小距离作为结果
// 白色 0.2622  0.4890  0.2488
// 红色 0.5926  0.3118  0.0955
// 绿色 0.1300  0.6446  0.2255
// 蓝色 0.1244  0.2746  0.6010
// 黄色 0.3734  0.5131  0.1135
// pink 0.3949  0.2279  0.3772
// 绿蓝 0.0983  0.5042  0.3975
long countColor(long r, long g, long b)
{
  float sum = r + g + b;
  float in_c[3] = {0};
  float countcolor[7] = {0};
  diapcolorinfo(r, g, b);

  in_c[0] = float(r) / sum;
  in_c[1] = float(g) / sum;
  in_c[2] = float(b) / sum;

  for (int i = 0; i < 7; i++)
  {
    countcolor[i] = distinctColor(in_c, staticcolor + i * 3);
    Serial.print(countcolor[i]);
    Serial.print("   ");
  }
  Serial.println();
  //从7种颜色里选出最小的值,作为识别到的颜色。
  // Serial.println(findMinVal(countcolor));
  return findMinVal(countcolor);
}
//从识别到的颜色(0~7) 转换成颜色的数值
int changeColorRGB(int color)
{
  switch (color)
  {
  case 0:
    return tft.color565(255, 255, 255); //白光
    break;
  case 1:
    return tft.color565(255, 0, 0); // red
    break;
  case 2:
    return tft.color565(0, 255, 0); // green
    break;
  case 3:
    return tft.color565(0, 0, 255); // blue
    break;
  case 4:
    return tft.color565(255, 255, 0); // yellow
    break;
  case 5:
    return tft.color565(255, 0, 255); // pink
    break;
  case 6:
    return tft.color565(0, 255, 255); // cyan
    break;
  }
  return 0;
}

通过以上方法,可以保障在遇到以上7中颜色的光线时,能够准确地模拟出对应的颜色,但是更多的颜色也终将落到这7色中去,无法完美地模拟出环境颜色。

心得体会

感谢电子森林举办的寒假一起练活动。知易行难,觉着很简单的任务,当自己动手去做时才会明白各种困难。也正是克服了各种困难才会有成就感。还要感谢群里的各位老师,提供了很多解决问题的思路。


附件下载
pico2024_color.zip
团队介绍
瞎捣鼓小能手。
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号