Source
Escape_Game_Final_ColorSensor.ino
// INCLUDES
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SPI.h> // Generic SPI interface, which is used to access the card reader
//Defines
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define CALIBRATE
// CONSTANTS
const byte chipSelectPin = 8;
// Define the Arduino pins to which the sensor is attached
// S0 and S1 control the output frequency scaling
const byte S0 = 5;
const byte S1 = 4;
// S2 and S3 control the selection of the photodiode filters
const byte S2 = 7;
const byte S3 = 6;
// Output from the sensor is a square wave with 50% duty cycle
const byte sensorOut = 8;
// Calibration values - these need to be obtained by running the sketch in the environment and ambient lighting in
// which it is to be used, and holding up white and black sample swatches - then copying down the values displayed
// in the serial monitor window to here:
const int32_t blackReading[3] = {0, 0, 0};//2272,2486,21, 1948,2756,24
const int32_t whiteReading[3] = {255, 255, 255}; //281,291,269 //355,372,342
// GLOBALS
// The raw sensor readings (the wave frequency) obtained from selecting the red, green, and blue filtered diodes
unsigned long currentReading[3] = {0, 0, 0};
// The RGB colour value calculated from that sensor reading expressed as a 3-byte array
byte colour[3] = {};
//variables for sine wave
bool puzzleState;
char* displayValue;
//UDF
void showDisplay(){
Serial.println("display");
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 10);
display.print("Artifact");
display.setCursor(0,30);
display.print("ID:");
display.setCursor(50,30);
display.print(displayValue);
display.display();
delay(2000);
}
void setup() {
// Initialise serial monitor to be able to read output values
Serial.begin(9600);
// Initialise the pins
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
// The S0 and S1 signals are used to select the output frequency scaling
// From the datasheet, LL=Power down, LH=2%, HL=20%, HH=100%
// Scaling the frequency will make the pulses longer, which might lead to more accurate reading, but will also slow down the code
digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);
// Initialise the display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print("Initializing...");
display.display();
delay(2000);
display.clearDisplay();
displayValue = 0;
}
void loop() {
// Setting S2 Low, S3 Low applies RED filtered photodiodes
digitalWrite(S2, LOW);
digitalWrite(S3, LOW);
// Read the output frequency
currentReading[0] = pulseIn(sensorOut, digitalRead(sensorOut) == HIGH ? LOW : HIGH);
// Setting S2 High, S3 High applies GREEN filtered photodiodes
digitalWrite(S2, HIGH);
digitalWrite(S3, HIGH);
// Reading the output frequency
currentReading[1] = pulseIn(sensorOut, digitalRead(sensorOut) == HIGH ? LOW : HIGH);
// Setting S2 LOW, S3 HIGH applied BLUE filtered photodiodes
digitalWrite(S2, LOW);
digitalWrite(S3, HIGH);
// Reading the output frequency
currentReading[2] = pulseIn(sensorOut, digitalRead(sensorOut) == HIGH ? LOW : HIGH);
#ifdef CALIBRATE
char rawOutput[32];
snprintf(rawOutput, 32, "Raw sensor values: %lu,%lu,%lu" , currentReading[0], currentReading[1], currentReading[2]);
Serial.println(rawOutput);
#endif
// Loop over each of the three measurements taken this frame
for (int i=0; i<3; i++) {
// Use map() function to rescale values to the range of readings taken for white/black extremes
int x = map(currentReading[i], blackReading[i], whiteReading[i], 0, 255);
// Copy result back into the corresponding component of the RGB "colour" variable
colour[i] = (byte)constrain(x, 0, 255);
}
// Send the RGB values to the serial monitor
char output[32];
snprintf(output, 32, "(%i,%i,%i)" , colour[0], colour[1], colour[2]);
Serial.println(output);
// The following code demonstrates how to perform some action if the colour detected
// is similar enough to a specified target colour. First, specify the RGB values of the target
int targetColourAR = 50, targetColourAG = 60, targetColourAB = 90; //(255,236,245) red (255,205,220)
int targetColourBR = 115, targetColourBG = 120, targetColourBB = 90; //(232,238,251) blue (210,212,232)
int targetColourCR = 90, targetColourCG = 90, targetColourCB = 100; //(248,255,238) green (232,240,213)
// The threshold value determines how similar the colours have to be to match - higher values = less sensitive
int threshold = 50;
// Call the getColourDistance function to determine the distance between the colours, and compare to the threshold
if(getColourDistance((int)colour[0], (int)colour[1], (int)colour[2], targetColourAR, targetColourAG, targetColourAB) < threshold) {
Serial.println(F("The sensor has detected the target colour!"));
displayValue = "17";
} else if (getColourDistance((int)colour[0], (int)colour[1], (int)colour[2], targetColourBR, targetColourBG, targetColourBB) < threshold) {
Serial.println(F("The sensor has detected the target colour!"));
displayValue = "34";
} else if (getColourDistance((int)colour[0], (int)colour[1], (int)colour[2], targetColourCR, targetColourCG, targetColourCB) < threshold) {
Serial.println(F("The sensor has detected the target colour!"));
displayValue = "86";
} else {
displayValue = ("...");
}
// Set the LEDs to match the colour detected
showDisplay();
}
// Test the similarity between two colours by calculating the Euclidean distance between their RGB values
// See https://en.wikipedia.org/wiki/Color_difference
int getColourDistance(int r1, int g1, int b1, int r2, int g2, int b2) {
//return (pow(r1-r2, 2) + pow(g1-g2, 2) + pow(b1-b2, 2));
return (abs(r1-r2) + abs(g1-g2) + abs(b1-b2));
}