We take a look at a colour sensing module.
There are all sorts of practical implementations for colour detection. You can use colour to signal machine operations (such as lane bounds - i.e. you’re too far to the left), sort fruit based on its colour for ripeness or variety, and loads more.
We have seen a number of these awesome colour-sensor modules around, but we hadn’t had a chance to play with them, until now! We picked up an XC3708 colour sensing module from Jaycar, which we notice is based around the TCS230 chip. This particular model, as with some others we have seen, is basically an array of photo diodes and coloured filters. You don’t have to do anything crazy to get it working however, as it’s all self-contained on a tiny SOIC package.
The additional features of this module include the usual pin headers, 4 x LEDs (we’ll explore these later), and a plastic shroud which limits the detection range (otherwise you’d be seeing light from many directions, making the task of detection even more difficult).
GETTING IT RUNNING
The Jaycar module came with some demo code to get us started. Looking at the code and the datasheet provided, it’s fairly easy to see how things come together.
Essentially there are two pins for controlling which colour filter is being used. By setting those pins high and low, we have four different colour reading options. Unfiltered (white / full spectrum), as well as red, green, and blue filters, which cover the three primary colours.
This means that reading of white / red / green / blue is done sequentially, with an intensity measurement for the current colour read being taken provided as a PWM level (it’s actually converted from the current in the photodiode array to a PWM output). Fortunately this makes reading the colour values relatively straight forward too.
However this hardware configuration presents an important consideration for inclusion in a project. It’s a white, red, green, blue detector - not a “your colour is fuschia” type detector. Therefore any detection of non-primary colours needs to be done with careful code development.
ADAPTING TO LIGHTING CONDITIONS
While the module has 4 x onboard LEDs to help provide constant illumination, there’s one tricky aspect introduced here. That is the inverse-square law. While the inverse-square law applies to various parts of physics, we’re going to discuss it in a simplified way, as it applies to the LEDs on the module and our readings.
“A physical quantity or strength is inversely proportional to the square of the distance from the source of that physical quantity.”
Don’t be too daunted by that description. It’s far more simple than it seems. You have probably observed the effects of this without even realising it. Have you ever noticed when you use flash photography in a dark area, everything near the camera is bright, and everything in the background is generally much darker. In the most simple observation, the foreground is bright.
During the day, the light from the sun has travelled 149,600,000km to get to Earth. For this reason, whether sunlight is hitting your head or your feet (unless you’re creating a shadow of course), the sunlight is basically the same intensity. The distance between your head and feet makes little difference.
This creates something of a challenge for distance when using the LEDs onboard with the module, because the distances are so small. If you’re measuring a colour by holding it just 1cm from the LEDs, and the object is moving just 1cm (between 1cm and 2cm from the LEDs), the light intensity on the object will fall to just 25% of the level detected at 1cm. For this reason, values can fluctuate wildly if the object is not at a very precise distance.
One potential solution is to consistently measure objects further away, say 10cm. Then the change between 10cm and 11cm in terms of the light intensity is actually reduced in impact (a 10-20% change rather than a 75% change). However this module has a recommended detection distance of just 1cm. This is likely because the light is not focused onto the detection array and could easily be confused if greater distances are used. But it’s an important consideration to have when developing a machine or project around this device.
The simplest workaround we found was to measure the unfiltered light levels, then divide our per-colour light levels into the unfiltered level. Based on our tests, this produced more consistent numeric outputs for different colours, rather than having to compensate for variable lighting. It then made the math a little simpler, to try and figure out what colours were being read.
This colour sensor is quite powerful, as long as you know its limitations and perform detection under ideal conditions. In essence, it’s like a really crude colour reader. If you’re looking for hardware to say “this is a lovely shade of lemon peel” or some other paint-store colour, it’s not the right choice.
If you’re dealing with highly reflective objects, transparent objects, or objects where the colour range is very narrow, then this probably isn’t the sensor for you either. However, if you’re measuring predictable colours (such as cardboard, manufactured items that are consistent in colour, etc), then it would be ideal.
The module sells for just $19.95 at Jaycar stores. Used within its design parameters, it works well with great repeatability. If you need finer grain detection or need to differentiate between 50 colours, this probably isn’t the module for your requirements. A photographic sensor would provide better granularity for that type of purpose, but also comes with the programming complexity and additional costs accordingly. If you have a suitable project with clear colour ranges you want to detect, you’ll love this module.
We have provided our upgraded code in the resources for anyone who wants light-adjusting code too. You’ll quickly see how it works and what it achieves.
Testing The Sensor
Getting the basics of this sensor running is fairly straightforward. We connect just the S2 and S3 pins to the UNO, as well as power, and the OUT pin so we can read the results.
On the opposite side of the module you'll notice there are Vcc / GND pins, as well S0/S1, and LED pins which we haven't connected.
Vcc / GND are bridged to their matching pins on the other side of the board, so you can essentially pick a side, or connect both sides for good measure. The S0 and S1 pins are used for internal frequency multipliers to change the PWM frequency to suit different microcontrollers. We didn't find it necessary to connect these at all when testing with an UNO, but we can see their potential value for other microcontrollers.
Lastly the LED pin can be pulled to ground to disable the onboard LEDs. This can be useful, but you'll need a solid external light source to get repeatable results. You'll also have to keep an eye out for shadows from the sensor on the item you're sensing - since you still need to be fairly close for an accurate read.
For all the caveats of the extremely close LEDs (such as inverse square as previously discussed), our testing gave us the most repeatable results using the onboard LEDs.
Load up our "colour_sense_test_adaptive.ino" sketch from the digital resources onto your UNO. Open serial monitor at 9600 baud, and you'll quickly see the Red, Green, Blue values. We pressed our sensor against some blue 3D printing tape, and it's easy to see there's more blue than anything else (our output shown below).
The values in this reading equal 104% which is obviously not possible, but small fluctuations and variations will exist - which is why any code assessing the actual colour must consider.
If we remove our intensity multiplier (shown in the second screenshot and provided as "colour_sense_test.ino") to give the actual readings, you can see there is still a clear blue bias, but we found the readings less distinctive for different colours.
Have a go placing different colours in front of the sensor!