PPOD-mini: 6-DOF Shaker

From Mech
Jump to navigationJump to search

Team Members

  • Ankur Bakshi (Biomedical Engineering, Class of 2009)
  • Donald Redding (Mechanical Engineering, Class of 2009)
  • Ben Tollberg (Mechanical Engineering, Class of 2009)

Introduction

The PPOD-mini is a miniaturized version of the Programmable Part-feeding Oscillatory Device {PPOD} found in the Laboratory for Intelligent Mechanical Systems (LIMS) at Northwestern. The PPOD-mini utilizes six speakers that act like actuators. The speakers are connected to a PVC plate via flexures of tygon and iron. In its current implementation, the phase of the speakers can be controlled independently, giving the device six degrees of freedom. The movement of objects placed on the PVC plate can be controlled by changing the phases of the speakers.

The PPOD mini measures about 12" x 12" x 8" and can be plugged into a wall outlet for power. It utilizes a switch to start the changing algorithm, a keypad for input to change the speaker phases, and an 16x2 line LCD for user interfacing and to output the speaker phases. A PIC 18f4520 provides the computing power. Each speaker is driven by an H-bridge, which is powered by a 10W power supply from Marlin Jones ([1]). The speakers are 1W, 16 ohm speakers from Jameco.

Operation

When first plugging in the PPOD-mini, the switch is triggered and the text on the LCD is garbled. By pressing the reset button on the PIC board or by pressing buttons on the keypad until clear text appears. To change the phase of a speaker, the switch must be pressed. Then following the instructions on the LCD, press the a number between one and six to select the speaker. Next, press a number between zero and five to choose a phase from 0-300 degrees in 60 degree increments. The increments can be changed by uploading a new program to the PIC. The speakers should then be running.

Mechanical Design

The PPOD consists of a circular plate mounted via flexible supports to six speakers. The six speakers are mounted in a circle on a base plate.

Speaker Mounts The speaker mounts are made of lightweight wood. The side of the mount which the speaker sits in is a 4" x 4" square. A circular hole is cut into the middle of this face to allow the speaker to fit in the mount. This face is elevated 30 degrees from the horizontal. There are two triangular sides on the speaker mount to achieve this angle. The height of the triangular sides is 2" and the base is 2*sqrt(3) (30-60-90 triangle).

Vibrating Plate Supports The flexible supports connecting the vibrating plate to the speakers is made of flexible plastic tubing. The tubing is 1/4" in diameter. To connect the tubing to the speakers, a hot glue gun was used. In order to ensure that the speakers are transmitting vibrations via the connections, a screw was placed in the middle of the tubing to increase the rigidity of the connection. This is done with one end of a 1/4" diameter screw stuck in to the tubing connected to the speaker. The other end of the 1/4"diameter screw is connected to another piece of tubing. This second piece of tubing goes to the vibrating plate.

Vibrating Plate The vibrating plate is circular and plastic. The diameter of this plate is 8". In order to connect the plate to the tubing, 6 holes are drilled equally spaced on a circle around the plate approximately half an inch from the plate's outer edge. Again 1/4" diameter screws are used to connect the tubing. The screws are fed down through the plate and into the second piece of tubing. Hot glue may be used as necessary on the plate around the screws to ensure the screws are held in place. Doing so ensures the vibration is transmitted from the speakers to the plate.

Circuit Diagram

Circuit schematic for PPOD mini project

To the right is the complete circuit schematic for our project. The +5V and GND for the L293D chips were supplied by the external power supply. The LCD was powered by the PIC +5V and GND in order to avoid some overheating issues that occurred when they were connected to the external supply. Each L293D chip controlled two speakers, with one full H-bridge for each speaker. The direction that voltage is applied to each speaker is controlled by the high or low signals that are output from the PIC to the H-bridges.

Code

The following is our main program code that was put on the PIC. The files flex_lcd.c and key.c must be included in the same folder to correctly operate the keypad and LCD. Our modified versions of those files are also included in this section.

Main Code

//Ankur Bakshi, Donnie Redding, Ben Tollberg
//Group 23: PPOD-mini: 6-DOF Shaker

#include <18f4520.h>
#fuses HS,NOLVP,NOWDT
#use delay (clock=40000000)
#include "key.c"             //keypad file
#include "flex_lcd.c"        //lcd file

int32 frequency = 40;        //Set speaker frequency in hertz, this is the one we used in an attempt to 
int ii;                      //maximize the acceleration of the speakers
int32 halfperiod;
int32 delays;
int8 s_p[6]={0,0,0,0,0,0};   //Array that will hold the phase of each speaker
char k;

#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
    int s;
    int flag=1;
    char speaker;
    char phase;
    
    int i, j, temp;
    
    printf(lcd_putc,"\fChanging Phase");
    delay_ms(10);
    printf(lcd_putc,"\n\fSpeaker Number:");
    while(flag==1){                         //Loop will repeat until acceptable input is pressed
        speaker = kbd_getc();               //Read speaker number from keypad
        if(speaker!=0) {                    //Determine speaker
            printf(lcd_putc,"%c",speaker);
            switch (speaker){
                case '1':
                    s=0;
                    flag=0;                 //Exits loop if acceptable input is entered
                    break;       
                case '2':
                    s=1;
                    flag=0;
                    break;
                case '3':
                    s=2;
                    flag=0;
                    break;
                case '4':
                    s=3;
                    flag=0;
                    break;
                case '5':
                    s=4;
                    flag=0;
                    break;
                case '6':
                    s=5;
                    flag=0;
                    break;
                default:
                    printf(lcd_putc,"\n\fInvalid input.");
                    delay_ms(10);
                    printf(lcd_putc,"\n\nSpeaker Number:");
                    break;
            }
        }
    }
    
    flag=1;
    printf(lcd_putc,"\nEnter Phase:");
    while(flag==1){                    //Loop repeats until acceptable input is pressed
        phase = kbd_getc();            //Reads in phase from keypad
        if(phase!=0) {
            printf(lcd_putc,"%c",phase);
            switch (phase){            //Set phase array
                case '0':
                    s_p[s]=0;
                    flag=0;
                    break;
                case '1':
                    s_p[s]=1;
                    flag=0;
                    break;
                case '2':
                    s_p[s]=2;
                    flag=0;
                    break;
                case '3':
                    s_p[s]=3; 
                    flag=0;
                    break;
                case '4':
                    s_p[s]=4;
                    flag=0;
                    break;
                case '5':
                    s_p[s]=5;
                    flag=0;
                    break;
                default:
                    printf(lcd_putc,"\nInvalid input.");
                    delay_ms(10);
                    printf(lcd_putc,"\nEnter Phase:");
                    break;
            }
        }
    }
}

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
    halfperiod = 500000/frequency;     //Converts frequency in hertz to half of the period
                                       //in microseconds  
    delays = halfperiod/3;             //Sets delays to one-sixth of a full period, for a 60 degree
                                       //phase shift
    lcd_init();
    kbd_init(); //initialize keypad
    
    printf(lcd_putc,"Starting...\n");
    delay_ms(1000);
    printf(lcd_putc,"\n");
    
    while(true) {                                //This function sets the speakers high or low based on
        if(s_p[0] == 0){                         //the information saved in the phase array s_p. It checks
               output_high(PIN_A0);              //to see which speakers are supposed to be changed at
               output_low(PIN_A1);               //a certain time, waits for a time that equates to 60
        }                                        //degrees of phase shift and checks again. Changing which
        if(s_p[1] == 0){                         //pin is high and which is low changes the direction of
               output_high(PIN_A2);              //the voltage across the speakers.
               output_low(PIN_A3);
        }
        if(s_p[2] == 0){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 0){
               output_high(PIN_C6);
               output_low(PIN_E0);
        }
        if(s_p[4] == 0){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 0){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 3){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 3){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 3){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 3){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 3){
               output_low(PIN_E1);
               output_high(PIN_E2);
        }
        if(s_p[5] == 3){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        if(s_p[0] == 1){
               output_high(PIN_A0);
               output_low(PIN_A1);
        }
        if(s_p[1] == 1){
               output_high(PIN_A2);
               output_low(PIN_A3);
        }
        if(s_p[2] == 1){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 1){
               output_high(PIN_C6);
               output_low(PIN_E0);
        }
        if(s_p[4] == 1){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 1){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 4){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 4){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 4){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 4){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 4){
               output_low(PIN_E1);
               output_high(PIN_E2);
        }
        if(s_p[5] == 4){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        if(s_p[0] == 2){
               output_high(PIN_A0);
               output_low(PIN_A1);
        }
        if(s_p[1] == 2){
               output_high(PIN_A2);
               output_low(PIN_A3);
        }
        if(s_p[2] == 2){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 2){
               output_high(PIN_C6);
               output_low(PIN_E0);
        }
        if(s_p[4] == 2){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 2){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 5){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 5){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 5){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 5){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 5){
               output_low(PIN_E1);
               output_high(PIN_E2); 
        }
        if(s_p[5] == 5){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        if(s_p[0] == 3){
               output_high(PIN_A0);
               output_low(PIN_A1);
        }
        if(s_p[1] == 3){
               output_high(PIN_A2);
               output_low(PIN_A3);
        }
        if(s_p[2] == 3){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 3){
               output_high(PIN_C6);
               output_low(PIN_E0);
        }
        if(s_p[4] == 3){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 3){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 0){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 0){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 0){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 0){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 0){
               output_low(PIN_E1);
               output_high(PIN_E2);
        }
        if(s_p[5] == 0){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        if(s_p[0] == 4){
               output_high(PIN_A0);
               output_low(PIN_A1);
        }
        if(s_p[1] == 4){
               output_high(PIN_A2);
               output_low(PIN_A3);
        }
        if(s_p[2] == 4){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 4){
               output_high(PIN_C6);
               output_low(PIN_E0);
        }
        if(s_p[4] == 4){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 4){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 1){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 1){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 1){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 1){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 1){
               output_low(PIN_E1);
               output_high(PIN_E2);
        }
        if(s_p[5] == 1){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        if(s_p[0] == 5){
               output_high(PIN_A0);
               output_low(PIN_A1);
        }
        if(s_p[1] == 5){
               output_high(PIN_A2);
               output_low(PIN_A3);
        }
        if(s_p[2] == 5){
               output_high(PIN_A4);
               output_low(PIN_A5);
        }
        if(s_p[3] == 5){
               output_high(PIN_C6);
               output_low(PIN_E0); 
        }
        if(s_p[4] == 5){
               output_high(PIN_E1);
               output_low(PIN_E2);
        }
        if(s_p[5] == 5){
               output_high(PIN_C5);
               output_low(PIN_D0);
        }
        if(s_p[0] == 2){
               output_low(PIN_A0);
               output_high(PIN_A1);
        }
        if(s_p[1] == 2){
               output_low(PIN_A2);
               output_high(PIN_A3);
        }
        if(s_p[2] == 2){
               output_low(PIN_A4);
               output_high(PIN_A5);
        }
        if(s_p[3] == 2){
               output_low(PIN_C6);
               output_high(PIN_E0);
        }
        if(s_p[4] == 2){
               output_low(PIN_E1);
               output_high(PIN_E2);
        }
        if(s_p[5] == 2){
               output_low(PIN_C5);
               output_high(PIN_D0);
        }
        
        delay_us(delays);
        
        
        printf(lcd_putc,"\n\fPhases:%i%i%i%i%i%i\n",s_p[0],s_p[1],s_p[2],s_p[3],s_p[4],s_p[5]);
    }

}

LCD Code

Keypad Code

Issues with Design

Future Steps

As mentioned in the previous section, the all the speakers do not vibrate with the same force. There are several ways to deal with this issue. First, a little experimentation may need to be done with the flexures. The flexures may be too stiff, preventing the diaphragm of the speakers from fully vibrating. The next thing to do is to check the level of the plate and the geometry of the speakers and insertion points. If the mass of the plate is unevenly distributed, some speakers may have to apply more force than others. Since the speakers will inevitably output unequal forces, amplitude control will most likely be necessary. This can be achieved by place a potentiometer between a line from the H-bridge and the speaker. Given the weak output of some speakers at 5V, reducing amplitude may not be sufficient. Raising the power source to 7V and getting higher power speakers (for example [2]) will resolve this issue.

The original PPOD used feedback from six accelerometers to independently control the amplitude of each of the speakers. One possible method to implement a simpler system would be to use one accelerometer in the middle of the plate. When all the speakers are set in phase, there should be Y acceleration without X acceleration. However, if not all of the speakers are firing equally, there will be X acceleration. Based on the X acceleration, the node that is misfiring can be calculated.

During testing, it was noted that holding down a speaker diaphragm (effectively turning it off) caused distinct movements. If the speakers are not strong enough to cause movement, adding the ability to turn of individual speakers may be necessary.