Color Sensor TCS34725 / Piano Glove

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

I've started a project based on the adafruit Piano Glove.
The aim is, to make sound out of colors.

Therefore I use the Flora Color Sensor TCS34725. My Problem:
How / Is it possible to use more than one color sensor at the same time?
I would like to be able to produce multiple soundtracks simultaneously.

In the code of the Piano Glove there is a delay of 60 ms with the comment "takes 50ms to read".
Does this mean, that the sensor cannot scan in real-time?

The Code:
(https://github.com/adafruit/pianoglove/ ... oglove.ino)

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by Franklin97355 »

In the code of the Piano Glove there is a delay of 60 ms with the comment "takes 50ms to read".
Does this mean, that the sensor cannot scan in real-time?
If you mean instantaneously then no it can't. It takes a bit for the sensor to process incoming data.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

Yes, I meant instantaneously.

Is it possible to use multiple sensors with one FLORA / Arduino Uno?

User avatar
Renate
 
Posts: 291
Joined: Tue Nov 13, 2012 3:21 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by Renate »

Yes/no. Mostly no.
The TCS34725 works on a fixed I²C address of 0x29.
There are no address select pins on the device.

Most controllers only have a single I²C interface.
If you have a controller with more GPIO output pins you can "roll your own" I²C interfaces with "bit bashing".
You might have better luck putting in an external 2 bit data multiplexor for SDA/SCL.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

Thanks a lot. I'm going to read about such multiplexers. Never heard about it.
I'm kind of a newbie ;-)

Which controller might have more GPIO outputs?
In the end I need to control 5 sensors at once.

User avatar
Renate
 
Posts: 291
Joined: Tue Nov 13, 2012 3:21 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by Renate »

Actually, using a dual 8 channel CMOS multiplexer is a bit of a hassle.
You can just wire all the SDAs together and use a 1 of 8 demultiplexer to distribute the SCL signal.
See: https://learn.adafruit.com/delorean-tim ... t-trickery

The sample rate (integration time, ATIME) can be reduced beyond the 50 mS if you like and can put up with less sensitivity.
Note also, that all 5 sensors can be running the 50 mS at the same time.
You don't need to run them sequentially.
Last edited by Renate on Mon Jun 23, 2014 6:38 am, edited 1 time in total.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

Thank you for this idea, I ordered a SN74HC138 and am going to try this the next days.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

Hello again,
now I've got another question:
Is it possible to work with two floras and two color sensors but only one VS1053 Codec Breakout?
So is it possible to give the VS1053 two signals to get two different sounds simultaneously?
What could be the way to work around with this?

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by adafruit_support_mike »

That's somewhere around the 'n' in "here there be dragons".

In theory it's possible to distribute control of a chip across multiple processors, but that means you have to keep everything in sync. The general strategy for that is to make a single logical processor and assign the various bits of hardware to perform functions in that.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

It works! I've got two floras and two sensors - one flora sends a signal to the second, which reads a second signal and transfers both signals to the VS1053.
After a while, I'm getting in trouble because of the serial connection.
The second flora receives weird values instead of values between 40.0 and 76.0 (float).
Like -2035784.5 ...

What could be the problem? I think, it could have something to do with addressing the bytes.

Here is my code from the sending sensor:

Code: Select all

#include <Wire.h>
#include "Adafruit_TCS34725.h"  // Bibliothek für Farbsensor
#include <SoftwareSerial.h>      // für mehr Serial Ports als pin 0 und 1

Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_24MS, TCS34725_GAIN_4X);  // Variable tcs

int prevNote = -1; // vorherige Note für Kanal 0
int LED = 7;

void setup () {
  Serial.begin(9600);  // Data Rate in bits per second (baud) 
  Serial1.begin(9600);  // Data Rate in bits per second (baud) 
  tcs.begin();
  pinMode(LED, OUTPUT);
}


void loop () {
  digitalWrite(LED, LOW);
  uint16_t red, green, blue, clear;
  tcs.setInterrupt(false);      // turn on Led of Farbsensor
  delay(60);  // takes 50ms to read 
  tcs.getRawData(&red, &green, &blue, &clear);
  
  // not close enough to colorful item
  if (clear < 2000) { // 2000 = CLEARTHRESHOLD
    float clearKeynum = -1;
    Serial.println(clearKeynum);
    byte * f_p = (byte *) &clearKeynum;  // keynum wird in byte verwandelt und in Variable f_p gespeichert
    Serial1.write(f_p[0]);
    Serial1.write(f_p[1]);
    Serial1.write(f_p[2]);
    Serial1.write(f_p[3]);
    return;
  }

  float rgbt = calcRainbowTone(red, green, blue, clear);
  
  float keynum = 40 + (76 - 40) * rgbt; // 40 = LOWKEY, 76 = HIGHKEY, 64 + 12 * rainbowtone

  byte * b = (byte *) &keynum;  // keynum wird in byte verwandelt und in Variable f_p gespeichert
  Serial1.write(b[0]);
  Serial1.write(b[1]);
  Serial1.write(b[2]);
  Serial1.write(b[3]);
  
  digitalWrite(LED, HIGH);
  
  Serial.print("keynum: "); 
  Serial.println(keynum);

}
Here is the code from the receiving sensor:

Code: Select all

#include <Wire.h>
#include "Adafruit_TCS34725.h"  // Bibliothek für Farbsensor
#include <SoftwareSerial.h>      // für mehr Serial Ports als pin 0 und 1

Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_24MS, TCS34725_GAIN_4X);  // Variable tcs

SoftwareSerial VS1053_MIDI(0, 10); // RX, TX, 10 = VS1053_RX

int prevNoteChan0 = -1; // vorherige Note für Kanal 0
int prevNoteChan1 = -1; // vorherige Note für Kanal 1

int LED = 7;

union u_tag {
    byte b[4];
    float ival;
} u;

float oldReceivedKeynum;


void setup () {
  Serial.begin(9600);  // Data Rate in bits per second (baud) 
  Serial1.begin(9600);
  
  oldReceivedKeynum = 0;
  
  pinMode(LED, OUTPUT);     
  tcs.begin();

  pinMode(9, OUTPUT);  // PIN als OUTPUT definieren
  digitalWrite(9, LOW);  // Output > ground > LOW
  delay(10);  // Verzögerung
  digitalWrite(9, HIGH);  // Output > 5V > HIGH
  delay(10);  // Verzögerung
  
  setupMidi(); // Aufruf der SetupMidiFunction
}


void loop () {
     float receivedKeynum;
  
  // http://macherzin.net/article94-Serielle-Kommunikation-zwischen-2-Arduino
  if (Serial1.available() > 3) // wenn Daten empfangen
  {
     u.b[0] = Serial1.read();
     u.b[1] = Serial1.read();
     u.b[2] = Serial1.read();
     u.b[3] = Serial1.read();
     receivedKeynum = u.ival;
     
     Serial.print("receivedKeynum: "); 
     Serial.println(receivedKeynum); 
     if (u.ival != oldReceivedKeynum) {
       oldReceivedKeynum = u.ival;  
     } 
  }

  uint16_t red, green, blue, clear;
  tcs.setInterrupt(false);      // turn on LED of Farbsensor
  delay(60);  // takes 50ms to read 
  tcs.getRawData(&red, &green, &blue, &clear);

  if (receivedKeynum >= 0) {
      playNoteChan1(receivedKeynum);
  }

  // not close enough to colorful item
  if (clear < 2000) { // 2000 = CLEARTHRESHOLD
    playNoteChan0(-1);
    return;
  }

  float rgbt = calcRainbowTone(red, green, blue, clear);
  
  float keynum = 40 + (76 - 40) * rgbt; // 40 = LOWKEY, 76 = HIGHKEY, 64 + 12 * rainbowtone
  Serial.print("keynum: "); 
  Serial.println(keynum); 
  playNoteChan0(keynum);
}

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by adafruit_support_mike »

My guess is that your receiver is falling out of sync with the sender.

Your communication loop reads four bytes on the assumption that those are the ones that contain the value you want. If something happens to interfere with the transmission.. line noise, a buffer overrun, some kind of timing issue.. you could end up reading bytes 2, 3, and 4 from one transmission and then byte 1 from the next. That would cause the values to skew all over the place.

There are several things you can do to make the transmission more robust.. including ping and ack messages, echoing, checksums, etc.

Probably the least complicated solution would be to do some encoding and padding.

On the sender side:

Code: Select all

    uint8_t i;
    uint32_t data = whatever;

    for ( i=4 ; i ; i-- ) {
        Serial1.write( 0 );
    }
    for ( i=8 ; i ; i-- ) {
        Serial1.write( (( data >> 28 ) & 0x0f ) + 0xf0 );
        data <<= 4;
    }
    for ( i=4 ; i ; i-- ) {
        Serial1.write( 0 );
    }
    Serial1.flush();
on the receiver side:

Code: Select all

    uint8_t input, count;
    uint32t data;

    while ( Serial1.available() ) {
        input = 0;
        while ( 0xf0 != ( input & 0xf0 ) ) {
            input = Serial1.read();
        }
    
        data = 0;
        count = 8;
        while ( 0xf0 == ( input & 0xf0 ) ) {
            data += input & 0x0f;
            data <<= 4;
            input = Serial1.read();
            count--;
        }
        while ( count-- ) {
            input = Serial1.read();
        }
    }
The sender pads the transmission before and after the data with zeros that the receiver will ignore. It breaks the actual data into 4-bit chunks and adds them to a byte whose upper half is all ones. That upper half is a marker that means "this byte contains data".

The receiver reads and discards any bytes that don't have the "this byte contains data" marker in their upper half, then extracts and reassembles the data from the bytes that do have the marker. On the off chance that a byte was garbled by line noise or lost to some other problem, the extraction loop keeps a count of the bytes that it's read and ensures that it will read 8 bytes from the input stream once it sees the first byte with data.

Transmission problems will still give you bad readings, but one bad reading won't throw off the next. The stream of input will always contain a pad of bytes that can be discarded between one chunk of data and the next.

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

I understand the problem.
After including your code, I only get the number "4294967280" (in HEX 0xfffffff0) in the Serial Monitor of the receiver.
Could it be a problem that I'm trying to send floats or am I missing something by passing the data the wrong way?

sender side:

Code: Select all

void loop () {
  digitalWrite(LED, LOW);
  uint16_t red, green, blue, clear;
  tcs.setInterrupt(false);      // turn on Led of Farbsensor
  delay(60);  // takes 50ms to read 
  tcs.getRawData(&red, &green, &blue, &clear);
  


  float rgbt = calcRainbowTone(red, green, blue, clear);
  
  float keynum = 40 + (76 - 40) * rgbt; // 40 = LOWKEY, 76 = HIGHKEY, 64 + 12 * rainbowtone

    uint8_t i;
    uint32_t data = keynum;

    for ( i=4 ; i ; i-- ) {
        Serial1.write( 0 );
    }
    for ( i=8 ; i ; i-- ) {
        Serial1.write( (( data >> 28 ) & 0x0f ) + 0xf0 );
        data <<= 4;
    }
    for ( i=4 ; i ; i-- ) {
        Serial1.write( 0 );
    }
    Serial1.flush();
    
  
  digitalWrite(LED, HIGH);
  
  Serial.print("keynum: "); 
  Serial.println(keynum);

}
receiver side:

Code: Select all

void loop () {
     float receivedKeynum;
  
    uint8_t input, count;
    uint32_t data;

    while ( Serial1.available() ) {
        input = 0;
        while ( 0xf0 != ( input & 0xf0 ) ) {
            input = Serial1.read();
        }
    
        data = 0;
        count = 8;
        while ( 0xf0 == ( input & 0xf0 ) ) {
            data += input & 0x0f;
            data <<= 4;
            input = Serial1.read();
            count--;
        }
        while ( count-- ) {
            input = Serial1.read();
        }
    }

  Serial.print("data: "); 
  Serial.println(data); 


  uint16_t red, green, blue, clear;
  tcs.setInterrupt(false);      // turn on LED of Farbsensor
  delay(60);  // takes 50ms to read 
  tcs.getRawData(&red, &green, &blue, &clear);

  if (receivedKeynum >= 0) {
      playNoteChan1(receivedKeynum);
  }

  // not close enough to colorful item
  if (clear < 2000) { // 2000 = CLEARTHRESHOLD
    playNoteChan0(-1);
    return;
  }

  float rgbt = calcRainbowTone(red, green, blue, clear);
  
  float keynum = 40 + (76 - 40) * rgbt; // 40 = LOWKEY, 76 = HIGHKEY, 64 + 12 * rainbowtone
  Serial.print("keynum: "); 
  Serial.println(keynum); 
  playNoteChan0(keynum);
}

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by adafruit_support_mike »

I was a bit sloppy when writing the code..

Serial.read() returns -1 if there's nothing in the buffer to read, and the binary representation of -1 is 0xff. The top half of that matches the 0xf0 token value I'd chosen, so the "no data available" values were getting added into the data.

I also failed to make sure there was data to read before actually reading it. That screwed up the counts and data.

Here are a couple of sketches that I've actually tested on a pair of Arduinos with a Serial link between them:

Sender:

Code: Select all

#include <SoftwareSerial.h>

SoftwareSerial Serial1( 2, 3 );

void setup () {
    Serial1.begin( 9600 );
}

uint32_t base = 7;
uint8_t count;

void loop () {
    uint8_t i;
    uint32_t data = base << count++;
    count %= 32;
    
    for ( i=4 ; i ; i-- ) {
        Serial1.write( (byte)0 );
    }
    for ( i=8 ; i ; i-- ) {
        Serial1.write( (byte)(( data >> 28 ) & 0x0f ) + 0x70 );
        data <<= 4;
    }
    for ( i=4 ; i ; i-- ) {
        Serial1.write( (byte)0 );
    }
    Serial1.flush();
    
    delay( 1000 );
}
Receiver:

Code: Select all

#include <SoftwareSerial.h>

SoftwareSerial Serial1( 2, 3 );

enum state { SCAN, READ };

void setup () {
    Serial1.begin( 9600 );
    Serial.begin( 115200 );
}

state state = SCAN;
uint8_t count = 8;
uint32_t data;

void loop () {
    uint8_t input;
    
    while ( Serial1.available() ) {
        input = Serial1.read();
        state = ( 0x70 == ( input & 0xf0 ) ) ? READ : SCAN;
        
        if ( READ == state ) {
            data <<= 4;
            data += input & 0x0f;
            count--;
            Serial.print( input & 0x0f );
            Serial.print( " - " );
            Serial.println( data );
        }
    }
    if ( 0 == count ) {
        Serial.println( data );
        data = 0;
        count = 8;
    }
}
These examples transmit data as integers, which is easier.

I also changed the upper-half "this is data" value to 0x70 so it wouldn't accept "no input" 0xff values from Serial.read() as data any more.

If you want to send floating point values, I'd suggest deciding how many digits of resolution you want, converting the value to an integer for transmission, then converting it back to a floating point value in the receiver:

For three decimal places of resolution, the sender would do this:

Code: Select all

uint32_t data = floatValue * 1000;
//  transmit
and the revceiver would do this:

Code: Select all

uint32_t data = // receive
float floatValue = data / 1000;

anneklappe
 
Posts: 15
Joined: Wed Jun 18, 2014 10:46 am

Re: Color Sensor TCS34725 / Piano Glove

Post by anneklappe »

Thanks a lot for all your help! It works! :-)

There was only little flaw in your code. The division operator in C automatically gets rid of the position after decimal point. Therefore I had to explicitly cast the received data into a float.

Except for this little flaw, I'm very very happy that the connection and communication work very stable now.

Code: Select all

   
if ( 0 == count ) {
        float receivedData = (float)data / 100;
        data = 0;
        count = 8;
        return receivedData;
    }

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Color Sensor TCS34725 / Piano Glove

Post by adafruit_support_mike »

You're right.. casting to (float) will work, or you can divide by 10.0 (which the compiler will recognize as a float).

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”