User login

Powered by Drupal, an open source content management system

Theory and Practice of Tangible User Interfaces

Sensing 2: Programming + Mechanical- Virtual "Etch-iSketch"

Submitted by Michael Manoochehri on Wed, 10/01/2008 - 22:18

Assignment: Sensing PART II: Force sensors and photocells

Collaborators:

Etch-iSketch

Example Etch-iSketch ArduinoDescription:

After playing with 2 potentiometers, I felt compelled to create a virtual Etch-A-Sketch type program using the Processing programming environment. The program takes values corresponding to resistances from the Arduino board, and translates those to coordinates on the screen. The circuit setup is simple - two variable resistors, one controls vertical coordinates, and the other controls horizontal. A Force Sensitive Resistor controls the color of the Etch-iSketch, the softer one presses, the "redder" the color, and the harder one presses, the "bluer" the color gets.


Components List:

  • Potentiometer X 2
  • Force Sensitive Resistor
  • Photocell
  • LED
  • 220 Ohm Resistor
  • 10k Ohm Resistor X 2
  • Arduino board
  • 12 Wires
  • Power came from computer via USB Cable

Notes:

The circuitry of the board is very simple - two potentiometers, a photocell and an FSR attached to the analog inputs of the Arduino board. The pseudo Etch-a-Sketch style of the program window was created by drawing one red 500 X 412 rectangle, and then one 360 X 262 gray rectangle in the center of the larger one. The drawing output is limited to the area in the grey rectangle. Activating the photocell causes the screen to clear.

I took the potentiometer resistances and divided them by 2 to keep them roughly in the 0 to 500 range (which is the size of my program's window). Since Processing can only read input from the serial port one character at a time, resistance values from the four inputs must be output in some delimited way. I decided to output the resistance data to the serial port in this form: "x-cord,y-cord,colortoggle,clearscreen,|" I used the "|" (pipe) character as an "end of line" character. Note: I added a second comma after the "clearscreen," otherwise, I could not get the Processing environment to properly split the coordinates into an array.

The FSR sends values roughly between 0 to 1000 (but I limit it to about 750 in software.) If the FSR is pressed softly, it makes the Etch-iSketch draw red, but if one presses harder, it turns green, and then blue.

Future Work:

It would be great to make the system actually look like more like a real Etch-a-Sketch, with a shake function, wheels that move when the pots move, etc. Maybe even a "save" your image function!

Etch iSketch Screenshot

Java builds for this assignment for Linux/Mac/Win can be found in this zip file (1.5 MB).

Code used in this Assignment:

Arduino Code:

/*
*  Virtual Psuedo Etch-a-Sketch
*  Etch-a-Sketch AnalogInput
*
* Pot 1: UP and DOWN
* Pot 2: LEFT and RIGHT
*
* version 0.2
* October 1, 2008
*/

// Analog pin settings
int aIn = 0;    // Potentiometers connected to analog pins 0, 1, and 2
int bIn = 1;    //   (Connect power to 5V and ground to analog ground)
int cIn = 2;
int dIn = 3;

// Digital pin settings
// YOU CAN USE THESE FOR SOME KIND OF VISUAL OUTPUT ON THE BOARD
int aOut = 9;   // LEDs connected to digital pins 9, 10 and 11
int bOut = 10;  //   (Connect cathodes to digital ground)


// Values
int aVal = 0;   // Variables to store the input from the potentiometers
int bVal = 0; 
int cVal = 0;
int dVal = 0;


// Variables for comparing values between loops
int i = 0;            // Loop counter
int wait = (100);    // Delay between most recent pot adjustment and output

int checkSum     = 0; // Aggregate pot values
int prevCheckSum = 0;
int sens         = 3; // Sensitivity theshold, to prevent small changes in
// pot values from triggering false reporting

// FLAGS
int PRINT = 0; // Set to 1 to output values
int DEBUG = 0; // Set to 1 to turn on debugging output

void setup() {
pinMode(aOut, OUTPUT);   // sets the digital pins as output
pinMode(bOut, OUTPUT);  
Serial.begin(9600);     // Open serial communication for reporting

}


void loop()
{
  i += 1; // Count loop
  aVal = analogRead(aIn) / 2;  // read input pins, convert to 0-500 scale

  // Set the minimum amount of "A" to 70
  if (aVal < 70) {
    aVal = 70;
  }

  // Set the maximum amount of "A" to 430
  if (aVal > 430) {
    aVal = 430;
  }

  // Reads Potentiometer 2
  bVal = analogRead(bIn) / 2;

  // Set the minimum amount of "B" to 70
  if (bVal < 70) {
    bVal = 70;
  }

  // Set the maximum amount of "B" to 332
  if (bVal > 332) {
    bVal = 332;
  }

  // Reads the FSR
  cVal = analogRead(cIn);

  if (cVal > 750) {
    cVal = 750;
  }


  // Reads PHOTOCELL
  dVal = analogRead(dIn);
  if (dVal < 30) {
    analogWrite(aOut, 100); 
  } else {
    analogWrite(aOut, 0);   
  }
  

  Serial.print(aVal);
  Serial.print(",");
  Serial.print(bVal);
  Serial.print(",");
  Serial.print(cVal);
  Serial.print(",");
  Serial.print(dVal);
  Serial.println(",|");




  if (i % wait == 0)                // If enough time has passed...
  {   
    checkSum = aVal+bVal+cVal;      // ...add up the 3 values.
    if ( abs(checkSum - prevCheckSum) > sens )   // If old and new values differ
    // above sensitivity threshold
    {
      if (PRINT)  // ...and if the PRINT flag is set...
      {
       Serial.print("horizontal: ");        // ...then print the values.
       Serial.print(aVal);        
       Serial.print("\t");
       Serial.print("vertical: ");       
       Serial.print(bVal);
       Serial.print("\t");
       PRINT = 0;
      }
     } 
   else
   {
    PRINT = 1;  // Re-set the flag  
   }
   prevCheckSum = checkSum;  // Update the values

   if (DEBUG)   // If we want debugging output as well...
   {
     Serial.print(checkSum);
     Serial.print("<=>");
     Serial.print(prevCheckSum);
     Serial.print("\tPrint: ");
     Serial.println(PRINT);
   }
  }
}

 

Processing Code:

/*
 * Virtual Psuedo Etch-a-Sketch
 * Using the Processing Programming Environment
 *
 * Michael Manoochehri
 *
 * version 0.2
 * October 1, 2008
 *
 */

// Import processing serial library
import processing.serial.*;

// Change this to the USB Port your Arduino board
// On Linux it's usually ttyUSB0, ttyUSB1, ttyUSB2 etc...
String portname = "/dev/ttyUSB0";

Serial port; // Variable to hold the serial object
String buf="";
int var1 = 250; // Set to a value for a starting point (x-coordinate)
int var2 = 200; // Set to a value for a starting point (y-coordinate)
int var3 = 0; // Does the system draw or not?
int var4 = 200; // If this dips below 30 erase the screen!
int drawcolor = 0; // What color is the drawing?

void setup() {
  size(500,412); //Size of the program window...
  frameRate(15);
  smooth();


  // Draw the initial Red background 
  // (RGB values R:187, B:0, G:0)
  // Taken from Etch a Sketch jpeg from web!
  fill(187,0,0);
  beginShape();
  vertex(0, 0);
  vertex(500, 0);
  vertex(500, 412);
  vertex(0, 412);
  endShape(CLOSE);
  
  PImage b;
  b = loadImage("header.gif");
  image(b, 50, 5);
  
  // Draw the center grey drawing surface 
  // (RGB values R:228, B:228, G:228)
  // Taken from Etch a Sketch jpeg from web!
  fill(228,228,228);
  beginShape();

  vertex(70, 70);
  vertex(430, 70);
  vertex(430, 332);
  vertex(70, 332);
  endShape(CLOSE);

  // Set the port object to 9600 baud
  port = new Serial(this, portname, 9600);
  
  // Sets the point drawing color to BLACK
  stroke(drawcolor);
}



// I don't know if I really need this function or not
void draw() {
}


// Serial Event function:
// called whenever serial data arrives
//read the message in Processing
void serialEvent(Serial p){
  
String myString = port.readStringUntil(124); //the ascii value of the "|" character 
  if(myString != null ){
    
    // This splits the string on commas into the inputs[] array
    myString = trim(myString);
    int inputs[] = int(split(myString, ','));

   // Set the x-coord value
   var1 = inputs[0];

   // Set the y-coord value
   var2 = inputs[1];

   // Set the drawcolor toggle value
   var3 = inputs[2];

   // Set the erase toggle value
   var4 = inputs[3];
   
   if (var4 < 30) {
     // Redraw the center rectangle
     fill(228,228,228);
     beginShape();
     vertex(70, 70);
     vertex(430, 70);
     vertex(430, 332);
     vertex(70, 332);
     endShape(CLOSE);
   }
   

   if (var3 < 50) {
     
     if (drawcolor > 0) {
        drawcolor = 0; 
        stroke(drawcolor);
     }
     
     // Place a point at the (x,y) coordinate...
     point(var1, var2);
   } else {
     if (var3 < 255) {
       drawcolor = var3;
       stroke(drawcolor,0,0);
       print("red: "); 
       println(drawcolor); 
      } 
      
      if (var3 > 255 && var3 < 510) {
       drawcolor = var3 - 254;
       stroke(0,round(drawcolor),0);
       print("green: "); 
       println(drawcolor); 
      }
     
      if (var3 > 510) {
       drawcolor = var3 - 509;
       stroke(0,0,round(drawcolor));  
       print("blue: "); 
       println(drawcolor); 
      }
      
     // Draw the pixel 
     point(var1, var2);
   }
  
   // Print the coordinate to std out 
   // to make sure it is getting the values properly
   print(var1);
   print(",");
   print(var2);
   print(",");
   print(var3);
   print(",");
   println(var4);
  } 
}