Sunday 31 January 2010

Colour Variations....



I have been experimenting with the colour of the observation unit to see what best fits its form & function. So far I am more inclined to use blue as it is cold, but strangely welcoming. I'm also interested in the dark grey (but the only problem with this is that most designers use black, grey & white & I don't want to blend in with the crowd...).

Saturday 30 January 2010

Industrial Facility




I really like the simple aesthetics of Industrial Facility- clean lines with a limited colour scheme. I think it might be too simple for the style of my product. I want to have some nice details on it with possibly contrasting colours to make it more interesting.

Sketches







Here are some sketches that I was needing to post up. Some form development & extra details such as control locations...

The Observer


Just a quick (fictional) example of people who take recording to the extreme - "The Observer", from the sci-fi television series Fringe.

Language

As I want my product to look & feel quite cold & "scientific", I have decided that the language it will use should be very formal. I will use words like "observe", "activate", "operational", "sever" , "initiate"... to make the whole experience of using the object very cold & formal.

Friday 29 January 2010

Peep Rig MK V.





Here are some pictures of (what potentially could be) my final form & interaction. More info on this will be posted soon e.g. video, sketches etc.

Hero Code

After creating my program, I encountered some small problems regarding refreshing web feeds. I posted the problem & my code on the Processing forum & one of the other members made me a completely new program that works better than I could ever imagine! After tinkering with the code to work seamlessly with Arduino, I have got my finished code:

import processing.video.*; // import theProcessing video library
import processing.serial.*; // import the Processing serial library

static final boolean USE_ARDUINO = true;

static final boolean USE_WEBCAM = false;
static final String WEBCAM_STRING = "USB PC Camera-WDM";

static final int MAX_LOAD_ATTEMPTS = 15; // Number of times to try loading a web image

static final String[] feedSetup = new String[] {
"Adelaide Market Observer", "http://www.adelaidecitycouncil.com/netcatapps/webcam/images/centralMkt.jpg", // Adelaide Market
"Vancouver Observer", "http://www.cbc.ca/bc/webcam/images/webcam.jpg", // Vancouver Building Site
"Adelaide Lantern Observer", "http://www.adelaidecitycouncil.com/netcatapps/webcam/images/rundleEast.jpg", // Rundle Mall East & Lantern
"Colony Observer", "http://www.draperbee.com/webcam/pic/image.jpg?1262444320177", // Beehive
"Adelaide 3 Observer", "http://www.adelaidecitycouncil.com/NetcatApps/webcam/images/bellsth.jpg", // Adelaide Bell Street South
"Aruba Observer", "http://www.bucuticam.com/arubacam.jpg", //Aruba, Netherlands Antilles
"Turtle Dome Observer", "http://www.yosemite.org/DSN/wwwyosemiteassociationorg/Content/Webcam/turtleback.jpg", //Yosemite, Turtle Dome
"Brooklyn Bridge Observer", "http://brooklyn-bridge.mobotixcam.de/record/current.jpg?rand=380424", //Brooklyn Bridge
"Bass Rock Observer", "http://www.outercam.co.uk/ssc/camera3.jpg?1260446915311", // Bass Rock, North Berwick
"Bar Observer", "http://ecoast.vs.oiccam.com:443/ftp/capcom/jackalope/image.jpg?rand=14:52:10", //Jackalope Jacks Bar, North Carolina
"Panama Canal Observer", "http://webcams.pancanal.com/webcam/miraflores.jpg", // Panama Canal
"Dundee Satellite Observer", "http://www.sat.dundee.ac.uk/webcam/cam0.jpg", //Dundee Tower Building
"Living Room Observer", "http://www.xs4all.nl/~twocats/cam/Cam-A.jpg", //Amsterdam House
"Ablerta University Observer", "http://www.cs.ualberta.ca/~lake/cam/jpg/large/201.jpg", //Alberta University
"Drama Observer", "http://facweb.furman.edu/~rbryson/dramadept/TheatreCamPic.jpg", //Student Theatre
};

Serial Arduino; // The serial port

//boolean onoff = true; // Display the local webcam?

PFont font; // Description text font

// Feeds, current feed index and reference for current feed (from the ArrayList)
private ArrayList feeds;
int feedIndex; // Current feed index
int camIndex = -1; // Index of cam (if available)
Feed currentFeed;

float xpos, ypos, onoff; // Starting position of the webcam feed
float specialWidth = 1450.0;

float scrollOffset = 0; // Text scrolling offset
float scrollSpeed = 3; // Text scrolling speed

int scrolltext;

long clock; // Realtime clock in milliseconds, based on millis(), updated in ticktock()

void setup()
{
ticktock();

size(1050,760,P3D);

font = loadFont("Consolas-36.vlw");
textFont(font, 36);

if (USE_ARDUINO && !online)
{
// List all the available serial ports
println(Serial.list());

Arduino = new Serial(this, Serial.list()[1], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
Arduino.bufferUntil('\n');
}

feeds = new ArrayList();

if (USE_WEBCAM && !online) try
{
// List all the available cameras
println(Capture.list());
CaptureFeed captureFeed = new CaptureFeed(this, "Camera One", WEBCAM_STRING, width/2, height/2, 30);
camIndex = feeds.size();
feeds.add(captureFeed);
}
catch (Exception e)
{
println("Error initialising webcam (" + WEBCAM_STRING + "): " + e.getMessage());
}

// Set up web feeds
for (int i = 0; i <>
{
Feed feed = new WebFeed(feedSetup[i], feedSetup[i+1]);
feeds.add(feed);
}

selectFeed(0); // Maybe webcam
}

void draw()
{
ticktock();

background(0);
rotate(-PI/2);

scrollOffset += scrollSpeed;
if (scrollOffset > width + specialWidth)
{
scrollOffset = 0;
}

currentFeed.update();
currentFeed.display();

if(onoff == 0){
background(0);
}
}

public void ticktock()
{
clock = millis();
}

void serialEvent(Serial Arduino)
{
// Read the serial buffer:
String myString = Arduino.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null){

myString = trim(myString);

// split the string at the commas
// and convert the sections into integers:
int sensor[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum <>
print("sensor " + sensorNum + ": " + sensor[sensorNum] + "\t");
}
// add a linefeed after all the sensor values are printed:
println();
if (sensor.length > 1){
xpos = map(sensor[0], 0, 1023, -width/2, -(width/4)*3);
ypos = map(sensor[1], 0, 1023, 0, (height- 150 - height/2));
int feedSelection = constrain((int)map(sensor[2], 0, 1023, 0, feeds.size() - 1), 0, feeds.size() - 1);
selectFeed(feedSelection);
onoff = map(sensor[3], 0, 1, 0, 1);

if (onoff == 1)
{
selectFeed(camIndex);
}

scrolltext = (int)map(sensor[4], 0, 1023, 0, currentFeed.description.length() - 1);
}
}
}


void displayScrollText(String displayText)
{
text(displayText, width - scrollOffset, height + 200);
}

public void selectFeed(int feedSelection)
{
if (feedSelection <>= feeds.size())
{
println("Cannot select feedIndex " + feedSelection);
return;
}

feedIndex = feedSelection;
currentFeed = (Feed)feeds.get(feedIndex);
}

//============================================================

/**
* Feed class
* Contains feed metadata (description and locator) and
* proscription for update() and display() methods in subclasses
*/

abstract class Feed
{
public String description;
public String locator;

public Feed(String description, String locator)
{
this.description = description;
this.locator = locator;
}

public abstract void update(); // Must be implemented in subclasses
public abstract void display(); // Must be implemented in subclasses
}

//============================================================

/**
* WebFeed class
* Access periodically-updated image from the web
* Load image in separate thread so as not to block main thread
* Delayed refresh (after error or sucessful load)
*/

class WebFeed extends Feed
{
public int refreshDelay = 2000; // Number of milliseconds to wait between refresh() calls
public PImage loadedImage; // Last loaded image

private PImage loadingImage; // Used for requestImage()
private boolean loading; // Waiting for result from requestImage()?
private boolean requestRefresh; // Set true when a refresh() is wanted
private long refreshAt; // Time (based on millis()) at which to refresh() if requestRefresh true
private int loadFailures; // Number of times the load has failed (since last successful load)

public WebFeed(String description, String locator)
{
super(description, locator);
println("new WebFeed(" + description + ", " + locator + ")");
loadedImage = null;
refresh();
}

public void update()
{
if (loading)
{
if (loadingImage.width == 0)
{
// Image is not yet loaded
}
else if (loadingImage.width == -1)
{
// This means an error occurred during image loading
println("requestImage() failed for " + description + " [" + locator + "]");
loading = false;
loadFailures++;
if (loadFailures <>
{
requestRefresh();
}
}
else
{
// Image is loaded; save a copy and request a fresh copy
println("Loaded: " + description);
loadedImage = loadingImage;
loading = false;
loadFailures = 0;

requestRefresh();
}
}

if (requestRefresh && clock >= refreshAt)
{
refresh();
}
}

public void requestRefresh()
{
requestRefresh = true;
refreshAt = clock + refreshDelay;
println("refreshAt: " + refreshAt + " (now: " + clock + ")");
}

public void refresh()
{
println("Refresh " + description + " [" + locator + "]");
loadingImage = requestImage(locator);
loading = true;
requestRefresh = false;
}

public void display()
{
if (loadedImage == null)
{
displayScrollText(description + " LOADING...");
}
else
{
image(loadedImage, xpos, ypos, width/2, height/2);
displayScrollText(description + " ONLINE");
}
}
}

//============================================================

class CaptureFeed extends Feed
{
public Capture capture; // A local webcam

public CaptureFeed(PApplet p5, String description, String locator, int feedWidth, int feedHeight, int fps)
{
super(description, locator);
capture = new Capture(p5, feedWidth, feedHeight, locator, fps);
}

public void update()
{
if (capture.available())
{
capture.read();
}
}

public void display()
{
image(capture, xpos, ypos);
displayScrollText(description + " LIVE");
}
}

Deciding not to use "live" webcams

As the observation unit will be mainly used & displayed at the degree show & new designers, I have decided to remove the "live" webcams from the setup. The whole point to the system is that the user places the camera where ever they want in a REMOTE location, away from the viewer. By having a webcam capturing video beside the unit, it will send a confusing message to the people using the product. I will have a model of a webcam beside it, but it will not be functional.

Wednesday 27 January 2010

Rationale Revised

My rationale is still developing, but here it is the jist of it as it stands so far:

I am designing a observation unit for remote viewing & the collection of information. I am designing it for people who have a compulsion for recording everything they see. The object is a critique of people having access of watching the world , the implications of it & if the user would develop a bond with the content.

I think it's sounding pretty good!

Code Development

To tie in with my revised rational, I have changed my Processing code, so you can turn on the system, change between manually placed webcams & cameras on the internet, select a certain feed & move the image about on the screen all through inputs from Arduino.

import processing.video.*; // import theProcessing video library
import processing.serial.*; // import the Processing serial library
Serial Arduino; // The serial port
Capture webCamOne; // The webcam feed
Capture webCamTwo;
PFont font;

float xpos, ypos, manualauto, x; // Starting position of the webcam feed
int autoselect, manualselect;
float size = 700.0;

String[] feed = new String[] {
"http://www.adelaidecitycouncil.com/netcatapps/webcam/images/centralMkt.jpg", //Adelaide Market
"http://www.cbc.ca/bc/webcam/images/webcam.jpg", // Vancouver Building Site
"http://www.adelaidecitycouncil.com/netcatapps/webcam/images/rundleEast.jpg", //Rundle Mall East & Lantern
"http://www.draperbee.com/webcam/pic/image.jpg?1262444320177", //beehive
"http://www.adelaidecitycouncil.com//NetcatApps/webcam/images/bellsth.jpg" //Adelaide Bell Street South
};

String[] description = new String[]{
"Adelaide 1 Observer ONLINE",
"Vancouver Observer ONLINE",
"Adelaide 2 Observer ONLINE",
"Colony Observer ONLINE",
"Adelaide 3 Observer ONLINE",
};
PImage[] images;

void setup() {
size(678,510,P3D);

font = loadFont("01_Digit-23.vlw");
textFont(font, 23);
// List all the available serial ports & cameras
//println(Serial.list());
println(Capture.list());

webCamOne = new Capture(this, width/2, height/2, "USB PC Camera-WDM", 30);
webCamTwo = new Capture(this, width/2, height/2, "PC Camer@-WDM", 30);

Arduino = new Serial(this, Serial.list()[1], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
Arduino.bufferUntil('\n');

/ need as many images as we have feeds
images = new PImage[feed.length];
// initial load of images (slow);
for (int i = 0 ; i <>
images[i] = loadImage(feed[i]);
}
}

void draw() {
background(0);
if (manualauto == 1){
if (manualselect == 0){
if (webCamOne.available()){
webCamOne.read();
}
image(webCamOne, xpos, ypos);
translate(-x, 0, 0);
text("OBSERVER 1 ONLINE", 0, 494);
}
if (manualselect == 1){
if (webCamTwo.available()){
webCamTwo.read();
}
image(webCamTwo, xpos, ypos);
translate(-x, 0, 0);
text("OBSERVER 2 ONLINE", 0, 494);
}
if (manualselect == 2){
translate(-x, 0, 0);
text("OBSERVER 3 OFFLINE", 0, 494);
}
}
else{
loadImage(feed[autoselect]);
image(images[autoselect], xpos, ypos, width/2, height/2);
translate(-x, 0, 0);
text(description[autoselect], 0, 494);
}

x = x +3;
if (x > width + size){
x = -size;
}
}


void serialEvent(Serial Arduino) {
// read the serial buffer:
String myString = Arduino.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// split the string at the commas
// and convert the sections into integers:
int sensor[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum <>
print("sensor " + sensorNum + ": " + sensor[sensorNum] + "\t");
}
// add a linefeed after all the sensor values are printed:
println();
if (sensor.length > 1) {
xpos = map(sensor[0], 0, 1023, 0, width/2);
ypos = map(sensor[1], 0, 1023, 0, (height/2 - 50));
autoselect = (int)map(sensor[2], 0, 1023, 0, images.length - 1);
manualauto = map(sensor[3], 0, 1, 0, 1);
manualselect = (int)map(sensor[4], 0, 1023, 0, 2);
}
}
}

On Top Form

On Monday, the class did a little exercise to help us understand our personal styles & product semantics a bit better. We each put on a wall a selection of objects that have influenced us during the project. I put up images of work from Troika, Dunne & Raby, Alice Wang, Stasi devices, Braun & Deiter Rams.
After a little deliberation, the class decided that the main identifiers of the products in question were:
Boxy, modular, simple, basic, bland..., clinical, highlight colours, sheet metal, cold, laboratory, pseudo-scientific, 1950's, modernism, form follows function, honest.

& the main characteristics were:
Masculine, modern, serious, expensive, technology, science, rational.

We then had to try to mix two of the words together to sum up my personal stlye.

So far I've got 50's Pseudo Tech - still working on it...

The Curious Home



After talking to one of my lecturers about the form of my object, reminded me about The Curious Home project at Goldsmiths in London, in particular, the Local Barometer. Their forms are very basic, but honest - they do what they look like they will do, display information. I want my product to have these qualities, but have a darker look to it...

Monday 25 January 2010

Brains & ...




Braun! I really love the work of Braun, especially when Dieter Rams was the in house designer. I would like to take references from these great industrially designed products & use them in the design of my object - nice clean lines, good use of product semantics & a limited range of colour.

Friday 22 January 2010

The Lives of Others/Stasi Objects






I was recommended to watch the film "The Lives of Others" for the style the observation unit that I will be making, & found it very inspirational - both in the objects & the story. I want the user of the product to build a deep relationship with the content via the interaction of the object - starting with an ordinary, even obligatory usage to developing an emotional bond with the machine, letting them live out someone else's life through it.

After watching the film, I want the object to look very functional & serious - harsh lines & no curves, with an array of different, but identical looking buttons & dials, so the user has to learn how to manipulate the machine (creating the first step to developing a bond).

Here are some pictures of German Stasi (Secret Police) surveillance objects from the 1980's - just through the way they look, they feel cold, calculated...

Wednesday 20 January 2010

Lenses




Just some quick experiments with a small selection of lenses :
A 3.5x zoom diamond viewer
A 20x zoom pocket magnifier
A wallet variable magnifier

The result was that the wallet magnifier performed the best - as it was completely flat & was consistently easier to focus the webcam with than the other two.

Directives

The whole point of the Mass Observation is to respond to "directives" - a series of questions or topics for the observers to record. I have created a small code that scrolls this information across the screen to constantly remind the observer of what their objective is:

PFont font;
float x;
float size = 430.0;
// The font must be located in the sketch's
// "data" directory to load successfully
void setup(){
size(600, 100, P3D);

font = loadFont("SubwayTicker-32.vlw");
textFont(font, 23);
}

void draw(){
background(0);
x = x +3;
if (x > width + size){
x = -size;
}

translate(x, 0, 12);
text("Directive 1: Mid-life transitions", 0, 44);

}

The only problem with the Mass Observation is that the topics are very broad & not a lot of deliberate observation is needed, mostly past experiences. I want the user to interact with the object as if it is necessary for the completion of the "mission". Maybe the content of the directives need to be customised...

The code so far...

Here is the Arduino & Processing code for the system below:

Arduino:

int potpinx = 0; //analog input
int potpiny = 1; //analog input
int potpinzoom = 2; //analog input
int onoff = 3; //digital input
int scroll = 5; //analog input
int onoffled = 13; // digital output

int sensorValue = 0; //analog value
int onoffvalue = 0; //digital value

void setup() {
// configure the serial connection:
Serial.begin(9600);
// configure the digital input
pinMode(onoff, INPUT);
// configure the digital output
pinMode(onoffled, OUTPUT);
}

void loop() {
// read the sensor:
sensorValue = analogRead(potpinx);
// print the results:
Serial.print(sensorValue, DEC);
Serial.print(",");

// read the sensor:
sensorValue = analogRead(potpiny);
// print the results:
Serial.print(sensorValue, DEC);
Serial.print(",");

// read the sensor:
sensorValue = analogRead(potpinzoom);
// print the results:
Serial.print(sensorValue, DEC);
Serial.print(",");

// read the sensor:
sensorValue = digitalRead(onoff);
Serial.print(sensorValue, DEC);
Serial.print(",");

//read the sensor:
sensorValue = analogRead(scroll);
Serial.println(sensorValue/255, DEC);

delay(90);

//read the onoff switch again & assign the output as a different name
onoffvalue = digitalRead(onoff);

//if the digital switch is in the on position, turn on the led
if (onoffvalue == HIGH){
digitalWrite(onoffled, HIGH);
}
else{
digitalWrite(onoffled, LOW);
}
}


Processing:

import processing.video.*; // import theProcessing video library
import processing.serial.*; // import the Processing serial library
Serial Arduino; // The serial port
Capture webCam; // The webcam feed
PImage hide; //Declare variable "hide" of type PImage

float xpos, ypos, zoom, onoff; // Starting position of the webcam feed

void setup() {
size(640,480,P3D);

// List all the available serial ports & cameras
//println(Serial.list());
//println(Capture.list());

webCam = new Capture(this, width/2, height/2, "USB PC Camera-WDM", 30);
Arduino = new Serial(this, Serial.list()[1], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
Arduino.bufferUntil('\n');

}

void draw() {
background(153, 153, 0);
scale(zoom/100);
if (webCam.available()){
webCam.read();
}
if (onoff == 1){
image(webCam, xpos, ypos);
}
}

void serialEvent(Serial Arduino) {
// read the serial buffer:
String myString = Arduino.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// split the string at the commas
// and convert the sections into integers:
int sensor[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum <>
print("sensor " + sensorNum + ": " + sensor[sensorNum] + "\t");
}
// add a linefeed after all the sensor values are printed:
println();
if (sensor.length > 1) {
xpos = map(sensor[0], 0,width,0,width);
ypos = map(sensor[1], 0,height,0,height);
zoom = map(sensor[2], 1, 1023, 1, 1023);
onoff = map(sensor[3], 0, 1, 0, 1);
}
}
}


New Interactions



As I want some of the interactions of my product to be microscope-ish, I wanted to use potentiometers to control some aspects of the image on screen - such as moving the feed on the x & y axis, & changing the scale of the picture (as well as turning the feed on & off).

Instead of using Pure Data as I originally thought, I have managed to use an Arduino board & Processing. The video of the system working is below:


Early Form Prototype




Here are a couple of pictures of the original form of the observation unit - I wanted the aesthetics to be very simple & angular (to be slightly threatening, as if you shouldn't be looking into it).
The whole idea of this shape was so you could put your whole head into it to totally immerse yourself in the experience - along with the web feed, surround sound would make you feel like you were in the room with the "subject".

Mass Observation Project

As I want my project to be about studying & recording people, my lecturer told me about The Mass Observation Project:

"The Mass Observation Project (MOP) is a unique UK-based writing project which has been running since 1981. It exists to:

  • Provide a structured programme within which “ordinary” people can write directly about their lives in the knowledge that what they send in will be archived for posterity and used for social research
  • Create a resource of qualitative longitudinal social data with an emphasis on subjectivity and self representation which will contribute to our understanding of everyday life in the late 20th and early 21st century.

The MOP differs from other similar social investigations because of its historical link to the original Mass Observation and because of its focus is on voluntary, self-motivated participation. It revives the early Mass Observation notion that everyone can participate in creating their own history or social science. The Mass Observers do not constitute a statistically representative sample of the population but can be seen as reporters or “citizen journalists” who provide a window on their worlds.

The material is solicited in response to “Directives” or open-ended questions sent to them by post or email three times a year. The Directives contain two or three broad themes which cover both very personal issues and wider political and social issues and events. Over 4,000 people have taken part to date, many of them corresponding over several years.

The collection comprises in-depth accounts (both opinion and experience) of everyday life: stories, memoirs, lists, letters, diagrams, drawings, maps, diaries, photographs, press cuttings, confessions, reports on people, places and events, across a wide variety of topics."

This seems to be the perfect outlet for my product - a tool for the studying of society. I just need to alter my rationale to fit in with this type of activity...