vivianqiu – Physical Computing https://courses.ideate.cmu.edu/16-223/f2014 Carnegie Mellon University, IDeATe Fri, 11 Aug 2017 21:41:33 +0000 en-US hourly 1 https://wordpress.org/?v=4.7.28 Final Project – #ISelfie https://courses.ideate.cmu.edu/16-223/f2014/iseflie/ Thu, 11 Dec 2014 01:01:27 +0000 http://courses.ideate.cmu.edu/physcomp/f14/16-223/?p=3327 IMG_3258#ISelfie is a data visualization project that brings attention to a festering social phenomenon our generation is grappling with today: self-obsession. This project shows, in real time, every tweet that includes the hashtag, #selfie, and the hashtag, #ISIS. In light of recent events, such as Rand Paul proposing a declaration of war, the Israeli State has been a prominent topic under the public’s eye for months. Despite this, an overwhelming amount of attention is still directed toward the heavily edited, self important snapshots  individuals feel so obligated to share with the twitter-sphere. This project sheds light on the inappropriate allocation of attention we live with everyday, and encourages otherwise.

#ISelfie is composed of two incandescent lightbulbs; one flashes whenever a twitter post containing ‘#selfie’ is tweeted, and the other ‘#ISIS.’ Not surprisingly, the #selfie lightbulb flashes exponentially more hour to hour. The flashes of light represents both the flash of a camera on an iPhone, and the other the light flashes of warfare caused by the Islamic State. Synchronized with the flashes given off by the lightbulbs is the drops of ink that represent destruction, dropping and filling two vases of clean water. Because this is a message about the allocation of attention on twitter, when the ink fills the vase representing #selfie, it shows self deprecation, when the ink fills the vase representing #ISIS, it shows defeat and triumph.

Our circuit consisted of two sets of the same circuit. Each side had an Electric Imp, a pump, a steady-state relay, an incandescent lightbulb, an AC power connector, and a few batteries.

The electric imp would send out logic signals to the relay and the pump whenever the key word was tweeted, turning them off for a specific amount of time, and then turning them off again. We used a relay to turn the lightbulb off and on again in order to have it connected to AC power, but still be able to use the logic given from the imp.

 

Agent code:

// Copyright (c) 2013 Electric Imp

// This file is licensed under the MIT License

// http://opensource.org/licenses/MIT

 

// Twitter Keys

const API_KEY = “5NPSSMQlFGVdB1hMjnWC0xjfD”;

const API_SECRET = “IgBWsw6fOTlF9CnXE1n5khBdoliabQNIqaIPXRxFffgaEcQONH”;

const AUTH_TOKEN = “2900565861-Xe5FcUOQAzsdJSO8pbwoKKCbkunVuoUhgyV3FdC”;

const TOKEN_SECRET = “gNXMCn9D6pvebFsMzZT3d5XWjCjLEQiAr22ktnLjWr5iM”;

 

class Twitter {

// OAuth

_consumerKey = null;

_consumerSecret = null;

_accessToken = null;

_accessSecret = null;

 

// URLso

streamUrl = “https://stream.twitter.com/1.1/”;

tweetUrl = “https://api.twitter.com/1.1/statuses/update.json”;

 

// Streaming

streamingRequest = null;

_reconnectTimeout = null;

_buffer = null;

 

 

constructor (consumerKey, consumerSecret, accessToken, accessSecret) {

this._consumerKey = consumerKey;

this._consumerSecret = consumerSecret;

this._accessToken = accessToken;

this._accessSecret = accessSecret;

 

this._reconnectTimeout = 60;

this._buffer = “”;

}

 

/***************************************************************************

* function: Tweet

*   Posts a tweet to the user’s timeline

*

* Params:

*   status – the tweet

*   cb – an optional callback

*

* Return:

*   bool indicating whether the tweet was successful(if no cb was supplied)

*   nothing(if a callback was supplied)

**************************************************************************/

function tweet(status, cb = null) {

local headers = { };

 

local request = _oAuth1Request(tweetUrl, headers, { “status”: status} );

if (cb == null) {

local response = request.sendsync();

if (response && response.statuscode != 200) {

server.log(format(“Error updating_status tweet. HTTP Status Code %i:\r\n%s”, response.statuscode, response.body));

return false;

} else {

return true;

}

} else {

request.sendasync(cb);

}

}

 

/***************************************************************************

* function: Stream

*   Opens a connection to twitter’s streaming API

*

* Params:

*   searchTerms – what we’re searching for

*   onTweet – callback function that executes whenever there is data

*   onError – callback function that executes whenever there is an error

**************************************************************************/

function stream(searchTerms, onTweet, onError = null) {

server.log(“Opening stream for: ” + searchTerms);

// Set default error handler

if (onError == null) onError = _defaultErrorHandler.bindenv(this);

 

local method = “statuses/filter.json”

local headers = { };

local post = { track = searchTerms };

local request = _oAuth1Request(streamUrl + method, headers, post);

 

 

this.streamingRequest = request.sendasync(

 

function(resp) {

// connection timeout

server.log(“Stream Closed (” + resp.statuscode + “: ” + resp.body +”)”);

// if we have autoreconnect set

if (resp.statuscode == 28 || resp.statuscode == 200) {

stream(searchTerms, onTweet, onError);

} else if (resp.statuscode == 420) {

imp.wakeup(_reconnectTimeout, function() { stream(searchTerms, onTweet, onError); }.bindenv(this));

_reconnectTimeout *= 2;

}

}.bindenv(this),

 

function(body) {

try {

if (body.len() == 2) {

_reconnectTimeout = 60;

_buffer = “”;

return;

}

 

local data = null;

try {

data = http.jsondecode(body);

} catch(ex) {

_buffer += body;

try {

data = http.jsondecode(_buffer);

} catch (ex) {

return;

}

}

if (data == null) return;

 

// if it’s an error

if (“errors” in data) {

server.log(“Got an error”);

onError(data.errors);

return;

}

else {

if (_looksLikeATweet(data)) {

onTweet(data);

return;

}

}

} catch(ex) {

// if an error occured, invoke error handler

onError([{ message = “Squirrel Error – ” + ex, code = -1 }]);

}

}.bindenv(this)

 

);

}

 

/***** Private Function – Do Not Call *****/

function _encode(str) {

return http.urlencode({ s = str }).slice(2);

}

 

function _oAuth1Request(postUrl, headers, data) {

local time = time();

local nonce = time;

local parm_string = http.urlencode({ oauth_consumer_key = _consumerKey });

parm_string += “&” + http.urlencode({ oauth_nonce = nonce });

parm_string += “&” + http.urlencode({ oauth_signature_method = “HMAC-SHA1” });

parm_string += “&” + http.urlencode({ oauth_timestamp = time });

parm_string += “&” + http.urlencode({ oauth_token = _accessToken });

parm_string += “&” + http.urlencode({ oauth_version = “1.0” });

parm_string += “&” + http.urlencode(data);

 

local signature_string = “POST&” + _encode(postUrl) + “&” + _encode(parm_string);

 

local key = format(“%s&%s”, _encode(_consumerSecret), _encode(_accessSecret));

local sha1 = _encode(http.base64encode(http.hash.hmacsha1(signature_string, key)));

 

local auth_header = “oauth_consumer_key=\””+_consumerKey+”\”, “;

auth_header += “oauth_nonce=\””+nonce+”\”, “;

auth_header += “oauth_signature=\””+sha1+”\”, “;

auth_header += “oauth_signature_method=\””+”HMAC-SHA1″+”\”, “;

auth_header += “oauth_timestamp=\””+time+”\”, “;

auth_header += “oauth_token=\””+_accessToken+”\”, “;

auth_header += “oauth_version=\”1.0\””;

 

local headers = {

“Authorization”: “OAuth ” + auth_header

};

 

local url = postUrl + “?” + http.urlencode(data);

local request = http.post(url, headers, “”);

return request;

}

 

function _looksLikeATweet(data) {

return (

“created_at” in data &&

“id” in data &&

“text” in data &&

“user” in data

);

}

 

function _defaultErrorHandler(errors) {

foreach(error in errors) {

server.log(“ERROR ” + error.code + “: ” + error.message);

}

}

 

}

 

function onTweet(tweetData) {

// log the tweet, and who tweeted it (there is a LOT more info in tweetData)

server.log(format(“%s – %s”, tweetData.text, tweetData.user.screen_name));

 

device.send(“catchTweet”, tweetData.text)

}

 

 

twitter <- Twitter(API_KEY, API_SECRET, AUTH_TOKEN, TOKEN_SECRET);

twitter.stream(“selfie”, onTweet);

 

Device Code:

/***** DEVICE CODE *****/

// create a global variabled called led,

// and assign pin9 to it

pump <- hardware.pin9;

lightbulb <- hardware.pin1;

// configure led to be a digital output

pump.configure(DIGITAL_OUT);

lightbulb.configure(DIGITAL_OUT);

 

function catchTweet(tweetData) {

//server.log(“Tweet ” + tweetData);

lightbulb.write(1);

pump.write(1);

 

imp.sleep(0.0043);

pump.write(0);

 

imp.sleep(0.05);

lightbulb.write(0);

 

}

 

agent.on(“catchTweet”, catchTweet); Screen Shot 2014-12-10 at 8.05.40 PM

]]>
Final Project Sketch – Superpower – Wrecking Ball https://courses.ideate.cmu.edu/16-223/f2014/superpower-wrecking-ball/ Mon, 01 Dec 2014 15:48:05 +0000 http://courses.ideate.cmu.edu/physcomp/f14/16-223/?p=3120 IMG_9156

Our project will display data in an easily viewable and interesting way. We will have a grid of ping pong balls on a fan (each being able to move in the vertical direction up and down). We will pull information from twitter, using an electric imp, which will send the state to the fans to move the ping pong balls.

]]>
Autonomous Robot Part 3 – Waddle https://courses.ideate.cmu.edu/16-223/f2014/autonomous-robot-iii-waddle/ Wed, 19 Nov 2014 03:00:57 +0000 http://courses.ideate.cmu.edu/physcomp/f14/16-223/?p=3012 Vivian Qiu – Scribe, Jake – Designer, Myles – Tutor

Introduction 

Waddle is a robot that explores the idea of an autonomous entity with an inherent personality achieved through different behaviors triggered by a variety of stimuli. Originally intended to embody an anthropomorphic form, Waddle evolved to  a quirky robot with movements reminiscent of a duck. After exploring the wide range of potential behaviors achieved through the design of the robot, we decided to match the robot’s movement to its lovability. As a result, Waddle is a waddling robot that effectively navigates around obstacles.

Fabrication Design 

The robot’s mechanical structure is adapted from an online video. Waddle has been adapted to have a completely redesigned frame to achieve a wider range of motion, durability, and precision, but most importantly an entertaining and identifiable behavior. This personality is achieved through sensing two types of stimulus with proximity sensors and sound sensors. In this iteration, Waddle exhibits an engaging reaction to music or sound, while navigating throughout its environment to avoid collision.

Waddle’s mechanical structure is a refined result of three completed prototypes that led to a final design with the most mobility as well as smoothest range of motion in both its gait and its dance. Challenges in previous iterations include finding the correct counterweight to counteract the robot’s constantly shifting center of gravity from step to step, maintaining the structural rigidity in parts of the frame while allowing for movement in others, packaging electronics without interfering with the robot’s movement, and finding appropriate mounting mechanisms. This final iteration shows a further improved structure that allows for a wider span for the balance servo to move, allowing the feet of the robot a larger distance to move up and down. Consequently, Waddle moves with more stability and does not require as much finesse in its counterweights.

Technical Notes

The technical aspects of this project can be addressed in two aspects: the hardware and software components. To detail the former, three servos were utilized, two that act as the left and right feet and the third as a balancing mechanism. An Arduino Uno was utilized as the microprocessor along with two sensors, a sound sensor and a distance sensor. A mini protoboard was utilized to connect the power to the servos and sensor. The main power source for this iteration was a USB due to complications in battery powering, which will be solved by the next deliverable. On the software side, the algorithm for walking was heavily adjusted through design and many tweaks, which this class is referring to as iterations, to account for the new fabrication of Waddle. The walking formula is significantly different from the first iteration. The servos were distanced to offer a wider range of motion, which created instability in the middle, balance servo. This was combatted with a piece of acrylic bolted to said servo and the connection between the left and right foot servos.

Additionally, a distance sensor was implemented to allow the robot to turn when in the presence of any obstruction that would prevent it from moving forward. To respond to music or other audio stimuli, sound sensors would prompt Waddle to dance when engaged. Whenever sound levels surpass a certain threshold, Waddle will trigger a dancing sequence. However, the use of a sound sensor proved to be difficult in the presence of the other components of the circuit; Implementing the sound sensor would require a complete redesign of the established circuitry. This is because the sound sensor would result in the robot drawing more than 500 milliamps, which is more than the step ups were able to manage.

DSC_7800 DSC_7802Waddle

]]>