Go Down

Topic: Phototransistor Rotary Encoder (Read 765 times) previous topic - next topic

mjszabo

I am working on finalizing a small wind turbine about 2.5' in diameter.  The turbine is built and currently I am working on designing a control system using an Arduino micro-controller.  I am trying to read in the RPM of the shaft as an analog in.  I have an infrared led emitting to a phototransistor through a slotted disc, then I have Processing running code to translate the signal into a RPM value.  Here is my code for Arduino:
Code: [Select]
//Sending 8 bit reading (256) so analog
//reading can be sent in 1 byte
int AnalogIn = 0;    // first analog sensor
int inByte = 0;     // incoming serial byte

void setup(){
 Serial.begin(9600);  // start serial port at 9600 bps:
 establishContact();  // send a byte to establish contact until Processing responds
 pinMode(2,OUTPUT); // set pin 2 as an output pin
}

void loop(){
 // if we get a valid byte, read analog ins:
 if (Serial.available() > 0) {
   inByte = Serial.read();  // get incoming byte
   AnalogIn = analogRead(0)/4;  // read input and make range 0-255
   //delay(10);  // delay 10ms to let the ADC recover

   Serial.print(AnalogIn , BYTE);  // send sensor value
 }//else if (Serial.available() == 'B')
  //   for(int i = 1; i <= 20; i++){  // loop 20 times
  //     digitalWrite(2, HIGH); // turn on pin2 for 1 second
       //delay(1000);
       //digitalWrite(2, LOW);  // turn off pin2 for 1 second
       //delay(100);
//   }
// delay(2000);
 }//}

void establishContact() {
while (Serial.available() <= 0) {
     Serial.print('A', BYTE);   // send a capital A
     delay(300);
 }}

And my code for Processing:
Code: [Select]
// Feel Free to edit these variables ///////////////////////////
String  xLabel = "Analog Inputs";
String  yLabel = "Voltage (V)";
String  Heading = "Wind Turbine";
String  URL = "11/10/2010";
float Vcc = 5.0;    // the measured voltage of your usb
int NumOfVertDivisions=5;      // dark gray
int NumOfVertSubDivisions=10;  // light gray
int ScreenWidth = 600, ScreenHeight=400;
int Ntimes = 1, ticks = 0;
float t0 = 0, t1 = 0;
int LeftMargin=100, RightMargin=100;
int TextGap=50;
int compare = 0;
int GraphYposition=80;
float BarPercent = 0.4;
int value;
PFont font;
PImage bg;
int temp;
float yRatio = 0.58;
int BarGap, BarWidth, DivisionWidth;
int[] bars = new int[2];
/////////////////////////////////////////////////////////

//  Serial port stuff ///////////////////////
import processing.serial.*;
Serial myPort;
boolean firstContact = false;
int AnalogValue = 0;
///////////////////////////////////////////////

void setup(){
 /// PORT SETTING ////////////////////////////////////////////////////////
 myPort = new Serial(this, Serial.list()[1], 9600);
 ////////////////////////////////////////////////////////////////////////

 DivisionWidth = (ScreenWidth-LeftMargin-RightMargin)/(2);
 BarWidth = int(BarPercent*float(DivisionWidth));
 BarGap = DivisionWidth - BarWidth;

 size(ScreenWidth,ScreenHeight);
 font = createFont("Arial",12);
 textAlign(CENTER);
 textFont(font);
}

void draw(){
 background(250);      // Background as a plain color
 //Headings();           // Displays bar width, Bar gap or any variable.
 Axis();
 Labels();
 PrintBars();
}

// Send Recieve data //
void serialEvent(Serial myPort) {

 int AnalogValue = myPort.read();  // read a byte from the serial port

 if (firstContact == false) {
   if (AnalogValue == 'A') {
     myPort.clear();          // clear the serial port buffer
     firstContact = true;     // you've had first contact from the microcontroller
     myPort.write('A');       // ask for more
   }}
 else {
   println("Ntimes = " + Ntimes + "volt = " + AnalogValue + " ticks = " + ticks);
//Add a time counter and tick counter
   if (Ntimes <= 100){
       if (Ntimes == 1){
         t0 = millis();
         if (AnalogValue > (1.2 * compare)){
           ticks++;
         }
         compare=AnalogValue;
       }
       else if(Ntimes == 100){
         t1 = millis();
         if (AnalogValue > (1.2 * compare)){
           ticks++;
         }
         bars[1] = int(ticks/((t1-t0)*.001));
         println("t0 = " + t0 + ", t1 = " + t1 + ", ticks = " + ticks + ", rps = " +bars[1]);
         Ntimes=0;
         ticks=0;
         delay(10);  
         if(bars[1] >20){
           myPort.write('B');
         }
       }
     else{
       if (AnalogValue > (1.2 * compare)){
          ticks++;
       }
       compare=AnalogValue;
     }
     Ntimes++;
   }
 bars[0] = int (yRatio*(ScreenHeight)*(AnalogValue/256.0));
 myPort.write('A');      // Send a capital A to request new sensor readings:
 }
}

/////// Display any variables for testing here//////////////
void Headings(){
 fill(0 );
 text("BarWidth",50,TextGap );
 text("BarGap",250,TextGap );
 text("DivisionWidth",450,TextGap );
 text(BarWidth,100,TextGap );
 text(BarGap,300,TextGap );
 text(DivisionWidth,520,TextGap );
}

void PrintBars(){

 int c=0;
 for (int i=0;i<2;i++){

   fill((0xe4+c),(255-bars[i]+c),(0x1a+c));
   stroke(90);
   rect(i*DivisionWidth+LeftMargin,   ScreenHeight-GraphYposition,   BarWidth,   -bars[i]);
   fill(0x2e,0x2a,0x2a);
   text(float(bars[i])/(yRatio*(ScreenHeight))*Vcc,   i*DivisionWidth+LeftMargin+BarWidth/2,   ScreenHeight-bars[i]-5-GraphYposition );
   text("A",   i*DivisionWidth+LeftMargin+BarWidth/2 -5,   ScreenHeight-GraphYposition+20 );
   text(i,   i*DivisionWidth+LeftMargin+BarWidth/2 +5,   ScreenHeight-GraphYposition+20 );
 }
}

void Axis(){

 strokeWeight(1);
 stroke(220);
 for(float x=0;x<=NumOfVertSubDivisions;x++){

   int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertSubDivisions));
   line(LeftMargin-15,bars,ScreenWidth-RightMargin-DivisionWidth+50,bars);
 }
 strokeWeight(1);
 stroke(180);
 for(float x=0;x<=NumOfVertDivisions;x++){

   int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
   line(LeftMargin-15,bars,ScreenWidth-RightMargin-DivisionWidth+50,bars);
 }
 strokeWeight(2);
 stroke(90);
 line(LeftMargin-15, ScreenHeight-GraphYposition+2, ScreenWidth-RightMargin-DivisionWidth+50, ScreenHeight-GraphYposition+2);
 line(LeftMargin-15,ScreenHeight-GraphYposition+2,LeftMargin-15,GraphYposition);
 strokeWeight(1);
}

void Labels(){
 textFont(font,18);
 fill(50);
 rotate(radians(-90));
 text(yLabel,-ScreenHeight/2,LeftMargin-45);
 textFont(font,16);
 for(float x=0;x<=NumOfVertDivisions;x++){

   int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
   text(round(x),-bars,LeftMargin-20);
 }

 textFont(font,18);
 rotate(radians(90));
 text(xLabel,LeftMargin+(ScreenWidth-LeftMargin-RightMargin-50)/2,ScreenHeight-GraphYposition+40);
 textFont(font,24);
 fill(50);
 text(Heading,LeftMargin+(ScreenWidth-LeftMargin-RightMargin-50)/2,70);
 textFont(font);

 fill(150);
 text(URL,ScreenWidth-RightMargin-40,ScreenHeight-15);
 textFont(font);

}



I was wondering if there was anyway to make this code work better, since currently it is not giving reasonable RPM values. It does read in the signal really well though (in my opinion.)  Any thoughts?

From there I was going to have it send out a signal through digitalout, to pulse a relay circuit with a resistor attached across the generator leads.  With hopes that it would create a load resulting in greater power.

(Just started two weeks ago and have never worked with micro-controllers before.)

Thanks!

PaulS

You are only reading the speed sensor now and then, and then reporting HIGH or LOW when asked, missing all the times the sensor pin went HIGH or LOW while you weren't being asked.

The phototransistor should trigger an interrupt. The handler for that interrupt should simply increment a counter.

When serial data arrives, record the time, disable interrupts, copy the counter value, reset the counter, and re-enable interrupts.

Then report the count and time since last request. The count divided by the time will be (a function of) the rpm.

Go Up