Pet your weather

Made by menghui hu, Advait Tinaikar and Wu-Chou Kuo

Found in Ambient Affect

(Rotate the image to see the dog in 3D!) PYW is a device that takes the data of whether and presents it as motion. Inspired by dogs motion, when it’s sunny outside, PYT wagging its tail and rocking its head in delight; when it’s rainy outside PYW wags its body, as if to get water off its fur; when its cold out side, PYW starts to shiver.

0

Pet your weather

Peter wakes up on a dim Saturday morning. He feels exhausted because of the heavy work last night. He wish he could wake up with something hilarious indicating the weather.

PetYourWeather (PYW) is a device that shows the weather forecast for the day through the subtle and friendly gesture of a pet. It is inspired by the motion of a dog. When it’s sunny outside, PYW starts wagging its tail and rocking its head in delight; when it’s rainy outside PYW shakes, as if to get water off its fur; when its cold outside PYW starts to shiver creating a vibratory motion. 

0

Emotion of the dogs:

Sunny – Comfortable, Happy

http://www.puppiesclub.com/wp-content/uploads/2016/05/puppy-wagging-tail.jpg

Inspired by this action, we want PYW to shake its tail and turn its head to tell us the happiness to stay in this weather.

Action video

Raining – Wet

https://i.ytimg.com/vi/6MOg6lu9JpU/maxresdefault.jpg

Dogs shake off the water on its fur when they are wet. We have PYW turn its body to express this action.

Cold – Shivering

http://www.doglistener.tv/wp-content/uploads/cold-dog.jpg

Just as human will shiver during the cold, the dog will shiver in the cold also.

Story board


Design challenge 

The design could be separated into 3 parts.

1. Code

2. Physics

3. interaction

In the coding part the main issue is that we had a tough time converting the format of data we collected to a right format that can work on particle.

When we are making the product physically function, components crapped easily. And the biggest challenge is too accurately put the components at the right place to make it work.

When we finish the code and physical function of the device, the biggest challenging we are facing is that how to make the thing act like a dog and convey the right emotion to people.

Hack PYW

Components used:

1*Photon

1*Vibrator Motor

3* servo motor

Cardboard to shape body

Tail

Prototyping Process

1. Use cardboard to build up the main body (the cylinder)

2. Seal one side of the cylinder as the dimension base.

3. Drill a hole on the sealed side as the tail

4. Cut holes as the support of the head and room for body to move

5. Confined the motion of each actuator (Tail, neck, body).

6. Make the dog aesthetic! 

Circuit Board



0
#include <string.h>
#include <stdio.h>

String location=NULL;
String weather=NULL;
String temperature=NULL;
String wind=NULL;
String precip=NULL;
String fv;
String foreValue=NULL;
String foreString=NULL;
String weath_str=NULL;
String weathstr_in=NULL;
String weathstr_out=NULL;
String weath_cond=NULL;

int loc=0;
int weath=0;
int temp=0;
int win=0;
int prec=0;
int forecast_string=0;
int forecast_value=0;

bool cloudy;
bool sunny;
bool rainy;
bool snowy;

int servoPin1 = A4;
int servoPosition1 = 90;
Servo servo1; //Body Servo

int servoPin2 = A5;
int servoPosition2 = 90;
Servo servo2; //Head Servo

int servoPin3 = D0;
int servoPosition3 = 80;
Servo servo3; //Tail Servo

int vibratorPin = D6;
int vibratorspeed = 255;
int vibratortime = 5;

int swingtime = 5; //body movement
int swingrange1 = 75;
int swingrange2 = 105;

int shaketime = 5; // head movement
int shakerange1 = 70;
int shakerange2 = 120;

int tailtime = 5; // tail movement
int tailrange1 = 30;
int tailrange2 = 150;

int rain = 0;
int sun = 0;
int cold = 0;

void setup(){
  Serial.begin(9600);

  setupParticleData();

  servoAttach();

  servo1.write( servoPosition1 );
  servo2.write( servoPosition2 );
  servo3.write( servoPosition3 );
  pinMode(vibratorPin, OUTPUT);

  for(int i=0;i<7;i++)
  {
    publish_weather_event();
    if(location != NULL && temperature != NULL && wind != NULL && precip != NULL)
    {
      printData();
      break;
    }
    delay(5000);
  }

  for(int i=0;i<7;i++)
  {
    publish_weather_forecast();
    /*weath_str=foreValue;*/
    if(foreValue!=NULL)
    {
      weathstr_out=foreValue;
      break;
    }
  }
}

void setupParticleData(){
  Particle.subscribe("hook-response/weather_forecast",setForecastFromHook,MY_DEVICES);
  Particle.variable("temperature",&temperature,STRING);
  Particle.variable("wind",&wind,STRING);
  Particle.variable("location",&location,STRING);
  /*Particle.variable("fs",&foreString,STRING);*/
  Particle.variable("fv",&foreValue,STRING);
  Particle.variable("precip",&precip,STRING);
  Particle.variable("weather",&weath_str,STRING);
  Particle.variable("conditions",&weath_cond,STRING);

  Particle.function("vspeed", set_v_speed);
  Particle.function("vtime", set_v_time);
  Particle.function("Rain", setrain);
  Particle.function("Sun", setsun);
  Particle.function("Cold", setcold);
}

void servoAttach(){
  servo1.attach( servoPin1 );
  servo2.attach( servoPin2 );
  servo3.attach( servoPin3 );
}

String check_weather_conditions()
{
  cloudy = check_substring("cloud");
  if(cloudy)
    return "It's cloudy.";

  sunny = check_substring("sun");
  if(sunny)
    return "It's sunny.";

  snowy = check_substring("snow");
  if(snowy)
    return "It's snowy.";

  rainy = check_substring("rain");
  if(rainy)
    return "It's rainy.";
  /*if(check_substring("snowyday","snow"))
      weath_str="Substring is working!";*/

  /*check_substring("snow");*/
}

bool check_substring(String sub)
{
  if(foreValue==NULL)
  {
    weath_str="Forevalue is null!";
    return false;
  }
  else
  {
    String val = String(foreValue);
    std::string str (foreValue);
    std::string str2 (sub);

    weath_str="Inside substring!";

    size_t found = str.find(str2);
    if(found!=std::string::npos)
    {
      weath_str="Substring found!";
      return true;
    }

    return false;
  }

}

void publish_weather_forecast()
{
  Serial.println("Published weather forecast.");
  Particle.publish("weather_forecast","",PRIVATE);
}

// Returns any text found between a start and end string inside 'str'
// example: startfooend  -> returns foo
String tryExtractString(String str, const char* start, const char* end)
{
    if (str == NULL) {
        return NULL;
    }

    int idx = str.indexOf(start);
    if (idx < 0) {
        return NULL;
    }

    int endIdx = str.indexOf(end);
    if (endIdx < 0) {
        return NULL;
    }

    return str.substring(idx + strlen(start), endIdx);
}

void setForecastFromHook(const char *event, const char *value)
{
  String weather = String(value);
  foreValue = tryExtractString(weather,"<icon>","</icon>");
  foreString = tryExtractString(weather,"<fcttext>","</fcttext>");

  if(foreValue!=NULL)
  {
    /*weath_str=foreValue;*/

    weath_cond = check_weather_conditions();

    Serial.println("Inside forecast str.");

  }
}

void printForecast()
{
    Serial.print("Following is what is expected today:");
    Serial.println(foreValue);

    Serial.print("The forecast conditions for the day are: ");
    Serial.println(foreString);
}

void printData()
{
    Serial.print("The weather data has been received for location: ");
    Serial.println(location);

    Serial.print("The temperature (in deg F) is: ");
    Serial.println(temperature);

    Serial.print("The wind speed (in mph) is: ");
    Serial.println(wind);

    Serial.print("The precip (in mm) is: ");
    Serial.println(precip);
}

//Function that is called when hook returns data
void setDataFromHook(const char *event, const char *value)
{
    String weather = String(value);

    /*Serial.println(weather);*/

    String locStr = tryExtractString(weather,"<city>","</city>");

    /*if(locStr==NULL)
      Serial.println("Loction string is null!");*/

    if(locStr!=NULL && loc==0)
    {
      location = locStr;
      loc++;
      /*Serial.println("Inside locstr.");*/
    }

    String tempStr = tryExtractString(weather,"<temp_f>","</temp_f>");

    if(tempStr!=NULL && temp==0)
    {
      temperature = tempStr;
      temp++;
      /*Serial.println("Inside tempstr.");*/
    }

    String windStr = tryExtractString(weather,"<wind_mph>","</wind_mph>");

    if(windStr!=NULL && win==0)
    {
      wind = windStr;
      win++;
      /*Serial.println("Inside windstr.");*/
    }

    String precStr = tryExtractString(weather,"<precip_today_string>","</precip_today_string>");

    if(precStr!=NULL && prec==0)
    {
      precip = precStr;
      prec++;

    }
}

void publish_weather_event()
{
  Serial.println("Published weather event.");
  Particle.publish("weather_xml","",PRIVATE);
}
void loop(){
  if (cold > 0){
    for( int i = 0; i < vibratortime ; i++ ){
      digitalWrite(vibratorPin, HIGH);
      delay(1000);
      digitalWrite(vibratorPin, LOW);
      delay(500);
    }
    cold = 0;
  }
  delay(1000);

  if (rain > 0){
    for (int iii = 0; iii<swingtime ; iii++){
      servo1.write(swingrange1);
      delay(300);
      servo1.write(swingrange2);
      delay(300);
      Serial.println("Shake Shake Shake");
    }
    servo1.write(servoPosition1);
    rain = 0;
  }
  delay(1000);
  if ( sun > 0){
    for (int iiii = 0; iiii< shaketime ; iiii++){
      servo2.write(shakerange1);
      servo3.write(tailrange1);
      delay(300);
      servo2.write(shakerange2);
      servo3.write(tailrange2);
      delay(300);
      Serial.println("Happy!");
    }
    servo2.write(servoPosition2);
    servo3.write(servoPosition3);
    sun = 0;
  }
  delay(1000);
}

int setPosition1( String command ){

  Serial.println( "setSpeed1: " + command );

  int value1 = command.toInt();
  if( value1 < 0 ) return -1;
  if( value1 > 180 ) return -1;

  servoPosition1 = constrain( value1, 0, 180 );
  servo1.write( servoPosition1 );
  return 1;
}

int setPosition2( String command ){

  Serial.println( "setSpeed2: " + command );

  int value2 = command.toInt();
  if( value2 < 0 ) return -1;
  if( value2 > 180 ) return -1;

  servoPosition2 = constrain( value2, 0, 180 );
  servo2.write( servoPosition2 );
  return 1;
}

int set_v_speed( String command ){
  int value3 = command.toInt();
  if( value3 < 0 ) return -1;
  if( value3 > 255 ) return -1;

  vibratorspeed = constrain( value3, 0, 255 );
  analogWrite(vibratorPin, vibratorspeed);
  return 1;
}

int set_v_time( String command ){
  int value4 = command.toInt();
  if( value4 < 0 ) return -1;
  if( value4 > 10 ) return -1;
  vibratortime = constrain( value4, 0, 10 );
  return 1;
}

int setrain( String command ){
  int value6 = command.toInt();
  if( value6 < 0 ) return -1;
  rain = value6;
  return 1;
}

int setsun( String command ){
  int value7 = command.toInt();
  if( value7 < 0 ) return -1;
  sun = value7;
  return 1;
  }

int setcold( String command ){
  int value8 = command.toInt();
  if( value8 < 0 ) return -1;
  cold = value8;
  return 1;
  }
Click to Expand
x
Share this Project

Courses

49-713 Designing for the Internet of Things

· 26 members

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


Focused on
About

(Rotate the image to see the dog in 3D!)

PYW is a device that takes the data of whether and presents it as motion. Inspired by dogs motion, when it’s sunny outside, PYT wagging its tail and rocking its head in delight; when it’s rainy outside PYW wags its body, as if to get water off its fur; when its cold out side, PYW starts to shiver.

Created

February 9th, 2017