Difference between revisions of "Ferrofluid Art Display"

From Mech
Jump to navigationJump to search
Line 1: Line 1:
== Overview ==
== Overview ==
The goal of this project was to create an interesting display using Ferrofluid (link here), which is composed of ferrous(iron?) particles suspended in oil. The project was inspired by the work of artists such as Sachiko Kodama and Yasushi Miyajima, shown in this [http://www.youtube.com/watch?v=me5Zzm2TXh4&feature=related video] of their installation "Morpho Towers". Our display consisted of a hexagonal array of solenoids used to actuate magnets towards or away from the fluid, allowing us to control which regions were smooth and which displayed spikes (technical name?). The display could then be controlled via a user interface with the PC.
The goal of this project was to create an interesting display using [http://en.wikipedia.org/wiki/Ferrofluid Ferrofluid], which is composed of ferrimagnetic particles suspended in a carrier fluid. The project was inspired by the work of artists such as Sachiko Kodama and Yasushi Miyajima, shown in this [http://www.youtube.com/watch?v=me5Zzm2TXh4&feature=related video] of their installation "Morpho Towers". Our display consisted of a hexagonal array of solenoids used to actuate magnets towards or away from the fluid, allowing us to control which regions were smooth and which displayed spikes (technical name?). The display could then be controlled via a user interface with the PC.





Revision as of 23:09, 14 March 2010

Overview

The goal of this project was to create an interesting display using Ferrofluid, which is composed of ferrimagnetic particles suspended in a carrier fluid. The project was inspired by the work of artists such as Sachiko Kodama and Yasushi Miyajima, shown in this video of their installation "Morpho Towers". Our display consisted of a hexagonal array of solenoids used to actuate magnets towards or away from the fluid, allowing us to control which regions were smooth and which displayed spikes (technical name?). The display could then be controlled via a user interface with the PC.


Team Members

  • Todd H. Poole (Mechanical Engineering & Electrical Engineering, Class of 2010)
  • Katy Powers (Mechanical Engineering, Class of 2010)
  • Max Willer (Material Science and Engineering, Class of 2011)

Mechanical Design

Todd An evolution of concepts. -Early sketches --Pros & Cons Decision of

Electrical Design

Max

Code

The code for the display setup consists of a GUI on the PC allowing the user to select which solenoids to turn on and off and code on the PIC to control the solenoids.

Processing

Screenshot of User Interface. Green circles represent solenoids that are up while blue circles represent solenoids that are down.

The PC side of the user interface was created with Processing, an open source programming environment with many options for interesting visual display. This code creates a display of circles arranged in the same way as the solenoids in our hardware, which will change from blue to green when clicked and output a character via RS232 to the PIC.

//Katy Powers
//3/11/2010
//ME 333 Ferrofluid Art GUI
//Lots of code taken from processing website and previous ME 333 labs..thanks!

// add the serial library
import processing.serial.*; 
Serial[] myPorts = new Serial[1];

//setup parameters for hexagonal array
//cx,cy define center position, rc is circle radius, sp is how far apart they are
int cx = 250;
int cy = 250;
int rc = 50;
int sp = 10;


//circleX and circleY store center locations of every circle in array
//solenoidON stores state of solenoid
//chararr stores characters corresponding to each solenoid
int[] circleX = {cx, cx + rc + sp,cx + 2*(rc + sp),cx - (rc + sp),cx - 2*(rc + sp),cx + rc/2 + sp/2,
cx + 3*rc/2 + 3*sp/2,cx - (rc/2 + sp/2),cx - (3*rc/2 + 3*sp/2),cx,cx+rc+sp, cx - (rc+sp),
cx + rc/2 + sp/2, cx + 3*rc/2 + 3*sp/2,cx - (rc/2 + sp/2),cx - (3*rc/2 + 3*sp/2),cx, 
cx + rc + sp,cx-(rc + sp)};

int[] circleY = {cy,cy,cy,cy,cy,cy + rc +sp,cy + rc +sp,cy + rc +sp,cy + rc +sp,cy + 2*(rc+sp),
cy + 2*(rc+sp), cy + 2*(rc+sp),cy - (rc +sp),cy - (rc +sp),cy - (rc +sp),cy - (rc +sp),
cy - 2*(rc+sp),cy - 2*(rc+sp),cy - 2*(rc+sp)};

int[] solenoidON = new int[19];
char[] chararr = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s'};
PFont font;
PFont smallfont;


void setup()
{
InitSerial();
background(0);
font = loadFont("FangSong-48.vlw");
smallfont = loadFont("FangSong-16.vlw");
size(500,500);
textAlign(CENTER);
for (int i = 0; i < 19; i = i+1){ //zero array of solenoid values, mouse state data
  solenoidON[i] = 0;
}
rectMode(CENTER);
}

void draw()
{
  fill(0,0,255);
  textFont(font, 48);
  text("Ferrofluid Art", cx, cy-200);
  textFont(smallfont, 16);
  text("Click a circle to make patterns in the Ferrofluid", cx, cy + 200);
  hexagon(cx,cy,rc,sp, solenoidON);
    
} 

void hexagon(int cx, int cy, int rc, int sp, int[] sols) //draws hexagon of cirlces
{
for (int i = 0; i < 19; i = i+1){
  if(sols[i] == 0) {fill(0,0,255);}
  else {fill(0,255,0);}
  ellipse(circleX[i], circleY[i], rc, rc);
} 

}

void mousePressed() //executes when mouse is pressed, much like an interrupt routine
{
  float disX, disY;
  for (int i = 0; i < 19; i = i+1){ //see where mouse is
    disX = circleX[i] - mouseX;
    disY = circleY[i] - mouseY;
    if(sqrt(sq(disX) + sq(disY)) < rc/2 ) { //if mouse is in circle, toggle state and send character
      solenoidON[i] = 1 - solenoidON[i];
      myPorts[0].write(chararr[i]);
      println(chararr[i]); //to debug
       }   
    } 
}

PIC

The PIC side of the code runs an infinite while loop, executing an interrupt routine every time a character is received from the RS232. The PIC then updates the state of all the solenoids.

/**Ferrofluid Art Project Code**********************************/
/* Katy Powers Winter 2010 */	 

/** INCLUDES ***************************************************/
#include "HardwareProfile.h"
#include "LCD.h" //needed for Delayms
 
/** Constants **************************************************/ 
 
#define TRUE 		1
#define FALSE		0

#define ENABLE1 LATDbits.LATD1 //Enable pins for H bridge circuit
#define ENABLE2 LATDbits.LATD2
#define OUT1   LATBbits.LATB11 //Output pins for solenoid control
#define OUT2   LATBbits.LATB10
#define OUT3   LATBbits.LATB9
#define OUT4   LATBbits.LATB8 
#define OUT5   LATAbits.LATA10
#define OUT6   LATAbits.LATA9
#define OUT7   LATBbits.LATB7
#define OUT8   LATBbits.LATB6
#define OUT9   LATBbits.LATB0
#define OUT10  LATBbits.LATB1 
#define OUT11  LATBbits.LATB2
#define OUT12  LATBbits.LATB3
#define OUT13  LATBbits.LATB5 
#define OUT14  LATEbits.LATE9
#define OUT15  LATEbits.LATE8
#define OUT16  LATGbits.LATG9 
#define OUT17  LATGbits.LATG8
#define OUT18  LATGbits.LATG7
#define OUT19  LATGbits.LATG6 

#define DESIRED_BAUDRATE    	(19200)      // The desired BaudRate 
 

/** Function Declarations **************************************/
void initInterruptController();

void initUART2(int pbClk);

void sendDataRS232(void);

void setSols(void); //sets solenoids on and off depending on global variable sols

/** Global Variables *******************************************/

int sols[19]; //vector to store if solenoids are on or off	

/** Main Function **********************************************/

int main(void)
{
	int	pbClk;
	int i;
	// Configure the proper PB frequency and the number of wait states
	pbClk = SYSTEMConfigPerformance(SYS_FREQ);
	AD1PCFG = 0xFFFF; //this line sets up the B bits as digital outputs

	TRISAbits.TRISA10 = 0; //set all solenoid and enable output pins to output
	TRISAbits.TRISA9 = 0;
	TRISBbits.TRISB11 = 0;
	TRISBbits.TRISB10 = 0;	
	TRISBbits.TRISB9 = 0;
	TRISBbits.TRISB8 = 0;
	TRISBbits.TRISB7 = 0;
	TRISBbits.TRISB6 = 0;	
	TRISBbits.TRISB5 = 0;
	TRISBbits.TRISB3 = 0;
	TRISBbits.TRISB2 = 0;
	TRISBbits.TRISB1 = 0;	
	TRISEbits.TRISE9 = 0;
	TRISEbits.TRISE8 = 0;
	TRISGbits.TRISG8 = 0;
	TRISGbits.TRISG7 = 0;	
	TRISGbits.TRISG6 = 0;
	TRISBbits.TRISB0 = 0;
	TRISGbits.TRISG9 = 0;
	TRISDbits.TRISD1 = 0;
	TRISDbits.TRISD2 = 0;

	OUT1 = 0; //initialize outputs to low
	OUT2 = 0;
    	OUT3 = 0;
	OUT4 = 0;
        OUT5 = 0;
	OUT6 = 0;
        OUT7 = 0;
	OUT8 = 0;
	OUT9 = 0;
	OUT10 = 0;
	OUT11 = 0;
	OUT12 = 0;
    	OUT13 = 0;
	OUT14 = 0;
	OUT15 = 0;
	OUT16 = 0;
        OUT17 = 0;
	OUT18 = 0;
	OUT19 = 0;

	//also initialize sols array to 0
	for(i = 0; i < 19; i++){
	sols[i] = 0;
	}
	setSols(); //this is probably redundant
		
	mInitAllLEDs();
		
		
	initUART2(pbClk);
	INTEnableSystemMultiVectoredInt();

	while(1)
	{
	  1;//just keep going and wait for interrupts from RS232
	} //end main

} 
/** Interrupt Handlers *****************************************/
		 
void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void)
{
	int i;
       unsigned char data2; //store character received from PC
	char chararr[19] =  {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s'}; //array of characters for comparison
	// Is this an RX interrupt?
	if(mU2RXGetIntFlag())
	{
		// Clear the RX interrupt Flag
	    mU2RXClearIntFlag();

		data2 = ReadUART2(); //get character

		// Toggle LED to indicate UART activity
		mLED_1_Toggle();

		for(i = 0; i<19; i++){
		if (data2 ==(int) chararr[i]){ sols[i] = 1 - sols[i];} //toggle solenoid  corresponding to character received
		}
		setSols(); //update all solenoids

	}

	// We don't care about TX interrupt
	if ( mU2TXGetIntFlag() )
	{
		mU2TXClearIntFlag();
	}
} 


/** Other Functions ********************************************/

void initUART2(int pbClk)
{
	 // define setup Configuration 1 for OpenUARTx
		// Module Enable 
		// Work in IDLE mode 
		// Communication through usual pins 
		// Disable wake-up 
		// Loop back disabled 
		// Input to Capture module from ICx pin 
		// no parity 8 bit 
		// 1 stop bit 
		// IRDA encoder and decoder disabled 
		// CTS and RTS pins are disabled 
		// UxRX idle state is '1' 
		// 16x baud clock - normal speed
	#define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE |  UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN
 	 
 	 // define setup Configuration 2 for OpenUARTx
		// IrDA encoded UxTX idle state is '0'
		// Enable UxRX pin
		// Enable UxTX pin
		// Interrupt on transfer of every character to TSR 
		// Interrupt on every char received
		// Disable 9-bit address detect
		// Rx Buffer Over run status bit clear
	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE |  UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	
 
	// Open UART2 with config1 and config2
	OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD  generate value.
  		
	// Configure UART2 RX Interrupt with priority 2
	ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);
}

void setSols(){
	OUT1 = sols[0]; //set all outputs to correct value
	OUT2 = sols[1];
	OUT3 = sols[2];
	OUT4 = sols[3];
	OUT5 = sols[4];
	OUT6 = sols[5];
	OUT7 = sols[6];
	OUT8 = sols[7];
	OUT9 = sols[8];
	OUT10 = sols[9];
	OUT11 = sols[10];
	OUT12 = sols[11];
	OUT13 = sols[12];
	OUT14 = sols[13];
	OUT15 = sols[14];
	OUT16 = sols[15];
	OUT17 = sols[16];
	OUT18 = sols[17];
	OUT19 = sols[18];
	ENABLE1 = 1; //turn on enable pins
	ENABLE2 = 1;
	Delayms(500); //wait for half a second for solenoids to change position
	ENABLE1 = 0; //turn off enable pins
	ENABLE2 = 0;
}

Results

Max

Reflections

Todd