media controller [ Dec 8 2010 ]

For [ Nov 3 2010]
black ink drops on postcard


For our midterm project, Avery Max, Paul Christophe, and I created a media controller that takes one’s heart rate and transforms it in to a visual piece. We wanted to produce something that would capture one’s moment in time, not a photograph, memory, or in writing, but a biology reflection of their state of being. The heartbeat controls a solenoid valve which would drip ink on a blank postcard mounted on a turntable. The more excited the individual, the faster the heart would beat, and the more frequent the ink would drip. Because it is so dependent on the person’s current physical and or emotional state, the piece would be produced slightly differently each time. We expect that one would return to our media controller every so often to see the visual output of their heart beat, and would notice the difference in the art work created by their biology . It is printed on the front of a blank postcard, so this imagery made from the body can be sent as an intimate personal message.

There were three major components to the product: the heart pulse sensor, a solenoid that controlled the drip rate, and a motor which turned the piece of paper in one full rotation every 30 seconds.


For our heart sensor, we used an infrared LED with a TSL 230 light sensor that converts light intensity into frequencies that we can use to measure heart beats. For our purposes, this means that the more light that is read through the finger tip, the higher the light intensity , thus the higher the frequency that the chip outputs. The less light, the lower the frequency. When the heart contracts and pulses, blood is rushed into the fingers, so the light intensity  and frequency is less because the finger is filled with more opaque blood.

We originally used a red LED, which would measure oxygen content in the blood. Oxygen rich red blood cells absorb more of the red wavelength of light, so you can measure oxygen content in that way. But an IR Led is more for general use. It was more appropriate for our purpose to measure the heart pulse rate, and it also gave more accurate readings than the red LED.

Here is an image of what we had built initially.The user would place their finger in the “cave,” where the finger would be placed on top of the light sensor. The IR LED is positioned directly above the light sensor.  You can take a look at the second version of this heart sensor below to get an idea how the two components were positioned.

There is some fairly complicated wiring going here, but for the tsl230 chip, most important elements are shown in the diagram below. The S0 and S1 inputs control the how sensitive the light intensity is read by adjusting how many light receptors are active at once. With a higher sensitivity, smaller amounts of light can be read, but this also means that it would have difficulty measuring light at higher intensity levels. Sensitivity for our TSL230 is set to 100x, with s0 and s1 both at  HI.  s3 and s2 are scaling inputs which divide the output frequency by  either y  2, 10, or 100 , nor by none at all. Our scaling was set to 10x with S3 and S2 set at Hi and Low respectively.   The output enable (OE) is only used to enable or disable the scaled- frequency output (6), and set to ground. S0 through s3 were the only pins we used for our purposes.

After many days of texting and playing around with the build, we were unable to get clear enough of a heart pulse reading. So we resorted to creating a working prototype with a fake heart pulse. I think it still shows a clear idea of the product we wanted to create. Instead of getting an input reading from the sensor, we now created a false pulse. Once a person places their finger in the contraption, we press the “start button” to simulate a 10 second reading from our machine. At this point, both the solenoid and the turntable motor kicks in.


The motor was used as an output  to pin 9, a PWM / analog , and was connected to the the start button input at pin 12.  Because we needed the motor and paper to make a full rotation in 30 seconds, we set pin 9 to analogWrite at a  strength of 27.


While the motor was turning, we activated the the solenoid valve with with a fake pulse. This fake pulse  is set to a random number between 60 and 80 , so that we could simulate a different readings for different people. We then set 1/(the heart rate) to get the number of milliseconds between each pulse. We triggered the valve by seeing if from the time we start the reading is larger or equal to the number of milliseconds between the pulses. The solenoid is opening and closing with a delay of 8 milliseconds to give us a drop of ink that would give us  an approximately one centimeter (in diameter) splash.  Once we see that its longer than 30 seconds, we stop the fake pulse which stops the motor and the valve.


The project was definitely a learning experience for us. For awhile we were stuck and bogged down because we could not get our heart sensor to give us an accurate reading.  Although not the a permanent solution, the fake heart pulse was the perfect temporary resolution and it let us move on to focus on other parts of the project.

I think we could have spent a little more time solidifying the physical build that connected the three components together. During our presentation, at the last minute we decided to clip our tubing to a ladder at multiple points. In hind sight, I think it may have really affected the pressures in the tubing that affected our solenoid valve. It ended up with ink splattering everywhere rather than small concise drops.

As a whole,  it was a very fun project to work on with Avery and Paul. A struggle at times, but I learned a lot from them, and we definitely got a lot of jokes and laughs from working together.


int inPin = 2; //Interrupt pin, monitoring when pulse goes high
int s0 = 3; //chip config pin
int s1 = 4; //chip config pin
int s2 = 5; //chip config pin
int s3 = 6; //chip config pin

int TOTAL_DURATION_MS = 30000; //30 Seconds, how long we want the experience to be

int control_pin = 13; //Valve control
int button_pin = 12; //Button to start/stop session

int pulseWidth=27; //Strength of motor
int motor_pin = 9; //Motor Pin

unsigned long duration = 75; //ms we read the light sensor for

//Keep track of data from light sensor
unsigned long count;
unsigned long base_time;

//Switch between real/fake pulse data
boolean from_sensor = false;

//For fake heart rate, if we need it
int heart_step = 0;
long pulse_rate = 0;

void setup(){
 count = 0;
 pinMode(control_pin, OUTPUT);
 pinMode(motor_pin, OUTPUT);
 pinMode(button_pin, INPUT); 

 digitalWrite(control_pin, LOW);

 pinMode(inPin, INPUT);
 pinMode(s0, OUTPUT);
 pinMode(s1, OUTPUT);
 pinMode(s2, OUTPUT);
 pinMode(s3, OUTPUT);

 //Sensitivity x10

 digitalWrite(s1, HIGH);
 digitalWrite(s0, HIGH);
 //Divide By 2

 //Had to comment this out, millis wasn't working with
 //interrupts enabled...mystery...
 //attachInterrupt(0, riseDetected, RISING);
 base_time = millis();


void riseDetected(){
  count++; //Add 1 to the count, this is how we get the frequency

void loop(){
  if (from_sensor){
     if (millis() - base_time >= duration){
     count = 0;
     base_time = millis();
 if (digitalRead(button_pin) == HIGH){


 //Fake pulse rate if we can't get the sensor working
void false_pulse(){
   pulse_rate = random(60,80); //set to random pulse between 60-80bpm
   heart_step = 60000/pulse_rate; //get the #of ms between each pulse
   long base_start = millis(); //Start time (now)
   long start = base_start; //Same as now, but we will use it differently later

   boolean in_time = true; //Saying we are still within the time limit (since we just started)

   analogWrite(motor_pin, pulseWidth); //start the motor runnin'
   while (in_time){ //while we are in the alloted time

     //Serial.println(millis() - start);
     if ((millis() - start) >= heart_step){ //if NOW - TIME-WE-STARTED is >= #of ms between pulses
       trigger_valve();// start valve
       start = millis();

     if ((millis() - base_start) >= TOTAL_DURATION_MS)
       in_time = false;
  analogWrite(motor_pin, 0);

void trigger_valve(){
    //Serial.println("IN VALVE");
     digitalWrite(control_pin, HIGH); //Open Valve at pin 13
     delay(8); //8ms works best
     digitalWrite(control_pin, LOW); //Close
    //Serial.println("CLOSING VALVE");

Posted: December 18th, 2010
Categories: Arduino, Physical Computing
Comments: 2 Comments.
Pingback from Media Controller | HeartWave | Engin Ayaz - November 7, 2011 at 4:09 pm

[...] Ink and Heartbeat (ITP project) [...]

Pingback from HeartWave (Final Documentation) | dougkanter - November 28, 2011 at 5:42 pm

[...] Ink and Heartbeat (ITP project) [...]