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
We made a very simple and intuitive way to remind people to work out, and motivate them to work out with friends.
There are a ton of wearables today. They all create a flood of information. These informations are either filled within high resolution screens or within a phone app, constantly reminding you to work out & stand up, bombing you and vibrating about phone notifications, etc. They can get quite annoying at times, and if anything, they exacerbate your anxiety in the already too noisy life.
We envision an intimate wearable companion that connects 2 people, loved ones or close friends, and builds their relationships through activity. The activity tracking is designed to be subtle and not bothersome. The 2 people have to work together on a playful ‘goal’: their activity levels will be synced to be encouraged complete a “heart” together.
We utilized 1 accelerometer, 1 logic level converter, 1 capacitor and 1 8x8 led matrix for each of the 2 breadboards. The general idea was identifying the raw data generated by the accelerometer to be converted to number of steps based on change of values, then displaying and updating the pattern on the pixel matrix based on the values the user produced. In the same time, data from 2 devices are synced in real time via Wi-Fi to complete the ‘pattern’ together.
Step 1. Connect accelerometer and write algorithms to identify data as “steps”.
Because the pixel matrix we ordered had not arrived yet at this point, we used a pixel band as a temporary display option for the progress. More led lights are light up as a person progresses. The first step included setting up algorithms of translating the accelerometer's reading to number of steps.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
#define x_axis A0
#define y_axis A1
#define z_axis A2
#define PIXEL_PIN D4
#define PIXEL_COUNT 11
#define PIXEL_TYPE WS2812
int x_val;
int y_val;
int z_val;
int steps = 0;
int up = 0;
int down = 0;
long lastPublishedAt = 0;
int publishAfter = 10000;
int ledPos = 0;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
void setup() {
Particle.subscribe( "diot2019/steps_count" , handleSharedEvent );
strip.begin();
strip.show();
pinMode(x_axis, INPUT);
pinMode(y_axis, INPUT);
pinMode(z_axis, INPUT);
Particle.variable("X",&x_val,INT);
Particle.variable("Y",&y_val,INT);
Particle.variable("Z",&z_val,INT);
Particle.variable("Steps",&steps,INT);
Particle.variable("LED",&ledPos,INT);
}
void loop() {
//up=0;
//down = 0;
x_val = analogRead(x_axis);
y_val = analogRead(y_axis);
z_val = analogRead(z_axis);
if (x_val<1820) {
up = 1;
delay(200);
}
if (x_val>2020) {
down=1;
delay(200);
}
if (up==1&&down==1) {
steps++;
up=0;
down=0;
}
publishMyEvent();
}
void publishMyEvent() {
if( lastPublishedAt + publishAfter < millis() ) {
String eventName = "diot2019/steps_count" + System.deviceID();
Particle.publish(eventName, String(steps));
lastPublishedAt = millis();
}
}
void handleSharedEvent(const char *event, const char *data) {
String eventName = String(event);
String dataValue = String(data);
String deviceID = System.deviceID();
if (eventName.indexOf( deviceID ) != -1) {
return;
} else {
ledPos = (dataValue.toInt()/10)%11;
lightUp();
}
}
void lightUp() {
uint16_t i;
uint32_t c = strip.Color(255, 0, 0);
uint32_t c2 = strip.Color(0, 0, 0);
for(i=0; i< strip.numPixels(); i++) {
if (i==ledPos) {
strip.setPixelColor(i, c);
} else {
strip.setPixelColor(i, c2);
}
strip.show();
delay( 100 );
}
}
Click to Expand
Step 2. test with led matrix.
This is where we encountered the majority of our issues. Due to the limitation of library resources in Particle, we had to write the algorithms, animations from scratch frame by frame. Particle does not support 64 bit reading, and we therefore needed to code in binary terms.
Step 3. finishing up the connectivity between the 2 devices.
Writing up codes and publishing on particle to have 2 screens sharing the same screen and sharing data from each other.
Step 4. polishing the aesthetics of the watch.
Aesthetics matter, even for a project prototype of a course. We decided to go all "retro" with every part readily available in the studio, even including the band. For the demo, we used portable chargers, which enabled us to hide all rest of the parts in sleeves or pockets, avoiding unnecessary distractions from the audience. After all, audience care about your actual ideas, not every detail of how they work.
The 2 screens are synced in real time, and are sharing data from each other. As you can see from below, the colors of blue and red represents each half is from one of the 2 devices. At all times, the 2 screens are exactly the same. When both the red and blue parts of the heart finish, the "reward", rainbow-colored heart, will show up on both devices at the same time.
#include <dotstar.h> //Library for operating the dotstar led matrix
#define x_axis A0 //X-Axis reading pin for accelerometer
#define y_axis A1 //Y-Axis reading pin for accelerometer
#define z_axis A2 //Z-Axis reading pin for accelerometer
#define DotstarMatrixPin D2 //Dotstar matrix Digital Input pin
#define MatrixSize 64 //Dotstar matrix size
#define ClockPin D1 //Clock pin for dotsar matrix
int x_val; //X-Axis reading value of accelerometer
int y_val; //Y-Axis reading value of accelerometer
int z_val; //Z-Axis reading value of accelerometer
int steps = 0; //Number of steps walked
// Variables to maintain account of the state of the screens
int count1 = 0;
int count1_new = 0;
int count2 = 0;
int count2_new = 0;
int pixelsOn1 = 0;
int pixelsOn2 = 0;
int toInc1 = 0;
int toInc2 = 0;
int laps = 0;
// Variables to store the positional movement of the hand
int up = 0;
int down = 0;
long lastPublishedAt = 0; //Time stamp for last published event
int publishAfter = 2000; //Required time difference between consecutive
int rainbow = 0; //Flag for rainbow animation
int toReset = 0; //Flag for resetting the screens
int baseColor[] = {26,26,26}; //Color of the unfilled heart
Adafruit_DotStar matrix = Adafruit_DotStar(MatrixSize, DotstarMatrixPin, ClockPin); //Defining the matrix
// Heart image
int heart[] = {
0,1,1,0,0,1,1,0,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,0,
0,0,1,1,1,1,0,0,
0,0,0,1,1,0,0,0,
};
int heartSize = 48; //Number of pixels in the heart image
// First half heart image of one partner
int heart1[] = {
0,0,0,0,0,1,1,0,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,0,
0,0,0,0,1,1,0,0,
0,0,0,0,1,0,0,0,
};
// Copy of first half heart image for operations
int heart1_copy[] = {
0,0,0,0,0,1,1,0,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,1,
0,0,0,0,1,1,1,0,
0,0,0,0,1,1,0,0,
0,0,0,0,1,0,0,0,
};
// Second half heart image of one partner
int heart2[] = {
0,1,1,0,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
0,1,1,1,0,0,0,0,
0,0,1,1,0,0,0,0,
0,0,0,1,0,0,0,0,
};
// Copy of second half heart image for operations
int heart2_copy[] = {
0,1,1,0,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
1,1,1,1,0,0,0,0,
0,1,1,1,0,0,0,0,
0,0,1,1,0,0,0,0,
0,0,0,1,0,0,0,0,
};
int heart_1_2_Size =24; //Size of half heart images
int heartColor1[] = {25,0,0}; //Fill color of first half of the heart image
int heartColor2[] = {0,25,25}; //Fill color of second half of the heart image
// Colors for the rainbow animation
int c1[] = {26,0,0};
int c2[] = {13,26,0};
int c3[] = {0,26,0};
int c4[] = {0,26,13};
int c5[] = {0,13,26};
int c6[] = {0,0,26};
int c7[] = {13,0,26};
int c8[] = {26,0,13};
// Frames for the rainbow animation
int rain1_r[] = {
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0]
};
int rain1_b[] = {
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1]
};
int rain1_g[] = {
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2]
};
int rain2_r[] = {
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0]
};
int rain2_b[] = {
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1]
};
int rain2_g[] = {
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2]
};
int rain3_r[] = {
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0]
};
int rain3_b[] = {
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1]
};
int rain3_g[] = {
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2]
};
int rain4_r[] = {
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0]
};
int rain4_b[] = {
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1]
};
int rain4_g[] = {
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2]
};
int rain5_r[] = {
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0]
};
int rain5_b[] = {
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1]
};
int rain5_g[] = {
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2]
};
int rain6_r[] = {
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0]
};
int rain6_b[] = {
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1]
};
int rain6_g[] = {
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2]
};
int rain7_r[] = {
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0],
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0]
};
int rain7_b[] = {
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1],
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1]
};
int rain7_g[] = {
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2],
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2]
};
int rain8_r[] = {
c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0],
c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0], c5[0],
c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0], c4[0],
c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0], c3[0],
c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0], c2[0],
c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0], c1[0],
c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0], c8[0],
c8[0], c1[0], c2[0], c3[0], c4[0], c5[0], c6[0], c7[0]
};
int rain8_b[] = {
c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1],
c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1], c5[1],
c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1], c4[1],
c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1], c3[1],
c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1], c2[1],
c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1], c1[1],
c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1], c8[1],
c8[1], c1[1], c2[1], c3[1], c4[1], c5[1], c6[1], c7[1]
};
int rain8_g[] = {
c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2],
c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2], c5[2],
c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2], c4[2],
c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2], c3[2],
c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2], c2[2],
c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2], c1[2],
c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2], c8[2],
c8[2], c1[2], c2[2], c3[2], c4[2], c5[2], c6[2], c7[2]
};
void setup() {
Particle.subscribe( "diot2019/steps_count" , handleSharedEvent ); //Subscribing to the event handle
pinMode(x_axis, INPUT); //Input for X-axis reading of the accelerometer
pinMode(y_axis, INPUT); //Input for Y-axis reading of the accelerometer
pinMode(z_axis, INPUT); //Input for Z-axis reading of the accelerometer
matrix.begin(); //Starting the matrix screen
// Setting the initial base unfilled heart image
for (int i=0;i<MatrixSize;i++) {
if (heart[i]==1) {
matrix.setPixelColor(i,baseColor[0],baseColor[1],baseColor[2]);
} else {
matrix.setPixelColor(i,0,0,0);
}
matrix.show();
}
}
void loop() {
x_val = analogRead(x_axis); //Reading the X-Axis value from the accelerometer
y_val = analogRead(y_axis); //Reading the Y-Axis value from the accelerometer
z_val = analogRead(z_axis); //Reading the Z-Axis value from the accelerometer
// Level-1 Position based algorithm to count the estimated steps
if (x_val<1820) {
up = 1;
delay(200);
}
if (x_val>2020) {
down=1;
delay(200);
}
if (up==1&&down==1) {
steps++;
up=0;
down=0;
}
publishMyEvent(); //Publishing the event
toInc1 = count1_new-pixelsOn1; //Calculating the number of pixels to be turned on for first half heart
toInc2 = count2_new-pixelsOn2; //Calculating the number of pixels to be turned on for second half heart
// Algorithm to fill the first half heart
for (int j=0;j<toInc1;j++) {
if (pixelsOn1<heart_1_2_Size) {
for (int i=0;i<MatrixSize;i++) {
if (heart1[i] == 1 && heart1_copy[i]==1 && toInc1>0) {
matrix.setPixelColor(i,heartColor1[0],heartColor1[1],heartColor1[2]);
heart1_copy[i]=2;
pixelsOn1++;
toInc1--;
} else if (heart1[i]==1 && heart1_copy[i]==2) {
matrix.setPixelColor(i,heartColor1[0],heartColor1[1],heartColor1[2]);
} else if (heart1[i]==1) {
matrix.setPixelColor(i,baseColor[0],baseColor[1],baseColor[2]);
} else if (heart2[i]!=1) {
matrix.setPixelColor(i,0,0,0);
}
}
matrix.show();
}
}
// Algorithm to fill the second half heart
for (int j=0;j<toInc2;j++) {
if (pixelsOn2<heart_1_2_Size) {
for (int i=0;i<MatrixSize;i++) {
if (heart2[i] == 1 && heart2_copy[i]==1 && toInc2>0) {
matrix.setPixelColor(i,heartColor2[0],heartColor2[1],heartColor2[2]);
heart2_copy[i]=2;
pixelsOn2++;
toInc2--;
} else if (heart2[i]==1 && heart2_copy[i]==2) {
matrix.setPixelColor(i,heartColor2[0],heartColor2[1],heartColor2[2]);
} else if (heart2[i]==1) {
matrix.setPixelColor(i,baseColor[0],baseColor[1],baseColor[2]);
} else if (heart1[i]!=1){
matrix.setPixelColor(i,0,0,0);
}
}
matrix.show();
}
}
// Checking if the heart is fully filled
if (pixelsOn1==heart_1_2_Size && pixelsOn2==heart_1_2_Size) {
rainbow=1; //Raising rainbow flag
}
// Displaying rainbow animation of completing the heart
if (rainbow==1) {
for (int j=0;j<10;j++) {
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain1_r[i],rain1_b[i],rain1_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain2_r[i],rain2_b[i],rain2_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain3_r[i],rain3_b[i],rain3_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain4_r[i],rain4_b[i],rain4_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain5_r[i],rain5_b[i],rain5_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain6_r[i],rain6_b[i],rain6_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain7_r[i],rain7_b[i],rain7_g[i]);
}
}
matrix.show();
delay(100);
for( int i = 0; i < MatrixSize; i++) {
if (heart[i]==1) {
matrix.setPixelColor(i, rain8_r[i],rain8_b[i],rain8_g[i]);
}
}
matrix.show();
delay(100);
}
rainbow=0;
toReset=1; //Initiating reset
}
// Resetting the screen after rainbow animation
if (toReset==1) {
// Changing the base color towards greener side after increment in the laps
laps++;
if (laps==1) {
baseColor[1]=0;
} else if (laps==2) {
baseColor[0]=0;
}
// Resetting the screen image to unfilled heart
for (int i=0;i<MatrixSize;i++) {
if (heart[i]==1) {
matrix.setPixelColor(i,baseColor[0],baseColor[1],baseColor[2]);
heart1_copy[i]=heart1[i];
heart2_copy[i]=heart2[i];
} else {
matrix.setPixelColor(i,0,0,0);
}
}
//Resetting the variables for next fill cycle
steps = 0;
pixelsOn1 = 0;
count1_new=0;
pixelsOn2 = 0;
count2_new=0;
matrix.show();
toReset=0;
}
}
// Publishing the event
void publishMyEvent() {
if( lastPublishedAt + publishAfter < millis() ) {
String eventName = "diot2019/steps_count" + System.deviceID(); // Signing the event by the sender's ID
Particle.publish(eventName, String(steps)); // Sending the number of steps
lastPublishedAt = millis(); //Updating the published time
}
}
// Handling a published event
void handleSharedEvent(const char *event, const char *data) {
//Variables for defining the event action
String eventName = String(event);
String dataValue = String(data);
String deviceID = System.deviceID();
if (eventName.indexOf( deviceID ) != -1) { //If the event caught us published by self
//Updating the self count variables for image filling
count1 = count1_new;
count1_new = dataValue.toInt()/1;
} else { //If the event caught us published by partner
//Updating the partner count variables for image filling
count2 = count2_new;
count2_new = dataValue.toInt()/1;
}
}
Click to Expand
The initial screen is a heart shape in white color. This indicates a blank shape waiting to be filled. As each person’s activity level increases (i.e. walk more and more steps), the half of the heart on his/her behalf will begin to fill up. The 2 sides are differentiated with red and blue colors. The screens are synced up on the 2 people’s wearables as they progress. When the 2 people both finish, the heart is complete, and a screen of rainbow-colored heart is shown as a reward. Then the white heart becomes a yellow heart waiting to be filled, which is an indication of next level. There are total of 3 levels of white, yellow, and green to encourage the users to move onto next levels.
Feedbacks from the guest judges and Daragh were really interesting. The guest judges recommended adding sensors such as GPS to complete the functionalities for the devices serving each individual. Daragh also brought up interesting point about refraining from adding more and more functionalities which might make the device to be more complex and lose its original goal.
Following up, we will:
1. Add more patterns to add to the playfulness of the device.
2. Make the device gain access from cellphone for GPS data, so that when idle, the devices will display a degree of light green, green, and dark green to show how far the 2 people are from each other. A rainbow animation appears when the 2 people actually find each other. This mode adds to a playfulness of exploration.
The process was unexpectingly complex, mostly due to Particle’s rather limited functions and library. Nearly all of the tutorials were on Arduino, and the libraries included in the codes were therefore not usable for our case. Further, Particle does not support reading of 64 bit, and we realized the problem and solved it with a logic converter.
We composed and created the patterns frame by frame and pixel by pixel.
Assembly list
Part 1: Particle Argon. Quantity: 2.
Part 2: LED matrix (DotStar High Density 8x8, adafruit ID: 3444). Quantity: 2
Part 3: Accelerometer (ADXL 337). Quantity: 2.
Part 4: Capacitor. Quantity: 2.
Part 5: Logic level converter. Quantity: 2.
Shopping list
LED matrix (DotStar High Density 8x8, adafruit ID: 3444).
Additional:
Wire bands.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
We made a very simple and intuitive way to remind people to work out, and motivate them to work out with friends.
February 17th, 2019