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
A set of augmented objects to allow pedestrians at stop light to interact with other pedestrians on the other side of the street.
We were interested in transforming what is normally a boring waste of time into a fun playful experience. We found that crossing the street is an interesting daily scenario. It's too short to be even realized. But people are still too impatient to wait for the street light. From our observation in the CMU campus, jaywalking is a common scene. Sometimes people can get impatient easily and push the push-to-walk button a lot to fulfill their desire of urging the light changing time. While they push the button many times, they are spreading some sort of negative emotions. The less patience and tolerance people give to each other, the more inappropriate behaviors and safety risks can occur.
So we decided to create a pair of gamified objects with which pedestrians can challenge each other to see who can win the game. The game needs two sides of the pedestrians to participate. Once both people press the start button, the neopixel will light up to indicate that the game has started. Within a limited time (before they can go across the street), they will press the game button as fast as they can and the first person reaches the threshold number will win the game. We believe that adding this simple tug-of-war type game will make waiting to cross the street more entertaining.
We explained the concept to our potential users. I found that some of them are reluctant to use the shaker because they worry that they would be unsanitary. So we decided to change the game input to be buttons which requires less hand exposures from people and can potentially integrate with the push-to-walk buttons in the future.
3. Programming the game
We then drafted the state flow of the game and built the code without adding complicated light effects. In this step, we built and tested the code piece by piece so that it's easier for us to debug it. According to the National Association of City Transportation Officials, an average wait time at red light is 60 - 90 seconds. Assuming someone takes 1 second to press a button on average, we decided to make 50 times as a threshold that won't take too long or too short.
5. Adding lighting animations
After testing the devices and making sure they are working properly, we tweaked the lighting effects in the ready state, the game state, the winner's side and the loser's side. We were careful to choose the colors so that they are not similar or contradict with the traffic light colors.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
#include <math.h>
int startButtonPin = D5;
int buttonPin = D7;
int ledPin = D2;
int counter = 0;
bool buttonState; //current game button state
bool lastButtonState = HIGH; //previous game button state
bool startButtonState; //starter button state
long lastPublishedAt = 0;
int publishAfter = 10000;
bool myState = false; //indicate my ready state
bool yourState = false; //indicate the other person's ready state
#define PIXEL_PIN D2
#define PIXEL_COUNT 14
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(startButtonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
Particle.subscribe( "gameStart" , handleSharedEvent ); // Subscribe to game starting event
Particle.subscribe( "gameEnd" , handleSharedEvent ); // Subscribe to game ending event
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
startButtonState = digitalRead(startButtonPin);
buttonState = digitalRead(buttonPin);
if (startButtonState == LOW) {
publishStartingEvent();
}
if (myState == true and yourState == true){
counts();
//standby animation beginning
breathe();
}
if (counter >= 50){
publishEndingEvent();
//winner animation
uint32_t a = strip.Color(22, 0, 123); // Blue
uint32_t b = strip.Color(173, 12, 232); // Purple
uint32_t c = strip.Color(255, 0, 121); // Violet
uint32_t d = strip.Color(232, 46, 12); // Red
uint32_t e = strip.Color(255, 116, 0); // Orange
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, a); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, b); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, c); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, d); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, e); // set a color
strip.show();
delay( 35 );
} for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, a); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, b); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, c); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, d); // set a color
strip.show();
delay( 35 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(i, c); // set a color
strip.show();
delay( 35 );
}
counter = 0;
}
}
void counts()
{
if (buttonState == LOW and lastButtonState == HIGH){
counter += 1;
}
lastButtonState = buttonState;
}
void publishStartingEvent() // Publish function for the starting event
{
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
String eventName = "gameStart" + System.deviceID();
// then we share it out
Particle.publish( eventName, "data goes here" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
// lastPublishedAt = millis();
myState = true;
}
}
void publishEndingEvent() // Publish function for the ending event
{
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
String eventName = "gameEnd" + System.deviceID();
// then we share it out
Particle.publish( eventName, "data goes here" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
// lastPublishedAt = millis();
myState = false;
yourState = false;
}
}
void handleSharedEvent(const char *event, const char *data){ // Only need one handle event function for both events
// Let's check the event name
String eventName = String( event ); // convert to a string object
// We can use this to check if our event name contains the
// id of this device
String deviceID = System.deviceID();
// device id = 0123456789abcdef
// event = "diot/2019/paired/0123456789abcdef"
if( eventName.indexOf( deviceID ) != -1 ){
// if we get anything other than -1
// the event came from this device.
// so stop doing stuff
return;
}
if(eventName.startsWith("gameStart")){
yourState = true;
}
if(eventName.startsWith("gameEnd")){
myState = false;
yourState = false;
//loser animation
uint32_t f = strip.Color(100, 0, 0); // Deep Red
uint32_t x = strip.Color(0, 0, 0); // OFF
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(6, f); // set a color
strip.setPixelColor(5, f); // set a color
strip.setPixelColor(4, f); // set a color
strip.setPixelColor(1, x); // set a color
strip.setPixelColor(2, x); // set a color
strip.setPixelColor(3, x); // set a color
strip.setPixelColor(7, x); // set a color
strip.setPixelColor(8, x); // set a color
strip.setPixelColor(9, x); // set a color
strip.setPixelColor(10, x); // set a color
strip.setPixelColor(11, x); // set a color
strip.setPixelColor(12, x); // set a color
strip.setPixelColor(13, x); // set a color
strip.setPixelColor(14, x); // set a color
strip.show();
delay( 10 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(5, f); // set a color
strip.setPixelColor(4, f); // set a color
strip.setPixelColor(3, f); // set a color
strip.setPixelColor(1, x); // set a color
strip.setPixelColor(2, x); // set a color
strip.setPixelColor(6, x); // set a color
strip.setPixelColor(7, x); // set a color
strip.setPixelColor(8, x); // set a color
strip.setPixelColor(9, x); // set a color
strip.setPixelColor(10, x); // set a color
strip.setPixelColor(11, x); // set a color
strip.setPixelColor(12, x); // set a color
strip.setPixelColor(13, x); // set a color
strip.setPixelColor(14, x); // set a color
strip.show();
delay( 10 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(3, f); // set a color
strip.setPixelColor(4, f); // set a color
strip.setPixelColor(5, f); // set a color
strip.setPixelColor(1, x); // set a color
strip.setPixelColor(2, x); // set a color
strip.setPixelColor(6, x); // set a color
strip.setPixelColor(7, x); // set a color
strip.setPixelColor(8, x); // set a color
strip.setPixelColor(9, x); // set a color
strip.setPixelColor(10, x); // set a color
strip.setPixelColor(11, x); // set a color
strip.setPixelColor(12, x); // set a color
strip.setPixelColor(13, x); // set a color
strip.setPixelColor(14, x); // set a color
strip.show();
delay( 10 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(2, f); // set a color
strip.setPixelColor(3, f); // set a color
strip.setPixelColor(4, f); // set a color
strip.setPixelColor(1, x); // set a color
strip.setPixelColor(5, x); // set a color
strip.setPixelColor(6, x); // set a color
strip.setPixelColor(7, x); // set a color
strip.setPixelColor(8, x); // set a color
strip.setPixelColor(9, x); // set a color
strip.setPixelColor(10, x); // set a color
strip.setPixelColor(11, x); // set a color
strip.setPixelColor(12, x); // set a color
strip.setPixelColor(13, x); // set a color
strip.setPixelColor(14, x); // set a color
strip.show();
delay( 10 );
}
for( int i = 0; i < strip.numPixels(); i++ ){
strip.setPixelColor(1, f); // set a color
strip.setPixelColor(2, f); // set a color
strip.setPixelColor(3, f); // set a color
strip.setPixelColor(4, x); // set a color
strip.setPixelColor(5, x); // set a color
strip.setPixelColor(6, x); // set a color
strip.setPixelColor(7, x); // set a color
strip.setPixelColor(8, x); // set a color
strip.setPixelColor(9, x); // set a color
strip.setPixelColor(10, x); // set a color
strip.setPixelColor(11, x); // set a color
strip.setPixelColor(12, x); // set a color
strip.setPixelColor(13, x); // set a color
strip.setPixelColor(14, x); // set a color
strip.show();
delay( 10 );
}
}
}
/* Calc the sin wave for the breathing color led led */
float breathe(){
float val = (exp(sin(millis()/800.0*M_PI)) - 0.36787944)*108.0;
uint16_t i;
uint32_t c = strip.Color(123, val, 123);
uint32_t d = strip.Color(val, 100, val);
uint32_t o = strip.Color(0, 0, 0); //off
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, c );
}
strip.show();
}
Click to Expand
A hands-on introductory course exploring the Internet of Things and connected product experiences.
A set of augmented objects to allow pedestrians at stop light to interact with other pedestrians on the other side of the street.
February 18th, 2019