0

First off let me preface this my explaining my background. I am a mechanical engineering student and have some programming knowledge but it's limited. I'm trying to make a skittle sorter and I right now I'm working on the color identification part. I bought a ColorPal sensor for the project but I'm having trouble using it. I modified the demo a bit and it sort of works but not as well as I would like. Can someone please help me with my code or perhaps suggest an easier color sensor to use. Also I hope I paste my code correctly.

#include <SoftwareSerial.h>

#define sio      6           // ColorPAL connected to pin 6
#define unused   255         // Non-existant pin # for SoftwareSerial
#define sioBaud  4800

// Received RGB values from ColorPAL
int red;
int grn;
int blu;

// Set up two software serials on the same pin.
SoftwareSerial serin(sio, unused);
SoftwareSerial serout(unused, sio);

void setup() {

  delay(2000);

  Serial.begin(9600);
  reset();                    // Send reset to ColorPal
  serout.begin(sioBaud);
  pinMode(sio, OUTPUT);
  serout.print("=(00 $ m)!"); // Loop print values, see ColorPAL documentation
  serout.end();               // Discontinue serial port for transmitting
  pinMode(sio, INPUT);
  serin.begin(sioBaud);       // Set up serial port for receiving
}

void loop() {
  readData();
}

// Reset ColorPAL; see ColorPAL documentation for sequence
void reset() {
  delay(200);
  pinMode(sio, OUTPUT);
  digitalWrite(sio, LOW);
  pinMode(sio, INPUT);
  while (digitalRead(sio) != HIGH);
  pinMode(sio, OUTPUT);
  digitalWrite(sio, LOW);
  delay(80);
  pinMode(sio, INPUT);
  delay(200);
}

void readData() {
  char buffer[32];

  if (serin.available() > 0) {
    // Wait for a $ character, then read three 3 digit hex numbers
    buffer[0] = serin.read();
    if (buffer[0] == '$') {
      for (int i = 0; i < 9; i++) {
        while (serin.available() == 0);     // Wait for next input character
        buffer[i] = serin.read();
        //Serial.print(buffer[i]);
        if (buffer[i] == '$')               // Return early if $ character encountered
          return;
      }
      //Serial.println("");
      parseAndPrint(buffer);
      delay(10);
    }
  }
}

// Parse the hex data into integers
void parseAndPrint(char * data) {
  sscanf (data, "%3x%3x%3x", &red, &grn, &blu);  // Pull the R, G, and B values from the data string

  char buffer[48];                               // create a buffer
  //sprintf(buffer, "r = %4.4d    g = %4.4d    b = %4.4d", red, grn, blu);   //print the values into a buffer as formatted integers
  int sum = red + grn + blu;
  //Serial.println(sum);
  if (sum >= 120 && sum < 126) {
    Serial.println("Purple");
  }
  if (sum >=  238 && sum < 248) {
    Serial.println("Green");
  }
  if (sum >= 230 && sum < 235) {
    Serial.println("Red");
  }
  if (sum >=  330 && sum < 340) {
    Serial.println("Orange");
  }
  if (sum >=  420 && sum < 430) {
    Serial.println("Yellow");
  }
}
5
  • Sorry, I typed this on my phone so of course I misspelled things, how great. Mar 9 '17 at 2:20
  • 3
    Please edit your question (click "edit") and mark the code as code. When including code in a stackexchange question or answer, first paste the code into the question or answer editing box; then in that editing box, highlight the code and press ctrl-k. Or highlight the code and click the {} icon in the toolbar at the top of the editing box. To highlight text click-drag across it or use the arrow keys while holding the shift key. Note, instead of “sort of works but not as well as I would like” say what it actually does and what you actually want. Mar 9 '17 at 2:29
  • 2
    Indeed, please say what is wrong with it. I can see a bug, but maybe it's nothing to do with the problem you're seeing.
    – Mark Smith
    Mar 9 '17 at 7:02
  • 2
    You can't just sum the RGB values and expect to differentiate the colors.
    – gre_gor
    Mar 9 '17 at 13:33
  • Probably converting it to hue and then checking it's value will work much better. Did you try using red/green/blue sheets to check if the sensor works?
    – Paul
    Apr 4 '18 at 22:00
1

In parseAndPrint

You need to check the return value of sscanf to see if the function read the data.

The problem you are having is the difference between + and &. The sensor is providing 3, 3 digit hex values (which should be sprintfed with %03x not %4.4d). Adding these together isn't going to give you the write answer. For instance $001001001 should give you a colour of r=1, g=1 and b=1. If you add those together you get 3, but you really want 0x001 0x001 0x001.

You need to recalibrate you system and keep the three values separate and represent each colour by a minimum and max of those three colours and then check the value 3 values you receive are within the 3 ranges you have.

// Define a structure (could be a class) to hold the data
struct ColourData
{
    int redMin;
    int redMax;
    int grnMin;
    int grnMax;
    int bluMin;
    int bluMax;
    char Name[30];
    ColourData (int rm, int rx, int gm, int gx, int bm, int bx, char* name)
      : redMin(rm), redMax(rx)
      , grnMin(rm), grnMax(rx)
      , bluMin(bm), bluMax(bx)
    {
        sprint(Name, "%s", name);
    }
};

// Define an array containing the data
ColourData colours[MaxColours] = {ColourData(150, 200, 0, 20, 150, 200, "Purple")
                         , // Add some more

// The code to check the colours
for (int index = 0; index < MaxColours; ++index)
{ 
    if (  red >= colours[index].redMin && red <= colours[index].redMax
       && grn >= colours[index].grnMin && grn <= colours[index].grnMax
       && blu >= colours[index].bluMin && blu <= colours[index].bluMax)
    {
       Serial.println(colours[index].Name)
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.