Stress Makes Art: Galvanic Skin Response and Visual Generation




Introduction: Stress Makes Art: Galvanic Skin Response and Visual Generation

I'm a graphic design student and built this project for a beginning electronics class. I'm interested in connecting the signals generated by one's body to the act of visual generation. This piece takes the galvanic skin response value of the user and uses it to fuel the creation of a visual on screen. Galvanic skin response is thought to be correlated to a person's stress level and is used in lie detectors. In this particular work, the GSR value affects the speed at which a black growth is visualized on screen. This represents the idea that the more stressed we are, the faster diseases and other negative consequences can spread.

The hardware part of this project is fairly straightforward and uses an Arduino Uno board and the following other materials:
- Arduino Uno w/usb connector
- 2 250K resistors, in a series
- Jumper wires
- Stranded wires
- 2 ring terminals (or other metal objects to place fingers on)
- Solder + soldering iron 

The more complicated part of this project was coding in the Processing environment. These instructions will be in two main steps, "Hardware" and "Code" with a brief mention in step three of the construction of the enclosure for the electronics.

Step 1: Hardware

To make the sensors, I soldered the two ring terminals to jumper wires (you can also use stranded wires) and connected the wires to the breadboard as noted in the photograph and schematic. One wire is connected to 5V and the second wire is connected to GND through two 250K resistors in a series. This second sensor's wire is also connected to the A0 terminal on the Arduino. These connections to the Arduino are all made via the breadboard.

Step 2: Code

For the coding part of this project, I referred to the two sources below. You don't need to look at these sources unless you want to understand them in their original form. If you just want to copy/paste code that works, skip to 3) My Code.

1) GSR Source Code
The first was which includes the Arduino code (for Arduino and Processing to communicate) and the Processing code to use the galvanic skin response data from the constructed sensors. Wang's code basically charts a person's galvanic skin response value in a moving line graph, which looks a little like an EKG reading visually. I wanted to have a more abstract visualization of the data so used code from another source to generate the visuals. 

2) Visual Source Code
The code to create the visuals is from:

3) My Code


void setup(){

void loop(){
  int a=analogRead(0);
  if (Serial.available() > 0)




// you can copy/paste this code into a new Processing sketch
// Visual source code from:
// GSR source code from:

import processing.pdf.*;
import java.util.Calendar;

boolean recordPDF = false;

import processing.serial.*;
Serial myPort; 

int hPosition = 1;    
float currentReading;
float lastReading;
int count=0;
int zeroLinePos=0;

float gsrAverage,prevGsrAverage;
float baseLine=0;
long lastFlatLine=0;
int baselineTimer=10000;//10 sec
int gsrValue;
int gsrZeroCount=0;
float gsrRange=0;
int downhillCount=0;
int uphillCount=0;
boolean downhill;
boolean peaked=false;
float peak, valley;
int speed ;
int NORTH = 0;
int NORTHEAST = 1;
int EAST = 2;
int SOUTHEAST = 3;
int SOUTH = 4;
int SOUTHWEST = 5;
int WEST = 6;

float stepSize = 1;
float diameter = 1;

int direction;
float posX, posY;
int minCurrentReading = 1000;
int maxCurrentReading = 0;

void setup() {
  size(800, 800);//size of window for image
  posX = width/2;
  posY = height/2;

//find the right serial port for your computer and enter in the number inside []
  myPort = new Serial(this, Serial.list()[8], 9600);

void serialEvent (Serial myPort) {
  gsrValue=inByte;//taking value sent from Arduino

void draw() {
  println("currentReading = " + currentReading);
  // map currentReading to speed
  if (currentReading <= 50)
    currentReading = minCurrentReading; 
  } else  if (currentReading > 1000)
    currentReading = maxCurrentReading; 
  else // valid zone
  if (currentReading< minCurrentReading)
    minCurrentReading = int( currentReading);
   if (currentReading> maxCurrentReading)
    maxCurrentReading = int(currentReading);
println("currentReading = " +  currentReading + " minCurrentReading = " + minCurrentReading + " maxCurrentReading = " + maxCurrentReading);
   currentReading = map (currentReading, minCurrentReading,maxCurrentReading,10,15000);
   speed = int (currentReading);
  println("mapped value = "+  speed);
    delay(50);//delay for stability
//applying the GSR reading to drive the speed of that the organic drawing "grows"
  for (int i=0; i<=speed; i++) {
    direction = (int) random(0, 8);

    if (direction == NORTH) { 
      posY -= stepSize; 
    else if (direction == NORTHEAST) {
      posX += stepSize;
      posY -= stepSize;
    else if (direction == EAST) {
      posX += stepSize;
    else if (direction == SOUTHEAST) {
      posX += stepSize;
      posY += stepSize;
    else if (direction == SOUTH) {
      posY += stepSize;
    else if (direction == SOUTHWEST) {
      posX -= stepSize;
      posY += stepSize;
    else if (direction == WEST) {
      posX -= stepSize;
    else if (direction == NORTHWEST) {
      posX -= stepSize;
      posY -= stepSize;

    if (posX > width) posX = 0;
    if (posX < 0) posX = width;
    if (posY < 0) posY = height;
    if (posY > height) posY = 0;

    fill(0, 40);
    ellipse(posX+stepSize/2, posY+stepSize/2, diameter, diameter);
     //send 'a' for more bytes

void calculateGSR () {
  //best delay setting for gsr readings
  //image(myMovie, 0, 0);

  if (gsrValue<15 &&gsrValue>-15){ // anything between -15 and +15 is considered zero
   //if someone lifts fingers off for 10 seconds resulting in 10 0s, just reset

    if( gsrZeroCount>10){
      // println("reset");
  } // end of test for close to zero
  else{ // ggood reading

    baseLine=gsrAverage;//if we got at least 10 seconds of reading since the last flatline



int thres=7;

  if (currentReading-thres>lastReading && peaked==true){
    point(hPosition-1, height/2.0-lastReading);

  if(currentReading+thres<lastReading && peaked==false){
    point(hPosition-1, height/2.0-lastReading);

  //send 'a' for more bytes

int smooth(float data, float filterVal, float smoothedVal){
  if (filterVal > 1){      // check to make sure param's are within range
    filterVal = .99;
  else if (filterVal <= 0){
    filterVal = 0;
  smoothedVal = (data * (1 - filterVal)) + (smoothedVal  *  filterVal);
  return (int)smoothedVal;

Step 3: External Design/Enclosure (silver Box With Black Hand)

If you want to make a simple paper box enclosure for the electronics, you can look at this box template. I made the box with metallic cardboard and printed a hand mark on top so that people at the exhibition knew to place their hand on the box to start the experience. This is obviously optional and there are many ways to make sturdier enclosures.



    • Tiny Home Contest

      Tiny Home Contest
    • Water Contest

      Water Contest
    • Fix It! Contest

      Fix It! Contest

    19 Discussions

    The project is very useful . But How can we actually figure out that a person is in stress state ? The speed of growing BLACK regions is appearing to be same for multiple persons. PLZ REPLY !!!

    PLEASE HELP ME. while compiling its shows error which states " 'import' does not name a type".

    Does the electrode material effect the readings(sensitivity) sensor?

    I tried to make this without the Processing part, and code doesn't work. I have a science project due in a couple of days and I need help quick. Can you help me?

    It's really strange I have this page bookmarked on another computor which shows part two it now seems the code there for the gsr is no longer valid could you update this and kindly give more detales on how to convert the reading from a wiggally line to the dot pattern shown there and if possable provide some help to acheive Nigmans ability to randomly colour the dots.

    Is it possible to show the changing results on serial monitor for the arduino without refering back to processing ?

    The listening component is not essential. My project was set up in a loud gallery space with multiple projects surrounding it, many with audio components. I decided to try to enhance the user's experience a little by having a looping soundtrack of stressful sounds such as car horns and cell phone alarms and calming sounds like rain and classical music so that he/she could see how those sounds changed the reading.

    really thank you sir...its a great instructables...the problem of using "BYTE"for arduino is also solved by replacing it with "WRITE"............but since i m a novice....small question........

    Is it possible to do without soldering the rings on..? I understand why they're soldered on, but I'm a little limited in materials in money to get a soldering iron.

    1 reply

    I haven't tried it without soldering, but I would think if you have the metal have good contact somehow without soldering, it could work. You would just need to try it out.

    Nigman - thanks for the add! C. Wheeler - sorry I don't know anything about polaroid.

    interesting project - users who copy your code may run into an out of bound error with this line: myPort = new Serial(this, Serial.list()[8], 9600);

    changing the 8 to 0 will fix that.

    I added a void on mine to adjust the colour at each serial request to make it a little more arty (and remove some of that stress being mapped :p )

    stress art.png
    1 reply

    Could you help me please? I bought a Polaroid S7 pad. (I'm sort of computer ignorant).
    Anyway, I want to use it to download and read books offline. I've got a nook library, didn't like the nook. I can't open up my books with the Polaroid. Do you have any experience with these devices? Thanks