49713 Designing for the Internet of Things
· 16 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
A plant that reminds owners of its existence through one primary functionality: active listening. This IoT device is a plant that rotates to watch the current speaker. This gives the speaker a sense of impact, reminds them of the plants existence, and also subtly reminds users that their data is being logged. It's an impactful but subtle way to approach disclosure and transparency - all while helping to keep this cute little guy alive!
My approach to this project has gone through many changes to reflect the various challenges that have come up.
The original idea was to have 'ears' on the plant, and then rotate left and right until the left and right ears inputs were somewhat balanced. However, this proved difficult for several reasons. Firstly, I quickly found out that sound travels in waves, and therefore a single measurement might snag the top or bottom of the wave. To solve this, I took multiple samples (15), each ten milliseconds apart. I then averaged those measurements to try and level out the rough volume of each sensor.
Another problem came up with the sensors themselves. They were too low of quality to pick up any sensitive-enough data disparity that I could use to find the sound proximity. Plus, we didn't have 2 of any kind of sensor at the Studio. So I ordered 2 sound sensors from Amazon, and luckily that worked out. I used the Sparkfun mic sensors, specifically the Envelope port.
Then came another problem. Getting the mics to pick up sound of any sort was tremendously difficult. First it was improper soldering. Then it was a Particle login/update problem (solved by going into Safe Mode, by the way). Then it was a calibration issue to get the two sensors on the same level field. After that, it was an issue with directionability, solved by creating "cones" that direct the mic in certain angles.
Once I figured all those issues out, which took the bulk of the project to be honest, I constructed the first iteration of the creation. This didn't go as planned either. I learned that the sensors were too large to fit inside the plant area I had on hand. So I created what appeared like "glasses" to go around the outside of the planter to hold the sensors. Then came another issue. The Servo was too weak to rotate the weight of the plant.
So back to the drawing board. I decided to construct a complicated stand that would suspend the plant and all its weight about an inch off the ground. Then, under the plants frame, the Servo would spin a long arm extending out around from under the base. This arm held up the glasses, so as it spun, so did the exterior structure (containing the 'ears')!
This also failed though, revealing the biggest problem I faced during this project. The Servo is designed to hit an exact angle, and with the awkward weight of the arms, it would vibrate trying to overfix passing the perfect angle mark. Even with no weight, the Servo made minor vibrations that caused huge issues for the mic. To give an idea, ambient noise in a silent room is about '50' on the mics. Loud music directed at the mics produced about '600' or so. The vibrations from the Servo, seemingly small to us, caused a '1200'+ reading.
It was once again time to go back to the drawing board. I found 2 spare skateboard bearings, and built a plank between them with popsicle sticks. I then used more popsicle sticks to keep my 'axle' level as it spun. The stabilizing sticks did cause some resistance, but since the bearings held nearly all the weight of the plant, the Servo had no trouble spinning now. Knowing that I couldn't put the sound sensor on the rotating piece due to vibration, I placed the 'ears' around the corners of the base. This made a huge improvement in the system, and I finally got accurate readings. Though, the code had to be rewritten.
The code went from rotating left or right until the ears were somewhat balanced to finding the ratio of left to right noise, and then placing the servo at an angle accordingly. It doesn't work in 360*, but would with more sensors. This is probably how I should have coded it to begin with since all I had to do was map the sensor input to correlating Servo angles.
I then finished the code and spent several hours tweaking the variables to get the best performance I could in the room I was in at the time. I would have liked to add a 'self calibration' window at setup of the code, so that whenever it turns on it learns a new 'ambient' value and can measure accordingly, but ran out of time. In different rooms with different levels of people, noise, and acoustics, the device would perform very differently.
This project proved to be a massive challenge (more than I was expecting) but produced a very fun, captivating little device that meets its goals. The users are drawn in and interested. They are aware of its data capture, but it keeps its friendly attitude. I really need to add googly eyes.
Enjoy building The Listening Plant yourself using the code down below!
Servo mainServo;
int soundSensorPin1 = A1;
int soundSensorValue1 = 0;
int soundSensorPin2 = A2;
int soundSensorValue2 = 0;
int servoPos = 0;
int servoPin = A3;
int newPos;
int sensor1Min=999999;
int sensor1Max=0;
int sensor2Min=999999;
int sensor2Max=0;
void setup() {
pinMode( soundSensorPin1, INPUT);
Particle.variable("sound_amount_1", &soundSensorValue1, INT);
pinMode( soundSensorPin2, INPUT);
Particle.variable("sound_amount_2", &soundSensorValue2, INT);
Particle.variable("position_angle", &newPos, INT);
//servo code
mainServo.attach( A3 ); //attached the servo to analog 3
mainServo.write(90); //set Servo to 90, the middle
delay(100);
}
void loop() {
int read1_1 = analogRead( soundSensorPin1 );
int read1_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read1_1>=sensor1Max){
sensor1Max = read1_1;
}
if (read1_2>=sensor2Max){
sensor2Max = read1_2;
}
//minimum check for sensor 1 and sensor 2
if (read1_1<=sensor1Min){
sensor1Min = read1_1;
}
if (read1_2<=sensor2Min){
sensor2Min = read1_2;
}
delay(10);
int read2_1 = analogRead( soundSensorPin1 );
int read2_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read2_1>=sensor1Max){
sensor1Max = read2_1;
}
if (read2_2>=sensor2Max){
sensor2Max = read2_2;
}
//minimum check for sensor 1 and sensor 2
if (read2_1<=sensor1Min){
sensor1Min = read2_1;
}
if (read2_2<=sensor2Min){
sensor2Min = read2_2;
}
delay(10);
int read3_1 = analogRead( soundSensorPin1 );
int read3_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read3_1>=sensor1Max){
sensor1Max = read3_1;
}
if (read3_2>=sensor2Max){
sensor2Max = read3_2;
}
//minimum check for sensor 1 and sensor 2
if (read3_1<=sensor1Min){
sensor1Min = read3_1;
}
if (read3_2<=sensor2Min){
sensor2Min = read3_2;
}
delay(10);
int read4_1 = analogRead( soundSensorPin1 );
int read4_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read4_1>=sensor1Max){
sensor1Max = read4_1;
}
if (read4_2>=sensor2Max){
sensor2Max = read4_2;
}
//minimum check for sensor 1 and sensor 2
if (read4_1<=sensor1Min){
sensor1Min = read4_1;
}
if (read4_2<=sensor2Min){
sensor2Min = read4_2;
}
delay(10);
int read5_1 = analogRead( soundSensorPin1 );
int read5_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read5_1>=sensor1Max){
sensor1Max = read5_1;
}
if (read5_2>=sensor2Max){
sensor2Max = read5_2;
}
//minimum check for sensor 1 and sensor 2
if (read5_1<=sensor1Min){
sensor1Min = read5_1;
}
if (read5_2<=sensor2Min){
sensor2Min = read5_2;
}
delay(10);
int read6_1 = analogRead( soundSensorPin1 );
int read6_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read6_1>=sensor1Max){
sensor1Max = read6_1;
}
if (read6_2>=sensor2Max){
sensor2Max = read6_2;
}
//minimum check for sensor 1 and sensor 2
if (read6_1<=sensor1Min){
sensor1Min = read6_1;
}
if (read6_2<=sensor2Min){
sensor2Min = read6_2;
}
delay(10);
int read7_1 = analogRead( soundSensorPin1 );
int read7_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read7_1>=sensor1Max){
sensor1Max = read7_1;
}
if (read7_2>=sensor2Max){
sensor2Max = read7_2;
}
//minimum check for sensor 1 and sensor 2
if (read7_1<=sensor1Min){
sensor1Min = read7_1;
}
if (read7_2<=sensor2Min){
sensor2Min = read7_2;
}
delay(10);
int read8_1 = analogRead( soundSensorPin1 );
int read8_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read8_1>=sensor1Max){
sensor1Max = read8_1;
}
if (read8_2>=sensor2Max){
sensor2Max = read8_2;
}
//minimum check for sensor 1 and sensor 2
if (read8_1<=sensor1Min){
sensor1Min = read8_1;
}
if (read8_2<=sensor2Min){
sensor2Min = read8_2;
}
delay(10);
int read9_1 = analogRead( soundSensorPin1 );
int read9_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read9_1>=sensor1Max){
sensor1Max = read9_1;
}
if (read9_2>=sensor2Max){
sensor2Max = read9_2;
}
//minimum check for sensor 1 and sensor 2
if (read9_1<=sensor1Min){
sensor1Min = read9_1;
}
if (read9_2<=sensor2Min){
sensor2Min = read9_2;
}
delay(10);
int read10_1 = analogRead( soundSensorPin1 );
int read10_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read10_1>=sensor1Max){
sensor1Max = read10_1;
}
if (read10_2>=sensor2Max){
sensor2Max = read10_2;
}
//minimum check for sensor 1 and sensor 2
if (read10_1<=sensor1Min){
sensor1Min = read10_1;
}
if (read10_2<=sensor2Min){
sensor2Min = read10_2;
}
delay(10);
int read11_1 = analogRead( soundSensorPin1 );
int read11_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read11_1>=sensor1Max){
sensor1Max = read11_1;
}
if (read11_2>=sensor2Max){
sensor2Max = read11_2;
}
//minimum check for sensor 1 and sensor 2
if (read11_1<=sensor1Min){
sensor1Min = read11_1;
}
if (read11_2<=sensor2Min){
sensor2Min = read11_2;
}
delay(10);
int read12_1 = analogRead( soundSensorPin1 );
int read12_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read12_1>=sensor1Max){
sensor1Max = read12_1;
}
if (read12_2>=sensor2Max){
sensor2Max = read12_2;
}
//minimum check for sensor 1 and sensor 2
if (read12_1<=sensor1Min){
sensor1Min = read12_1;
}
if (read12_2<=sensor2Min){
sensor2Min = read12_2;
}
delay(10);
int read13_1 = analogRead( soundSensorPin1 );
int read13_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read13_1>=sensor1Max){
sensor1Max = read13_1;
}
if (read13_2>=sensor2Max){
sensor2Max = read13_2;
}
//minimum check for sensor 1 and sensor 2
if (read13_1<=sensor1Min){
sensor1Min = read13_1;
}
if (read13_2<=sensor2Min){
sensor2Min = read13_2;
}
delay(10);
int read14_1 = analogRead( soundSensorPin1 );
int read14_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read14_1>=sensor1Max){
sensor1Max = read14_1;
}
if (read14_2>=sensor2Max){
sensor2Max = read14_2;
}
//minimum check for sensor 1 and sensor 2
if (read14_1<=sensor1Min){
sensor1Min = read14_1;
}
if (read14_2<=sensor2Min){
sensor2Min = read14_2;
}
delay(10);
int read15_1 = analogRead( soundSensorPin1 );
int read15_2 = analogRead( soundSensorPin2 );
//maximum check for sensor 1 and sensor 2
if (read15_1>=sensor1Max){
sensor1Max = read15_1;
}
if (read15_2>=sensor2Max){
sensor2Max = read15_2;
}
//minimum check for sensor 1 and sensor 2
if (read15_1<=sensor1Min){
sensor1Min = read15_1;
}
if (read15_2<=sensor2Min){
sensor2Min = read15_2;
}
int average1 = (((read1_1)+(read2_1)+(read3_1)+(read4_1)+(read5_1)+(read6_1)+(read7_1)+(read8_1)+(read9_1)+(read10_1)+(read11_1)+(read12_1)+(read13_1)+(read14_1)+(read15_1))/15);
int average2 = (((read1_2)+(read2_2)+(read3_2)+(read4_2)+(read5_2)+(read6_2)+(read7_2)+(read8_2)+(read9_2)+(read10_2)+(read11_2)+(read12_2)+(read13_2)+(read14_2)+(read15_2))/15);
//note that we could have subtracted the min and max of each sensor set, then divided by 13 to try and weed out bad values. But I found this hurts more than helps, so left it out.
//but the variables are already created and used. Just type them in.
soundSensorValue1 = average1;
soundSensorValue2 = average2;
if(soundSensorValue1 > 55 && soundSensorValue2 > 55){
//note that 1 is left and 2 is R. The larger the number, the more left to go.
int LR_Value = (soundSensorValue1+7) - soundSensorValue2;
//ifs with the newPos categories
if(LR_Value>=40){
newPos = 15;
}
else if (LR_Value>=25){
newPos = 55;
}
else if (LR_Value>=5){
newPos = 90;
}
else if (LR_Value>=-10){
newPos = 90;
}
else if (LR_Value>=-30){
newPos = 120;
}
else if (LR_Value>=-45){
newPos = 150;
}
else{
newPos = 165;
}
//send the servo to that spot
mainServo.write(newPos);
delay(3000);
}
}
Click to Expand
A hands-on introductory course exploring the Internet of Things and connected product experiences.
A plant that reminds owners of its existence through one primary functionality: active listening. This IoT device is a plant that rotates to watch the current speaker. This gives the speaker a sense of impact, reminds them of the plants existence, and also subtly reminds users that their data is being logged. It's an impactful but subtle way to approach disclosure and transparency - all while helping to keep this cute little guy alive!
November 7th, 2019