By Terrene Huang and
Brys Fleming-Henning
Problem Space & Process:
We wanted to focus on providing something for gardeners in their home backyards. Though we started out unsure of what to sense on plants, we slowly shifted towards the decision of reading plant colors with the intent to detect when a plant had yellowing leaves. From there, we decided we wanted to read a broader range of colors and expanded into being able to read fruit ripeness from color. We wanted the user to be able to know information from afar, and so we chose to mount the sensor in a way where it could be moved by motors and a joystick around a plant. The lights were then a fun way for a user to understand the information from the sensor.
Testing color and RGB strip code
Testing Hoberman sphere arm
Laser cut cardboard prototype
Final Product & Components:
Structure
- Laser cut birch
- Laser cut acrylic
- Assorted fasteners
- Blue clay plant pot
- Arduino
- Ornamental Red Pepper plant
Input
- Joystick
- RGB Color Sensor
Processing
- Arduino Eno
- Breadboard
Output
- Continuous servo motor
- Servo motor
- NeoPixel LED strip
Power
- AA Battery pack for Neo Pixel strip
- Mini Lithium battery back for Arduino
Willo
Willo is a lamp that displays a small light show of the most prominent color read off a plant part. Willo adds a fun spectacle to the home backyard and allows for reading the ripeness of a fruit through color.
Willo consists of a laser cut wooden frame that sits against a plant pot, with the sensor hanging over the plant. The sensor can be controlled with a small joystick that allows it to circle and drop down into the plant to read its color when the joystick is pressed. Once read, the sensor detects colors in RGB and outputs the most prominent color onto a NeoPixel LED strip.
Moving the sensor is done through one continuous servo motor and one servo motor. One direction of the joystick is programmed to rotate the servo motor's arm 180 degrees then back, while the other direction rotates the continuous servo motor where indicated. Pressing the button on the joystick runs the code for the RGB sensor. Since the sensor reads wave frequencies, the values must be mapped to RGB hues instead. From there, the code detects the most prominent of color from red, green, blue, purple, and yellow. The NeoPixel strip then flashes white, before doing a light show of the detected shade of the most prominent color.
The frame design of Willo contours slightly to the specific pot's curvature using laser cut living hinges. Slots in the frame allow for the continuous servo motor to sit on top and be moved to different heights depending on plant height.
The base of the frame wraps around the bottom of the pot and utilizes the weight of the pot to hold the stand upright.
The arm holding the sensor emulates a branch of a Hoberman sphere in order to extend into the plant in a similarly curved manner.
Code:
// import libraries for servo motor and neopixel#include <Servo.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
// define pins for NeoPixel strip
#define PIXEL_PIN 12
#define PIXEL_COUNT 30
// color sensor pins wiring to Arduino
#define S0 6
#define S1 7
#define S2 8
#define S3 9
#define sensorOut 10
// create servo object
Servo servoY;
Servo servoX;
// set up NeoPixel strip mode
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// set joystick in y direction, servo motor pin, and joystick y value
int joyYPin = A0;
int servoYPin = 13;
int joyY = 0;
// set joystick in x direction, servo motor pin, and joystick x value
int joyXPin = A1;
int servoXPin = 11;
int joyX = 0;
// stores frequency read by photodiodes of color sensor
int redFrequency = 0;
int greenFrequency = 0;
int blueFrequency = 0;
// stores red, green, and blue colors
int redColor = 0;
int greenColor = 0;
int blueColor = 0;
// set button pin and state
int buttonPin = 2;
int buttonState = 0;
void setup() {
Serial.begin(9600);
// attaches servo motor objects to respective pins
servoX.attach(servoXPin);
servoY.attach(servoYPin);
// sets up NeoPixel strip, initializes strip object, initializes pixels to off
strip.begin();
// sets pins for ouput for color sensor and joystick
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
digitalWrite(S0, HIGH);
digitalWrite(S1, LOW);
// pin mode set for button switch
pinMode(buttonPin, INPUT_PULLUP);
for (int i = 2; i <= 5; i++){
pinMode(i, INPUT_PULLUP);
}
}
void loop() {
// moves servo motor in/out (x direction)
joyX = analogRead(joyXPin);
if (joyX > 0 && joyX < 511.5) {
joyX = map(joyX, 0, 511.5, 0, 180);
}
if (joyX > 511.5 && joyX < 1023) {
joyX = map(joyX, 511.5, 1023, 180, 0);
}
servoX.write(joyX);
delay(15);
// moves servo motor in/out (y direction)
joyY = analogRead(joyYPin);
joyY = map(joyY, 0, 1023, 0, 180);
servoY.write(joyY);
delay(15);
// checks state of joystick button
buttonState = digitalRead(buttonPin);
// reads fruit color if button is pressed
if (buttonState == LOW) {
// clears NeoPixel strip when button is pressed
strip.clear();
strip.show();
// read red
digitalWrite(S2, LOW);
digitalWrite(S3, LOW);
redFrequency = pulseIn(sensorOut, LOW);
// map red frequency from 0-255 with lowest and highest number from frequency reads
redColor = map(redFrequency, 20, 142, 255, 0);
// Serial.print("R: ");
// Serial.print(redFrequency);
// Serial.print(redColor);
delay(100);
// read green
digitalWrite(S2, HIGH);
digitalWrite(S3, HIGH);
greenFrequency = pulseIn(sensorOut, LOW);
greenColor = map(greenFrequency, 35, 208, 255, 0);
// Serial.print(" | G: ");
// Serial.print(greenFrequency);
// Serial.print(greenColor);
delay(100);
// read blue
digitalWrite(S2, LOW);
digitalWrite(S3, HIGH);
blueFrequency = pulseIn(sensorOut, LOW);
blueColor = map(blueFrequency, 23, 183, 255, 0);
// Serial.print(" | B: ");
// Serial.println(blueFrequency);
// Serial.print(blueColor);
delay(100);
Serial.print(redColor);
Serial.print(" , ");
Serial.print(greenColor);
Serial.print(" , ");
Serial.println(blueColor);
// changes NeoPixel strip color to shade of most prominent color detected
// change to red
if(redColor > greenColor && redColor > blueColor && abs(redColor - blueColor > 50)){
for(int i = 0; i<PIXEL_COUNT; i++){
redColor = redColor - 30;
colorWipe(strip.Color(127, 127, 127), 30);
theaterChase(strip.Color(redColor, 0, 0), 70);
break;
}
}
// change to green
else if (greenColor > redColor && greenColor > blueColor && greenColor - redColor > 30){
for(int i = 0; i<PIXEL_COUNT; i++){
greenColor = greenColor - 50;
colorWipe(strip.Color(127, 127, 127), 30);
theaterChase(strip.Color(0, greenColor, 0), 70);
break;
}
}
// change to blue
else if (blueColor > redColor && blueColor > greenColor && abs(redColor - blueColor) > 50 ){
for(int i = 0; i<PIXEL_COUNT; i++){
blueColor = blueColor - 50;
colorWipe(strip.Color(127, 127, 127), 30);
theaterChase(strip.Color(0, 0, blueColor), 70);
break;
}
}
// change to purple
else if (abs(redColor - blueColor) < 50 && redColor > greenColor && blueColor > greenColor) {
for(int i = 0; i<PIXEL_COUNT; i++){
redColor = redColor - 20;
blueColor = blueColor - 20;
colorWipe(strip.Color(127, 127, 127), 30);
theaterChase(strip.Color(redColor, 0, blueColor), 70);
break;
}
}
// change to yellow
else if (greenColor - redColor < 30 && greenColor - redColor > 0 && greenColor > redColor && greenColor > blueColor) {
for(int i = 0; i<PIXEL_COUNT; i++){
redColor = redColor - 20;
greenColor = greenColor - 20;
colorWipe(strip.Color(127, 127, 127), 30);
theaterChase(strip.Color(redColor, greenColor, 0), 70);
break;
}
}
// otherwise no color
else {
strip.Color(0, 0, 0);
strip.show();
}
}
}
// sets whole strip to single color
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// flashes color across strip
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
No comments:
Post a Comment