Ostrich

Made by yifeiy1, Swarna Srimal and Sanjay kumar R

Found in Ambient Affect

Let you keep track of how your youtube channel was doing.

0
Ostrich Demo
Yifei Yin - https://vimeo.com/203312137
0

Emotion 

From the 5 universal emotions described in the Atlas of Emotions, we chose to invoke the enjoyment emotion. We wanted to design our device to invoke sensory pleasure(using nice LED lights and pleasing sounds along with an aesthetic look and feel), amusement / wonder (using the organic movement of the neck).

0

Inspiration 

We got inspired from the technology snake robots use to maneuver challenging terrains. They have individual actuators that look like caps with three holes parallel to its axis on the periphery of the actuator. We can connects number of those actuators together using strings and manipulating the strings can bring different movements to the snake robot structure. This motions produced look organic and the manipulation of the neck could be done using servos. We borrowed some individual link actuators from a Robotics Institute PhD student to make our neck portion of the ostrich.

0

Design

We went through brainstorming sessions to finalize on the snake robot technology to implement our ostrich neck, another idea was to use a series of strings connected to servos to manipulate the rise of fall of various points in the neck (team felt this was more complicated than the snake robot idea). For the outer casing that represents the ostrich body, we initially tried to use foam boards to cut layers to create a concave shell, but could not get the board to cut in proper shape. So for the next iteration used compressed wood board and laser cutter. We designed the body of ostrich such that the servo could be easily housed and created the shapes needed in Adobe illustrator and used Rabbit Laser cutter in ideate lab to cut the board. We resourced boards from wastage to cut our parts. For the iterations on the display modes of information, we initially decided to make the neck move up when the likes to dislikes ration increases and based on the necks position the led on the head of ostrich turns to a different color. Then we realised we can make it more interesting and can inform the user in a mild way with sounds from a piezo if there is a big jump on likes in the past hour.

0

Prototype 

After we cut our parts using the laser cutter, we assembled the outer casing of the ostrich body. Then we soldered wires to RGB LED and inserted them into the snake robot neck. At this point we got 4 wires coming from the LED and 3 threads holding the shape of the ostrich neck. For the ostrich neck movement we wanted in Z axis only, we sealed the movement of two of 3 strings and connected the remaining to the servo. The servo pulling the string will make the ostrich neck to move in Z axis. The wires from the LED was passed on through the ostrich body casing without disturbing the servo and provide it to the breadboard. Then we fastened the starting of the ostrich neck to the body. After this physical model was setup, we tested this with the code developed in parallel with an rough skeleton version of the setup. Development of code happened in stages. Testing this code with the physical prototype worked well and we could see the neck rise up with color changes when we linked it with a trending controversial super bowl 2017 commercial.

0

Interaction

The modes of interaction for the ostrich is to move its neck, glow its head and make sounds based on the likes and dislikes ratio.

0

Bill of Materials:

1. Servo

2. Breadboard

3. RGB LED

4. Resistors

5. Piezo sound

6. Particle photon microcontroller

7. Connecting wires

8. Compressed wood board

9. Snake robot actuator rings

10. Thread


0
import sys
import urllib.request, urllib.response, urllib.error
from bs4 import BeautifulSoup
import re
from apiclient.discovery import build
from oauth2client.tools import argparser
import requests

flag = 0;
dLIKE = 0 ;
dDis = 0;
like = [];
dis = [];
like.append(0);
dis.append(0);


class SoupScrape:

    def GetStats(self, code):
        #

        global originalRatio
        global ratio
        global factor

        video_url = 'http://www.youtube.com/watch?v=' + code
        startpage = urllib.request.urlopen(video_url)
        soup = BeautifulSoup(startpage.read(), "lxml")
        # Get Number of Views

        rawview_data = soup.find('div', {'class': 'watch-view-count'})
        view_number = rawview_data.contents[0]
        view_number = re.sub('[^0-9]', '', view_number)
        # Get Number of Likes and Dislikes

        raw_like = soup.find('button', {'class': 'like-button-renderer-like-button'})
        raw_dislike = soup.find('button', {'class': 'like-button-renderer-dislike-button'})
        # Likes

        likes = raw_like.contents[0]
        for data in likes:
            num_of_likes = data

        # Dislikes

        dislikes = raw_dislike.contents[0]
        for data in dislikes:
            num_of_dislikes = data
        #video name

        raw_name=soup.find('span', {'class': 'watch-title'})
        video_name=raw_name.contents[0]
        video_name=video_name.replace('\n', '')
        #print(video_name,"-","VIEWS",view_number, "-", "LIKES", num_of_likes, "-","DISLIKES", num_of_dislikes,'\n')

        num_of_likes = int(num_of_likes.replace(",", ""))
        num_of_dislikes = int(num_of_dislikes.replace(",", ""))
        like.append(num_of_likes);
        dis.append(num_of_dislikes);

        dLike= like[-1]- like[-2]
        dDis= dis[-1]- dis[-2]

        if (dLike<0):
            dDis = dDis-dLike
        elif (dDis<0):
            dLike = dLike-dDis

        print(dLike, dDis)

        if (dLike == 0):
            if (dDis == 0):
                r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/neu", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})
            else:
                r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/dis", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})
        elif (dDis == 0):
            r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/like", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dLike})
        else:
            if (dLike >100):
                originalRatio = (num_of_likes/num_of_dislikes)
                factor = ((num_of_likes+1)/num_of_likes)
                print("originalRatio, factor")
                print(originalRatio,factor)

            else:
                if (dLike/dDis == originalRatio):
                    r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/neu", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})
                elif (dLike/dDis > originalRatio):
                    r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/like", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dLike})
                elif (dLike/dDis < originalRatio):
                    r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/dis", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})
                else:
                    print("error")






        """
        if (dLike == dDis):
            r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/neu", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})
        elif (dLike > dDis):
            if (dLike >100):
                originalRatio = (num_of_likes/num_of_dislikes)
                factor = ((num_of_likes+1)/num_of_likes)
                print("originalRatio, factor")
                print(originalRatio,factor)
            else:
                r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/like", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dLike})
        elif (dLike < dDis):
            r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/dis", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': dDis})

        """


        ratio = (num_of_likes/num_of_dislikes)
        print('ratio, originalRatio')
        print(ratio,originalRatio)
        if (ratio/originalRatio >= factor):
            #if the increase is more than a certain percent, call function youtube to pull the trigger to LIFT UP

            r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/youtube", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': ratio})
            #set the baseline to this new ratio


            originalRatio = ratio
            print("newbaseline-higher")
            print(originalRatio)

        elif (ratio/originalRatio <= (2-factor)):
            #if the decrease is more than a certain percent, call function youtube2 to pull the trigger to PULL DOWN

            r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/youtube2", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': ratio})
            #set the baseline to this new ratio

            originalRatio = ratio
            print("newbaseline-lower")
            print(originalRatio)
        #r = requests.post("https://api.particle.io/v1/devices/22002b001351353432393433/youtube2", data={'access_token': 'ada24d2045a440d9f975c0861224febe6b414065', 'args': num_of_dislikes})


        #print(r.text)

        #a=r.text.split(',')

        #b=a[3].split(':')[1]

        #b=b[:-1]

        #b= int(b)

        #print(b)







DEVELOPER_KEY = "AIzaSyDXvzq3fviM_WaXeuoqpLUK74ezsS9LzOc"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"



#   Youtube Search Functions


def youtube_search(search_string, max_results=25):
    input = search_string.q
    print(input)
    outfile = open('temp.txt', 'w')
    youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY)
    search_response = youtube.search().list(q=search_string.q, part="id,snippet", maxResults=max_results).execute()
    videos = []
    # Add each result to the appropriate list, and then display the lists of

    # matching videos

    for search_result in search_response.get("items", []):
        if search_result["id"]["kind"] == "youtube#video":
            videos.append("%s (%s)" % (search_result["snippet"]["title"], search_result["id"]["videoId"]))

    for x in range(0, len(videos)):
        outfile.write(videos[x] + '\n')

    outfile.close()


def search(artist):
    argparser.add_argument("--q", help="Search term", default=artist)
    argparser.add_argument("--max-results", help="Max results", default=5)
    args = argparser.parse_args()
    youtube_search(args)


# Main Program


if __name__ == "__main__":
    #

    # Youtube

    #


    while (flag != -1):
        stat_fetch = SoupScrape()
        stat_fetch.GetStats('HVyq6kAN6u4')
Click to Expand
0
Servo myservo;// create servo object using the built-in Particle Servo Library

int servoPin = D0;  //declare variable for servo
int speakerPin = D3;

int command_int;     //variable to keep track number of times the senser detects magnet
extern int original = 110;
int redPin = A4;    // RED pin of the LED to PWM pin **A4**
int greenPin = D1;  // GREEN pin of the LED to PWM pin **D1**
int bluePin = D2;   // BLUE pin of the LED to PWM pin **D2**
int redValue = 255; // Full brightness for an Cathode RGB LED is 0, and off 255
int greenValue = 255; // Full brightness for an Cathode RGB LED is 0, and off 255
int blueValue = 255; // Full brightness for an Cathode RGB LED is 0, and off 255</td>

int buzzertone[] = {2273, 2000};

void setup()
 {
   //Sensor setup
   Serial.begin(9600);
   Particle.function("youtube", youtube);
   Particle.function("youtube2", youtube2);
   Particle.function("like", like);
   Particle.function("dis", dis);
   Particle.function("neu", neu);
   //LED setup
   // Set up our pins for output
   pinMode( redPin, OUTPUT);
   pinMode( greenPin, OUTPUT);
   pinMode( bluePin, OUTPUT);
   pinMode( speakerPin, OUTPUT );

   // turn them all off...
   analogWrite(redPin, redValue);
   analogWrite(greenPin, greenValue);
   analogWrite(bluePin, blueValue);

   //Servo setup
   analogWrite(greenPin, 50);
   delay(500);
   analogWrite(greenPin, 255);
   delay(500);
   myservo.attach(D0);      //Initialize the servo attached to pin D0
   myservo.write(0);        //set servo to initial position
   delay(5000);              //delay to give the servo time to move to its position
   analogWrite(redPin, 50);
   delay(500);
   analogWrite(redPin, 255);
   delay(500);
   //myservo.detach();        //detach the servo to prevent it from jittering
   myservo.write(100);        //set servo to initial position
   delay(2500);


 }

 void loop()
 {
   
 }

 // this function automagically gets called upon a matching POST request
 //ratio baseline has been LIFTED
 int youtube(String command){//turns in a ratio of num_like/num_dislike
   /*Serial.println(command);
   command_int = atoi(command);
   Serial.println(command_int); //ratio number
   return 10;*/
   uint16_t i;
   analogWrite(redPin, 50);
   delay(500);
   analogWrite(redPin, 255);
   delay(500);

   for (i=0; i< 5;i++){
     if((10*i+original)<=160){
       myservo.attach(servoPin);
       myservo.write((10*i+original));
       delay(500);
       myservo.detach();
     }
     else{
       myservo.attach(servoPin);
       myservo.write(158);
       delay(500);
       myservo.detach();
     }


   }
   if (i == 5){
     if(original<=110){
       myservo.attach(servoPin);
       myservo.write((10*i+original));
       delay(500);
       Serial.println("baseline-raised");
       Serial.println(original);
       original = original+10*i;
       Serial.println(original);
       myservo.detach();
     }
     else{
       myservo.attach(servoPin);
       myservo.write(158);
       delay(500);
       myservo.detach();
       original = 160;
       Serial.println(original);
     }


   }
 }

//ratio baseline has been DROPPED
 int youtube2(String command){

   uint16_t j;
   analogWrite(bluePin, 50);
   delay(500);
   analogWrite(bluePin, 255);
   delay(500);
   for (j=0; j< 5;j++){
     myservo.attach(servoPin);
     myservo.write((-j*10+original));
     delay(500);
     myservo.detach();

   }
   if (j == 5){
     if(original>=50){
       myservo.attach(servoPin);
       myservo.write((-j*10+original));
       delay(500);
       Serial.println("baseline-dropped");
       Serial.println(original);
       original = original-10*j;
       Serial.println(original);
       myservo.detach();
     }
     else{
       myservo.attach(servoPin);
       myservo.write(0);
       delay(500);
       myservo.detach();
       original = 0;
       Serial.println(original);
     }
   }
 }

 int like(String command){
    Serial.println("like");
    analogWrite(redPin, 200);
    delay(500);
    analogWrite(redPin, 255);
    delay(200);

 }

 int dis(String command){
    Serial.println("dislike");
    analogWrite(bluePin, 200);
    analogWrite(greenPin, 250);
    delay(500);
    analogWrite(bluePin, 255);
    analogWrite(greenPin, 255);
    delay(200);
 }

 int neu(String command){
    analogWrite(bluePin, 200);
    analogWrite(greenPin, 200);
    analogWrite(redPin, 200);
    delay(500);
    analogWrite(bluePin, 255);
    analogWrite(greenPin, 255);
    analogWrite(redPin, 255);
    delay(200);
    Serial.println("neutral");
 }
Click to Expand
0

Reflection

We as a team worked on a new design to create an ambient device that looks beautiful and moves organically to display some information you care about. We had some roadblocks while creating the setup, but overall we think it was a success in terms of the technical achievement and using unique materials. Each one of us learnt something new. The next steps could be to make the ostrich neck more natural looking and also the movement more organic. Maybe we can control the neck better by manipulating all the three threads instead of just one. The size of the ostrich base was also bigger and little disproportional, we can fix that in next iteration. We also burnt few servos and we need to figure out how to avoid that situation. 

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.


About

Let you keep track of how your youtube channel was doing.

Created

February 9th, 2017