Difference between revisions of "Ball Balancing Challenge"

From Mech
Jump to navigationJump to search
Line 77: Line 77:


==Software Design==
==Software Design==

Source Code:

<pre>

/*
touchscreen.c Mechatronics 333 Team 14 2/22/08
Reads the touchscreen individually as two axes. Actuates motor based on either touchscreen or joystick control.
PIC powers either the Upper Left (Y-axis reading) or the Lower Right (X-axis reading) and grounds what it doesn't power.
Output reading is the value on that axis.
Two channels of PWM output, with the PWM2 output moved from pin 16 to pin 36 to avoid conflict with Timer1 input
Upper Left (UL) corner is PIN_C1, and Lower Left (LR) corner is always its inverse.
Upper Right (UR) corner is always high, and lower right (LL) is always ground, its inverse.
Peak voltage: Top reading voltage=4V and bottom reading voltage=1.2V
Min xread,yread values: 62,70
Max xread,yread values: 189,177
*/

#include <18f4520.h>
#DEVICE ADC=8 // set ADC to 8 bit accuracy
#fuses HS,NOLVP,NOWDT,NOPROTECT, CCP2B3 // CCP2B3 moves PWM2 output to pin 36 (RB3) rather than pin 16 (RC1)
#device icd=true
#use delay(clock=20000000)


int yread,xread,m,j=0;
int read1pwm,read2pwm=0;
int read1,read2=0;
int coin,strike,ball=0;
signed int16 counter=0;

void buzz();

void main() {
for (j=0;j<3;j++){
output_d(0b11111111);
delay_ms(250);
output_d(0);
delay_ms(250);
}
coin=0;
strike=0;
ball=0;
counter=0;
output_high(PIN_C1); //Start with UL high, LR low ***THESE WILL CHANGE***
output_high(PIN_C0); //This is the pin for UR. It will be run through an inverter for LL
//the bottom left corner. ***THESE ARE PERMANENT***
setup_adc_ports(AN0_TO_AN2); // Enable analog inputs; choices run from just AN0, up to AN0_TO_AN11
setup_adc(ADC_CLOCK_INTERNAL); // the range selected has to start with AN0
setup_timer_2(T2_DIV_BY_4, 77, 16); // clock at 16KHz, interrupt every 4*50nS * 4 * (155+1) * 16 = 2.00mS

enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM); // PWM output on CCP1/RC2, pin 17 this goes to y-axis motor
setup_ccp2(CCP_PWM); // PWM output on CCP2/RB3, pin 36 this goes to x-axis motor

set_pwm1_duty(39);
set_pwm2_duty(39);
while (TRUE) {
set_pwm1_duty(39);
set_pwm2_duty(39);
//Wait for coin to be inserted
while (coin==0) {
if (input(PIN_E1)) coin=1;
else delay_ms(100);
}
//Gameplay begins. Controls go dead when strikes go too high;
while (coin==1) {
//TOUCHSCREEN READing, looks at the touchscreen readings
if (m==0) {
output_high(PIN_C1); //UL goes high, thus LR goes low; y-axis can be read
set_adc_channel(0);
delay_us(10);
yread = read_adc(); //Read y axis
m++;
}
else {
output_low(PIN_C1); //UL goes low, thus LR goes high; x-axis can be read
set_adc_channel(0);
delay_us(10);
xread = read_adc(); //Read x axis
m=0;
}
//Check to see if the Ball is outide the allowed range of values to be "in the black" of the touchscreen
if ((yread< 90) | (yread >150) | (xread <90) | (xread > 150)) {
counter++;
if ((counter==3) && (strike==ball)) {
strike++; //If ball is "in the red" for a sufficiently long time, a strike is added.
}
}
else {
counter--;
//Check to see if the ball has returned from being "in the red."
if ((counter==-1) && (strike>ball)) {
ball++;
}
}
if ((counter==3) | (counter == -2)) counter=0;
if (strike==2) {
output_high(PIN_A3);
}
if (strike==3) {
output_high(PIN_A4);
}
if (strike==4) {
output_high(PIN_A5);
}
if (strike==5) {
output_high(PIN_E2);
}
if (strike==6) {
output_high(PIN_E0);
set_pwm1_duty(39);
set_pwm2_duty(39);
buzz();
}

//Joystick Control
if (input(PIN_C7) != 0) { // toggle switch that switches between Joystick control system and Touchscreen control system
set_adc_channel(2); // there's only one ADC so select which input to connect to it; here pin AN1
delay_us(10); // wait 10uS for ADC to settle to a newly selected input
read1 = read_adc(); //x-axis
if (read1<145 && read1>115) read1pwm=39;
else read1pwm=(read1*.3);
set_pwm1_duty(read1pwm);
set_adc_channel(1); // there's only one ADC so select which input to connect to it; here pin AN2
delay_us(10); // wait 10uS for ADC to settle to a newly selected input
read2 = read_adc(); //y-axis
if (read2<145 && read2>115) read2pwm=39;
else read2pwm=(read2*.3);
set_pwm2_duty(read2pwm);
}
else {
output_d(0);
set_pwm1_duty(39);
set_pwm2_duty(39);
}
//LED readings for XY locations of the touchscreen
if (xread<75) {
output_low(PIN_D0);
output_low(PIN_D1);
output_low(PIN_D2);
output_low(PIN_D3);
}
else if (xread<110) {
output_high(PIN_D0);
output_low(PIN_D1);
output_low(PIN_D2);
output_low(PIN_D3);
}
else if (xread<145) {
output_high(PIN_D0);
output_high(PIN_D1);
output_low(PIN_D2);
output_low(PIN_D3);
}
else if (xread<180) {
output_high(PIN_D0);
output_high(PIN_D1);
output_high(PIN_D2);
output_low(PIN_D3);
}
else {
output_high(PIN_D0);
output_high(PIN_D1);
output_high(PIN_D2);
output_high(PIN_D3);
}
if (yread<75) {
output_low(PIN_D4);
output_low(PIN_D5);
output_low(PIN_D6);
output_low(PIN_D7);
}
else if (yread<110) {
output_high(PIN_D4);
output_low(PIN_D5);
output_low(PIN_D6);
output_low(PIN_D7);
}
else if (yread<145) {
output_high(PIN_D4);
output_high(PIN_D5);
output_low(PIN_D6);
output_low(PIN_D7);
}
else if (yread<180) {
output_high(PIN_D4);
output_high(PIN_D5);
output_high(PIN_D6);
output_low(PIN_D7);
}
else {
output_high(PIN_D4);
output_high(PIN_D5);
output_high(PIN_D6);
output_high(PIN_D7);
}
}
}
}

void buzz() {

coin=0;
strike=0;
ball=0;
output_low(PIN_A3);
output_low(PIN_A4);
output_low(PIN_A5);
output_low(PIN_E2);
output_low(PIN_E0);

while (input(PIN_C6)==0) {
output_high(PIN_C4);
delay_us(100);
output_low(PIN_C4);
delay_us(100);
}
}

</pre>


==Results==
==Results==

Revision as of 18:11, 20 March 2008

T14-project-action-08.jpg




Team Members

Left to right: JJ Darling, Alex Leung, Ben Schriesheim
  • JJ Darling - Electrical Engineering Class of 2009
  • Ben Schriesheim - Manufacturing Engineering Class of 2008
  • Alex Leung - Biomedical Engineering Graduate Student

Overview

We built a horizontal circular platform that is actuated from underneath by three speakers placed in an equilateral triangle. The vibration of the platform causes a small object (e.g., an IC socket or a coin) to act as an hour "hand" on top of the platform. The object slides around the circular platform, impelled by friction forces due to the vibration. By placing the speakers at different phases and amplitudes, we got the objects to move to desired positions. Due to the nodes created by the speaker vibrations, the object will move back to the correct hour if it is moved away. Our project was given to us by Professor Colgate and was based upon the research of Professor Lynch.

Mechanical Design

The Vibratory clock consists of a wooden base, held up by adjustable legs, three speakers, and a circular platform. The following material were used to create the design:

Base:

  • wood: 16" diameter, 0.75" thick
  • holes: 6" diameter (3 total)
  • adjustable legs: 3 rods: 3/8"-16; 4" long; 6 nuts total
Speaker supports.jpg

Speakers:

  • 3 Pyramid Power PW677X: 300W, 4 Ohms, 6.5" Chrome Subwoofer
    • previously adapted speakers replaced center of speaker with attachments 3" in height and 1/2" hole on top
    • 1/2" diameter PVC used to attach previous attachment to platform with a screw
      • held in place by 2 set screws each
    • centers placed 7.125" apart

Circular Platform

  • PVC/Acrylic: 11.75" diameter, 0.25" thick
    • machined on the LaserJet
    • screw holes counter-sunk at 7.125" apart
  • 2.875" above wooden base
  • Silver Sharpie used for numbers

Reasoning for Geometry of Design

Equilateral Triangle: By having the speakers equidistant from each other, we were able to create symmetry in our design, which made programming the various nodes much easier. For example, we were able to use the same theory to find the node at 12 o'clock, 4 o'clock, and 8 o'clock. If the speakers were not placed equidistant from each other, two speakers placed at equal amplitudes and opposite phases would not have created a sink in the exact middle of the two speakers.

Adjustable Legs:

We needed to make the legs adjustable since it is essential that the platform be perfectly level in order for the objects placed on the platform to move in expected patterns. For example, if one leg is slightly shorter than the other two, the objects placed on the platform would tend to move towards that leg and we could no longer rely on symmetry to program the various nodes due to the effects of gravity.

Height of Platform:

Through our own experimentation and from Professor Lynch's research, we found that we needed to have the pivot point (i.e. the speaker diaphragm) significantly below the platform in order to create sinks. At one point in the design process, we attempted to create a different pivot point by replacing the PVC with 1/2" outer diameter, 1/4" inner diameter Tygon 2001 tubing that only was able to bend in one point since it had stand-offs and screws inside the tube. However, this replacement in a sense created two pivot points (the speaker diaphragm and the Tygon), causing the platform to only create sources and not sinks. In addition, the different height of the pivot point may have also led to the plate acting differently.

Electrical Design

The Electical Design was fairly simple for this project. The inputs to the PIC were the joystick, coin slot, and the touchscreen. The outputs were the motors and the LED "strike" array. The touchscreen was also an output as it was controlled by the PIC.

The user would control the joystick that was simply two potentiometers that would output a value between 0V and 5V, corresponding to both the x-axis and the y-axis.


Circuit Board

Component List:

PartPart No.QtyVendorPrice (Total)
Microchip 8-bit PIC Microcontroller (U1)PIC18F45201N/AN/A
Quadruple Half-H DriversL293D 2Digi-Key$1.93
Hex InverterSN74HC041Digi-Key$0.47
TouchscreenBER237-ND1Digi-Key$62.00
JoystickN/A1N/AN/A

Circuit Diagram:

Ball Balancing Circuit Diagram

Software Design

Source Code:


/*
touchscreen.c Mechatronics 333 Team 14 2/22/08
Reads the touchscreen individually as two axes. Actuates motor based on either touchscreen or joystick control.
PIC powers either the Upper Left (Y-axis reading) or the Lower Right (X-axis reading) and grounds what it doesn't power.
Output reading is the value on that axis.
Two channels of PWM output, with the PWM2 output moved from pin 16 to pin 36 to avoid conflict with Timer1 input
Upper Left (UL) corner is PIN_C1, and Lower Left (LR) corner is always its inverse.
Upper Right (UR) corner is always high, and lower right (LL) is always ground, its inverse.
Peak voltage: Top reading voltage=4V and bottom reading voltage=1.2V
Min xread,yread values: 62,70
Max xread,yread values: 189,177
*/

#include <18f4520.h>
#DEVICE ADC=8                      // set ADC to 8 bit accuracy
#fuses HS,NOLVP,NOWDT,NOPROTECT, CCP2B3      // CCP2B3 moves PWM2 output to pin 36 (RB3) rather than pin 16 (RC1)
#device icd=true
#use delay(clock=20000000)


int yread,xread,m,j=0;
int read1pwm,read2pwm=0;
int read1,read2=0;
int coin,strike,ball=0;
signed int16 counter=0;

void buzz();

void main() {
   for (j=0;j<3;j++){
      output_d(0b11111111);
      delay_ms(250);
      output_d(0);
      delay_ms(250);
   }
  
   coin=0;
   strike=0;
   ball=0;
   counter=0;
  
   output_high(PIN_C1);          //Start with UL high, LR low ***THESE WILL CHANGE***
   output_high(PIN_C0);          //This is the pin for UR. It will be run through an inverter for LL
                                 //the bottom left corner. ***THESE ARE PERMANENT***
  
   setup_adc_ports(AN0_TO_AN2);        // Enable analog inputs; choices run from just AN0, up to AN0_TO_AN11
   setup_adc(ADC_CLOCK_INTERNAL);      // the range selected has to start with AN0
  
   setup_timer_2(T2_DIV_BY_4, 77, 16);        // clock at 16KHz, interrupt every 4*50nS * 4 * (155+1) * 16 = 2.00mS

   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);  
 
   setup_ccp1(CCP_PWM);       // PWM output on CCP1/RC2, pin 17   this goes to y-axis motor
   setup_ccp2(CCP_PWM);       // PWM output on CCP2/RB3, pin 36   this goes to x-axis motor

   set_pwm1_duty(39);
   set_pwm2_duty(39);
  
   while (TRUE) {
  
      set_pwm1_duty(39);
      set_pwm2_duty(39);
     
      //Wait for coin to be inserted
      while (coin==0) {                
         if (input(PIN_E1)) coin=1;
         else delay_ms(100);
      }
      
      //Gameplay begins. Controls go dead when strikes go too high; 
      while (coin==1) {
         //TOUCHSCREEN READing, looks at the touchscreen readings
         if (m==0) {
            output_high(PIN_C1);       //UL goes high, thus LR goes low; y-axis can be read
            set_adc_channel(0);
            delay_us(10);          
            yread = read_adc();       //Read y axis           
            m++;
         }
         else {
            output_low(PIN_C1);        //UL goes low, thus LR goes high; x-axis can be read
            set_adc_channel(0);
            delay_us(10);          
            xread = read_adc();       //Read x axis
            m=0;
         }
        
         //Check to see if the Ball is outide the allowed range of values to be "in the black" of the touchscreen
         if ((yread< 90) | (yread >150) | (xread <90) | (xread > 150)) {
            counter++;
            if ((counter==3) && (strike==ball)) {
               strike++;         //If ball is "in the red" for a sufficiently long time, a strike is added.
            }
         }       
         else {
            counter--;
            //Check to see if the ball has returned from being "in the red."
            if ((counter==-1)  && (strike>ball)) {
               ball++;
            }
         }
        
         if ((counter==3) | (counter == -2)) counter=0;
        
        
         if (strike==2) {
            output_high(PIN_A3);
         }
         if (strike==3) {
            output_high(PIN_A4);
         }
         if (strike==4) {
            output_high(PIN_A5);
         }
         if (strike==5) {
            output_high(PIN_E2);
         }
         if (strike==6) {
            output_high(PIN_E0);
            set_pwm1_duty(39);
            set_pwm2_duty(39);
            buzz();
         }
        
 
        
     

         //Joystick Control
         if (input(PIN_C7) != 0) {  // toggle switch that switches between Joystick control system and Touchscreen control system
            set_adc_channel(2);     // there's only one ADC so select which input to connect to it; here pin AN1
            delay_us(10);           // wait 10uS for ADC to settle to a newly selected input
            read1 = read_adc();                       //x-axis
            if (read1<145 && read1>115) read1pwm=39;
            else read1pwm=(read1*.3);
            set_pwm1_duty(read1pwm);
           
            set_adc_channel(1);     // there's only one ADC so select which input to connect to it; here pin AN2
            delay_us(10);           // wait 10uS for ADC to settle to a newly selected input
            read2 = read_adc();                      //y-axis
            if (read2<145 && read2>115) read2pwm=39;
            else read2pwm=(read2*.3);
            set_pwm2_duty(read2pwm);
         }
         else {
            output_d(0);
            set_pwm1_duty(39);
            set_pwm2_duty(39);
            }
        
         //LED readings for XY locations of the touchscreen
         if (xread<75) {                
            output_low(PIN_D0);     
            output_low(PIN_D1);
            output_low(PIN_D2);
            output_low(PIN_D3);
         }
         else if (xread<110) {
            output_high(PIN_D0);     
            output_low(PIN_D1);
            output_low(PIN_D2);
            output_low(PIN_D3);
         }
         else if (xread<145) {
            output_high(PIN_D0);     
            output_high(PIN_D1);
            output_low(PIN_D2);
            output_low(PIN_D3);
         }
         else if (xread<180) {
            output_high(PIN_D0);     
            output_high(PIN_D1);
            output_high(PIN_D2);
            output_low(PIN_D3);
         }
         else  {
            output_high(PIN_D0);     
            output_high(PIN_D1);
            output_high(PIN_D2);
            output_high(PIN_D3);
         }
         if (yread<75) {
            output_low(PIN_D4);     
            output_low(PIN_D5);
            output_low(PIN_D6);
            output_low(PIN_D7);
         }
         else if (yread<110) {
            output_high(PIN_D4);     
            output_low(PIN_D5);
            output_low(PIN_D6);
            output_low(PIN_D7);
         }
         else if (yread<145) {
            output_high(PIN_D4);     
            output_high(PIN_D5);
            output_low(PIN_D6);
            output_low(PIN_D7);
         }
         else if (yread<180) {
            output_high(PIN_D4);     
            output_high(PIN_D5);
            output_high(PIN_D6);
            output_low(PIN_D7);
         }
         else  {
            output_high(PIN_D4);     
            output_high(PIN_D5);
            output_high(PIN_D6);
            output_high(PIN_D7);
         }
      }
   }
}

void buzz() {

   coin=0;
   strike=0;
   ball=0;
   output_low(PIN_A3);
   output_low(PIN_A4);  
   output_low(PIN_A5);
   output_low(PIN_E2);
   output_low(PIN_E0);

  
   while (input(PIN_C6)==0) {
      output_high(PIN_C4);
      delay_us(100);
      output_low(PIN_C4);
      delay_us(100);
   }
}

Results

VibratoryClock.jpg

We were able to get our project working so that the plate moves an object placed anywhere on the plate to the correct time and then moves the objects around the clock face, acting as the hour "hand" of a clock. However, we increased the speed so that it takes about 2 minutes for objects placed on the clock to move around so that it is easy to demonstrate. Check out the working Vibratory Clock here.

Reflections

Useful Resources

Vibration-Induced Frictional Force Fields for Part Manipulation

Universal Planar Manipulator