Go Down

Topic: Average of reading on IR sensor (Read 2170 times) previous topic - next topic

mortni11

Hey people

I'm using a SHARP IR sensor for a school project. When im testing the sensor, it works but in between there are some irregular
readings when nothing is infront of the sensor (so i should read zero) but there are some very sort signal (of high value mostly).
I need to use it as a trigger and therefore need a way around this. Is it maybe poissble to gather lets say the last six or seven last
read values and create a average of this? Or is there some other way. I guess its because the sensor has some kind of loose connection?

Thanks!

Trught

Here is the code for the IR that could help you.
http://www.ladyada.net/learn/sensors/ir.html

robtillaart

Quote
Is it maybe poissble to gather lets say the last six or seven last
read values and create a average of this? Or is there some other way.


maybe these libs can be useful
- http://arduino.cc/playground/Main/RunningAverage -
- http://arduino.cc/playground/Main/RunningMedian -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Chagrin

To smooth an analog sensor I always do something like:

Code: [Select]
void loop() {
  x = analogRead(PIN);

  if (x > reading) {
    reading = reading + 1;
  } else if (x < reading) {
    reading = reading - 1;
  }
}




Constantin

Could be a noise issue. Have you checked your wiring and power supply to rule that out? I.e. there are no other relays, other things that are potentially interfering with the ADC?

You could also try putting a small capacitor across the output to smooth the response and resist spikes. Naturally, such a cap will slow the responsiveness of the sensor. You could also filter the results in software as suggested above. One technique I like using on (relatively speaking) slow moving signals is decimation. You end up with better accuracy and it filters noise too. See the Atmel AVR white paper for more info on this. Plus, you get to learn about bit shifting.

Last but not least, depending on the speed with which you are switching channels on the ADC, there can be problems also. If you left the ADC pre-scaler alone, this should not be an issue.

robtillaart

@chagrin

I think your filter handles large changes and small noise the same way. I expect most people want the fine noise (last bit) to be suppressed.


I mostly use something like this
Code: [Select]

void loop()
{
  x = x - 0.15 * (x - analogRead(PIN) );  // 0.15 can be any value between 0.001 and 1.0
}


(it is a cleaner variation of x = 0.85*x + 0.15*analogRead(PIN); as it only has one tuneable param in the formula.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

jraskell

Actually, a small cap on the power in for the Sharp sensor is recommended and often needed (on the order of a few tens of microfarads, ie 20-30uf).  The sensor does not have a constant power draw, but a very spikey power draw (it pulses an IR LED, which are fairly high current LEDs), and a cap on the power line can help stabilize the entire sensor and provide a more stable output.

Constantin


Actually, a small cap on the power in for the Sharp sensor is recommended and often needed (on the order of a few tens of microfarads, ie 20-30uf).  The sensor does not have a constant power draw, but a very spikey power draw (it pulses an IR LED, which are fairly high current LEDs), and a cap on the power line can help stabilize the entire sensor and provide a more stable output.

Well, there you go.  :) A stable power supply is always on the path to happiness. But putting a cap on the analog input on the arduino can also help alleviate spurious fluctuations.

_Leo_


...
I mostly use something like this
Code: [Select]

void loop()
{
  x = x - 0.15 * (x - analogRead(PIN) );  // 0.15 can be any value between 0.001 and 1.0
}

...


I like that :)

Is there a way of changing the formula so it calculates in int instead of float?
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

robtillaart

Quote
Is there a way of changing the formula so it calculates in int instead of float?

Of course there is

Code: [Select]

unsigned int x
void loop()
{
  x = (64 *x -10 * (x - analogRead(PIN) ))/64;   
}

// 64 gives a quick bitshift for division and 0.15 * 64 = 9.6 => 10

the max value is 1023 so 64 *1023 does not overflow!

the 10 can be replaced by (0..64) giving different weights to the oldvalue and the new value.

Test the difference in memory (sketch size) and speed (e.g. 10000 calls). 



Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

Thank you very much Rob.

The speed is what I'm after :)
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

robtillaart


Code: [Select]


// http://arduino.cc/forum/index.php/topic,56396.0.html
// and
// http://arduino.cc/forum/index.php/topic,74895.0.html

/*
  Sketch to demonstrate how to decrease time of analog read.
it shortens the delay by manipulating registers and reducing the prescale
timer value from 128 to 16;

Note Serial Speed! Change to suit yourself!

Sample Sketch From Arduino Cookbook by Margolis (O'Reilly Press)
Modified by Willr March24, 2011

Tested on Mega2560 Arduino board with an MA7361 Z output hooked to
Sensor 5
*/

// CHANGE Sensor Pin to suit yourself...
const int sensorPin = 5;

// Change  number of entries to a value divisible by 100 only
const int numberOfEntries = 100;

unsigned long microseconds;
unsigned long duration1;
unsigned long duration2;

int results[numberOfEntries];

void setup()
{
  Serial.begin(9600); ///CHANGED
  Serial.flush();


  // standard analog read performance -- prescale == 128
  microseconds = micros();
  for (int i=0; i < numberOfEntries; i++)
  {
    results[i] = analogRead(sensorPin);
  }

  duration1 = micros() - microseconds;

  Serial.print(numberOfEntries);
  Serial.print("   readings took ");
  Serial.println(duration1);

  // This double loop just prints a neat table..
  for( int j=0; j < numberOfEntries; j=j+20)
  {
    for (int i=0; i < 20; i++)
    {
      Serial.print(results[j+i]);
      Serial.print(",  ");
    } //end loop i
    Serial.println();
  } //end loop j

  Serial.println();

  // prescale clock to 16
  bitClear(ADCSRA,ADPS0);
  bitClear(ADCSRA,ADPS1);
  bitSet(ADCSRA,ADPS2);

  // Performance with Changeed Prescale...
  microseconds = micros();
  for (int i=0; i < numberOfEntries; i++)
  {
    results[i] = analogRead(sensorPin);
  }

  duration2 = micros() - microseconds;
  Serial.print(numberOfEntries);
  Serial.print("   readings took ");
  Serial.println(duration2);

  for( int j=0; j < numberOfEntries; j=j+20)
  {
    for (int i=0; i < 20; i++)
    {
      Serial.print(results[j+i]);
      Serial.print(",  ");
    } //end loop i
    Serial.println();
  } //end loop j

  Serial.println();

  Serial.print("Ratio of read times is : ");
  Serial.println((float)duration1/duration2);
  Serial.println("********************");
}

void loop()
{
  // empty main loop is deliberate...
}


There are also optimizations known if the pin number is hard coded at compile time - could not find and example though -



Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

Thanks Rob, but I'm going to test the simple formula with my MS5611-01BA01 pressure sensor.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Go Up