//
// This example shows one way of creating an optoswitch
// using an IR LED as emiter and an IR LED receiver as
// light sensor.
// On this case it acts as a tachometer to count the
// revolutions per second of an aeromodelism plane's
// propeller.
//
// + GROUND +GROUND
// | |
// < <
// > 220 ohm resistor > 220 omh resistor
// < <
// | |
// | |
// ----- -----
// / \ >>IR LED emiter >>>>>>>>>>>>>>>> / \ IR LED receiver
// ----- -----
// | |
// | |
// + +5VCD + ANALOG INPUT 0
//
int val;
long last=0;
int stat=LOW;
int stat2;
int contar=0;
int sens=75; // this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording on the
// distance the leds are placed.
int nPalas=2; // the number of blades of the propeller
int milisegundos=500; // the time it takes each reading
void setup()
{
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop()
{
val=analogRead(0);
if(val<sens)
stat=LOW;
else
stat=HIGH;
digitalWrite(13,stat); //as iR light is invisible for us, the led on pin 13
//indicate the state of the circuit.
if(stat2!=stat){ //counts when the state change, thats from (dark to light) or
//from (light to dark), remmember that IR light is invisible for us.
contar++;
stat2=stat;
}
if(millis()-last>=milisegundos){
double rps=((double)contar/nPalas)/2.0*1000.0/milisegundos;
double rpm=((double)contar/nPalas)/2.0*60000.0/(milisegundos);
Serial.print((contar/2.0));Serial.print(" RPS ");Serial.print(rps);
Serial.print(" RPM");Serial.print(rpm);Serial.print(" VAL ");Serial.println(val);
contar=0;
last=millis();
}
}
in the code if I change int nPalas=2; // the number of blades of the propeller to int nPalas=1;
as in my engine one pulse output is one rotation..
and the code checks for number of pulses in 500 miliseconds, the reading is not that accurate all the time..
it fluctuates a lot
and the code checks for number of pulses in 500 miliseconds, the reading is not that accurate all the time..
it fluctuates a lot
This goes along the lines of what I was saying in my first post. With only 1 pulse per rotation, and relatively low speed, you won't get many counts in a 500 millisecond window, which means any fluctuation in counts is going to create a magnified fluctuation in RPMs.
The easiest way to remedy that is to increase the duration in which you're counting pulses, possibly increasing it to several seconds. Unless you are using the RPM as an input to some other high speed process, like a PID, that shouldn't be a problem.
First. Check your sensor and make sure it is "clean" <--- no bouncing
So you are using one cylinder engine <-- Just like a lawn mower
My Theory :
Let assume the RPM is 600. 600 pulse / min / 60 second = 10 pulse / second +/- 100 rpm or 1 pulse / second ( the variation )
If using 500 ms, you should get 5 pulse / 500 ms = 10 pulse / second
In you code you have "contar" meaning count, can you modify so you can see the variale "contar" to check your "pulse", if you have 5 pulse +/- 1, well it work fine, if not, check the calculations, maybe check sensor, and maybe re-modify the code.
int val;
long last=0;
int stat=LOW;
int stat2;
int contar=0;
int sens=75; // this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording on the
// distance the leds are placed.
int nPalas=2; // the number of blades of the propeller
int milisegundos=500; // the time it takes each reading
void setup()
{
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop()
{
val=analogRead(0);
if(val<sens) // Software comparator
{
stat=LOW;
}
else
{
stat=HIGH;
}
digitalWrite(13,stat); //as iR light is invisible for us, the led on pin 13
//indicate the state of the circuit.
if(stat2!=stat)
{ //counts when the state change, thats from (dark to light) or
//from (light to dark), remmember that IR light is invisible for us.
contar++;
stat2=stat;
}
if(millis()-last>=milisegundos)
{ // isolated the calculations to check the pulse count and check the pulse counting routine
/*
double rps=((double)contar/nPalas)/2.0*1000.0/milisegundos;
double rpm=((double)contar/nPalas)/2.0*60000.0/(milisegundos);
Serial.print((contar/2.0));Serial.print(" RPS ");Serial.print(rps);
Serial.print(" RPM");Serial.print(rpm);Serial.print(" VAL ");Serial.println(val);
*/
Serial.println(contar); // to check the contar variable
contar=0; // reset contar variable
last=millis();
}
}
...and then the rpm reading becomes just an analog read and scale factor & no need to worry about timing pulses. Note the "minimum component tachometer" on p. 8.
...and then the rpm reading becomes just an analog read and scale factor & no need to worry about timing pulses. Note the "minimum component tachometer" on p. 8.
Joe
Thats a great thing I have come through,..
It will be great..
But can u help me out like how to do with it...??
how do I know what frequency input is what output voltage..
There is other better way to do it for better precession and accuracy..??
None of what you suggest here will make for better precision or accuracy. Multiplying an inaccurate value won't make it more accurate.
Getting the signal each and every time, at the exact time it is sent, is how you improve accuracy. Precision is rather meaningless in this context. Either you got the pulse or you didn't. There isn't any middle ground.
Converting what is essentially a digital signal to analog via a frequency-to-voltage chip and then converting it back to digital strikes me as being a very silly way to make a digital RPM meter. Much better is to:
Clean up the input pulse if necessary so that you get one (or more) well-defined pulse(s) per revolution (you would have to do this anyway if you use a frequency-to-voltage chip);
Feed the pulse into an Arduino pin that supports interrupts. In the ISR, record the time that the pulse occurred using a call to micros(), and calculate the time since the previous pulse. Then the RPM is just 60 divided by the interval (in seconds) between pulses.
dc42:
Converting what is essentially a digital signal to analog via a frequency-to-voltage chip and then converting it back to digital strikes me as being a very silly way to make a digital RPM meter. Much better is to:
Clean up the input pulse if necessary so that you get one (or more) well-defined pulse(s) per revolution (you would have to do this anyway of you use a frequency-to-voltage chip);
Feed the pulse into an Arduino pin that supports interrupts. In the ISR, record the time that the pulse occurred using a call to micros(), and calculate the time since the previous pulse. Then the RPM is just 60 divided by the interval (in seconds) between pulses.
You are right.. I even had the same thought in my mind that why convert frequency to voltage and feed arduino when arduino itself can take the frequency directly..
If you read my posts right from the beginning, you will notice thats what I wanted to do ..
I wanted to find the time gap between pulses and calculate the RPM...But I just couldn't get how to find the interval...
can you please help me with the coding as you said..??
OK, I'll assume you are using an Arduino Uno. This can generate interrupt 0 on pin 2 and interrupt 1 on pin 3. I'll assume you are feeding the ignition pulse (cleaned up if necessary) to pin 2. Here is a sketch to calculate the rpm:
const int ignitionPin = 2;
const int ignitionInterrupt = 0;
const unsigned int pulsesPerRev = 1;
unsigned long lastPulseTime = 0;
unsigned long rpm = 0;
void ignitionIsr()
{
unsigned long now = micros();
unsigned long interval = now - lastPulseTime;
if (interval > 2000)
{
rpm = 60000000UL/(interval * pulsesPerRev);
lastPulseTime = now;
}
}
void setup()
{
pinMode(ignitionPin, INPUT);
attachInterrupt(ignitionInterrupt, &ignitionIsr, RISING);
}
void loop()
{
// insert code here to show the RPM on the display and delay for e.g. 0.2 seconds
}
I've included some pulse cleanup in the software (i.e. ignore pulses that are less than 2ms apart).
I have a Arduino duemilanove with the Atmega328.. Hope it will also able to take interrupts as the uno on the same pins.. as the uno also uses the 328...
have a Arduino duemilanove with the Atmega328.. Hope it will also able to take interrupts as the uno on the same pins.. as the uno also uses the 328...
As far as software code and hardware pin numbers there is no difference between Uno and your board. Only difference for Uno is smaller size bootloader that also uploads at a faster baudrate, everthing else is the same.
dc42:
OK, I'll assume you are using an Arduino Uno. This can generate interrupt 0 on pin 2 and interrupt 1 on pin 3. I'll assume you are feeding the ignition pulse (cleaned up if necessary) to pin 2. Here is a sketch to calculate the rpm:
const int ignitionPin = 2;
const int ignitionInterrupt = 0;
const unsigned int pulsesPerRev = 1;
unsigned long lastPulseTime = 0;
unsigned long rpm = 0;
void ignitionIsr()
{
unsigned long now = micros();
unsigned long interval = now - lastPulseTime;
if (interval > 2000)
{
rpm = 60000000UL/(interval * pulsesPerRev);
lastPulseTime = now;
}
}
void loop()
{
// insert code here to show the RPM on the display and delay for e.g. 0.2 seconds
}
I've included some pulse cleanup in the software (i.e. ignore pulses that are less than 2ms apart).
@ dc42
First tell me how do I setup my hardware portion of pulse input to the arduino board..??
I thought of using something like this http://www.sportdevices.com/rpm_readings/index.htm
or
tell me if there is any other way to pickup and feed the pulse which will just match your coding..
I went through your code, its just what I want to do, but couldnt plot out how to do it as I am not much advance in coding..
will you please make me understand this part... rpm = 60000000UL/(interval * pulsesPerRev); what is that 60000000UL...??