Couple questions about color sorting

Hello dear all,

I am a new in this forum and here is my first topic.

I am planning to make color sorter with Arduino. I am aiming to detect 4 colors of candies and sort them with using servo. I have couple questions about it

  1. I bought GY-31 Color sensor which is similar with TSC3200 but it has 10 pins. What is the purpose of adding one more VCC and GND pin?

2)I found sample code for it and edited some parts to understand process. It actually works fine but in this code we don’t use LED pin in whole code. But what’s the purpose of LED pin on color sensor?

(Here is the code that I edit)

#include <TimerOne.h>

#define S0     6
#define S1     5
#define S2     4
#define S3     3
#define OUT    2

int redPin = 9;
int greenPin = 10;
int bluePin =11;

//#define COMMON_ANODE

int   g_count = 0;    // count the frequecy
int   g_array[3];     // store the RGB value
int   g_flag = 0;     // filter of RGB queue
float g_SF[3];        // save the RGB Scale factor
 
 
// Init TSC230 and setting Frequency.
void TSC_Init()
{
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
 
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH); 
}
 
// Select the filter color 
void TSC_FilterColor(int Level01, int Level02)
{
  if(Level01 != 0)
    Level01 = HIGH;
 
  if(Level02 != 0)
    Level02 = HIGH;
 
  digitalWrite(S2, Level01); 
  digitalWrite(S3, Level02); 
}
 
void TSC_Count()
{
  g_count ++ ;
}
 
void TSC_Callback()
{
  switch(g_flag)
  {
    case 0: 
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;

        // ledYak();
         
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
    
}
 
void TSC_WB(int Level0, int Level1)      //White Balance
{
  g_count = 0;
  g_flag ++;
  TSC_FilterColor(Level0, Level1);
  Timer1.setPeriod(1000000);             // set 1s period
}
 
void setup()
{
  TSC_Init();
  Serial.begin(9600);
  Timer1.initialize();             // defaulte is 1s
  Timer1.attachInterrupt(TSC_Callback);  
  attachInterrupt(0, TSC_Count, RISING);  
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT); 
  delay(4000);
 
  for(int i=0; i<3; i++)
    Serial.println(g_array[i]);
 
  g_SF[0] = 255.0/ g_array[0];     //R Scale factor
  g_SF[1] = 255.0/ g_array[1] ;    //G Scale factor
  g_SF[2] = 255.0/ g_array[2] ;    //B Scale factor
 
  Serial.println(g_SF[0]);
  Serial.println(g_SF[1]);
  Serial.println(g_SF[2]);
}

void ledYak(){
          
          /*analogWrite(redPin,255-g_array[0] * g_SF[0]);
          analogWrite(greenPin,255-g_array[1] * g_SF[1]);
          analogWrite(bluePin,255-g_array[2] * g_SF[2]);
  */
         {
           if((g_array[0]>g_array[1])&&(g_array[0]>g_array[2]))
           {
          Serial.println("Kirmizi");
          analogWrite(redPin,0);
          analogWrite(greenPin,255);
          analogWrite(bluePin,255);
           }
            else if(g_array[1]>g_array[2])
            {
          Serial.println("Yesil");
          analogWrite(redPin,255);
          analogWrite(greenPin,0);
          analogWrite(bluePin,255);
            }
            else
          {
            Serial.println("Blue");
          analogWrite(redPin,255);
          analogWrite(greenPin,255);
          analogWrite(bluePin,0);
         }  
       } 

}
 
void loop()
{
   g_flag = 0;
   for(int i=0; i<3; i++)
    Serial.println(int(g_array[i] * g_SF[i]));
    ledYak();
   delay(4000);
   
   
 
}
  1. For the next part of project, I guess I will need 2 servo motors but what kind of servo motors should I use? Do you have specific model advice? For example mini or medium or??

Thank you for your helps.(Sorry about my english grammer mistakes)

I guess I will need 2 servo motors

To do what?

but what kind of servo motors should I use?

Ones that have enough torque to do whatever they need to do.

Do you have specific model advice?

I'm partial to Harley Davidson TriGlide's myself.

What is the purpose of adding one more VCC and GND pin?

To reduce the resistance into the device and allow it to draw more current without upsetting the voltage too much.
See decoupling:-
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

But what's the purpose of LED pin on color sensor?

Normally these are white and are for providing light of a fixed colour to give the surface something to reflect.

Grumpy_Mike:

What is the purpose of adding one more VCC and GND pin?

To reduce the resistance into the device and allow it to draw more current without upsetting the voltage too much.
See decoupling:-
De-coupling

But what’s the purpose of LED pin on color sensor?

Normally these are white and are for providing light of a fixed colour to give the surface something to reflect.

Thanks for serious answer. http://www.youtube.com/watch?v=aRayjgAdrHQ For this kind of project which servo motor type should I use? Mini or medium?
Thanks

PaulS:

I guess I will need 2 servo motors

To do what?

but what kind of servo motors should I use?

Ones that have enough torque to do whatever they need to do.

Do you have specific model advice?

I'm partial to Harley Davidson TriGlide's myself.

:sleeping:

of project which servo motor type should I use? Mini or medium?

I would always tend towards the larger motor to give you a bit of margin.

I have one more question about detecting yellow: what is the most reliable mathematical way to detect yellow?

As you know, yellow tones red and green almost equal blue is lower. For now I wrote smth like this

(Abs(red-green)<20) &&( (red>blue) ||( green>blue))

It works fine for now but it’s not reliable. Do you have any suggestion?

I would use a different range for each colour, that is you would have to get red between two values, green between another two and blue between a third set. This is called a window comparator.

Work out where the center of these windows are by printing out the individual colour readings when the sensor is in front of the required colour.

Just a point, are you sure that the motor in that video is a servo? It looks like a stepping motor to me.

Grumpy_Mike:
I would use a different range for each colour, that is you would have to get red between two values, green between another two and blue between a third set. This is called a window comparator.

Work out where the center of these windows are by printing out the individual colour readings when the sensor is in front of the required colour.

Just a point, are you sure that the motor in that video is a servo? It looks like a stepping motor to me.

Thank you for window comparator advice, I'll search about it.

Yea I noticed that for seperating part, they used step motor but I guess I can also do this with medium servo motor right?

but I guess I can also do this with medium servo motor right

You can but it will be more expensive and you have to make sure it can cover the degree of rotation you need.

Hi again, I bought all components and began to work on it again.

I tried to make them work individual first Color sensor part and servo was working great when I run them individual but I have really big problem now about servos and interrupt.

I’m not sure if it’s about interrupt or voltage-current problem but color sensor and servo motor don’t work together when I put both of them arduino. I hear some sounds from servo motor but it’s just making little movement in each second. Even I put 12 V batery to arduino motor shield, still confronting same problem. Before this project I tried to understand INTERRUPTS for Arduino signal waveform generator, I couldn’t get it . And this interrupt again made me in trouble… =(

#include <TimerOne.h>
#include <Servo.h>

#define S0     6
#define S1     5
#define S2     4
#define S3     3
#define OUT    2


int   g_count = 0;    // count the frequecy
int   g_array[3];     // store the RGB value
int   g_flag = 0;     // filter of RGB queue
float g_SF[3];        // save the RGB Scale factor

Servo servo360;
int cpos=0;

 
 
// Init TSC230 and setting Frequency.
void TSC_Init()
{
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
 
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH); 
}
 
// Select the filter color 
void TSC_FilterColor(int Level01, int Level02)
{
  if(Level01 != 0)
    Level01 = HIGH;
 
  if(Level02 != 0)
    Level02 = HIGH;
 
  digitalWrite(S2, Level01); 
  digitalWrite(S3, Level02); 
}
 
void TSC_Count()
{
  g_count ++ ;
}
 
void TSC_Callback()
{
  switch(g_flag)
  {
    case 0: 
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;

         
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
    
}
 
void TSC_WB(int Level0, int Level1)      //White Balance
{
  g_count = 0;
  g_flag ++;
  TSC_FilterColor(Level0, Level1);
  Timer1.setPeriod(1000000);             // set 1s period
}
 
void setup()
{
  TSC_Init();
  Serial.begin(9600);
  Timer1.initialize();             // defaulte is 1s
  Timer1.attachInterrupt(TSC_Callback);  
  attachInterrupt(0, TSC_Count, RISING);  

  servo360.attach(9); 
  
  delay(4000);
 
  for(int i=0; i<3; i++)
    Serial.println(g_array[i]);
 
  g_SF[0] = 255.0/ g_array[0];     //R Scale factor
  g_SF[1] = 255.0/ g_array[1] ;    //G Scale factor
  g_SF[2] = 255.0/ g_array[2] ;    //B Scale factor
 
  Serial.println(g_SF[0]);
  Serial.println(g_SF[1]);
  Serial.println(g_SF[2]);
}

void ledYak(){
          
     {
            if((g_array[0]<15)||(g_array[1]<15)||(g_array[2]<15))
            {

          servoDrive(0);//if no color detected
          
          
           }
           else if((abs(g_array[0]-g_array[1])<20)&&((g_array[0]>g_array[2])||(g_array[1]>g_array[2]))){

          //yellow
         servoDrive(1);
       }
           else if((g_array[0]>g_array[1])&&(g_array[0]>g_array[2]))
           {
          Serial.println("Kirmizi");

          //red
         servoDrive(2);
           } 
            else if(g_array[1]>g_array[2])
            {
          Serial.println("Yesil");
        servoDrive(3);
        //green
            }
            else
          {
            Serial.println("Blue");
        servoDrive(4);
        //blue
         }  
       } 

}

void servoDrive(int curr){
    switch(curr)
  {
    case 0: 
        if(cpos!=0)
        {
        if(cpos==30)
      servo360.write(-30);
        else if(cpos==60)
      servo360.write(-60);
        else if(cpos==90)
      servo360.write(-90);
    }
    cpos=servo360.read();
    delay(1000);
         break;
    case 1:
       if(cpos!=30)
        {
        if(cpos==0)
      servo360.write(+30);
        else if(cpos==60)
      servo360.write(-30);
        else if(cpos==90)
      servo360.write(-60);
    }
    cpos=servo360.read();
    delay(1000);
         break;
    case 2:
      if(cpos!=60)
        {
        if(cpos==0)
      servo360.write(60);
        else if(cpos==30)
      servo360.write(60);
        else if(cpos==90)
      servo360.write(-30);
    }
    cpos=servo360.read();
    delay(1000);
         break;
 
    case 3:
      if(cpos!=90)
        {
        if(cpos==0)
      servo360.write(90);
        else if(cpos==30)
      servo360.write(60);
        else if(cpos==60)
      servo360.write(30);
    }
    cpos=servo360.read();
    delay(1000);
         break;
   default:
         g_count = 0;
         break;
}
}
 
void loop()
{
   g_flag = 0;
   for(int i=0; i<3; i++)
    Serial.println(int(g_array[i] * g_SF[i]));
    ledYak();
   delay(4000);
   
   
 
}

I just got color sensing code from somewhere on the internet but changed it. ledYak function is comparing values and giving color in serial monitor and also calling servoDrive function cases inside it. servoDrive function is checking current possition and moving servo depend of the color. I mean it supposed to be like that :)) But I can’t get what is the problem… If it’s about interrupt or voltage-current-connection problem.

Thanks for helping

Why on earth are you using interrupts. I can see no reason to do this.

If a motor interferes with other components then you supply needs decoupling like the link I posted earlier.

Grumpy I already decoupled sensor as you mention before, but I couldn't get it should I do it also for servo?

Or is this problem because of the interrupt in code?

If it's because of the interrupt, I couldn't find any example code for color sensing to modify.

I'm really confused.

I tried to record it link bellow, you can hear ticking of servo same time blinking led of the servos. 90 percent it's because of the interrupt but I dont know what to do...

The servo needs more decoupling than the sensor.

The code is very bad.
You should declair all the variables you want to use outside the ISR as volatile.
You should not use serial print from inside an ISR.
You should disable the interrupts when grabbing a multi byte number outside an ISR that is changed inside one.

Finaly I found example code which doesn’t use interrupts. With servo it works fine without any decoupling circuit.

But in this code there are 6 different situations about recognizing color as “white”,“orange”,“yellow”,“red”,“green”,“blue”,""
I’m trying to minimize it as yellow red green and blue by extend range of these colors.

char* ReadColor() { //0=white, 1=orange, 2=yellow, 3=red, 4=green, 5=blue, 6=object out of range
  float FrequencyClear,FrequencyRed,FrequencyGreen,FrequencyBlue;
  int PercentageRed,PercentageGreen,PercentageBlue;
  TCS3200_On();
  NoFilter();
  FrequencyClear=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  RedFilter();
  FrequencyRed=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  GreenFilter();
  FrequencyGreen=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  BlueFilter();
  FrequencyBlue=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  TCS3200_Off();
  //Output frequency blue, green, red percentage represents the ratio of the 
  //respective color to the Clear channel absolute value:
  PercentageRed=int((FrequencyRed/FrequencyClear)*100.0);
  PercentageGreen=int((FrequencyGreen/FrequencyClear)*100.0);
  PercentageBlue=int((FrequencyBlue/FrequencyClear)*100.0);
  //Learned blue, green, red percentage values of different colors
  int SavedColorRed[] = {28,55,42,50,19,13}; 
  int SavedColorGreen[] = {30,25,36,22,45,26};
  int SavedColorBlue[] = {45,20,20,30,36,58};
  char* GetColor[] = {"white","orange","yellow","red","green","blue",""};
  int ColorArray[3];
  int i_color; 
  int ClosestColor;
  int MaxDiff;
  int MinDiff=300;
  if(FrequencyClear<1.5){ClosestColor=6; 
  abc=6; }// Object out of range
  else {
    for (i_color=0; i_color<6; i_color++) { //Find closest color
      ColorArray[0]=abs(SavedColorRed[i_color]-PercentageRed);
      ColorArray[1]=abs(SavedColorGreen[i_color]-PercentageGreen);
      ColorArray[2]=abs(SavedColorBlue[i_color]-PercentageBlue);
      MaxDiff=maximum(ColorArray,3);
      if (MaxDiff<MinDiff) {
        MinDiff=MaxDiff;
        ClosestColor=i_color;
        abc=i_color;
       }
     }
   }
   return GetColor[ClosestColor];  
}

I need to change this part of code but I couldn’t get how author determine these values in array, what should I do.

  int SavedColorRed[] = {28,55,42,50,19,13}; 
  int SavedColorGreen[] = {30,25,36,22,45,26};
  int SavedColorBlue[] = {45,20,20,30,36,58};

any help would be appreciated

The clue is in the comment:-

//Learned blue, green, red percentage values of different colors

These values were printed out with some code that just looks at the sensors and prints them out. Then the required colours are placed in front of the sensor and those values were printed out and put in your current program.

I almost done the project but still confronting some problems.

Now I'm having problem with stepper motor to do same angle for each time. For example I want to make 45 angle for each time but It makes 46 more or less thats why it doesn't work well.

How can I fix it any ideas?

const int STEPS = 25; // 360 / stepAngle
// Initialize the Stepper class
Stepper myStepper(STEPS, dirA, dirB);

what's the problem with it?

Here is the problem video

Now I'm having problem with stepper motor to do same angle for each time. For example I want to make 45 angle for each time but It makes 46 more or less thats why it doesn't work well.

It could be that you are going too fast and the motor is missing steps on start up or over running on stop.
Slow it down and see if the accuracy improves.
If it does you might need a library with acceleration and deceleration.

Grumpy_Mike:

Now I’m having problem with stepper motor to do same angle for each time. For example I want to make 45 angle for each time but It makes 46 more or less thats why it doesn’t work well.

It could be that you are going too fast and the motor is missing steps on start up or over running on stop.
Slow it down and see if the accuracy improves.
If it does you might need a library with acceleration and deceleration.

I tried it with different speeds but still same error. Than found something about CALIBRATING STEPPER with microsteps but couldn’t understand code clearly.

void rotate(int steps, float speed){
  //rotate a specific number of microsteps (8 microsteps per step) - (negative for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  int dir = (steps > 0)? HIGH:LOW;
  steps = abs(steps);

  digitalWrite(DIR_PIN,dir);

  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay);

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);
  }
}



/*
* @summary
* calibrates sorting assembly
*/
void zero() {
  //rotate until magnet found
  while(digitalRead(HALL_PIN)) {
// Serial.println(digitalRead(HALL_PIN));
    rotate(SMALL_STEP, SMALL_SPEED);
    delay(200);
  }
  rotate(-12, .2);
}