49713 Designing for the Internet of Things
· 18 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Found in Diot 2019: Social Objects - Part 3 and DioT 2019: Social Objects - Part 2
Plantr is an empathetic plant that connects you with your loved ones who’s far away from you. It mirrors your inner state, your emotions and feelings, and communicates them to your loved ones visually. It fosters heart to heart connection.
Plantr is an empathetic plant that mirrors your inner state and communicates them to your loved ones who are far way from you. The idea is to have you brush a leaf which has a continuous touch spectrum embedded within it which simulates the intensity of your feelings. The spectrum of light ranges from dim dark to bright green - dim light indicates that you are feeling down, whereas bright green light indicates that you are feeling happy.
Plantr is an ambient object that subtly blends in with your environment. It does not consume the user's attention when not needed, yet appears when physically engaged. The goal is to use light as a visual language to communicate deeper feelings which are sometimes hard to put into words when your loved one is away.
Plantr challenges precedent projects such as "Expression Flower" (https://www.hackster.io/thingsexperiments/expression-flower-82210b), Disney's "Botanic Interact Us". Plantr differs from these projects in that it's a more intuitive way of interacting with plants - a touch or a caress, instead of blow or a pinch.
The initial idea was to have the user brush the leaves to change the leaves' colors from green to black symbolizing happy to sad. There would also be reinforcing affordances like indicator lights which dim and brighten to green at the base of the planter to further emphasize the user's emotions. The user could also press down the head of the leaf to make them wilt, utilizing a series of servos (see image below). When one user interacts with the first plant, the other person's plant mirrors its actions.
We immediately simplified the idea due to the overall complexity of actions. In terms of motion, the plant's wilting action was removed and the user interaction was adjusted from direct touch on the leaves to a touch capacitor at the base of the planter.
The main form factor also shifted significantly from a minimalist cylindrical vase to a delicate origami flower pot which would dim and brighten to green much like a simple light bulb. The user would simply slide their finger along the base of Plantr from left to right, to achieve dark to bright green. When the user's finger releases the capacitor, it plays a soft chime (first prototyped with a in a piezo). Again, when the first user interacts with the plant, the action is mirrored in the second.
For our first working prototype, we want to create a set of two connected neopixel and piezo devices. If one presses the button, the corresponding LED will light up and buzzer will buzz on both devices.
Below is the code for the model.
#include <neopixel.h> //includes the header file
#include <neopixel.h>
#define PIXEL_PIN A5 //define the input pin for neopixel
#define PIXEL_COUNT 1 //defines the number of pixels
#define PIXEL_TYPE WS2812 //defines the type of pixel used
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); //creates a neopixel object called strip
//input pin for the flex sensor and piezo is defined
//integer flex is defined to store values from the flex sensor
int flexPin = A0;
int flex = 0;
int ledBrightness = 0;
int bright = 0;
int speakerPin = D4;
int melody[] = {1908,2551,2551,2273,2551,0,2024,1908};// defining an array for sound values of the piezo
int noteDurations[] = {4,8,8,4,4,4,4,4 }; //note durations e.g. 4= quarter note, 8=eighth note etc.
long lastPublished=0; //keeps tracks of time of the last published event
int publishAfter=10000; //duration after which another event should be published
void setup()
{
pinMode(flexPin, INPUT);
pinMode(speakerPin, OUTPUT);
strip.begin(); //prepares data pin for output
strip.show(); // initialzes all neopixel to 'OFF'
delay( 100 );
Particle.variable("force", &flex, INT);
Particle.subscribe("plantr/team10/2019/bright/",handleSharedEventBright); //event is created to brighten the neopixels
//handleSharedEventBright is a function to read ths event when it will be published
Particle.subscribe("plantr/team10/2019/dark/",handleSharedEventDark); //event is created to darken the neopixels
}
void loop()
{
flex = analogRead(flexPin); //reads values from the flex sensor and stores in the integer flex
//if the flex sensor is pressed, brighten function is called to make the neopixels bright
if (flex > 500 && bright != 1) {
brighten();
} else if (flex < 300 && bright !=-1) { //when the flex sensor is released, darken function is called to dim the neopixels
darken();
}
}
void darken()
{
uint16_t i, j;
//create an integer j that keeps track of the brightness of the leds
//create an integer i that keeps track of the number of leds in neopixel
for (j = 127; j > 25; j--)
{
for (i = 0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i, 0, 0, j); //sets the colour of each led
// argument i is the number of pixel, 0 is for red colour, second 0 is for green, j is blue colour value
//with every iteration the leds are dimmed
}
strip.show(); //updates the whole neopixel
delay(10);
}
delay(1500);
bright = -1; // after the neopixel is dimmed, an event is published
publishMyEventDark();
}
void brighten()
{ //same as above, only the leds will brighten
uint16_t i, j;
for (j = 127; j < 255; j++)
{
for (i = 0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i, 0, 0, j);
}
strip.show();
}
delay(1500);
bright=1;
publishMyEventBright();//after neopixel is bright, an event is published
}
void publishMyEventDark()
{ //millis function keeps track of the real time clock
if(lastPublished+publishAfter<millis()) //have 10s passed since the last event was published
{
String eventname="plantr/team10/2019/dark/"+System.deviceID(); //add your argon device id to the event
Particle.publish(eventname,"data goes here"); //publish the above event and send an attached message with it
lastPublished=millis(); //last published is changed to now
}
}
void publishMyEventBright()
{ //same as above, only the event here is for the bright function
if(lastPublished+publishAfter<millis())
{
String eventname="plantr/team10/2019/bright/"+System.deviceID();
Particle.publish(eventname,"data goes here");
lastPublished=millis();
}
}
void handleSharedEventBright(const char *event, const char *data) //function to read the published bright event
{
String eventname=String(event); //converts the character event to a string
String deviceID=System.deviceID(); //creates a string to store the device id
if(eventname.indexOf(deviceID)!=-1) //checks if the published event is from another device
//by looking for it's own device id in the event name
{
return;
}
else
{ //since the event is from another device
brighten(); //calls brighten function to make the neopixels bright
playNotes(); //calls this function to play the piezo
}
}
void handleSharedEventDark(const char *event, const char *data)
{ //this is same as above for the dark function
String eventname=String(event);
String deviceID=System.deviceID();
if(eventname.indexOf(deviceID)!=-1)
{
return;
}
else
{
darken();
playNotes();
}
}
void playNotes()
{
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(speakerPin, melody[thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note’s duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(speakerPin);
}
}
Click to Expand
We received a lot of feedback from our class demo, which lead us to reconsider the following design questions:
1) Have we considered time difference of long distance couples? How do we factor that into our design?
2) How might we design Plantr in a way that is intuitive for users to interact with? IoT devices should be intuitive to use with minimal user instructions. It required us to design affordances that are natural and straightforward to everyone.
3) Have we considered the context in which users interact with Plantr? Is it placed near the door for users to quickly interact with when they are going out, or is it on a desk or near a window which would afford a more intimate interaction requiring a user's full attention?
With these questions in mind, we redesigned Plantr:
The final concept is a pair of plants that are placed on the desk or near a window of you and your loved one. Plantr is designed for intimate interactions. We decided to have two leaves on each stem to indicate the intensity of emotion. The LED (green) becomes brighter when the user naturally caresses the plant from the base of the leaf to the tip. If the user reverses the caress on the leaf, the light dims. If the user wishes to express a greater amount of emotion, they can touch another leaf.
Below are top of mind executional considerations:
HUMAN INTERACTIONS:
Time difference: We considered the time difference of long distance couples and decided to leave the light on in a certain time frame. The light returned to neutral position gradually in 24 hours.
Flexibility on the users' end to interact with Plantr: We considered different scenarios when the users on the receiving end see the color changes. What if they want to input colors as well? Does that create confusion? Should we design for a 5 minute delay before the other end can interact with the plant? The final decision was to 'minimize' design and let users decide what they want to do with their preferred method of communication: call the other person immediately, engage with asynchronous sms in a few minutes, whatsapp a "hug" emoji hours later, etc.
PROTOTYPING CONSIDERATIONS:
Time, cost, and ability to reiterate: The decision to utilize a bright white mineral vellum paper could be boiled down down to easy accessibility, ability to explore and iterate very quickly with the final materials, and refine based on our classmates' user feedback. We explored the height of the stem; number, size and texture of the paper leaves (e.g. veined vs flat); different paper stocks with tones of white; as well as color variations (gold, white, black, and a variety of gradients).
TECHNICAL CONSIDERATIONS:
We had to work under the constraints of available components and feasible technology. Our initial prototype was with a Force Resistive Sensor, while we wanted a much more seamless interaction. We tried working with Velostat, to have a natural appeal of a cloth, but were unable to get stable readings and then finally settled upon a 5-Pad Capacitive touch sensor, with their conductive wires attached under the leaves. There were two conductive wires, each on the other half of the leaf to detect a sad or a happy emotion. This capacitive touch sensor was interfaced with Particle, to brighten the plant we used 7- Jewel RGBW neopixel, one attached under every leaf to give it a bright green Colour.
DESIGN INSPIRATIONS:
Organic and material inspirations: The overall form and aesthetic of Plantr was determined by the unexpected juxtaposition of organic form and material choice. The goal was to create a pleasant ambient house object and not a sensor-rigged house plant. The final form was a visually arresting design form which connoted mid-century modern furnishings, luxury, and an arch delicateness. However, those very traits proved to be a barrier to more intimate interactions and prevented people from engaging with Plantr in a more tactile and casual manner. In subsequent iterations, we plan on adjusting the design to create a less intimidating and approachable object by testing different paper colors and materials.
FINDINGS
User feedback: We tested different design iterations and discovered that the users tended to be visually engaged, but very anxious to literally come closer. When prompted to physically touch Plantr, users touched the part painted gold (the stem in the first image). In order to have the color affordance guide the user better, we decided to paint the leaf to gold instead of the stem.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
#define PIXEL_PIN_1 A5 //define input pin number for the first neopixel
#define PIXEL_PIN_2 A3 //define input pin number for the second neopixel
#define PIXEL_COUNT 7//define pixel number
#define PIXEL_TYPE SK6812RGBW //define pixel type
Adafruit_NeoPixel StripOne = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN_1, PIXEL_TYPE); //create an object StripOne for the first neopixel
Adafruit_NeoPixel StripTwo = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN_2, PIXEL_TYPE); //create an object StripTwo for the second neopixel
uint32_t green1colour; //initialze colour green for StripOne
uint32_t green2colour; //initialize colour green for StripTwo
int touchPin0=D2; //initilaze the touchpins for capacitor
int touchPin1=D3;
int touchPin2=D4;
int touchPin3=D5;
long lastPublished=0; //keeps tracks of time of the last published event
int publishAfter=10000; //duration after which another event should be published
void setup()
{
StripOne.begin();//prepares datapin for output
StripOne.show();//initializes all neopixel to 'OFF'
delay( 100 );
StripTwo.begin();
StripTwo.show();
delay(100);
green1colour= StripOne.Color(255,0,0,0); //define colour green for the first neopixel
green2colour= StripTwo.Color(255,0,0,0); //define colour green for the second neopixel
FirstLeafInitialSetup(); //call function for the initial setup of the first leaf
SecondLeafInitialSetup(); //call function for the initial setup of the second leaf
pinMode( touchPin0, INPUT_PULLUP); //set touchpins as input pins in pullup mode
pinMode( touchPin1, INPUT_PULLUP);
pinMode( touchPin2, INPUT_PULLUP);
pinMode( touchPin3, INPUT_PULLUP);
Particle.subscribe("plantr/team10/2019/BrightLeaf1/",handleSharedEventBrightLeaf1); //event is created to brighten the first leaf
//handleSharedEventBrightLeaf1 is a function to read ths event when it will be published
Particle.subscribe("plantr/team10/2019/DarkLeaf1/",handleSharedEventDarkLeaf1); //event is created to darken the first leaf
Particle.subscribe("plantr/team10/2019/BrightLeaf2/",handleSharedEventBrightLeaf2); //event is created to brighten the second leaf
Particle.subscribe("plantr/team10/2019/DarkLeaf2/",handleSharedEventDarkLeaf2); //event is created to darken the second leaf
}
void loop()
{
if( digitalRead( touchPin0 ) == LOW ){ //when the first capacitor on the first leaf detects a touch call the bright function
FirstLeafBright();
publishMyEventBrightLeaf1();
delay( 1000 ) ;
}
else if(digitalRead(touchPin1) == LOW){ //when the second capacitor on the first leaf detects a touch call the dark function
FirstLeafDark();
publishMyEventDarkLeaf1();
delay(1000);
}
else if(digitalRead(touchPin2) == LOW){ //when the first capacitor on the second leaf detects a touch call the bright function
SecondLeafBright();
publishMyEventBrightLeaf2();
delay(1000);
}
else if(digitalRead(touchPin3) == LOW){ //when the second capacitor on the second leaf detects a touch call the dark function
SecondLeafDark();
delay(1000);
}
}
void FirstLeafInitialSetup()
{
StripOne.setBrightness(128); //set initial brightness for the first neopixel
for (int k=0; k< StripOne.numPixels(); k++) //set all the pixels to green colour
{
StripOne.setPixelColor(k,green1colour);
delay(100);
}
StripOne.show();
}
void SecondLeafInitialSetup()
{
StripTwo.setBrightness(128); //set initial brightness for the second neopixel
for (int k=0; k< StripTwo.numPixels(); k++) //set all the pixels to green colour
{
StripTwo.setPixelColor(k,green2colour);
delay(100);
}
StripTwo.show();
}
void FirstLeafBright()
{ //create an integer j that keeps track of the brightness of the leds
//create an integer i that keeps track of the number of leds in neopixel
for (int j=128; j<256; j++)
{
for (int i=0; i< StripOne.numPixels() ; i++)
{
StripOne.setBrightness(j); //increases the brightness of leds with every iteration
StripOne.setPixelColor(i, green1colour); //sets the colour of the leds to green
delay(100);
}
StripOne.show(); //updates the whole neopixel
delay(100);
}
}
void SecondLeafBright()
{ //same as above, for the second leaf
for (int j=128; j<256; j++)
{
for (int i=0; i< StripTwo.numPixels() ; i++)
{
StripTwo.setBrightness(j); //increases the brightness of leds with every iteration
StripTwo.setPixelColor(i, green2colour); //sets the colour of the leds to green
delay(100);
}
StripTwo.show(); //updates the whole neopixel
delay(100);
}
}
void FirstLeafDark()
{ //same as above, only the leds will dim
for (int j=128; j>0; j--)
{
for (int i=0; i< StripOne.numPixels() ; i++)
{
StripOne.setBrightness(j);
StripOne.setPixelColor(i, green1colour);
delay(100);
}
StripOne.show();
delay(100);
}
}
void SecondLeafDark()
{
//same as above, only the leds will dim
for (int j=128; j>0; j--)
{
for (int i=0; i< StripTwo.numPixels() ; i++)
{
StripTwo.setBrightness(j);
StripTwo.setPixelColor(i, green2colour);
delay(100);
}
StripTwo.show();
delay(100);
}
}
void publishMyEventBrightLeaf1()
{ //millis function keeps track of the real time clock
if(lastPublished+publishAfter<millis()) //have 10s passed since the last event was published
{
String eventname="plantr/team10/2019/BrightLeaf1/"+System.deviceID(); //add your argon device id to the event
Particle.publish(eventname,"data goes here"); //publish the above event and send an attached message with it
lastPublished=millis(); //last published is changed to now
}
}
void handleSharedEventBrightLeaf1(const char *event, const char *data) //function to read the published bright event
{
String eventname=String(event); //converts the character event to a string
String deviceID=System.deviceID(); //creates a string to store the device id
if(eventname.indexOf(deviceID)!=-1) //checks if the published event is from another device
//by looking for it's own device id in the event name
{
return;
}
else
{ //since the event is from another device
FirstLeafBright(); //calls the function to make the first leaf bright
}
}
void publishMyEventDarkLeaf1()
{ //same as above, only this is for the dark function of the first leaf
if(lastPublished+publishAfter<millis())
{
String eventname="plantr/team10/2019/DarkLeaf1/"+System.deviceID();
Particle.publish(eventname,"data goes here");
lastPublished=millis();
}
}
void handleSharedEventDarkLeaf1(const char *event, const char *data) //function to read the published dark event
{
String eventname=String(event); //converts the character event to a string
String deviceID=System.deviceID(); //creates a string to store the device id
if(eventname.indexOf(deviceID)!=-1) //checks if the published event is from another device
//by looking for it's own device id in the event name
{
return;
}
else
{ //since the event is from another device
FirstLeafDark(); //calls the function to make the first leaf dark
}
}
void publishMyEventBrightLeaf2()
{ //millis function keeps track of the real time clock
if(lastPublished+publishAfter<millis()) //have 10s passed since the last event was published
{
String eventname="plantr/team10/2019/BrightLeaf2/"+System.deviceID(); //add your argon device id to the event
Particle.publish(eventname,"data goes here"); //publish the above event and send an attached message with it
lastPublished=millis(); //last published is changed to now
}
}
void handleSharedEventBrightLeaf2(const char *event, const char *data) //function to read the published bright event
{
String eventname=String(event); //converts the character event to a string
String deviceID=System.deviceID(); //creates a string to store the device id
if(eventname.indexOf(deviceID)!=-1) //checks if the published event is from another device
//by looking for it's own device id in the event name
{
return;
}
else
{ //since the event is from another device
SecondLeafBright(); //calls the function to make the first leaf bright
}
}
void publishMyEventDarkLeaf2()
{ //same as above, only this is for the dark function of the second leaf
if(lastPublished+publishAfter<millis())
{
String eventname="plantr/team10/2019/DarkLeaf2/"+System.deviceID();
Particle.publish(eventname,"data goes here");
lastPublished=millis();
}
}
void handleSharedEventDarkLeaf2(const char *event, const char *data) //function to read the published dark event
{
String eventname=String(event); //converts the character event to a string
String deviceID=System.deviceID(); //creates a string to store the device id
if(eventname.indexOf(deviceID)!=-1) //checks if the published event is from another device
//by looking for it's own device id in the event name
{
return;
}
else
{ //since the event is from another device
SecondLeafDark(); //calls the function to make the second leaf dark
}
}
Click to Expand
Label | Part Type | Properties |
---|---|---|
Part1 | Particle Argon | variant variant 1s; part # Adafruit #3405 |
Part2 | NeoPixel Jewel | variant variant 1; part # 2226 |
Part3 | NeoPixel Jewel | variant variant 1; part # 2226 |
Part4 | Adafruit Standalone 5-Pad Capacitive Touch Sensor Breakout - AT42QT1070 | variant variant 2; part # Adafruit #1362 |
Amount | Part Type | Properties |
---|---|---|
1 | Particle Argon | variant variant 1s; part # Adafruit #3405 |
2 | NeoPixel Jewel | variant variant 1; part # 2226 |
1 | Adafruit Standalone 5-Pad Capacitive Touch Sensor Breakout - AT42QT1070 | variant variant 2; part # Adafruit #1362 |
Plantr Demo from Chi-Chi Bello on Vimeo.
In the final demonstration of the project we received various positive and negative feedback.
People who interacted with our prototype and guests liked the simplicity of our product, the interaction was minimalist. They liked our design inspirations and the aesthetics, it made them want to interact with our plant.
We got comments to work on the narrative and emotional aspect of the plant, to reconsider the gestures of interaction and to think about how do we interact with normal plants and incorporate them in our interaction design.
The further steps to improve this product would be :
1. Consider other technologies that could provide a much more seamless touch, like a capacitive spray paint
2. Think more in depth about the time difference and mood changes within those time frame, how will people respond to the emotions when the person on the other slide has gone to sleep.
3. Consider the natural interactions with plant such as ignoring it when you're sad rather than brushing it in a downwards direction, and how can these considerations be incorporated in our project
4. Refine the storyboard to reconsider the emotional significance this plant will have on it's users.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Plantr is an empathetic plant that connects you with your loved ones who’s far away from you. It mirrors your inner state, your emotions and feelings, and communicates them to your loved ones visually. It fosters heart to heart connection.
February 11th, 2019