_measure something: add a sensor to a microcontroller board that you’ve designed and read it
For this activity, I will try to design a sensor for my final project, the bacteria artefact.
The first step we made in our laboratory, we seek the largest possible number of sensors, in the picture below I share the sensors we have now:
1- Height Sensor/Pressure – MPL3115A2
2 – Accelerometer, three Axis – MMA8452Q
3 – Humidity Sensor HTU21D
4 – IR Receiver
5 – Magnetometer, three Axis – HMC5883L
6 – Gyroscope with digital outputs, three axes ITG-3200
7 – Ultrasonic Rangefinder – Maxbotix LV-EZ1
8 – PIR Motion Sensor
9 – Large Piezo Vibration Sensor
10, Reed Switch
11- Imam Square 0.25 ”
12 – Resistance Force-sensitive 0.5 ”
13 – SoftPot
14 – Cell Fotoeléctricia
15 – Optical Detector / Phototransistor
16 – Flexible Sensor
17 – Sound Sensor
18 – Color Sensor
As a starting point I will use the color sensor TCS34725, shared by Adafruit:
https://github.com/adafruit/Adafruit_TCS34725
To test the operation of the sensor, I used an Arduino Mega and the original sensor Adafruit, here we see sensor operating:
Here is the example code to control the sensor from the Arduino:
#include #include "Adafruit_TCS34725.h" #define redpin 3 #define greenpin 5 #define bluepin 6 #define commonAnode true byte gammatable[256]; Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X); void setup() { Serial.begin(9600); Serial.println("Color View Test!"); if (tcs.begin()) { Serial.println("Found sensor"); } else { Serial.println("No TCS34725 found ... check your connections"); while (1); // halt! } pinMode(redpin, OUTPUT); pinMode(greenpin, OUTPUT); pinMode(bluepin, OUTPUT); for (int i=0; i<256; i++) { float x = i; x /= 255; x = pow(x, 2.5); x *= 255; if (commonAnode) { gammatable[i] = 255 - x; } else { gammatable[i] = x; } } } void loop() { uint16_t clear, red, green, blue; tcs.setInterrupt(false); delay(60); tcs.getRawData(&red, &green, &blue, &clear); tcs.setInterrupt(true); Serial.print("C:\t"); Serial.print(clear); Serial.print("\tR:\t"); Serial.print(red); Serial.print("\tG:\t"); Serial.print(green); Serial.print("\tB:\t"); Serial.print(blue); uint32_t sum = clear; float r, g, b; r = red; r /= sum; g = green; g /= sum; b = blue; b /= sum; r *= 256; g *= 256; b *= 256; Serial.print("\t"); Serial.print((int)r, HEX); Serial.print((int)g, HEX); Serial.print((int)b, HEX); Serial.println(); analogWrite(redpin, gammatable[(int)r]); analogWrite(greenpin, gammatable[(int)g]); analogWrite(bluepin, gammatable[(int)b]); }
and here the code for viewing from Processing:
import processing.serial.*; import java.awt.datatransfer.*; import java.awt.Toolkit; Serial port; void setup(){ size(200,200); port = new Serial(this, "/dev/cu.usbmodem1411", 9600); } String buff = ""; int wRed, wGreen, wBlue, wClear; String hexColor = "ffffff"; void draw(){ background(wRed,wGreen,wBlue); while (port.available() > 0) { serialEvent(port.read()); } } void serialEvent(int serial) { if(serial != '\n') { buff += char(serial); } else { int cRed = buff.indexOf("R"); int cGreen = buff.indexOf("G"); int cBlue = buff.indexOf("B"); int clear = buff.indexOf("C"); if(clear >=0){ String val = buff.substring(clear+3); val = val.split("\t")[0]; wClear = Integer.parseInt(val.trim()); } else { return; } if(cRed >=0){ String val = buff.substring(cRed+3); val = val.split("\t")[0]; wRed = Integer.parseInt(val.trim()); } else { return; } if(cGreen >=0) { String val = buff.substring(cGreen+3); val = val.split("\t")[0]; wGreen = Integer.parseInt(val.trim()); } else { return; } if(cBlue >=0) { String val = buff.substring(cBlue+3); val = val.split("\t")[0]; wBlue = Integer.parseInt(val.trim()); } else { return; } print("Red: "); print(wRed); print("\tGrn: "); print(wGreen); print("\tBlue: "); print(wBlue); print("\tClr: "); println(wClear); wRed *= 255; wRed /= wClear; wGreen *= 255; wGreen /= wClear; wBlue *= 255; wBlue /= wClear; hexColor = hex(color(wRed, wGreen, wBlue), 6); println(hexColor); buff = ""; } }
You need to have a little careful with external light, but the sensor works perfectly.
The plate was Designed by Adafruit Industries. licensed Creative Commons Attribution, Here we can download the libraries:
https://github.com/adafruit/Adafruit-Eagle-Library
And here we see TCS34725 files in Eagle:
After this, generates a library model for bacteria, and I designed the sensor for the bacteria recognizer.
in process….
Now I’m waiting for the components, the plan is to make a FabKit (http://fabacademy.org/archives/2015/doc/fabkit-0.4.html) to control color sensors. At the moment I am advancing on python code for TCS34725:
https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/master/Adafruit_TCS34725
+#!/usr/bin/python + +import time +from Adafruit_I2C import Adafruit_I2C + +# =========================================================================== +# TCS3472 Class +# =========================================================================== + + +class TCS34725: + i2c = None + + __TCS34725_ADDRESS = 0x29 + __TCS34725_ID = 0x12 # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 + + __TCS34725_COMMAND_BIT = 0x80 + + __TCS34725_ENABLE = 0x00 + __TCS34725_ENABLE_AIEN = 0x10 # RGBC Interrupt Enable + __TCS34725_ENABLE_WEN = 0x08 # Wait enable - Writing 1 activates the wait timer + __TCS34725_ENABLE_AEN = 0x02 # RGBC Enable - Writing 1 actives the ADC, 0 disables it + __TCS34725_ENABLE_PON = 0x01 # Power on - Writing 1 activates the internal oscillator, 0 disables it + __TCS34725_ATIME = 0x01 # Integration time + __TCS34725_WTIME = 0x03 # Wait time (if TCS34725_ENABLE_WEN is asserted) + __TCS34725_WTIME_2_4MS = 0xFF # WLONG0 = 2.4ms WLONG1 = 0.029s + __TCS34725_WTIME_204MS = 0xAB # WLONG0 = 204ms WLONG1 = 2.45s + __TCS34725_WTIME_614MS = 0x00 # WLONG0 = 614ms WLONG1 = 7.4s + __TCS34725_AILTL = 0x04 # Clear channel lower interrupt threshold + __TCS34725_AILTH = 0x05 + __TCS34725_AIHTL = 0x06 # Clear channel upper interrupt threshold + __TCS34725_AIHTH = 0x07 + __TCS34725_PERS = 0x0C # Persistence register - basic SW filtering mechanism for interrupts + __TCS34725_PERS_NONE = 0b0000 # Every RGBC cycle generates an interrupt + __TCS34725_PERS_1_CYCLE = 0b0001 # 1 clean channel value outside threshold range generates an interrupt + __TCS34725_PERS_2_CYCLE = 0b0010 # 2 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_3_CYCLE = 0b0011 # 3 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_5_CYCLE = 0b0100 # 5 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_10_CYCLE = 0b0101 # 10 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_15_CYCLE = 0b0110 # 15 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_20_CYCLE = 0b0111 # 20 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_25_CYCLE = 0b1000 # 25 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_30_CYCLE = 0b1001 # 30 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_35_CYCLE = 0b1010 # 35 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_40_CYCLE = 0b1011 # 40 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_45_CYCLE = 0b1100 # 45 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_50_CYCLE = 0b1101 # 50 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_55_CYCLE = 0b1110 # 55 clean channel values outside threshold range generates an interrupt + __TCS34725_PERS_60_CYCLE = 0b1111 # 60 clean channel values outside threshold range generates an interrupt + __TCS34725_CONFIG = 0x0D + __TCS34725_CONFIG_WLONG = 0x02 # Choose between short and long (12x) wait times via TCS34725_WTIME + __TCS34725_CONTROL = 0x0F # Set the gain level for the sensor + __TCS34725_ID = 0x12 # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 + __TCS34725_STATUS = 0x13 + __TCS34725_STATUS_AINT = 0x10 # RGBC Clean channel interrupt + __TCS34725_STATUS_AVALID = 0x01 # Indicates that the RGBC channels have completed an integration cycle + + __TCS34725_CDATAL = 0x14 # Clear channel data + __TCS34725_CDATAH = 0x15 + __TCS34725_RDATAL = 0x16 # Red channel data + __TCS34725_RDATAH = 0x17 + __TCS34725_GDATAL = 0x18 # Green channel data + __TCS34725_GDATAH = 0x19 + __TCS34725_BDATAL = 0x1A # Blue channel data + __TCS34725_BDATAH = 0x1B + + __TCS34725_INTEGRATIONTIME_2_4MS = 0xFF # 2.4ms - 1 cycle - Max Count: 1024 + __TCS34725_INTEGRATIONTIME_24MS = 0xF6 # 24ms - 10 cycles - Max Count: 10240 + __TCS34725_INTEGRATIONTIME_50MS = 0xEB # 50ms - 20 cycles - Max Count: 20480 + __TCS34725_INTEGRATIONTIME_101MS = 0xD5 # 101ms - 42 cycles - Max Count: 43008 + __TCS34725_INTEGRATIONTIME_154MS = 0xC0 # 154ms - 64 cycles - Max Count: 65535 + __TCS34725_INTEGRATIONTIME_700MS = 0x00 # 700ms - 256 cycles - Max Count: 65535 + + __TCS34725_GAIN_1X = 0x00 # No gain + __TCS34725_GAIN_4X = 0x01 # 2x gain + __TCS34725_GAIN_16X = 0x02 # 16x gain + __TCS34725_GAIN_60X = 0x03 # 60x gain + + __integrationTimeDelay = { + 0xFF: 0.0024, # 2.4ms - 1 cycle - Max Count: 1024 + 0xF6: 0.024, # 24ms - 10 cycles - Max Count: 10240 + 0xEB: 0.050, # 50ms - 20 cycles - Max Count: 20480 + 0xD5: 0.101, # 101ms - 42 cycles - Max Count: 43008 + 0xC0: 0.154, # 154ms - 64 cycles - Max Count: 65535 + 0x00: 0.700 # 700ms - 256 cycles - Max Count: 65535 + } + + # Private Methods + def __readU8(self, reg): + return self.i2c.readU8(self.__TCS34725_COMMAND_BIT | reg) + + def __readU16Rev(self, reg): + return self.i2c.readU16Rev(self.__TCS34725_COMMAND_BIT | reg) + + def __write8(self, reg, value): + self.i2c.write8(self.__TCS34725_COMMAND_BIT | reg, value & 0xff) + + # Constructor + def __init__(self, address=0x29, debug=False, integrationTime=0xFF, gain=0x01): + self.i2c = Adafruit_I2C(address) + + self.address = address + self.debug = debug + self.integrationTime = integrationTime + self.initialize(integrationTime, gain) + + def initialize(self, integrationTime, gain): + "Initializes I2C and configures the sensor (call this function before \ + doing anything else)" + # Make sure we're actually connected + result = self.__readU8(self.__TCS34725_ID) + if (result != 0x44): + return -1 + + # Set default integration time and gain + self.setIntegrationTime(integrationTime) + self.setGain(gain) + + # Note: by default, the device is in power down mode on bootup + self.enable() + + def enable(self): + self.__write8(self.__TCS34725_ENABLE, self.__TCS34725_ENABLE_PON) + time.sleep(0.01) + self.__write8(self.__TCS34725_ENABLE, (self.__TCS34725_ENABLE_PON | self.__TCS34725_ENABLE_AEN)) + + def disable(self): + reg = 0 + reg = self.__readU8(self.__TCS34725_ENABLE) + self.__write8(self.__TCS34725_ENABLE, (reg & ~(self.__TCS34725_ENABLE_PON | self.__TCS34725_ENABLE_AEN))) + + def setIntegrationTime(self, integrationTime): + "Sets the integration time for the TC34725" + self.integrationTime = integrationTime + + self.__write8(self.__TCS34725_ATIME, integrationTime) + + def getIntegrationTime(self): + return self.__readU8(self.__TCS34725_ATIME) + + def setGain(self, gain): + "Adjusts the gain on the TCS34725 (adjusts the sensitivity to light)" + self.__write8(self.__TCS34725_CONTROL, gain) + + def getGain(self): + return self.__readU8(self.__TCS34725_CONTROL) + + def getRawData(self): + "Reads the raw red, green, blue and clear channel values" + + color = {} + + color["r"] = self.__readU16Rev(self.__TCS34725_RDATAL) + color["b"] = self.__readU16Rev(self.__TCS34725_BDATAL) + color["g"] = self.__readU16Rev(self.__TCS34725_GDATAL) + color["c"] = self.__readU16Rev(self.__TCS34725_CDATAL) + + # Set a delay for the integration time + delay = self.__integrationTimeDelay.get(self.integrationTime) + time.sleep(delay) + + return color + + def setInterrupt(self, int): + r = self.__readU8(self.__TCS34725_ENABLE) + + if (int): + r |= self.__TCS34725_ENABLE_AIEN + else: + r &= ~self.__TCS34725_ENABLE_AIEN + + self.__write8(self.__TCS34725_ENABLE, r) + + def clearInterrupt(self): + self.i2c.write8(0x66 & 0xff) + + def setIntLimits(self, low, high): + self.i2c.write8(0x04, low & 0xFF) + self.i2c.write8(0x05, low >> 8) + self.i2c.write8(0x06, high & 0xFF) + self.i2c.write8(0x07, high >> 8) + + #Static Utility Methods + @staticmethod + def calculateColorTemperature(rgb): + "Converts the raw R/G/B values to color temperature in degrees Kelvin" + + if not isinstance(rgb, dict): + raise ValueError('calculateColorTemperature expects dict as parameter') + + # 1. Map RGB values to their XYZ counterparts. + # Based on 6500K fluorescent, 3000K fluorescent + # and 60W incandescent values for a wide range. + # Note: Y = Illuminance or lux + X = (-0.14282 * rgb['r']) + (1.54924 * rgb['g']) + (-0.95641 * rgb['b']) + Y = (-0.32466 * rgb['r']) + (1.57837 * rgb['g']) + (-0.73191 * rgb['b']) + Z = (-0.68202 * rgb['r']) + (0.77073 * rgb['g']) + ( 0.56332 * rgb['b']) + + # 2. Calculate the chromaticity co-ordinates + xc = (X) / (X + Y + Z) + yc = (Y) / (X + Y + Z) + + # 3. Use McCamy's formula to determine the CCT + n = (xc - 0.3320) / (0.1858 - yc) + + # Calculate the final CCT + cct = (449.0 * (n ** 3.0)) + (3525.0 *(n ** 2.0)) + (6823.3 * n) + 5520.33 + + return int(cct) + + @staticmethod + def calculateLux(rgb): + "Converts the raw R/G/B values to color temperature in degrees Kelvin" + + if not isinstance(rgb, dict): + raise ValueError('calculateLux expects dict as parameter') + + illuminance = (-0.32466 * rgb['r']) + (1.57837 * rgb['g']) + (-0.73191 * rgb['b']) + + return int(illuminance)
Primary source: http://academy.cba.mit.edu/classes/input_devices/index.html
Contact: fernando.meneses@udem.edu / fernandomeneses@nodolab.com / f / in / g+ / w / v / mx