Snow Ball and Bus Tracker

Made by Yuhan Wu, Xuan Peng and Junke Zhao

Create an ambient display combining information of bus that need to catch and rain & snow status.

Created: December 5th, 2023

0

Intention

Commuting to campus by bus this semester, which is mainly 61 A / B / C / D, it is really common to see them come and go all together. As can be seen from the photo, it looks almost like a train coming through when is 4 of them arriving at the same time. 

Visualization created by CMU alumni Mark Egge is an amazing illustration for how bunching 61 routes are appearing in areas around the campus. [1]

Imagine when the weather gets worse and you miss a couple of buses that came together. This is really not a pleasant experience. And we would love to have a device that perhaps show us weather and bus status. 

0
Bunching.thumb Mark Egge
0

Historical Case

Weather System by Studio PSK [2], Paper Signals by Isaac Blankensmith [3], tempescope by Ken Kawamoto [4] are fascinating cases that signals and subtly display the weather, by sounds, visualization and motions. The key take away for us is that the status and translation of signaling by different types of actuators that creates various possibilities.
0

Expected Interaction

The project would be consisted of bus info display kit and the weather display kit. 
The bus tracker would be a box with an acrylic piece embedded in that could display different colors with a Neo Pixel strip or a few LED inside of the box. Interactions are pictured to be reminding users to get prepared to go get a bus, go down stairs to the bus station and lastly, inform that user might need to take another bus. When the bus is arriving, the light would start to subtly shifting to a blue or green hue. When is about time to go to the station, the transition would be quicker. And fading to a yellow color would mean that the bus is now here or gone.
The weather kit would show actions by solenoids working with wood or plastic sticks as well as plastic beads to display rain and snowfall respectively.

0

Estimated Bill of Materials 

  • 10 Solenoids (at least): To create motions for signaling rain and snow status
  • Wood Stick: Mocking rain
  • Small Plastic Beads: Mocking snowfall
  • Neo Pixel Strip or LEDs: Display bus status
  • Wood and Clear Acrylic for Laser Cutting: Fabrication of the device

0

Process of Bus Tracker

In terms of API for bus information. We managed to receive an API key from the PRT and start with the information provided. Among these we found that route data or vehicle locations might be useful. Also we tested with the web hook from prt to see how the API works.

When started to test with data from multiple routes and couldn't visualize the data in a legible way, as the indicators would get more complicated. So you went back to the one route solution. We chose to hook our argon with the data of prediction time for inbound bus route 61D at Forbes & Morewoods that takes all of the team members back to residence in Oakland from campus.

Below is the photo showing the process of testing the bus tracker on serial print monitor. We started with mapping the maximum brightness of the LEDs using the prediction time into the range of 255-100, meaning when the bus is almost there it would be fully on in red, when it is far away it would be a dim blue light. But it appears that the dim part of yellow and blue is not really seen. So we chose to map the brightness of each LED using its time within its range of loop. In that case the brightness is more obvious in every time range. 

We also found that the the analogWrite() could not turn the LED completely off and found some clear explanation on the Arduino Reference Page:

The PWM outputs generated on some pins will have higher-than-expected duty cycles  ... and may result in a value of not fully turning off the output. [5]

On argon the duty-cycle of each PWM group is not stated clearly, judging from the fact that the red LED is brighter than D4 and D6, D2 has a higher duty-cycle than the D4 and D6 pins. To solve this it would be necessary to add a digitalWirte( ledPin, LOW) to make sure that the LEDs are completely turned off when the loop finishes. But from a perspective of ambient display, what's the harm of a LED that is almost off? It might demonstrate a status without catching too much attention.

0

Process of Snow Ball

If there is a comparison between the ideas in the team, snow ball would be our favorite.

In terms of the weather api by Open Meteo, we tested with requesting temperature, rain, snowfall and weather code data. The rain and snow data is in format of depth. Because we did not have a clear clue of that indicators we were using some rather vague ranges for the if statements.
https://api.open-meteo.com/v1/forecast?latitude=40.4406&longitude=-79.9959&current=temperature_2m,rain,snowfall,weather_code

It didn't took us that long that the solenoids couldn't really punch enough beads to the air for that effect.

After that we started with testing with a 5 volt mini dc fan (photo below), we got a first go with that. Prof. Daragh encouraged us to use a much more powerful 12 volt dc fan and that feels like we finally got the chance to use a proper fan.

To test the effect we started with a rough model composed of a plastic cup, aluminium mesh screen. But in order to minimize the beads from flying all over the place, a rubber band, which is suggested by Prof. Daragh is really helpful. Among the material tested we found the appearance of the foam bead is really intriguing so we decided to work on that.

The pattern of the DC motor moving backwards is also a treat, during the test process, it kept spinning back and forth smoothly as we were testing on the granite counter top (see the YouTube video below).

Also we notice that id we point the fan up the structure of the DC fan with a framework blocking the center of the fan would block the air from blowing to the middle of the container. By reverse the direction, the air sucked out of he container tend to have a more decent result to blow on all the bead.

0
DC Fan Test
DIOT-Max - https://youtu.be/LbKurqKoprg
0

Process of Rain Drops

Our initial thought was to simulate the rain drops by the movements of wood stick by solenoids by the movement and maximum distance of that pattern is not an ideal choice for us. 

Prof. Daragh suggested that we might need to use a servo or stepper so that we could enlarge the distance of the wood stick for that movement. But this also means that the movement is going to be rotating and tilting within a range of angles, which didn't seem like an effect that we would  love to work with.

Unfortunately we gave up on that idea, but I hope I could come up with a better solution that both generate a vertical movement. For instance, when writing up the documentation I'm thinking about using a hobby motor to control a little stick that is hung on a thin rope.

0

Resulting Prototype

Content:

1. Final Bill of Materials
2. Fabrication Files
3. Workflow Diagram
4. Photo
5. Demo Video

0

Final Bill of Materials

  1. Microcontroller:
    Particle Argon x 2,

  2. Wiring:
    Alligator Clips x 2, 
    12 Volt Adaptor,
    USB micro B cable x 2
    Red, Blue and White Wires and wire stripper in Physical Computing Lab

  3. Components:

     N5192G Transmitter x 1
    Diode x 1
    LED lights x 3
    Resistors: 1 K ohm x 3, 47 ohm x 1  

  4. Motor:
    DC Brushless Fan: Delta Electronics AFB 1212 H, 12 V, 0.35 A

  5. Fabrication:
    1/16 '' Basswood, 22 '' x 11.5 ''

    1/8 '' Black & Clear Acrylic, 24 '' x 18 ''
    Tacky Glue, Scigrip Acrylic Glue
    Aluminum Mesh Screen, Wire Cutter
    Small Foam Beads: Dissembled from wrapping material

0

Fabrication Files

Below is a link to Drop Box folder containing laser cut files and model.
All materials needed is included in the fabrication section of the final bill of materials above.
https://www.dropbox.com/scl/fo/co6071ydvg9tjhv7jae0p/h?rlkey=sn2q4f10kdauhc8ig97066jcq&dl=0 

0

Workflow Diagram  

0
Photo of Bus Tracker
Bus.thumb
0
Code for Bus Tracker
//Code for Bus Tracker
int bPin = D6;
int yPin = D4;
int rPin = D2;

int busTime = 0;

void setup() {
  // Subscribe to the integration response event
  Particle.subscribe("hook-response/hook-response/bustime", predictionHandler);
  Serial.begin(9600);
  
    pinMode(bPin, OUTPUT);
    pinMode(yPin, OUTPUT);
    pinMode(rPin, OUTPUT);
}

void predictionHandler(const char *event, const char *data) {
  // Handle the integration response
  String dataStr = String(data);
  busTime = dataStr.toInt();
}

void loop() {

  Serial.print("Bus Time: ");
  Serial.print(busTime);
  Serial.println(" min");
  //Serial.print("brightness: ");
  //Serial.println(bright);

    if (busTime <= 10) {
        Serial.println("Setting red Pin on");
        Serial.println("Bus coming in 10 min");
        
        digitalWrite(yPin, LOW);
        digitalWrite(bPin, LOW);
        
        int brightness = map(busTime, 0, 10, 255, 100);
        Serial.print("Brightness: ");
        Serial.println(brightness);
        Serial.println();

        for(int i=0;i<brightness;i++){
            analogWrite(rPin,i);
            delay(50);
        }
        for(int i=brightness;i>=0;i--){
            analogWrite(rPin,i);
            delay(50);
        }
        
        
    } else if (busTime <= 15 && busTime > 10) {
        Serial.println("Setting yellow Pin on");
        Serial.println("Bus coming, go downstairs");

        digitalWrite(rPin, LOW);
        digitalWrite(bPin, LOW);
        
        int brightness = map(busTime, 10, 15, 255, 100);
        Serial.print("Brightness: ");
        Serial.println(brightness);
        Serial.println();
        
        
        for(int i=0;i<brightness;i++){
            analogWrite(yPin,i);
            delay(80);
        }
        for(int i=brightness;i>=0;i--){
            analogWrite(yPin,i);
            delay(80);
        }
        
        
    } else if (busTime <= 25 && busTime > 15) {
        Serial.println("Setting blue Pin on");
        Serial.println("Bus coming, get prepared");

        digitalWrite(yPin, LOW);
        digitalWrite(rPin, LOW);
        
        int brightness = map(busTime, 15, 25, 255, 100);
        Serial.print("Brightness: ");
        Serial.println(brightness);
        Serial.println();
        
        for(int i=0;i<brightness;i++){
            analogWrite(bPin,i);
            delay(150);
        }
        for(int i=brightness;i>=0;i--){
            analogWrite(bPin,i);
            delay(150);
        }
        
        
    } else {
        Serial.println("Turning off all LEDs");
        Serial.println("No bus coming in 20 min");
        Serial.println();
        
        digitalWrite(rPin, LOW);
        digitalWrite(yPin, LOW);
        digitalWrite(bPin, LOW);
    }

  Particle.publish("hook-response/bustime");
  // Wait 60 seconds
  delay(15000);
}
Click to Expand
0
Photo of Snow Ball
Snow.thumb
0
Code for Testing Fan without Webhook Data
int fanPin = D2;

void setup() {
    // Register the fan control function with Particle
    Particle.function("fanControl", fanControl);
    
    // Initialize the fan pin
    pinMode(fanPin, OUTPUT);
    digitalWrite(fanPin, LOW);
}

void loop() {
    // The loop remains empty as the fan control is handled by the Particle function
}

// Fan control function with time and cycle count
int fanControl(String command) {
    // Example command format: "10,3" for 10 seconds and 3 cycles
    int commaIndex = command.indexOf(',');
    if (commaIndex == -1) {
        return -1; // Error in command format
    }

    // Extract time and cycle count from command
    int time = command.substring(0, commaIndex).toInt();
    int cycles = command.substring(commaIndex + 1).toInt();

    if (time > 0 && cycles > 0) {
        for (int i = 0; i < cycles; i++) {
            // Turn the fan on
            analogWrite(fanPin, 255);

            // Keep the fan on for the specified time
            delay(time * 1000); 

            // Turn the fan off
            analogWrite(fanPin, 0);

            // Wait before the next cycle
            delay((6 - time)*1000);
        }
    } else {
        return -1; // Invalid time or cycle count
    }

    return 1; // Return a success status
}
Click to Expand
0
Code for Fan to Work with Webhook Data
//Code for Fan
String temperature_2m;
String rain;
String snowfall;
String weather_code;

int fanPin = D2;

void getData(){
	// Publish an event to trigger the webhook
  Particle.publish( "get-forecast" );
}

// This function will handle data received back from the webhook
void handleForecastReceived(const char *event, const char *data) {
  // Handle the integration response
    if (data) {
        String receivedStr = String(data);
        int loc1 = 0, loc2 = 0;

        loc1 = receivedStr.indexOf("~");
        temperature_2m = receivedStr.substring(0, loc1);

        loc2 = receivedStr.indexOf("~", loc1 + 1);
        rain = receivedStr.substring(loc1 + 1, loc2);

        loc1 = receivedStr.indexOf("~", loc2 + 1);
        snowfall = receivedStr.substring(loc2 + 1, loc1);

        weather_code = receivedStr.substring(loc1 + 1);
        
        if (rain == "1" || snowfall == "1") {
            controlFan(true);
        } else {
            controlFan(false);
        }
    }
    
    Particle.publish("snowData", snowfall, PUBLIC);
}


void controlFan(bool state) {
    if (state) {
        digitalWrite(fanPin, HIGH); // Turn the fan on
    } else {
        digitalWrite(fanPin, LOW); // Turn the fan off
    }
}

void setup() {
    Particle.subscribe("hook-response/get-forecast", handleForecastReceived );
    pinMode(fanPin, OUTPUT); 
    getData();
    
}

void loop() {

}
Click to Expand
0

Video

Containing demonstration of Snow Ball and Bus Tracker.

PS: The weather condition is not changing into every assumed conditions so specific pattern is trigger manually.

0
DIOT Final Demo
DIOT-Max - https://youtu.be/Jtox87Qk-wY
0

Conceptual Design:

By rebuilding the project, we approach some possible ways of designing an ambient display of data. How to imagine interaction and scenarios in the future? This question would rely on evaluation of previous interactions and patterns that were involved in a seemingly careless way.

First, inspired by Daniel, we could try to monitor and simulate the falling leaves outside the window. Imagine an array of small leaves blowing IoT devices on the desk, or your table. It could inform you when the Autumn comes, by making you feel how the fallen leaves would fly in the air. It don't have to be a big movement, the dialogue and pattern this could enable is just compelling all by itself and its own ecosystem.

Second is to refine the bus tracker so it response to the snowData event published from the snow ball and multiply the estimated time of the bus and provide a more detailed and interactive ecosystem. Also, adding rain, wind and other possible and influential factors.
(Inspired by Dina, see code below)

Third is to refine the mechanism for rain drops and find a similar expression that is both fun and delicate. For instance, using a hobby motor to pull a string that is attached to a little wood block, making it move like dropping. And when the wood stick remains below the surface it could serve as a solenoid to punch the beads or other pieces upwards, providing potential possibilities to combine different expressions and patterns.

0
Pin Wheels and Falling Leaves Ecosystem
Diagramideas123.thumb
0
Code for a Time Index to Multiply Estimated Time when Snowing
//code to handle walk time difference caused by snowfall 
//a time index inspired by Dina
//to response to the 
//Particle.publish("snowData", snowfall, PUBLIC);
//in the code for fan with api

int snowTimeIndex = 1; // Default multiplier = 1

void setup() {
  // Subscribe to the integration response event
  Particle.subscribe("snowData", snowfallHandler); // Subscribe to snowfall data
}

void snowfallHandler(const char *event, const char *data) {
  // Handle snowfall data received
  String snowfallData = String(data);
  snowTimeIndex= snowfallData.toInt() == 1 ? 2 : 1;
}

void predictionHandler(const char *event, const char *data) {
  // Handle the integration response
  String dataStr = String(data);
  busTime = dataStr.toInt() * snowTimeIndex; // Multiply bus time with the snowTimeIndex
}
Click to Expand
0
Time Index Ecosystem
Diagramideas12.thumb
0
Combined Ecosystem
Diagramideas1.thumb
0

Reflection and Critique:

Compared with the pre-mortum, the approach is almost totally different for the snow ball. We use fan instead of the proposed solenoids to simulate the movements of foam beads. In return we got more beads moving in the container. But, it is really what's like a snowfall? Having multiple solenoids meaning the movements would be incidental and more delicate. Maybe the scale we are using is a little brutal and too similar to a storm? At last, for the bus tracker, could it use another way of expression rather than sticking to the LEDs.

The difference here is because the team was kind of leaning towards the fun in doing the project instead of exploring subtle and ambient way of telling the data. We do have fun and it is definitely a treat for us. However, in terms of the delicacy, we might have done wrong. For the idea of ambient display and translation of information, previous work is always inspiring and worth revisit. And they would always stand for classical cases to be compared with.

0

Take away from the Final Demo:

Daniel: a possible way of iteration

"You know, like the pinwheels."

Daniel shared with us a poetic idea and we think this is an amazing iteration. He suggested that instead of an occasional event, subtle display of wind or falling leaves is also another natural pattern that could be simulated.

Daragh: a possible alternative data source

"Maybe use the regional annual snow fall data to get the depth of the expected range of depth. Or try to use status data that could avoid the problem of misunderstanding in terms representation."

Dina: a misunderstanding in terms of representation, combination of the two devices

"Wow but this looks like a storm to me."

"Maybe this would also affect on the estimated time to get to the bus stop, you should hook up the two devices. They could also be combined into one with LED or Neo Pixel strip on the bottom part."

Zach: a possible alternative selection of fan

"Well I guess these brushless fans are built with the plastic frame like this (that block the air in the center of it). Maybe another type of fan, like a squirrel cage blower would avoid this problem."

Zhenfang: a possible alternative solution for the fan

"Maybe you could try with multiple smaller fans to point at different angles."


0

Acknowledgements:

Thanks for Prof. Daragh's guide and tutorial on how to access and use the Prt API and the amazing DIOT lab website. Also thank you Zach for the wonderful resources in the Physical Computing Lab.

Shout out to Daniel, Dina, Zach and Zhenfang for your precious suggestions and opinions. Your critique has been a great asset to the project.

0

References:

Provide a list of academic papers, articles, videos, etc that you make reference to in your documentation. 

[1]. Pittsburgh's Bus Bunching Bad News Bears
[2]. Weaher System by Studio PSK
[3]. Paper Signals by Isaac Blankensmith
[4]. tempescope by Ken Kawamoto
[5]. Arduino Reference Page of  analogWrite()

x
Share this Project

Courses

48-675 Designing for the Internet of Things 24

· 11 members

A hands-on introductory course exploring the Internet of Things and connected product experiences.


About

Create an ambient display combining information of bus that need to catch and rain & snow status.