Difference between revisions of "PPOD-mini Project"

From Mech
Jump to navigationJump to search
Line 76: Line 76:
output_high(SS_PIN); //deselect the slave.
output_high(SS_PIN); //deselect the slave.
}
}

#INT_EXT
#INT_EXT
void INT0isr() { //Interrupt routine is called when Pin RB0 goes from low to high
void INT0isr() { //Interrupt routine is called when Pin RB0 goes from low to high
Line 95: Line 95:
{
{
case 0:
case 0:
mode_name = mode1;
mode_name = mode1; //LCD displays 12 digits in the top row,
//the phases and amplitudes, and then the
printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s _a[3],s_a[4],s_a[5],mode_name); //LCD displays 12 digits in the top row,
delay_ms(50); //the phases and amplitudes, and then the
//name of the pattern in the 2nd row
printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s _a[3],s_a[4],s_a[5],mode_name);
break; name of the pattern in the 2nd row
delay_ms(50);
break;
case 1:
case 1:
mode_name = mode2;
mode_name = mode2;

Revision as of 07:10, 15 June 2009

Overview

The goal of this project was to create a miniature, simplified version of the PPOD (Programmable Part-feeding Oscillatory Device) that is currently in the Laboratory for Intelligent Mechanical Systems. This smaller model needed to be easily transportable so that it could be taken to various locations and shown to different groups. The PPOD is a device that is able to manipulate parts placed on it by creating a velocity field that is dependent on the phases and amplitudes of the speakers that are connected to the platform. More information on the original PPOD and related research can be found at the LIMS website.

Physical Construction

Base

The base for the PPOD-mini is constructed out of acrylic sheets that are approximately 0.22" thick. Each section was designed in AutoCad and then transferred to the Laser cutter to be created. The sections were designed with a jigsaw pattern on the edges so they would fit together tightly and could be placed exactly where desired. The dimension of the base are 10" x 10" x 3.5". The goal was to keep it as small as possible while still making it functional, this width was required to fit all of the speakers and the height was necessary for the power supplies to fit in the enclosed space.

Speaker Mounts

Six speaker mounts were designed to hold the speakers. They were designed to take up the least amount of space possible while still being stable enough to hold a vibrating speaker for an extended period of time. They were designed similarly to the base, with interlocking acrylic pieces made on the laser cutter and then joined together with a chemical bonding agent. A dimensioned drawing for these pieces is shown on the right.

Speakers

The speakers used currently are Jameco 8 ohm speakers, measuring approximately two inches in diameter. When a 5 volt signal is applied these speakers produce 3.125 watts of power. They are secured into the speakers mounts with epoxy. The flexure attachments are epoxied into the center of the speakers and the flexures are held in place by a set screw which is holding on to a threaded rod that runs into the flexure. These flexures are then attached to the platform with is eight inches across and also made of acrylic. All of the drawing files for these parts can be downloaded at File:PPOD drawing files.zip.

Circuit

Each speaker is driven by a combination of four op-amps and a pair of transistors. We used ------- because each chip has four separate op-amps and they are able to go rail to rail which simplified our power supply setup. We used two +5V power supplies in series in order to get +/- 5V for the circuit. We are also using a digital potentiometer ------------- so we can instantly change the amplitude of each speaker individually. The circuit diagram is shown to the right. To adjust the setting you press the red button, then using the knob you choose one of three preset patterns or Custom to choose your own phases and amplitudes. If "custom" is chosen you can choose one of 16 settings for the phase and amplitude for each speaker.

PIC Code

The following is the PIC code used to control the PPOD-mini with comments.

#include <18f4520.h>  

#DEVICE ADC=8

#fuses EC,NOLVP,NOWDT,NOPROTECT
#use delay(clock=20000000)
#include "flex_lcd.c"  //Need to have this file in the same folder.

//These define the different SPI modes in terms of constants the compiler knows about
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)

#define SS_PIN PIN_B1         //this can be any output pin on the master

#DEFINE VAR_POT1 0            //Constants we defined to set digital potentiometers
#DEFINE VAR_POT2 1
#DEFINE VAR_POT3 2
#DEFINE VAR_POT4 3
#DEFINE VAR_POT5 4
#DEFINE VAR_POT6 5


int32 frequency = 50;        //Set speaker frequency in hertz.
int32 delays;
int8 s_p[6]={0,0,0,0,0,0};              //Array that will hold the phase of each speaker
int8 s_a[6]={15,15,15,15,15,15};        //Array that holds amplitude of each speaker
char * mode1 = "Custom";
char * mode2 = "Preset1";               //Names can be changed to fit whatever pattern you find
char * mode3 = "Preset2";
char * mode4 = "Preset3";
char mode_name; 

    int speaker;
    int phase;
    int amplitude;
    int mode;
    
    int i;

void setup(void)                       //Digital potentiometer setup
{
   output_high(SS_PIN);   

   setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_4);
}  
    


void set_var_pot(int channel, int value)    //Function to set resistance value on the digital potentiometer

{
   output_low(SS_PIN);                                        //pull the slave select line low to select the slave  
   spi_write((int8)((channel<<1)|((value>>7)&1)));            //This was necessary to make it work properly
   delay_us(1);                                              //Necessary delay to allow for communication
   spi_write((int8)(value<<1)); 

   output_high(SS_PIN);                                        //deselect the slave.
}

#INT_EXT
void INT0isr() {             //Interrupt routine is called when Pin RB0 goes from low to high
                             //which occurs when the red button is pressed and released
    
    setup_adc_ports(AN0_ANALOG);
    setup_adc( ADC_CLOCK_INTERNAL );
    set_adc_channel(0);     // there's only one ADC so select which input to connect to it; here pin AN0
    delay_ms(1000);
       
    while(!input(PIN_B0))
    {
      mode = read_adc();
      
      mode = mode >> 6;
      
      switch(mode)                                                                     //Chooses which pattern you want
      {
         case 0:
            mode_name = mode1;              //LCD displays 12 digits in the top row,
                                            //the phases and amplitudes, and then the
                                            //name of the pattern in the 2nd row
            printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s _a[3],s_a[4],s_a[5],mode_name); 
            delay_ms(50);                                                                             
            break;                                                                                    
         case 1:
            mode_name = mode2;
            printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
            delay_ms(50);
            break;
         case 2:
            mode_name = mode3;
            printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
            delay_ms(50);
            break;
         
         case 3:
            mode_name = mode4;
            printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
            delay_ms(50);
            break;
         
         default:
            printf(lcd_putc,"\n\fERROR");
            delay_ms(50);
            break;
      }
    }   
    delay_ms(1000);
    
    switch(mode)                       //Setting values for custom pattern
    {
      case 0:
         for(i=0; i<6; i++)
         {
            while(!input(PIN_B0))
            {
               speaker = i;
               phase = read_adc();
               phase = phase>>4;
               s_p[speaker]=phase;
               printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
               delay_ms(50);
            }
            delay_ms(1000);
         }
    
         for(i=0; i<6; i++)
         {
            while(!input(PIN_B0))
            {
               speaker = i;
               amplitude = read_adc();
               amplitude = amplitude>>4;
               s_a[speaker]=amplitude;
               printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
               delay_ms(50);
            }
            delay_ms(1000);
         }
         break;
      case 1:                    //Custom patterns: You should change these value to suit your needs
         s_p[0]=0;
         s_p[1]=0;
         s_p[2]=0;
         s_p[3]=0;
         s_p[4]=0;
         s_p[5]=0;
         s_a[0]=8;
         s_a[1]=8;
         s_a[2]=8;
         s_a[3]=8;
         s_a[4]=8;
         s_a[5]=8; 
         break;
      case 2:
         s_p[0]=0;
         s_p[1]=0;
         s_p[2]=0;
         s_p[3]=0;
         s_p[4]=0;
         s_p[5]=0;
         s_a[0]=8;
         s_a[1]=8;
         s_a[2]=8;
         s_a[3]=8;
         s_a[4]=8;
         s_a[5]=8;
         break;
      case 3:
         s_p[0]=0;
         s_p[1]=0;
         s_p[2]=0;
         s_p[3]=0;
         s_p[4]=0;
         s_p[5]=0;
         s_a[0]=8;
         s_a[1]=8;
         s_a[2]=8;
         s_a[3]=8;
         s_a[4]=8;
         s_a[5]=8;
         break;
      default:
         printf(lcd_putc,"ERROR");
         delay_ms(50);
    }
    
      
   set_var_pot(VAR_POT1,s_a[0]<<4);      //Set resistors to determined values
   delay_ms(10);
   set_var_pot(VAR_POT2,s_a[1]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT3,s_a[2]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT4,s_a[3]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT5,s_a[4]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT6,s_a[5]<<4);
   delay_ms(10);
    
}   
 




void main()
{
   enable_interrupts(INT_EXT);        //Enables external interrupts
   enable_interrupts(GLOBAL); 
   ext_int_edge(0, L_TO_H);           //Sets external interrupt to trigger when RB0 goes from low to high
   
   lcd_init();                        

   delays = 62500/frequency;          //This delay time corresponds to a 22.5 degree phase shift (360/16)
   //ground = input(PIN_E0);
   
   setup();
   set_var_pot(VAR_POT1,s_a[0]<<4);   //Set resistor values
   delay_ms(10);
    set_var_pot(VAR_POT2,s_a[1]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT3,s_a[2]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT4,s_a[3]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT5,s_a[4]<<4);
   delay_ms(10);
   set_var_pot(VAR_POT6,s_a[5]<<4);
   delay_ms(10);
   
   mode_name = mode1;
   
   while(true)
   {
      if(s_p[0]==0)output_high(PIN_A1);  //Sets speakers high or low depending on phase, always running except when the 
      if(s_p[1]==0)output_high(PIN_A2);  //interrupt is called.
      if(s_p[2]==0)output_high(PIN_A3);
      if(s_p[3]==0)output_high(PIN_A4);
      if(s_p[4]==0)output_high(PIN_A5);
      if(s_p[5]==0)output_high(PIN_E0);
      if(s_p[0]==8)output_low(PIN_A1);
      if(s_p[1]==8)output_low(PIN_A2);
      if(s_p[2]==8)output_low(PIN_A3);
      if(s_p[3]==8)output_low(PIN_A4);
      if(s_p[4]==8)output_low(PIN_A5);
      if(s_p[5]==8)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==1)output_high(PIN_A1);
      if(s_p[1]==1)output_high(PIN_A2);
      if(s_p[2]==1)output_high(PIN_A3);
      if(s_p[3]==1)output_high(PIN_A4);
      if(s_p[4]==1)output_high(PIN_A5);
      if(s_p[5]==1)output_high(PIN_E0);
      if(s_p[0]==9)output_low(PIN_A1);
      if(s_p[1]==9)output_low(PIN_A2);
      if(s_p[2]==9)output_low(PIN_A3);
      if(s_p[3]==9)output_low(PIN_A4);
      if(s_p[4]==9)output_low(PIN_A5);
      if(s_p[5]==9)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==2)output_high(PIN_A1);
      if(s_p[1]==2)output_high(PIN_A2);
      if(s_p[2]==2)output_high(PIN_A3);
      if(s_p[3]==2)output_high(PIN_A4);
      if(s_p[4]==2)output_high(PIN_A5);
      if(s_p[5]==2)output_high(PIN_E0);
      if(s_p[0]==10)output_low(PIN_A1);
      if(s_p[1]==10)output_low(PIN_A2);
      if(s_p[2]==10)output_low(PIN_A3);
      if(s_p[3]==10)output_low(PIN_A4);
      if(s_p[4]==10)output_low(PIN_A5);
      if(s_p[5]==10)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==3)output_high(PIN_A1);
      if(s_p[1]==3)output_high(PIN_A2);
      if(s_p[2]==3)output_high(PIN_A3);
      if(s_p[3]==3)output_high(PIN_A4);
      if(s_p[4]==3)output_high(PIN_A5);
      if(s_p[5]==3)output_high(PIN_E0);
      if(s_p[0]==11)output_low(PIN_A1);
      if(s_p[1]==11)output_low(PIN_A2);
      if(s_p[2]==11)output_low(PIN_A3);
      if(s_p[3]==11)output_low(PIN_A4);
      if(s_p[4]==11)output_low(PIN_A5);
      if(s_p[5]==11)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==4)output_high(PIN_A1);
      if(s_p[1]==4)output_high(PIN_A2);
      if(s_p[2]==4)output_high(PIN_A3);
      if(s_p[3]==4)output_high(PIN_A4);
      if(s_p[4]==4)output_high(PIN_A5);
      if(s_p[5]==4)output_high(PIN_E0);
      if(s_p[0]==12)output_low(PIN_A1);
      if(s_p[1]==12)output_low(PIN_A2);
      if(s_p[2]==12)output_low(PIN_A3);
      if(s_p[3]==12)output_low(PIN_A4);
      if(s_p[4]==12)output_low(PIN_A5);
      if(s_p[5]==12)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==5)output_high(PIN_A1);
      if(s_p[1]==5)output_high(PIN_A2);
      if(s_p[2]==5)output_high(PIN_A3);
      if(s_p[3]==5)output_high(PIN_A4);
      if(s_p[4]==5)output_high(PIN_A5);
      if(s_p[5]==5)output_high(PIN_E0);
      if(s_p[0]==13)output_low(PIN_A1);
      if(s_p[1]==13)output_low(PIN_A2);
      if(s_p[2]==13)output_low(PIN_A3);
      if(s_p[3]==13)output_low(PIN_A4);
      if(s_p[4]==13)output_low(PIN_A5);
      if(s_p[5]==13)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==6)output_high(PIN_A1);
      if(s_p[1]==6)output_high(PIN_A2);
      if(s_p[2]==6)output_high(PIN_A3);
      if(s_p[3]==6)output_high(PIN_A4);
      if(s_p[4]==6)output_high(PIN_A5);
      if(s_p[5]==6)output_high(PIN_E0);
      if(s_p[0]==14)output_low(PIN_A1);
      if(s_p[1]==14)output_low(PIN_A2);
      if(s_p[2]==14)output_low(PIN_A3);
      if(s_p[3]==14)output_low(PIN_A4);
      if(s_p[4]==14)output_low(PIN_A5);
      if(s_p[5]==14)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==7)output_high(PIN_A1);
      if(s_p[1]==7)output_high(PIN_A2);
      if(s_p[2]==7)output_high(PIN_A3);
      if(s_p[3]==7)output_high(PIN_A4);
      if(s_p[4]==7)output_high(PIN_A5);
      if(s_p[5]==7)output_high(PIN_E0);
      if(s_p[0]==15)output_low(PIN_A1);
      if(s_p[1]==15)output_low(PIN_A2);
      if(s_p[2]==15)output_low(PIN_A3);
      if(s_p[3]==15)output_low(PIN_A4);
      if(s_p[4]==15)output_low(PIN_A5);
      if(s_p[5]==15)output_low(PIN_E0);
      
      delay_us(delays);
       
      if(s_p[0]==8)output_high(PIN_A1);
      if(s_p[1]==8)output_high(PIN_A2);
      if(s_p[2]==8)output_high(PIN_A3);
      if(s_p[3]==8)output_high(PIN_A4);
      if(s_p[4]==8)output_high(PIN_A5);
      if(s_p[5]==8)output_high(PIN_E0);
      if(s_p[0]==0)output_low(PIN_A1);
      if(s_p[1]==0)output_low(PIN_A2);
      if(s_p[2]==0)output_low(PIN_A3);
      if(s_p[3]==0)output_low(PIN_A4);
      if(s_p[4]==0)output_low(PIN_A5);
      if(s_p[5]==0)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==9)output_high(PIN_A1);
      if(s_p[1]==9)output_high(PIN_A2);
      if(s_p[2]==9)output_high(PIN_A3);
      if(s_p[3]==9)output_high(PIN_A4);
      if(s_p[4]==9)output_high(PIN_A5);
      if(s_p[5]==9)output_high(PIN_E0);
      if(s_p[0]==1)output_low(PIN_A1);
      if(s_p[1]==1)output_low(PIN_A2);
      if(s_p[2]==1)output_low(PIN_A3);
      if(s_p[3]==1)output_low(PIN_A4);
      if(s_p[4]==1)output_low(PIN_A5);
      if(s_p[5]==1)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==10)output_high(PIN_A1);
      if(s_p[1]==10)output_high(PIN_A2);
      if(s_p[2]==10)output_high(PIN_A3);
      if(s_p[3]==10)output_high(PIN_A4);
      if(s_p[4]==10)output_high(PIN_A5);
      if(s_p[5]==10)output_high(PIN_E0);
      if(s_p[0]==2)output_low(PIN_A1);
      if(s_p[1]==2)output_low(PIN_A2);
      if(s_p[2]==2)output_low(PIN_A3);
      if(s_p[3]==2)output_low(PIN_A4);
      if(s_p[4]==2)output_low(PIN_A5);
      if(s_p[5]==2)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==11)output_high(PIN_A1);
      if(s_p[1]==11)output_high(PIN_A2);
      if(s_p[2]==11)output_high(PIN_A3);
      if(s_p[3]==11)output_high(PIN_A4);
      if(s_p[4]==11)output_high(PIN_A5);
      if(s_p[5]==11)output_high(PIN_E0);
      if(s_p[0]==3)output_low(PIN_A1);
      if(s_p[1]==3)output_low(PIN_A2);
      if(s_p[2]==3)output_low(PIN_A3);
      if(s_p[3]==3)output_low(PIN_A4);
      if(s_p[4]==3)output_low(PIN_A5);
      if(s_p[5]==3)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==12)output_high(PIN_A1);
      if(s_p[1]==12)output_high(PIN_A2);
      if(s_p[2]==12)output_high(PIN_A3);
      if(s_p[3]==12)output_high(PIN_A4);
      if(s_p[4]==12)output_high(PIN_A5);
      if(s_p[5]==12)output_high(PIN_E0);
      if(s_p[0]==4)output_low(PIN_A1);
      if(s_p[1]==4)output_low(PIN_A2);
      if(s_p[2]==4)output_low(PIN_A3);
      if(s_p[3]==4)output_low(PIN_A4);
      if(s_p[4]==4)output_low(PIN_A5);
      if(s_p[5]==4)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==13)output_high(PIN_A1);
      if(s_p[1]==13)output_high(PIN_A2);
      if(s_p[2]==13)output_high(PIN_A3);
      if(s_p[3]==13)output_high(PIN_A4);
      if(s_p[4]==13)output_high(PIN_A5);
      if(s_p[5]==13)output_high(PIN_E0);
      if(s_p[0]==5)output_low(PIN_A1);
      if(s_p[1]==5)output_low(PIN_A2);
      if(s_p[2]==5)output_low(PIN_A3);
      if(s_p[3]==5)output_low(PIN_A4);
      if(s_p[4]==5)output_low(PIN_A5);
      if(s_p[5]==5)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==14)output_high(PIN_A1);
      if(s_p[1]==14)output_high(PIN_A2);
      if(s_p[2]==14)output_high(PIN_A3);
      if(s_p[3]==14)output_high(PIN_A4);
      if(s_p[4]==14)output_high(PIN_A5);
      if(s_p[5]==14)output_high(PIN_E0);
      if(s_p[0]==6)output_low(PIN_A1);
      if(s_p[1]==6)output_low(PIN_A2);
      if(s_p[2]==6)output_low(PIN_A3);
      if(s_p[3]==6)output_low(PIN_A4);
      if(s_p[4]==6)output_low(PIN_A5);
      if(s_p[5]==6)output_low(PIN_E0);
      
      delay_us(delays);
      
      if(s_p[0]==15)output_high(PIN_A1);
      if(s_p[1]==15)output_high(PIN_A2);
      if(s_p[2]==15)output_high(PIN_A3);
      if(s_p[3]==15)output_high(PIN_A4);
      if(s_p[4]==15)output_high(PIN_A5);
      if(s_p[5]==15)output_high(PIN_E0);
      if(s_p[0]==7)output_low(PIN_A1);
      if(s_p[1]==7)output_low(PIN_A2);
      if(s_p[2]==7)output_low(PIN_A3);
      if(s_p[3]==7)output_low(PIN_A4);
      if(s_p[4]==7)output_low(PIN_A5);
      if(s_p[5]==7)output_low(PIN_E0);
      
      delay_us(delays);
      
      printf(lcd_putc,"\n\f%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X\n%s",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5],s_a[0],s_a[1],s_a[2],s_a[3],s_a[4],s_a[5],mode_name);
      
         
   }
     
 

}

Suggestions for Improvement