Show Posts
Pages: 1 ... 23 24 [25] 26 27 ... 35
361  Using Arduino / Sensors / Re: Too many if statements?? Please help on: August 26, 2012, 01:19:17 am
I am writing a program that reads multiple sensors on the Analog input pins and because I don't really understand how to initiate the switch/case parameters I am using if statements.  The sketch works fine when only using 2 IF statements but when I get to the third nothing works.  I didn't think there was a limit to the number of IF statements but am I wrong?  Each IF statement is exactly the same so it's not syntax errors or anything like that.  I am at my wits end trying to get this to work.  Please help with any input possible.  In the mean time I will keep working on it.  Thank you in advance for any input.

Auto Format is your friend!  Or it should be.

Are we to assume that you're talking about the IF statements in loop() or are you talking about playfile(char *name)?  And could you be anymore general than "nothing works"?

Your problem isn't IF statements or not using CASE statements.  Your problem is one of your code having some kind of bug.  Very hard for anyone to help when you're being so general and not giving specifics.

A good way to diagnose your problem is to put statements like the following inside your IF statements (as the first command).

Code:
Serial.println("1");

With each command being a different number, letter, or something to describe each IF statement.  Then, when you run your sketch you open the Serial Monitor so you can track where the code is and when it's failing.

In any case, it's not the fault of Arduino and using too many IF statements or needing to use CASE.  The problem is your code is wrong.  And for us to help specifically you should give DETAILS.

Tim
362  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 26, 2012, 01:03:26 am
Thinking...  Instead of measuring the time of a reflection returned from an object.  What if we had 2 devices synchronized by GPS or an accurate clock.  One sending the ping, the other receiving it.  If we can measure the delay within 1-2us that would be accurate.  Roughly 0.01".  Obviously that is not possible because of the physics of a sound wave. 

What is the theoretical limit using the frequency of the ultrasonic sensors in this configuration? 
It's the same as the normal method.
Let's use 100khz as an example.  Each cycle is 10us.  So 1/10"?  Certainly <1/2".  Averaging multiple readings.

Wouldn't this greatly increase the range compared to using only 1 device?

You could send a ping every 2ms once you know the rough distance. 
Then you'd have 500 measurements to average in only 1 sec, regardless of the distance.

Obviously the limitation would not be the accuracy of the PPS clock, since GPS is +-10ns.
10ns is about 10ft at the speed of LIGHT!
We'll leave that for another LightPing Library...

How can I use this method with the receiver in a Quadcopter?
The problem is the sound from the motors and blades.
The obvious answer is to put the transmitter in the air,
the receiver on the ground where you want to land, then Xbee to send the data.
This works much better, with a huge increase in range, compared to reflecting from the ground when it's grass.

Thoughts?

The current ping sensors I've found can't ping that quickly.  I'm finding some ping sensors now that can't really ping faster than about 48-49ms, and none can faster than once every 29-32ms.  Basically, they initiate a ping, then you can't initiate another ping till some set time has passed.

Also, when you initiate a ping they take a little while before they actually start (around 450uS).  This varies greatly from device to device.  My library waits for the sensor to be ready so an accurate measurement is taken.

Finally, when sending a large number of pings, there's no way the receiving sensor would be able to know when the ping that arrived was sent.  The only way that would be possible is if the ping itself actually contained a timestamp.

Without some kind of time stamp on the ping itself, very accurately synchronized sensors, and custom built sensors that would ping on command, it's not really possible.  There are probably easier ways of doing it, albeit probably just as expensive.

Tim
363  Using Arduino / Sensors / Re: Question on ultrasonic sensor! on: August 24, 2012, 12:52:02 pm
If I keep the ultrasonic sensors (40KHZ/25KHZ) in a sealed plastic container, will they still measure the distance? I want to measure the water level in a tank about 10ft depth and I don’t have the water proof ultrasonic sensors available at my place. Any suggestions are welcome.

I don't know your exact usage, but maybe instead of measuring the depth of the water from the surface down, you could measure the distance from above the surface to the water's surface.  Then, with a known surface level and depth, you could easily calculate the depth.

In other words, put the ultrasonic sensor let's say 1 foot above the surface of the water.  The sensor would measure the distance as 12 inches.  You then measure the distance from the sensor to the bottom of the tank, lets say it's 132 inches.  So, when the sensor reads 12 inches, you would do 132-12=120 inch water depth.  When the sensor reads 15 inches, 132-15=117 inch water depth.

While the ultrasonic sensor won't work under water, the ping will reflect off the water's surface.  Not knowing your exact usage maybe this won't work.  But, if it's a tank, it has a static depth and probably a place to mount the sensor above water.  If you do choose to use an ultrasonic sensor, may I suggest the NewPing library which has a ping_median method that would work nicely to filter out noise and get an accurate measurement with something like this that's probably not moving quickly.

Tim
364  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 23, 2012, 02:40:34 pm
fairorgan got me to thinking about exactly how much processing time is spent using the ping_timer method.  Which also helps to understand what else your sketch could be doing in the remaining time.  So, I wrote a sketch to tests this.  The sketch runs for 30 seconds and logs how much time is spent both initiating the ping and checking for the return echo.  It's not perfect, as there's some overhead in doing these calculations making these estimates a little on the high side.  Anyway, here's the results with pings happening every 29ms.

5cm pings = <1% load
20cm pings = 2% load
70cm pings = 7% load
125cm pings = 12% load
200cm pings = 19% load
500cm pings = 45% load

When reducing the maximum sensor distance value when calling the NewPing constructor, you can greatly reduce the maximum ping_timer load.  For example, if you leave it at the default of 500cm, using ping_timer every 29ms will use up to 45% processor load.  However, lowering the max distance to 200cm means the maximum load can be only 19%, or lowering it to 50cm makes the max load only 5%.  So, setting a maximum distance to the longest distance you need will greatly free up the ATmega to do other parts of your sketch.

The ping frequency also effects the processor load.  The above numbers were all done at a 29ms ping rate.  However, if the ping rate is every 100ms, the load is drastically reduced to only 5.5% (down from 19%).  200cm maximum distance and pinging every 50ms uses a maximum of 11% processor load.

So, when creating an interrupt driven sketch and using NewPing, setting the maximum sensor distance and ping rate to what you really need for your project will greatly effect how much processing time you have available to do other parts of your sketch.  Doing a maximum ping rate of 29ms and leaving the default maximum distance at 500cm will use almost half of the ATmega processing time (45%).  If your project really only needs to sense out to 200cm and pinging once every 100ms is all the faster you really need, you've lowered the processing time down to only 5.5% (almost 1/10th the load).

Keep in mind that these are maximum load amounts.  If the a ping echo is sensed at a shorter distance, the load can be greatly reduced.  For example, the 45% load for a max distance of 500cm at a 29ms ping rate is only if there's a NO_ECHO (zero value).  If under the same settings there's a constant ping echo at 10cm, the load is only 1%.  So, these are truly worse case numbers.  But, to avoid your sketch to be sluggish at times, you should consider the worst case scenario.

Tim
365  Using Arduino / Sensors / Re: What to do when I run out of analog inputs? on: August 22, 2012, 05:35:57 pm
I'm using the analog inputs on the Arduino Uno R3 to measure voltage values between 0-5V. I ran out of analog inputs. Is there a way to expand the amount of analog inputs? Can the digital pins be used as analog input pins?

Sorta un-related side question:
Whenever I have the Arduino Motor shield on top of the Arduino board, I notice that the A1 + A0 inputs no longer are able to sense any voltage values and the A2+A3 inputs are always measuring 5V, even when open. Is the motor shield broken? Is this abnormal behavior? Therefore, Im looking for other ways to increase the analog input sensors.

I suggest the Teensy board.  It's only $16 and has 12 analog inputs.  It's also wonderfully small and complete with USB.  It's like a micro version of a Leonardo.  Love it!

Tim
366  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 22, 2012, 05:08:59 pm
I was actually only thinking of using two SR-04 sensors (at most three), but like your use of the array in the 15 sensor example for holding the data. Would I be better just duplicating the new ping_median once per sensor and not use an array nor interrupt method?

My project: I am controlling a robot’s head position via servos, which currently have either remote control (via joystick) or automatic random positioning of x and y axis. I would like to add the ability for close object tracking of the x axis, so thought the best way would be two ultrasonic sensors pointing slightly apart concealed on the head itself, and in the event of an object coming within say a couple of metres range, the head will stop random movements and track the object in x axis by moving the servo to keep the signal from both ultrasonic sensors the same, until either the object goes out of range or the robot gets bored.

If you just wanted to use an array to store the ping results, you could easily modify the 15 sensor sketch to work with ping_median instead of ping_timer.  The problem is that the sketch would no longer be interrupt driven, and would be waiting for ping echos instead of doing anything else (like positioning the servo on the robot or doing probably much of anything else).  For example, if you had 3 sensors and each sensor would take 5 samples to find the median that would be a total of 15 pings with at least a 29ms delay between each or a total of around 435ms (about 1/2 second) every ping cycle where your robot can do nothing but read the sensors.  Not at all interrupt driven like the 15 sensor sketch where very little time is wasted monitoring the pings and you're free to do other things what seems like the same time.

A better solution is to continue to use the 15 sensor sketch as a base, but use oversampling to read the sensors multiple times, then average the results.  Here's an example sketch:

Code:
#include <NewPing.h>

#define SENSORS        3 // Number or sensors.
#define ITERATIONS     5 // Iterations for each sensor.
#define PING_NUM ITERATIONS * SENSORS // Calculates the number of pings.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 29 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

unsigned long pingTimer[PING_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[PING_NUM];         // Where the ping distances are stored.
uint8_t currentSensor = 0;         // Keeps track of which sensor is active.

NewPing sonar[PING_NUM] = {      // Sensor object array (Each sensor's trigger pin, echo pin, and max distance to ping).
  NewPing(12, 11, MAX_DISTANCE), // Sensor 0, sample 1
  NewPing(2, 3, MAX_DISTANCE),   // Sensor 1, sample 1
  NewPing(4, 5, MAX_DISTANCE),   // Sensor 2, sample 1
  NewPing(12, 11, MAX_DISTANCE), // Sensor 0, sample 2
  NewPing(2, 3, MAX_DISTANCE),   // Sensor 1, sample 2
  NewPing(4, 5, MAX_DISTANCE),   // Sensor 2, sample 2
  NewPing(12, 11, MAX_DISTANCE), // Sensor 0, sample 3
  NewPing(2, 3, MAX_DISTANCE),   // Sensor 1, sample 3
  NewPing(4, 5, MAX_DISTANCE),   // Sensor 2, sample 3
  NewPing(12, 11, MAX_DISTANCE), // Sensor 0, sample 4
  NewPing(2, 3, MAX_DISTANCE),   // Sensor 1, sample 4
  NewPing(4, 5, MAX_DISTANCE),   // Sensor 2, sample 4
  NewPing(12, 11, MAX_DISTANCE), // Sensor 0, sample 5
  NewPing(2, 3, MAX_DISTANCE),   // Sensor 1, sample 5
  NewPing(4, 5, MAX_DISTANCE)    // Sensor 2, sample 5
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;          // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < PING_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
  for (uint8_t i = 0; i < PING_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {        // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * PING_NUM;   // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == PING_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = NO_ECHO;                // Make distance NO_ECHO in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
    }
  }
  // The rest of your code would go here.
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
  unsigned int uS[ITERATIONS], last;
  uint8_t i, j, x, it, ii;
  for (x = 0; x < SENSORS; x++) {
    uS[0] = NO_ECHO;
    it = ITERATIONS;
    ii = 0;
    for (i = 0; i < ITERATIONS; i++) {
      last = cm[x + (i * SENSORS)];
      if (last != NO_ECHO) {   // Ping in range, include as part of median.
        if (i > 0) {           // Don't start sort till second ping.
          for (j = ii; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
            uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
        } else j = 0;          // First ping is starting point for sort.
        uS[j] = last;          // Add last ping to array in sorted position.
        ii++;                  // Next ping in insertion sort array.
      } else it--;             // Ping out of range, skip and don't include as part of median.
    }
    Serial.print(x);
    Serial.print("=");
    Serial.print(uS[it >> 1]);
    Serial.print("cm ");
  }
  Serial.println();
}

The above sketch is 3 sensors with 5 times oversampling.  Instead of just printing the results in the oneSensorCycle function, it does the same insertion sort/median calculation as NewPing does with the ping_median method.  It pings each sensor (0,1,2) then repeats 5 times.  For example, the ping order is: 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2.  This sketch will also accommodate different oversampling (iterations).  Just change the ITERATIONS define and sonar array to match.

The advantage is that this sketch is totally interrupt driven.  So, the ATmega has all kinds of time to do other things.  While pinging, every 24uS it checks for a ping echo, but the rest of the time your sketch can do other things (like rotate a servo, move, etc).  Once a full 3 sensor, 5 oversample pass is made, it goes to the oneSensorCycle function where the median values for the 3 sensors are calculated, which is very quick and only takes about 30uS.  Basically, the ATmega is free to do other things at the same time it's pinging.  Just be sure to not use any delay statements in your sketches!

Tim
367  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 21, 2012, 05:53:28 pm
Your code works fine for me.  I guess a loose connection could the the source of the problem.  But, it could also be that you're trying to get a ping that's just too far away.  These sensors really don't work all the way out to 400 or 500cm.  They seem to work okay to about 200cm for most, but I have some sensors that won't read anything consistently beyond around 75cm.  This is the fault of the sensors, not the library as the same thing happens with other libraries or with no library at all.  Try putting something 50cm away from the sensor and see what happens then.  It's just suspicious that it stops working around 200cm and then in your next test all the results are within 200cm.  Maybe it would work without you holding the sensor if all the readings were <50cm?  But, if it is a lose connection, that could also be why it's crashing after a few minutes, it's simply shorting out.  BTW, I've *never* got a zero reading that wasn't for a logical reason and I've *never* had any of my Arduino or Teensy 2.0 crash while using the NewPing library.  And, I've sometimes ran them for several hours or even overnight without a single issue.

Tim
368  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 21, 2012, 08:32:46 am
Fantastic job with this new library!

I am especially liking the median feature of v1.5 to eliminate rogue results, but how can this be integrated into the 15 sensor example sketch which does not use ping() but sonar.ping_timer(function) instead?

To actually combine the two would be simple.  However, in the process it would lose the interrupt aspect of the ping_timer() method.  I've been toying with the idea, and considering new ways of doing it.  One thing I've considered is a mass ping of all sensors at the same time followed by interrupt waiting for the ping echo.  With 15 sensors there could be crazy cross-talk.  But with 4 sensors it would probably work.

Also consider that with 15 sensors, if it were to poll each sensor 3 times it would take 3 times as long.  Not sure how much processing time you have left after pinging 15 sensors.  But, multiply the time it takes by 3 or 5 and you may no longer have time to do anything else, or the pings are just too slow to sense something in time if your robot is moving at a high enough speed.

Tim
369  Using Arduino / Sensors / Re: How to get a degree value of Accelerometer MMA7455? on: August 20, 2012, 03:46:50 pm
The application is to use it as a tilt sensor for a robot

A gyroscope would probably be what you need for a robot tilt sensor.  If you're trying to balance a robot, a gyroscope will work for a short while, then drift will cause it to fall over.  You really need both for a balancing robot.

So, do you want to measure tilt, or are you actually trying to get it to balance?
370  Using Arduino / Sensors / Re: High precision detection of distance and movement on: August 16, 2012, 03:17:43 pm
I want to detect and follow a fly in the room in the hope that in a next stage I can shoot it down with a laser.

You have my attention!  Have you considered a low-tech solution to your fly problem?  Like maybe fly paper ribbon?  An 8-pack for $5.17 including free shipping sounds like a cheaper and easier solution to me.

Tim
371  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 15, 2012, 05:29:22 pm
By the way, I went with just the median method for digital filtering.  It's fast, the overhead is much smaller, and the results were just as effective as finding the mean of a centered sample.  Using ping_median() is just as simple as using ping() too.  There's nothing to figure out, just change ping() to ping_median() in your sketch and it will automatically do 5 pings and return the median ping.  To specify a different number of samples, just specify the number of iterations you want like this: ping_median(9).  Here's a sample sketch that uses ping_median:

Code:
#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() {
  delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
  Serial.print(sonar.ping_median(3) / US_ROUNDTRIP_CM); // Send 3 pins and return the median ping converted to centimeters.
  Serial.println("cm");
}

Enjoy!
372  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.5 on: August 15, 2012, 05:19:17 pm
NewPing v1.5 released, here's what's new:

Added ping_median() method which does a user specified number of pings (default=5) and returns the median ping in microseconds (out of range pings ignored). This is a very effective digital filter. Optimized for smaller compiled size (even smaller than sketches that don't use a library).

Download NewPing v1.5

Tim
373  Using Arduino / Sensors / Re: Distance sensor (ultrasound) water / dirt resistant for car. on: August 11, 2012, 11:21:30 pm
Hi,

i want to build something like a park distance control.
The problem with the popular cheap sensors like HC-SR04 is that they will get wet or dirt will fill them when i look at the pictures.

When i look at the pdk´s you can buy at ebay or what car manufactt. use, they got closed housings (or at least very small gaps).
Also im wondering about the fact that they have both reciver and sening unit in one housing.
First i thought one sends all the time and one recives. But even the HC-SR04 seems to send and wait for signal, but why 2 sensors on the board?

I found some 14C01 sensors or USTR40-14A. But im not sure if they work.

Maby you can get me some advice, i found a mass of tutorials but only with these popular sensors that already have circuits and are not water/dirtproofed

thx smiley

Is this for parking in a garage?  If so, instead of putting the sensor on the car, you can put a HC-SR04 in the garage.

Or, are you wanting to make backup sensors?  Maybe a detailed example of what you're trying to do so we can better help.

Tim
374  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.4 on: August 11, 2012, 01:32:42 am
Here's also a simplified version that just finds the median.

Code:
unsigned int NewPing::ping_median(uint8_t it) {
int uS[it], last;
uint8_t j, i = 0;
uS[0] = NO_ECHO;
while (i < it) {
last = ping();           // Send ping.
if (last == NO_ECHO) {   // Out of range ping.
it--;                // Skip, don't include as part of median.
last = _maxEchoTime; // Adjust "last" variable so delay is correct length.
} else {                       // Ping in range, include as part of median.
if (i > 0)                 // Don't start sort till second ping.
for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
else j = 0;                // First ping is starting point for sort.
uS[j] = last;              // Add last ping to array in sorted position.
i++;                       // Move to next ping.
}
if (i < it -1) delay(PING_MEDIAN_DELAY - (last >> 10)); // Millisecond delay between pings.
}
return (uS[it >> 1]); // Return the ping distance median.
}

This saves 112 bytes of complied code size so it's worth considering.  I could add both a ping_median() and ping_mode() but I feel that's a little excessive.  Any statistic types out there may want to chime in on if a pure median calculation is good enough in removing digital noise.  Or, if the addition of the truncated mean with removed +/-2cm outliners is worth the 112 byte loss.  Median and truncated mean yield different cm results about 10% of the time, but which one is better or more correct?  When they return two different values there's not one value that's clearly more accurate more consistently as far as I can tell.

I'm leaning towards the above ping_median method as a digital filter.  It's 112 bytes smaller and seemingly just as effective (albeit sometimes different).

Tim
375  Using Arduino / Sensors / Re: NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.4 on: August 11, 2012, 01:11:36 am
Okay, I believe I've got the new digital filtering method down to as lean as it's going to get with all the kinks worked out.  For the coders out there, here's the method:

Code:
unsigned int NewPing::ping_ave(uint8_t it) {
int uS[it], last, median;
uint8_t i, j, cnt = 0;
unsigned long total = 0;
uS[0] = last = ping();   // Send first ping (done here to assist insertion sort).
for (i = 1; i < it; i++) {                                                    // Ping iterations.
if (last != NO_ECHO) cnt++;                                               // Array median tracking.
delay(PING_AVE_DELAY - ((last == NO_ECHO ? _maxEchoTime : last) / 1000)); // Delay between pings.
last = ping();                                                            // Send ping.
for (j = i; j > 0 && uS[j - 1] < last; j--) uS[j] = uS[j - 1];            // Insertion sort (big to small).
uS[j] = last;                                                             // Add last ping to array in correct order.
}
if (last != NO_ECHO) cnt++; // Array median tracking.
median = uS[cnt >> 1];      // Find median.
cnt = 0;                    // Reset counter.
for (i = 0; i < it; i++) {                           // Loop through results.
if (abs(median - uS[i]) < US_ROUNDTRIP_CM * 2) { // Exclude values outside +/-2cm range (digital noise).
total += uS[i];                              // Building truncated mean.
cnt++;                                       // Increment counter.
}
}
return (total / cnt); // Return the ping distance mean minus digital noise (truncated mean).
}

To actually implement it you would need to define PING_AVE_DELAY to 29 and add the method to the class (I set the iterations [it] to default to 5).  I know not everyone is adept at doing this, but this is a preview for those that are.  Also, if there's any statistical gurus out there that want to poke holes in my code, feel free (statistics is not my thing).

The method uses two passes to calculate a truncated mean with outliner pings removed (digital noise).  The first pass collects the pings, keeps track of successful pings, and sorts on-line using the very simple and fast insertion sort.  Before the second pass it then calculates the median ping (with the unsuccessful pings filtered out).

Once the median value is found, it then does another pass to calculate the truncated mean.  Outliner pings are those outside +/-2cm (these are not calculated as part of the mean).  Because insertion sort is done on-line instead of in another pass (like a typical bubble sort), even the max of 255 ping iterations can be done without any perceived slow-down (although 255 is a little excessive, 3-9 is typically plenty).  Insertion sort is *very* fast with a small quantity of values to sort.  So fast that highly complex sort algorithms like quicksort resort to insertion sort when there's only a few values to sort (like in this case).  Also, insertion sort has a very small stack footprint (only one variable) and extremely small code size (because it's so simple, 2 lines of code).  It's really the only sort to use on Arduino.

In laymen terms, the new method does a user-specified number of pings as fast as it can (29ms per ping) ignores out of range pings, sorts the ping values, gets the middle distance ping value, filters out pings outside +/-2cm of the middle distance ping, and returns the average of these pings in microseconds.

Code:
unsigned int us = sonar.ping_ave(); // Defaults to 5 iterations, returns the truncated mean in microseconds.
unsigned int us = sonar.ping_ave(3); // Do 3 iterations, returns the truncated mean in microseconds.
unsigned int cm = sonar.convert_cm(sonar.ping_ave(9)); // Do 9 iterations and get the truncated mean in cm.

A few explanations about the method specific to the programming.  First, some things may not appear as clean as they could be.    In many cases this is done to make the code smaller once compiled.  By making these changes around 100 bytes was saved on the final compiled code.  I believe this is a fair compromise with the limited memory in the ATmega.  Secondly, there are some items that may not be statistically perfect.  An example is the median when there's an even number of values.  The code only picks one median value, even if there technically should be the average of two.  This again was done to reduce compiled code size and it also doesn't make much difference as there's a lot of fuzzy logic in a truncated mean anyway.

Basically, the function could be re-worked to be more clear, logical, and maybe slightly more statistically accurate.  But, that's technically how the function started.  I tweaked it over the course of a few days to try and squeeze as many bytes as I could out of it.

With that said, if there's something wrong, a suggestion, or another performance tweak that doesn't make the compiled code larger, please let me know (that's one of the reasons I'm posting the method before it's released).

Tim
Pages: 1 ... 23 24 [25] 26 27 ... 35