Interactive art with textile sensor

by greatjudy

For this project I made a crocet pressure sensor with wool yarns and conductive (for sensor) yarns. Since I had no experience of crochet, this is a very interesting experience of learning this traditional technique. I added 1 stitch and 2 stitches alternatively to each of the stitches of the previous circle in order to create a flat piece. Then I used boiling water to bathe it and washed it with soap repeatedly. After around 6 rounds, it looked felted.
The result was good, though it seemed less sensitive to pressure after felting. I have to press it ver hardly.






I connected the textile sensor to the computer, using a very simple Arduino. I have no experience on programming language but I am always interested in the potential of processing for interaction and art. So I think this is a good opportunity for me to explore the processing, though it is very challenging for me. It is really hard and I spent long time on it, but it worth it to learn a new interesting thing.

The Bubble:
I firstly wrote some circles changing their locations and size based on the input from the sensor. Once I pressed the sensor, the circles got higher and smaller.
They looked like bubbles, which inspired me to write an interacrtion game responsive to people’s movements.

Catch the fish!-interactive game:
For the next step, I tried to create a game. A fish swims in the water, and you press the sensor to control the bubble to catch the fish. Once the bubble catch the fish, it changes color.
The difficult part of this game is to delete the trace of the fish while leaving the trace of the bubbles. I have tried two ways:
For the first method, I draw a blue square after the fish, which will delete the fish’s trace. It works smoothly. But there are still some traces above and under the fish (which look OK). And further, the blue square will delete some parts of the bubble as well.


For the second method, I firstly draw the fish and the bubble, and then refill the background every time after drawing. And then I re-draw the bubble. So the fish won’t leave any trace any more. I use Arraylist to remember the previous position of the bubbles. The problem of this program is the screen keeps flashing and it seems not very stable. I don’t know why.

Ink and wash painting- interactive abstract painting-in memory of Wu Guanzhong:

The processing visualizations always remind me the abstract art. I want to do some interactive art between people’s movement and the abstract painting. I get the inspiration from Wu Guanzhong, who is a famous abstract ink and wash painter. I think the essence of in and wash painting is “the amount of water added in ink” and the “white space in between”. Currently I cannot write too complicated processing. I tried “ink dots” with different transparency that randomly dispersed on the white “paper”. I used Agent to draw the random dots. Once I squeeze the sensor, the dots get bigger.


The process of drawing an abstract ink and wash painting:

THE VIDEO LINKS for this project:
The basic bubble
wTXJsA9hRW0
J0chHqeTypc

THE CODES OD PROCESSING:
1. BubblefishA(blue square):
import processing.serial.*;
// serial is an input from other computer

Serial myPort;
int xPos;
int xPos2;
PImage fishlazy;
PImage fishshock;
Boolean w = false;

void setup() {
size(800,600);
println (Serial.list());
myPort = new Serial(this, Serial.list()[2],9600);
myPort.bufferUntil(‘\n’);
background(0,0,255);
xPos = 0;
xPos2 = 1;
}

void serialEvent (Serial machine) {
String inString = myPort.readStringUntil(‘\n’);
if ( inString != null) {
inString = trim(inString);
float inByte = float(inString);
println (inByte);
inByte = map(inByte,0,1023,0,height);
xPos = xPos + 1;
xPos++;
xPos2 = xPos2 + 1;
xPos2++;
// when xPos >= width, renew
if (xPos2 >= width) {
xPos = 0;
xPos2 = 1;
background(0,0,255);
}
if(inByte*0.9=300) {
fishlazy = loadImage(“fishlazy.gif”);
image(fishlazy,xPos2,300,100,80);
fill(0,0,255);
noStroke();
rect(xPos2,300,2,80);
}
strokeWeight(map(inByte,0,1023,1,5));
noFill();
stroke(255);
ellipse(xPos,inByte*0.9,map(inByte,1023,0,100,10),map(inByte,0,1023,10,100));
//point(xPos, map(inByte,1023,0,height/1.5,100));
//line(xPos,height, xPos, map(inByte,1023,0,height,0));
}
}
void draw() {
}
void keyPressed() {
if ( key == ‘s’) {
w = true;
}

if ( key == ‘r’) {
w = false;
}

if ( key == ‘c’) {
saveFrame (“captureframe-####.jpg”);
}
}

2. BubblefishB(redraw the bubble):
import processing.serial.*;
// serial is an input from other computer

Serial myPort;
int xPos;
int yPos;
int r;
ArrayList bubblex;
ArrayList bubbley;
ArrayList bubbler;
PImage fishlazy;
PImage fishshock;
int fishx;
int fishy;
int fishdelay;
Boolean w = false;

void setup() {
size(800,600);
background(0,0,255);
xPos = 0;
fishlazy = loadImage(“fishlazy.gif”);
fishshock = loadImage(“fishshock.gif”);
fishx = 0;
fishy = height/2;
fishdelay = 10;

println (Serial.list());
myPort = new Serial(this, Serial.list()[2],9600);
myPort.bufferUntil(‘\n’);
}
//void draw() {
void serialEvent (Serial machine) {
String inString = myPort.readStringUntil(‘\n’);
if ( inString != null) {
inString = trim(inString);
float inByte = float(inString);
println (inByte);
// float inByte = random(0,1023);
inByte = int(map(inByte,0,1023,0,height));

if ((xPos > width)||(xPos == 0)) {
bubblex = new ArrayList();
bubbley = new ArrayList();
bubbler = new ArrayList();
xPos = 0;
}
background(0,0,255);
smooth();
frameRate(15);
//bubble
yPos = int(inByte*0.9);
r = int(map(inByte,1023,0,100,10));
bubblex.add(xPos);
bubbley.add(yPos);
bubbler.add(r);

for (int i = 0; i < bubblex.size(); i++) {
stroke(255);
//strokeWeight(map(inByte,0,1023,1,5));
noFill();
int tempx =(Integer)bubblex.get(i);
int tempy =(Integer)bubbley.get(i);
int tempr =(Integer)bubbler.get(i);
ellipse(tempx,tempy,tempr,tempr);
}

//fish
if (fishdelay == 10) {
image(fishlazy, fishx, fishy,100,80);
}
if (fishdelay < 10) {
image(fishshock,fishx, fishy,100,80);
fishdelay–;
}
if ((abs(xPos – fishx)<10) && (abs(yPos – fishy)< 10)) {
fishdelay–;
}
if (fishdelay == 0) {
fishdelay = 10;
fishx = 0;
}
if (fishx == width) {
fishx = 0;
}
xPos = xPos + 1;
fishx++;
}
}

void draw() {
}
void keyPressed() {
if ( key == 's') {
w = true;
}

if ( key == 'r') {
w = false;
}

if ( key == 'c') {
saveFrame ("captureframe-####.jpg");
}
}

3. The ink and wash painting:
import toxi.geom.*;
import processing.serial.*;
// here i import two libraries and declare machine// arraylist is like a package which consist of several items. its name is agents
// boolean is like a switch, i use it to stop and restart the script
Serial machine;
//Arraylist is like int. A An ArrayList stores a variable number of objects. This is similar to making an array of objects, but with an ArrayList, items can be easily added and removed from the ArrayList and it is resized dynamically.
ArrayList agents;
//Boolean judges two values (like a switch), true or false. here "true" is "turning off".
Boolean w = false;

void setup() {
size(600,600);
background(255,255,255);
// population means the number of generators, here i put 100 generators randomly (x ,y) in the windows
// x y is the location, it is random, sw is its opacity( black to white)
// agent. add means i put the item ( x,y,sw) into a bag called agents
// new Agent(x,y,sw) means the name of the item i call it Agent
// agents is the bag, each item inside called Agent, inside Agent there are x,y,sw int population = 100;
int population = 100;
//Arraylist name = new Arraylist. "new" means start/establish
agents = new ArrayList();
//for(condition){result} is a kind of circulation. (…)circulation. i only be used to run the program 100 times.
for (int i = 0; i < population; i++) {
int x = int( random(0, width));
int y = int(random(0, height));
int sw = int ( random(1,255));
agents.add(new Agent(x,y,sw));
}
machine = new Serial(this, Serial.list()[2],9600);
machine.bufferUntil('\n');

}

void draw() {
}

void serialEvent (Serial machine) {
String inString = machine.readStringUntil('\n');
if(inString != null) {
inString = trim(inString);
float inByte = float(inString);
println(inByte);
// here i try to draw now
//w is the switch, when it is false, we draw
// i recall the items in the bag and ask each of them to perform several actions
// 10 is the number which u can change.
//w controls "pause" of draw
if (w == false) {
//Arraylist.size() can read how many agents are there in the arraylist.
//Agent describes the properties of a
//Arraylist.get(i) means taking the sample No.i from the population
//name the selected sample as a
for ( int i = 0; i < agents.size(); i++) {
Agent a = (Agent) agents.get(i);
a.move(inByte);
a.drawdot();
if (inByte <= 900) {
a.drawcircle(inByte);
}
}
}
}
}

// here is about the item(Agent) inside the bag agents.
//class
class Agent {
//declare for the items inside
int xPos;
int yPos;
int sw;
//constructor. Agent(3 properties). Arraylist (named agents) contains 100 Agents.
//blabla=_blabla
Agent(int _xPos, int _yPos, int _sw) {
xPos = _xPos;
yPos = _yPos;
sw = _sw;
}
//behavior, action of each Agent//now it will move. acc is the coefficient linked to inByte scaled to -10 to 10//Vec3D is the distance, at last i add the distance to the position of the Agent
void move(float inByte) {
int acc = int(map(inByte,0,1023,-10,10));
//the Agent moves around the original position.
Vec3D vel = new Vec3D(random(-1,1)*acc,random(-1,1)*acc,0);
yPos = yPos + int(vel.y);
xPos = xPos + int(vel.x);
}
//draw the new position. stroke color is sw, u can change the number
void drawdot() {
stroke(sw);
strokeWeight(2);
point (xPos,yPos);
}
// draw the circle. change the color and the size as u want!
void drawcircle(float inByte) {
float r = map(inByte,0,1023,10,30);
fill (0, int(random(20,200)),0,10);
noStroke();
ellipse(xPos, yPos, r,r);
}
}
// here is the interface, s is stop, r is restart, c is capture frame
void keyPressed() {
if ( key == 's') {
w = true;
}

if ( key == 'r') {
w = false;
}

if ( key == 'c') {
saveFrame ("captureframe-####.jpg");
}
}

Thanks Leah and Ringo a lot for your help!