Távolságmérés SHARP optikai szenzorral

Az SHARP optikai szenzorok leírása itt található. A legnagyobb távmérést igérő GP2Y0A60SZ(LF) vettem meg az Ebay-ről egy további projektemhez tesztelésre, és rögtön az alábbi problémákba sikerült ezzel belefutnom. A táblázatba beírtam a megoldásaimat is:

Probléma a szenzorralMegoldás (amit használtam)
A távolságmérés elvileg 150 cm maximumot ígér, a mérésem szerint ez 110 cm fölött igencsak bizonytalanEz van, a mérés maximumát 110 cm-ben határoztam meg
A szenzor karakterisztikáján látszik, hogy adott távolság alatt (ebben az esetben ez kb 10 cm) "csal", azaz rossz értékeket mérA szenzort úgy kell telepíteni, hogy ebben a tartományban (..10cm) ne legyen lehetősége mérni (mert egyébként hülyeséget fog jelezni)
A szenzormérés bizonytalan, néha nagyon kiugró méréseket tud adni (ezt a soros monitorral lehet kiszúrniEgy kicsit bonyolultabb (szórás- és) átlagszámítási eljárással ez kiszűrhető

A projekthez felhasználtam még egy 4 pozíciós 7 szegmensű kijelzőt is, hogy lássam, mennyire stabil a mérés. Ez értelemszerűen elhagyható, leírása itt található.

A mért értékek közötti szűrőeljárás paraméterezhető.

GP2Y0A60SZ(LF) sensor:
SEN: Arduino A0

7 szegmensű kijelző:
CLK: Arduino A4
DIO: Arduino A5
GND: Arduino GND
5V: Arduino 5V

// Vamos Sandor 2018 - ob121.com
// Distance measuring with GP2Y0A60SZ(LF) sensor
// and display with TM1637 7-segment dispay

#include "TM1637.h"                              // 7-segment Display driver
#define CLK A4				         // CLK pin for 7-segment Display      
#define DIO A5			                 // DIO pin for 7-segment Display  
TM1637 tm1637(CLK,DIO);                          // init Display

#define avg_element 20                           // the numbers of elemens from measuring to calc avg
#define max_diff 10                              // maximum tolerant for an element (from avg) in %

unsigned long time_stamp, time_stamp_now;        // timer
int sensorPin   = A0;                            // a0 GP2Y0A60SZ(LF) sensor
int avg [avg_element];				 // array for avg calc
int average, max_val, Amax, Amin;                // avg, max different, abs diff max-min
int inside, Aval, Distance;                      // inside in tol, value, distance
int disp_one, disp_ten, disp_hundred;            // display 3 pos.
int show = 0;                                    // pointer
int sensorValue = 0;                             // value from sensor


void setup() {
  Serial.begin(9600);                            // opt: serial monitor
  tm1637.init();                                 // 7-segment dispay settings
  tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
}

void loop() {
  sensorValue = analogRead(sensorPin);           // read sensor (with 50 ms gap)
  avg[show] = sensorValue;                       // fill a position in array
  show++;                                        // next position (pointer)
  if (show > avg_element) {show = 0;};           // if fill the array, start from 0 pos.
  average = 0;                                   // start value 
  for (int i=0; i < (avg_element + 1); i++) {    // cycle in array
    average = average + avg[i];                  // add for average
  }                         
  average = average / avg_element;               // count average from array (all elements)
  
  max_val = average * (max_diff / 100.0);        // calc tolerant to average
  Amax = average + max_val;                      // abs. min from average
  Amin = average - max_val;                      // abs. max to average
  int j=0;                                       // startval
  inside=0;                                      // startval
  for (int i=0; i < (avg_element + 1); i++) {    // all elements in array
    if ((avg[i] < Amax) & (avg[i] > Amin)) {     // if this element is inside from tolerant
      j++;                                       // calc numbers
      inside = inside + avg[i];                  // cals value
    }
  }  
  inside = inside / j;                           // with tolerant corrected value

  if (inside > 0) {Aval = inside;};              // if this calculated value is valid, then use it
  
						 // the measuring from dist.sensor is not proportional
						 // then i use some measuring points from the curve.
						 // Next is the calculation (correction) from this curve.
  
       if (Aval < 115) {Distance = 110; }
  else if (Aval < 120) {Distance = 110 - (Aval - 115)*2;} 
  else if (Aval < 140) {Distance = 100 - (Aval - 120) /2;} 
  else if (Aval < 154) {Distance =  90 - (Aval - 140) /1.4;}   
  else if (Aval < 178) {Distance =  80 - (Aval - 154) /2.4;} 
  else if (Aval < 206) {Distance =  70 - (Aval - 178) /2.8;} 
  else if (Aval < 252) {Distance =  60 - (Aval - 206) /4.6;}   
  else if (Aval < 318) {Distance =  50 - (Aval - 252) /6.4;} 
  else if (Aval < 425) {Distance =  40 - (Aval - 318) /10.7;}   
  else if (Aval < 558) {Distance =  30 - (Aval - 425) /13.3;}
  
  time_stamp_now = millis();                     // time now
  if (abs(time_stamp_now - time_stamp) > 500) {  // if 500ms elapsed
    time_stamp = time_stamp_now;                 // set new "old" timestamp
    disp_hundred = Distance / 100;                                       // 3.pos for 7-segment display
    disp_ten = Distance / 10 - disp_hundred * 10;                        // 2.pos for 7-segment display
    disp_one = Distance - (disp_hundred * 100) - (disp_ten * 10);        // 1.pos for 7-segment display

    tm1637.display(0,0);                                                 // Display values
    tm1637.display(1,disp_hundred); 
    tm1637.display(2,disp_ten);
    tm1637.display(3,disp_one);
  }
  
  delay(50);                                                             // Waiting for dist.sensor 50 ms
}