Датчик цвета TCS3200

Тема в разделе "Arduino & Shields", создана пользователем DrProg, 6 сен 2015.

  1. DrProg

    DrProg Вечный нерд

    Эксперементировал с добытым по случаю модулем цвета. Забегая вперед скажу, что по итогам вечера я испытываю разочарования и недоумеваю почему этот модуль носит такое название и зачем он вообще нужен. Буду рад, если скажете что я не прав и в чем именно.

    Если коротко, принцип работы такой. Сердце модуля это датчик TCS3200, по сути это мини RGB матрица состоящая из массива 4х видов датчиков чувствительных каждый к своему цвету (точнее 3 к цвету, один к освещенности) и разбросанных равномерно по площади матрицы. Модуль работает так: чем выше интенсивность света, тем выше частота дёргания ноги OUT, при этом комбинацией пинов мы можем учитывать датчики только определенного цвета. Таким образом подсчитывая частоту теребления OUT трижды (каждый раз включая по очереди красную, зеленую и синюю группу датчиков) мы, теоретически, должны получить интенсивность всех трех цветов, что собственно даст нам информацию о цвете изучаемого объекта.

    Производитель приводит в пример такую тестовую программу:
    Код (Text):
    int s0=3,s1=4,s2=5,s3=6;
    int out=2;
    int flag=0;
    byte counter=0;
    byte countR=0,countG=0,countB=0;
    void setup()
    {
    Serial.begin(9600);
    pinMode(s0,OUTPUT);
    pinMode(s1,OUTPUT);
    pinMode(s2,OUTPUT);
    pinMode(s3,OUTPUT);
    }
    void TCS()
    {
    flag=0;
    digitalWrite(s1,HIGH);
    digitalWrite(s0,HIGH);
    digitalWrite(s2,LOW);
    digitalWrite(s3,LOW);
    attachInterrupt(0, ISR_INTO, CHANGE);
    timer0_init();
    }
    void ISR_INTO()
    {
    counter++;
    }
    void timer0_init(void)
    {
      TCCR2A=0x00;
      TCCR2B=0x07;  //the clock frequency source 1024 points
      TCNT2= 100;    //10 ms overflow again
      TIMSK2 = 0x01; //allow interrupt
    }
    int i=0;
    ISR(TIMER2_OVF_vect)//the timer 2, 10ms interrupt overflow again. Internal overflow interrupt executive function
    {
        TCNT2=100;
        flag++;
    if(flag==1)
      {
        countR=counter;
    //    Serial.print("red=");
    //    Serial.println(countR,DEC);
        digitalWrite(s2,HIGH);
        digitalWrite(s3,HIGH);
      }
      else if(flag==2)
      {
        countG=counter;
    //    Serial.print("green=");
    //    Serial.println(countG,DEC);
        digitalWrite(s2,LOW);
        digitalWrite(s3,HIGH);
      }
      else if(flag==3)
        {
        countB=counter;
        Serial.print("blue=");
        Serial.println(countB,DEC);
        Serial.println("\n");
        digitalWrite(s2,LOW);
        digitalWrite(s3,LOW);

        }
        else if(flag==4)
        {
        flag=0;
        }
          counter=0;
    }
    void loop()
    {
      TCS();
    while(1);
    }
    При помощи таймера каждые 10мс подсчитывается кол-во каждого прерывания при каждом включенном фильтре. И каждые же 10мс программа выводит в порт об этом отчет.

    Я немного упростил убрав таймер, оставив суть, выводя результаты раз в секунду:
    Код (Text):

    int s0 = 3, s1 = 4, s2 = 8, s3 = 9;
    volatile int counter = 0;
    int cR = 0, cG = 0, cB = 0;
    //unsigned long timerC = 0;

    void setup() {
      // put your setup code here, to run once:
      pinMode(s0, OUTPUT);
      pinMode(s1, OUTPUT);
      pinMode(s2, OUTPUT);
      pinMode(s3, OUTPUT);
      digitalWrite(s1, HIGH);
      digitalWrite(s0, HIGH);
      Serial.begin(9600);
      attachInterrupt(0, INT_0, CHANGE);
    }

    void loop() {
      // put your main code here, to run repeatedly:
      readColor();
      Serial.print("red=");
      Serial.println(cR, DEC);
      Serial.print("green=");
      Serial.println(cG, DEC);
      Serial.print("blue=");
      Serial.println(cB, DEC);
      Serial.println(" ");
      delay(1000);
      //  while (1);
    }

    void readColor () {
      digitalWrite(s2, LOW);  // вкл красный фильтр
      digitalWrite(s3, LOW);
      cR = delay10();
      digitalWrite(s2, HIGH); // вкл зеленый фильтр
      digitalWrite(s3, HIGH);
      cG = delay10();
      digitalWrite(s2, LOW);  // вкл синий фильтр
      digitalWrite(s3, HIGH);
      cB = delay10();
    }


    int delay10 () {
      //  timerC = millis() + 10;
      counter = 0;
      delay(20);
      //  while (timerC >= millis());
      return counter;
    }

    void INT_0()
    {
      counter++;
    }
     
    Результат от этого не изменился. Как выдавало все три цвета примерно одинаково при просмотре любого объекта, так и выдает. Заметная разница возникает лишь при общей интенсивности света, все три параметра увеличиваются или уменьшаются равномерно. При просмотре же разных цветов разницы никакой, если не считать хаотичных всплесков, вызванных, вероятно, помехами.

    Более того, остается загадкой, каким образом подсчет прерываний влияет на delay(). Паузы между измерениями то значительно сокращались, то увеличивались. Внешние прерывания влияют на таймер? Чудеса творятся под утро...
     
    Последнее редактирование: 6 сен 2015
    ИгорьК нравится это.
  2. geher

    geher Гуру

    Прерывания влияют на delay, поскольку при исполнении прерывания все другие прерывания, включая таймерное, запрещаются и не обрабатываются.
    Но учитывая "жуткую сложность" кода обработчика прерывания (одна строчка с инкрементом), это влияние должно быть исчезающе малым. Разве что прерывания поступают чуть ли не каждый такт.
    И вроде как надо не
    int counter = 0;
    а
    volatile int counter = 0;
     
  3. DrProg

    DrProg Вечный нерд

    Действительно, ладно я лажаю, а DFrobot чего? Но видимо причина не в этом, с volatile все то же самое. (
     
    ИгорьК нравится это.
  4. DrProg

    DrProg Вечный нерд

    Ладно, более-менее разобрался, худо-плохо работает, скопировал рабочую версию в первый пост мой вариант. Очень условно конечно же цвета определяет, особенно зеленый, больше половины всех зеленых считает красным или синим. Вопрос в том, можно ли покрасив 9 шариков в разный цвет отличать их друг от друга при помощи этого датчика?
     
    ИгорьК нравится это.
  5. DrProg

    DrProg Вечный нерд

    4 предмета отличает друг от друга по цвету довольно уверенно:

     
    ИгорьК нравится это.
  6. Tomasina

    Tomasina Иномирянин

    Ой, как мне пришлось намучаться с ними... Хотя сами цвета распознаются довольно точно, но мало того, что сенсор показания выдает в очень узком диапазоне, так ещё и шумов настолько много, что сложно выявить истинный цвет.
    А код от dfrobot очень невнятный по логике, будто индусы писали. На ютубе есть лекция какого-то профессора, видео длинное, полчаса наверное, но он очень внятно описал логику того, как они работают. И код там чуть другой.
    Мне в итоге пришлось применить медианный фильтр на каждый компонент цвета с выборкой из 20-50 измерений, только тогда качество распознавания приблизилось хотя бы к 70%.
     
    Последнее редактирование: 7 сен 2015
  7. DrProg

    DrProg Вечный нерд

    У меня немного другой алгоритм: сравнивает все показания с эталонными и тот, который ближе по всем трем (сумма модулей разниц) и признается победителем.
    В итоге я сделал вывод, что для использования в развлекательных изделиях, например лампа-хамелион, этот датчик вполне сгодиться. Для серьезных задач, например отличать предметы друг от друга по цвету в высокой надежностью - нет. Нужно искать другие пути, те же самые RFID-метки например.
     
    ИгорьК нравится это.
  8. Tomasina

    Tomasina Иномирянин

    У меня такое же сравнение с эталоном, но фильтр не по сумме модулей разница (кстати, что это такое?), а по медиане.
     
  9. DrProg

    DrProg Вечный нерд

    Допустим эталон: RGB 200, 300, 500 (и таких эталонов несколько, понятное дело). С датчика приходят цифры: 253, 289, 550. Делаем так: abs(200-253)+abs(300-289)+abs(500-550), получаем сумму разниц, если можно так выразиться. То же самое делаем с остальными эталонами. Тот, у которого эта сумма разниц меньше, то есть его показатели ближе всего с полученным и есть он самый. Если сумма больше некоего эмперического значения, (в моем случае это 800), считается что ни один цвет не подходит. Данные собираются в течении 10мс на каждый цвет. Возможно, более длительный сбор даст более точные результаты, особенно если предмет лежит неподвижно (зафиксирован в стойке). Пока в 9 случае из 10 случаев срабатывает и так. Могу код кинуть, если интересно.
     
    ИгорьК нравится это.
  10. Tomasina

    Tomasina Иномирянин

    Но ведь суммы 53+11+50 и 37+62+15 дадут одинаковый результат, хотя соответствуют разным цветам.
     
  11. Tomasina

    Tomasina Иномирянин

    Еще одна их особенность - ввиду дешевизны нет четкого соответствия различаемым цветам и цветам, видимым человеческому глазу, например, для них синий и зеленый почти схожи (настолько, что иногда показания почти идентичны), а вот малиновый, красный, оранжевый и желтый практически всегда распознаются без ошибок. Хотя, возможно, в этом вина не сенсора, а белого светодиода подсветки, у которого очень узкий диапазон, причем преимущественно в УФ- и синем спектре.
    Есть, конечно, более совершенные сенсоры, но их цена пока отпугивает.
     
  12. Vad33

    Vad33 Капитан-оригинал

    Если бы к этому датчику еще и RGB подсветку, чтобы анализировать не только отраженный
    белый свет на фильтрах, а все цвета.
     
  13. DrProg

    DrProg Вечный нерд

    Это практически без разницы, потому что при показаниях цветов 500-1500 единиц (при 10мс наблюдении) разброс в десятки на глаз не заметен. Минимальная сумма получается максимально близка к эталонному замеру как ни крути.
     
    ИгорьК нравится это.
  14. DrProg

    DrProg Вечный нерд

    Я вообще сначала думал, что светодиоды быстро перебирают цвета и датчик фиксирует яркость при каждом цвете. По-моему так работают сканеры. А вот они пошли другим путем.
     
    ИгорьК нравится это.
  15. DrProg

    DrProg Вечный нерд

    В общем, основная проблема этой конкретной конструкции модуля в том, что сенсор засвечивается собственной подсветкой и процентов на 70 ловит белый свет. Остальные 30% и есть отражение от исследуемой цветной поверхности. Да и то, если поверхность не глянцевая. Решения на ум приходит два: механическое - оградить сенсор непрозрачной трубкой и математическое - понизить минимальный уровень измерение до нуля и растянуть остальные. Трубка действительно сделала цвета менее блеклыми. Математика же сработала еще лучше, лампа "хамелеон" стала работать куда правдоподобнее.

    [​IMG]

     
    ИгорьК нравится это.
  16. Arhat109

    Arhat109 Гик

    Датчик своеобразный конечно же. И с типовой Ардуино работать ему несколько сложновато, ибо - получаются тормоза. Проблемы, с которыми столкнулся:
    1. Собственная засветка своими же светодиодами. Решается куском трубки от фломастера, подклеиваемой вокруг самого сенсора. Надо только найти подходящий диаметр.
    2. Отсутствие ИК-фильтра. Сильно искажает показания в зеленой и синей частях, что приводит к трудностям распознавания почему-то именно "зеленого" цвета. Он в отраженном свете часто и вовсе не "зеленый", а тут ещё и ИК накладывается.
    3. На разных уровнях освещенности, полезны разные алгоритмы работы с датчиком. Так на малой освещенности (низкие частоты выхода) - оч. хорошо работает режим счета на прерывании по захвату таймера. А на высоких яркостях лучше считать частоту за период.

    Итого, поигравшись с этим датчиком, могу заявить что его чувствительность в заявленные 0.2% даже избыточна, ибо сам процесс замера и восстановления баланса белого по обратной матрице - дает не лучше 1-1.5%. В целом как прибор определения цвета - использовать его можно, но время получения результата не менее 4-15мсек, что достаточно долго. Увы.

    В моей библиотеке есть пример работы с этим датчиком, сама библиотека писана и компилируется под ИДЕ 1.6.4, не выше. Искать где-то на гитхабе (потерял уже) по ARHAT_H.

    P.S. перестраивая алгоритм и задавая параметры усреднения в самом датчике, можно достаточно уверенно распознавать цвета и освещенность, начиная примерно с 7..10лк.