ru
![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Android Articles Browser games My programs About | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ultrasonic distance sensor HC-SR04Like any curious person, I was fascinated by the study of arduino. After purchasing a CPU was forced to think about the periphery. Starting from simple flashing LEDs. But this was not enough. And began designing toys. On old toy car jeep was electronic control system (with Arduino) of motor and turn the well. All motor connect with driver L293D chip, for save processor and to provide the necessary currents and voltages to the electric car motor. But on it I'm not stop and move next. So what is the robot-car, if this robot is no reference to the track. It was necessary to make the back data flow for search move track for robot car. Was bought ultrasonic sensor HC-SR04. HC-SR04, to determine the direction of movement had to install it on an improvised swivel platform, to providing the scanning direction and the correct ways of driving. The first result give good data, auto-robot went quite cheerfully, independently choosing a path. However, a number of questions that made me think, how balanced the system is and how it interacts. Have been a number of primary test, that describe on this text. Immediately had to solve the question of the precision of the ultrasonic sensor. For work with ultrasonic sensor under Arduino exist library NewPing.h. This library help to make measure of distance in inches and in centimeter. I have be test precision of this sensor on this text. Have be collected statistic data of distance of same objects. And have be check precision of this ultrasonic sensor. On the Internet can be found pfoto with under mark «HC-SR04» but other electronic board construction or with different electronic circuit element. On this photo show the sensor model that I has describe on this review. Software for plot graph, reproduce experimentFor collect statistic data ower COM-port I use Arduino SDK. For plot graph I using Open Office Calc, but you can use other table processor for it. For group data by sound delay at the first experiments I use OpenOffice Base (DB) and SQL (sketch 1). At the last experiment I wrote special program for Arduino, cause see that 2kB of memory has enought for process all statistic data up to 1 hour with non move object (sketch 2). Arduino sketch 1. At the first time I using this code for Arduino. It's collect all «raw ping» data to serial port into PC row by row. At the start wait 5 second (blink LED). Then get lines with: number of measure, time stamp of measure (ms), distance (sound delay, ns). This is easy sketch, you should rework raw data for plot statistic graphic.
// Sonar statistic's
#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 400 // 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 flashLed(int second) { for (int i=0;i<second*4;i++) { digitalWrite(13,HIGH); delay(250); digitalWrite(13,LOW); delay(250); } } void setup() { Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results. Serial.println("Collecting ping's data. Wait 5 second then start..."); pinMode(13, OUTPUT); flashLed(5); Serial.println("Start ping's... Number, Time after start , ping in microseconds"); } unsigned long number=0; // number of probe //* void loop() { number++; if ( number != 0 ) { unsigned int echoTime = sonar.ping(); // microseconds unsigned long t=millis(); Serial.print(number);Serial.print("\t"); Serial.print(t);Serial.print("\t"); Serial.print(echoTime);Serial.println(); delay(50); //todo check optimal time. Recomended ower 50 ms, but print take time too. } else { Serial.println("End of numbers. Wait 5 min then again..."); flashLed(5*60); // blink 5 min then again number=0 } } //*/ // as in ping demo: /* void loop() { delay(50); // Wait 50ms between pings (about 20 pings/sec). unsigned int echoTime = sonar.ping(); // microseconds Serial.print("Ping cm,ns:\t"); Serial.print(sonar.convert_cm(echoTime)); Serial.print("\t"); Serial.println(echoTime); } //*/ Sketch 2. After first experiment I was see that distance data is not too differend and can all store into small 1.5 kB of memory. This programm wait 5 second (blink LED) then show agregate statistic information on serial port. For plot graph you can get same table, sort by distance then plot graph. This program can make misstake after 1 hour of work, and can have forgot same data if the same object will be move and not enought memory (array cell) for store all data. This code will be write error message into console, if some data will be forgot.
// Sonar statistic's
The template MeasureMath can use not only for math length data, it can use for diffetent statistic data. The code on this page is under GNU GPL License v2.
// (C) www.AlexeyK.com 2016. This source code under GNU GPL v2 license. #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 400 // 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 flashLed(int second) { for (int i=0;i<second*4;i++) { digitalWrite(13,HIGH); delay(250); digitalWrite(13,LOW); delay(250); } } void setup() { Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results. Serial.println("Collecting ping's data. Wait 5 second then start..."); pinMode(13, OUTPUT); flashLed(5); Serial.println("Start ping's..."); } // ------ special statistic data 'processor' - group data into arduino ------ #define TArrayIndex unsigned int // template: array size, value type: signed/unsigned int/long/float(floating point values not recomended), count type: unsigned int/long template <int STAT_MAX_DATA, typename TValue,typename TCount> class MeasureMath { private: TCount MAX_COUNT; public: //#define MAX_COUNT 65535 // depends of TArrayIndex type: byte 255 or unsigned int 65535 TValue stat_value[STAT_MAX_DATA]; // measure data TCount stat_count[STAT_MAX_DATA]; // measure count TArrayIndex stat_using; // using array size for stat_count/stat_value. unsigned long stat_start; // time of start data collected. MeasureMath() { stat_using=0; stat_start=0; MAX_COUNT=0;//std::numeric_limits<TCount>::max(); // required limits.h MAX_COUNT--; // owerflow for get max value. TArrayIndex testI=STAT_MAX_DATA+1; // check TArrayIndex: must can store value up to STAT_MAX_DATA+1 if (testI<0 || testI!=STAT_MAX_DATA+1) Serial.println("ERROR: bad index type!"); } void onNewMeasure(long value) // this method call for register new measurement. { int dataI; for (dataI=0; (dataI<stat_using) && (stat_value[dataI]!=value);dataI++); // search cell if (dataI==stat_using) { // not found - make new cell if (stat_using>=STAT_MAX_DATA) { Serial.println("ERROR: no memory for store new value!"); return; } stat_value[stat_using]=value; stat_count[stat_using]=1; stat_using++; return; } if (stat_count[dataI]>=MAX_COUNT) { Serial.print("ERROR: owerflow for value ");Serial.print(value);Serial.println(); return; } stat_count[dataI]++; } void resetStat() { // clear statistic data stat_using=0; stat_start=millis(); } unsigned long getStatCountSumm() { // get all stored measurement count unsigned long s=0; for (TArrayIndex i=0;i<stat_using;i++) s+=stat_count[i]; return s; } TValue getStatMin() { // find minimal value if (stat_using==0) { Serial.println("No data for find min value."); return 0; } TValue m=stat_value[0]; for (TArrayIndex i=1;i<stat_using;i++) if (m>stat_value[i]) m=stat_value[i]; return m; } TValue getStatMax() { // find maximal value if (stat_using==0) { Serial.println("No data for find max value."); return 0; } TValue m=stat_value[0]; for (TArrayIndex i=1;i<stat_using;i++) if (m<stat_value[i]) m=stat_value[i]; return m; } double getStatAverage() { // return average of all stored measurement if (stat_using==0) { Serial.println("No data for find average value."); return 0; } double sum=0, count=0; for (TArrayIndex i=0;i<stat_using;i++) { double cnt=stat_count[i]; sum+=(double)stat_value[i] * cnt; count+=cnt; } //Serial.print("dbgAVG Count=");Serial.print(count);Serial.print(", sum=");Serial.println(sum); return sum/count; } double getStatStdE() { // math standard error of all collect data if (stat_using==0) { Serial.println("No data for find standard error."); return 0; } double average = getStatAverage(); double sumSq=0, count=0; for (TArrayIndex i=0;i<stat_using;i++) { double cnt=stat_count[i]; double a = sq(((double)stat_value[i]-average)) * cnt; sumSq+=a; count+=cnt; } double D = sumSq / count; // dispersion return sqrt(D); // standard error } void printStat() { //unsigned long timeSt=micros(); // for check CPU performance only. Or millis(); TValue sMin=getStatMin(); TValue sMax=getStatMax(); unsigned long sCount=getStatCountSumm(); double average=getStatAverage(); double variance=getStatStdE(); //unsigned long timeEnd=micros(); Serial.print("Count: ");Serial.print(sCount); Serial.print(", min: ");Serial.print(sMin); Serial.print(", max: ");Serial.print(sMax); Serial.print(", average: ");Serial.print(average); Serial.print(", variance: ");Serial.print(variance); Serial.println(); //Serial.print("Calculate time, ns: ");Serial.println(timeEnd-timeSt); } unsigned long getCollectTime() { return millis()-stat_start; } void printStatData() { Serial.print("Collecting data stored ");Serial.print(stat_using);Serial.print(" values, collect time ");Serial.print(getCollectTime());Serial.println(" ms, data count/values:"); for (TArrayIndex i=0;i<stat_using;i++) { Serial.print(stat_count[i]);Serial.print("\t");Serial.println(stat_value[i]); } } }; MeasureMath<220, unsigned int, unsigned int> mstat; // warning: with this MeasureMath on arduino - ower 16000 measure can make arifmetical misstake. void loop() { unsigned int echoTime; for (int i=0;i<40;i++) { delay(50); // Wait 50ms between pings (about 20 pings/sec). echoTime = sonar.ping(); // microseconds mstat.onNewMeasure(echoTime); } Serial.print("Ping cm,ns:\t"); Serial.print(sonar.convert_cm(echoTime)); Serial.print("\t"); Serial.println(echoTime); if (Serial.available()>0) { int cmd = Serial.read(); // int or byte or char? if (cmd=='r' || cmd =='R') { Serial.println("Reset stat data."); mstat.resetStat(); } } mstat.printStat(); mstat.printStatData(); } As you can see, the Arduino UNO have enought memory (1.5kB) for make same non trivial math statistic with array of data (≈250 of element). Same words aboud programm performance. The more often data (distance) will be stored first cell of array that no often distance (cause probability theory work). Cause it the more data point will be seek faster for inserting into data array (for found position in array usualy need seek less that 1/2 cell of array). But after long time the array of data will be stored more different elements and math summary statistic will be required more time (average, standard deviation, etc.). Measurements, data and graphics1. At the begin I was check distance to tree surface (table), length 22.5 cm (this value is result of check by roulette from sensor circuit board). Collect 31212 measurements of 27 minutes 18 seconds. The sound delays was between from 1199 ns to 1219 ns, average delay is 1208.55 ns. Standard deviation is ± 2.624 ns. See graph 1, data in table 1. ![]() ![]() Graphic 1. Distribution time (length)
2. At the second experiment was check distance to tree surface (table), distance 46 cm. Collect 40323 measurements of 36 minutes 12 seconds. The delay was from 2539 ns to 2587 ns, average delay was 2552.40 ns. Standard deviation was ± 6.153 ns. See graphic 2, data in table 2. ![]() ![]() Geaph 2. Distribution time (length)
3. At the next was check distance to plastic bag: length 118.7 cm. Collect 8453 measurements of 8 minutes. The delay was from 5779 ns to 6127 ns, average delay was 5955.40 ns. Standard deviation was ± 51.691 ns. See graph 3, data in table 3. ![]() ![]() Graph 3. Distribution time (length) (collapse)Table 3. The group data of measurement 3 (open)
4. At the next was check distance to cloth, length 67 cm. Collect 47586 measurements of 43 minutes 57 seconds. The delay was between from 4011 ns to 4779 ns, average delay was the 4114.44 ns. Standard deviation was ± 60.009 ns. See graph 4, data in table 4. (collapse)Table 4. The group data of measurement 4 (open)
5. At the next was check distance to wall (concrete), distance 291 cm. The data collect some of outlier, cause I show statistic with outlier data and without outlier, (in the bracket wrote with outlier). Collect 2315 (raw 2320) of measurements ≈ 3 minutes. Delay of sound was between 16715 (raw 11107) ns and 16883 ns, average delay was 16763.05 (with outlier 16750.94) ns. Standard deviation ± 29.8355 ns (with outlier 262.29 ns). See graph 5 (without outlier), data in table 5; graph 6 with full data (with outlier). ![]() ![]() Graph 5. Distribution time (length), without first rows ![]() Graph 6. Distribution time (length), all data (collapse)Table 5. The group data of measurement 5 (open)
The standard deviation (error) is depends of distance and square of object (material). See result in table 6 of standard deviation.
Distribution on first graph (1, 2) show that it is normal distribution, but other experiment (3 and 4) show that it is may be not normal distribution. Unfortunately, the feature averages converge to precission value work fine with normal distribution. With other distribution and discrete time intervall (4 ns), easy average value not enought for increase precission and get absolute best value of distance. In the math rules for normally distributed data (in the Russian this rule call the rule of 3th Sigma, 3σ), every 370 measure (in the normal distribution) will be have more different between average value, gread that 3 standard deviation. Despite non normal distribution, in experiment 3, rules for normally distributed data is work: only in 9 of 8453 (0.1%) measurement have error ower 155 ns (± 2.7 cm). This experiment was do in non moving object, without car motor noise, and some power surges. But realy work on moving car show that gread («unreal») error exist, and too often. The error found more often on non flat surface (small) objects. The moving car with ultrasonic sensor add new problems: the correct average of changing data in the fast moving, speed measure, noise and changing environment. See different betwen accuracy and precision for understanding whay average can not work for same data. For easy remove outlier I recomended use the median. The function for evaluate median distance exist in library NewPing::ping_median(it), the result of this function (in library) is nanosecond, you can transfer the nanosecod value into centimeters or inches. Small object and backgroundIf take object with small square for high detect error (square less that 5 cm2), and big background, then with collect too much statistic data can be see object and bacground together. On dotted graph 7 can see length (sound time, ns) from two object, without moving of object or sensor. ![]() Graph 7.How see ultrasonuc sensor small object and flat background On graph 7 can see backgroun on distance 215 cm, and small object before background (the big cloud of points) on distance 185 см, and one non real point (error) — it can be echo from background. Depends of standard deviation from square and lengthFor check exist of depends standard deviations of measurement from length was be make addition experiment. Some square plastic peaces was moved between 20 cm up to 180 cm. The result of this experiment present on graph 8. ![]() Graph 8, depends ultrasonic sensor standard deviation by length and square in naniseconds (20-180 cm) The data was too more noise and not enought data to make precission formuls for show depends standard deviation (error) from all parameters: length, square, material, ange of rotate square. But, if collect more data, it will be possible. At the result of experiment I make same formuls for show depend standard deviation from length (table 7), this formula able for distance between 20 cm to 160 cm.
In this table text ^2 wrote for share this formul's to table processor (Open Office Calc); the better result is where great coefficient of determination. The often of depends on 20 to 160 cm is linear. But for experiment with 54cm2 square the depends is non linear. It can be describe as non linear square of object (as concave lens or concave mirrow). The result: standard deviation (error) is depends from length to object, and shape of object. ConclusionsConducted a series of experiments in a stationary position on the measurement precision of distances to objects. The data seemed quite encouraging. According to these measurements, the sensor gave readings with an precision from 0.5 cm to 2-3 cm, at the depends of distance. But the stated range in datasheed at 4 meter seemed unconvincing. After 2 meter will start same big error in measure distance. Was be make graph of data, presentet in this text. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
© www.AlexeyK.com, 2016 |