Подключение Sharp 2y0a21

_mikka
Offline
Зарегистрирован: 01.11.2015

Народ, доброго дня, возникла проблема с подключением дальномера Sharp 2y0a21.

Датчик подключил к A5 arduino uno, между gnd и vcc воткнул конденсатор на 10 микрофарад.

Сам датчик выдает сигнал с шумом, т.е например на 5 примерно одинаковых значение приходится 1 значение отличающееся процентов на 70.

Есть ли какие либо еще особенности подключения датчика и как отфильтровать сигнал ?

 

_mikka
Offline
Зарегистрирован: 01.11.2015

Набросал небольшой класс, показания в см. считает по графику из даташита апроксимированному 2 линиями.

SHARP_2Y0A21.h

// SHARP_2Y0A21.h

#ifndef _SHARP_2Y0A21_h
#define _SHARP_2Y0A21_h

#if defined(ARDUINO) && ARDUINO >= 100
	#include "arduino.h"
#else
	#include "WProgram.h"
#endif
// длина массива, для медианной фильтрации
#define ARRLEN 11      

class SHARP_2Y0A21
{
  public:
    SHARP_2Y0A21(const SHARP_2Y0A21&);
    SHARP_2Y0A21& operator=(const SHARP_2Y0A21&);

  public:
    SHARP_2Y0A21 (byte port);//: _iS ensorPort(port);
    int  iGetDistanceRaw();
    int  iGetDistanceSm();
    
  private:
    word   _iArrRawData[ARRLEN-1];
    byte   _iSensorPort;
    word   _bMeasureCntr;
                                         
    uint16_t middle();
  //  uint16_t minimum();
    
};

#endif

и SHARP_2Y0A21.cpp

// обработка показаний с датчика SHARP 2Y0A21
//
// 

// Отладка
#define DEBUG           


#include "SHARP_2Y0A21.h"

SHARP_2Y0A21::SHARP_2Y0A21(byte port)// : _iSensorPort(port)
// конструктор
{
   _bMeasureCntr=0;
   _iSensorPort=port;
   pinMode( _iSensorPort, INPUT);
   _iArrRawData[_bMeasureCntr]=analogRead(_iSensorPort);
}

int  SHARP_2Y0A21::iGetDistanceRaw()
{
  
   word iTemp;
   
   if (_bMeasureCntr>=(ARRLEN-1))  { 
     _bMeasureCntr=0;
   }   
/*  Serial.print(_bMeasureCntr); */
  _iArrRawData[_bMeasureCntr]=analogRead(_iSensorPort);
  _bMeasureCntr++;
//    Serial.print(_bMeasureCntr); 
 
  return middle();

}

// uint16_t SHARP_2Y0A21::minimum()
// {
//   uint16_t iMin;
//   
//   iMin=_iArrRawData[0];
//   
// //     Serial.print("  || ");
// //     Serial.print(_iArrRawData[0]);
//   
//   for (int ii = 1; ii < ARRLEN; ii++)  {
//     if (iMin > _iArrRawData[ii]) {
//       iMin=_iArrRawData[ii];
//     }
// //      Serial.print(" "); 
// //      Serial.print(_iArrRawData[ii]);  
//   }
// 
//    
// //    Serial.print(" min=");
// // //  Serial.print(iMin); 
//   
//   return middle();//iMin;
// }

#define SWAP(A, B) { int t = A; A = B; B = t; }
  
uint16_t SHARP_2Y0A21::middle()
// медианный фильтр по произвольном кол-ву элементов
{
  word _iArrTmp[ARRLEN];
  
  for (int i = 0; i < ARRLEN; i++)  {
      _iArrTmp[i]=_iArrRawData[i];     
  }

  // сортировка пузырьком
	for (int i = ARRLEN-1 ; i >= 0; i--){
  	for (int j = 0; j < i; j++)  	{
    	if (_iArrTmp[j] > _iArrTmp[j + 1]) {
    	  SWAP( _iArrTmp[j], _iArrTmp[j + 1]);}
  	}
	}

  // медиана - центральный элемент отсортированного массива
  return (_iArrTmp[ ARRLEN/2]+_iArrTmp[ ARRLEN/2+1])/2;
  
}

int SHARP_2Y0A21::iGetDistanceSm()
{
   word iRaw=iGetDistanceRaw();
   if (iRaw > 266) {
     return (11304-14*iRaw)/379;
   } 
   else {
     return (7580-20*iRaw)/113; 
   }
   
}

Остаеться еще вопрос, датчик по умолчанию показывает значение 19 см, т.е.

analogRead(_iSensorPort); показывает среднее значение 282 при питании от usb компьютреа, хотя большие расстояния он ловит, так если поднести руку и отдалить ее, то можно получить значение 228 (т.е гдето 1.11 в - 25 см, если я правильно понял)...

з.ы. до этого на С не писал, проект первый, буду очень рад критике и конструктивным предложениями.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А pin А5 у Вас к земдле притянут? Как реагирует, если за провод рукой взяться - прямо поверх изоляции?

Duino A.R.
Offline
Зарегистрирован: 25.05.2015

_mikka пишет:

Сам датчик выдает сигнал с шумом, т.е например на 5 примерно одинаковых значение приходится 1 значение отличающееся процентов на 70.

Есть ли какие либо еще особенности подключения датчика и как отфильтровать сигнал ?

 


В моей практике наилучшие результаты для фильтрации одиночных импульсных помех на фоне легкой болтанки показаний давало последовательное применение медианного фильтра с апертурой 5 и усредняющего с той же апертурой. Оба фильтра при непрерывном характере измерений должны быть "скользящими". Если помехи действительно одиночные, то апертуру медианы можно ограничить 3-мя отсчетами. Апертура "скользящего среднего" - по вкусу экспериментатора.

_mikka
Offline
Зарегистрирован: 01.11.2015

ЕвгенийП пишет:

А pin А5 у Вас к земдле притянут? Как реагирует, если за провод рукой взяться - прямо поверх изоляции?

Использую стандартную плату arduino uno, про подтягивающий резистор прочел, попробую...

Duino A.R. пишет:
В моей практике наилучшие результаты для фильтрации одиночных импульсных помех на фоне легкой болтанки показаний давало последовательное применение медианного фильтра с апертурой 5 и усредняющего с той же апертурой. Оба фильтра при непрерывном характере измерений должны быть "скользящими". Если помехи действительно одиночные, то апертуру медианы можно ограничить 3-мя отсчетами. Апертура "скользящего среднего" - по вкусу экспериментатора .

У меня более менне ровные показатели получаются с использованием медианного фильтра с значением от 7... Плюс метод int SHARP_2Y0A21::iGetDistanceSm() выдает целое значение, что тоже в какойто мере устаканивает сигнал...

з.ы. Под "скользящим фильтром" имеется в виду, что я беру последниие 3-5-7-9 показаний?

з.з.ы. В моей реализации, мне не очень нравится сортировка пузырьком, да и вообще сортировка при использовании фильтра... Считаю, что задача решина ВЛОБ, возможно не совсем оптимально, но другого варианта я не придумал. Успокаивает только то, что число сортируемых элементов мало, и при таком кол-ве элементов реализация алгоритма сортировки не существенна.

 

Araris
Offline
Зарегистрирован: 09.11.2012

Подтягивающий резистор не нужен. Нужна программная фильтрация получаемых данных, например, как подсказывает уважаемый Duino A.R..

Araris
Offline
Зарегистрирован: 09.11.2012
// У меня с Шарповским сенсором работает вот это :
//
#define DISTANCE_SENSOR_PIN A0 // analog pin connected to distance sensor 
#define SMOOTH_NUMSAMPLES 7 // SMOOTH_NUMSAMPLES should  be an odd number, no smaller than 3 
//...
int RawDistance = 0;
float DistanceSmoothArray [SMOOTH_NUMSAMPLES];
float CurDistance = 0; 
//...
void setup() 
{ 
// Calibrate distance sensor.
int jj;
for (jj = 0; jj < SMOOTH_NUMSAMPLES; jj++) { DistanceSmoothArray[jj] = 99; }
for (jj = 0; jj < SMOOTH_NUMSAMPLES; jj++)
 {
 RawDistance = 12000 / analogRead(DISTANCE_SENSOR_PIN);
 CurDistance = int(digitalSmooth(RawDistance, DistanceSmoothArray));
 delay(100);
 } 
}
//...
void loop() 
{
//////////////////// Read Distance sensor
RawDistance = 12000 / analogRead(DISTANCE_SENSOR_PIN);
CurDistance = int(digitalSmooth(RawDistance, DistanceSmoothArray));  
delay(100); // на самом деле я читаю не в loop(), а в периодически вызываемой функции.
}
//...
float digitalSmooth(float rawIn, float *sensSmoothArray)
{
int j, k;
float temp, top, bottom, total;
static int i;
static float sorted[SMOOTH_NUMSAMPLES];
boolean done;
i = (i + 1) % SMOOTH_NUMSAMPLES; // increment counter and roll over if necc. -  % (modulo operator) rolls over variable
sensSmoothArray[i] = rawIn;  // input new data into the oldest slot
for (j=0; j < SMOOTH_NUMSAMPLES; j++)
 { // transfer data array into another array for sorting and averaging
 sorted[j] = sensSmoothArray[j];
 }
done = 0; // flag to know when we're done sorting              
while(done != 1)
 { // simple swap sort, sorts numbers from lowest to highest
 done = 1;
  for (j = 0; j < (SMOOTH_NUMSAMPLES - 1); j++)
   {
   if (sorted[j] > sorted[j + 1])
    { // numbers are out of order - swap
    temp = sorted[j + 1];
    sorted [j+1] =  sorted[j] ;
    sorted [j] = temp;
    done = 0;
    }
   }
 }
// throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom
bottom = max(((SMOOTH_NUMSAMPLES * 15) / 100), 1); 
top = min((((SMOOTH_NUMSAMPLES * 85) / 100) + 1 ), (SMOOTH_NUMSAMPLES - 1)); // the + 1 is to make up for asymmetry caused by integer rounding
k = 0;
total = 0;
for (j = bottom; j<top; j++)
 {
 total += sorted[j];  // total remaining indices
 k++; 
 }
return total / k;    // divide by number of samples
} 

 

Duino A.R.
Offline
Зарегистрирован: 25.05.2015

_mikka пишет:

У меня более менне ровные показатели получаются с использованием медианного фильтра с значением от 7... Плюс метод int SHARP_2Y0A21::iGetDistanceSm() выдает целое значение, что тоже в какойто мере устаканивает сигнал...

Медиана прекрасно работает как фильтр от одиночных импульсов. Минимальная и реально работающая апертура - 3. Если апертура уходит за 7, то это - "ненормально". Т.е. на ширину импульса помехи приходится несколько отсчетов, что требует увеличения апертуры и снижения эффективности метода. Действенный способ улучшения ситуации - прорежение отсчетов. Сделайте так, чтобы период между измерениями у Вас был регулируемым и на практике подберите его величину так, чтобы действительно было, как Вы указали в начале - на 5 хороших отсчетов один, отличающийся на 70%. В такой ситуации прекрасно сработает и медиана с апертурой 3. Большое количество отсчетов в Вашем случае будет только мешать. Вам не надо исследовать помеху (тогда это было бы необходимо), Вам нужно ее задавить.

Медиана режет только импульсные помехи. Болтанка устраняется другими средствами. Обычно это либо усреднение, либо цифровые ФНЧ, либо еще всяко. Усреднение на практике просто реализуется и работает хорошо при мелкой болтанке значений. Если появляются помехи другого вида, то дело усложняется. Но все конкретно. В своей системе я даже делал возможность интерактивного подбора последовательности и параметров цифровых фильтров для каждого конкретного случая применения. Помогало.

_mikka пишет:

з.ы. Под "скользящим фильтром" имеется в виду, что я беру последниие 3-5-7-9 показаний?

з.з.ы. В моей реализации, мне не очень нравится сортировка пузырьком, да и вообще сортировка при использовании фильтра... Считаю, что задача решина ВЛОБ, возможно не совсем оптимально, но другого варианта я не придумал. Успокаивает только то, что число сортируемых элементов мало, и при таком кол-ве элементов реализация алгоритма сортировки не существенна.

Фильтры со "скользящей" апертурой работают следующим образом. При пуске фильтра сначала набираются разгонные точки, чтобы заполнить реальными отсчетами всю апертуру. Фильтр срабатывает первый раз. Потом все значения в апертуре стдвигаются на одну позицию так, чтобы самый старый отсчет отбросить совсем, а на место самого молодого поместить только что сделанный отсчет. Фильтр срабатывает. Данные в апертуре снова сдвигаются. Добавляется один новый отсчет. Фильтр срабатывает. И так по кругу. Теперь фильтр вышел на стационарный режим.

Может оказаться, что лучшие результаты дадут реккурентные фильтры. Т.е. значения с выхода фильтра не только идут дальше, но и вносятся на место отфильтрованных значений в апертуру фильтра и участвуют в расчетах наравне с "чистыми отсчетами".

_mikka пишет:

з.з.ы. В моей реализации, мне не очень нравится сортировка пузырьком, да и вообще сортировка при использовании фильтра... Считаю, что задача решина ВЛОБ, возможно не совсем оптимально, но другого варианта я не придумал. Успокаивает только то, что число сортируемых элементов мало, и при таком кол-ве элементов реализация алгоритма сортировки не существенна.

Следует различать метод и его реализацию. Метод медианного фильтра работает эффективно. Если не нравится "пузырьковая" реализация... Ну не нравится. :) В сети попадались всякие методы оптимизации расчетных схем медианной фильтрации. Хороша та реализация, которая реализует, то что требуется при приемлемых трудозататах. :)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. Обнаружил, что один из самых эффективныфх методов фильтрации - аппаратный, т.е. простая RC-цепочка на входе АЦП/

2. В свое время сравнивал различные алгоритмы сортировки. Выяснилось, что при длине выборки примерно до 20 самый быстрый - пузырек. Правда, это на PC с его длинным конвейером. Но, думаю, при 5 отсчетах что-либо эффективнее пузырька вряд ли существует.

3. По поводу реализации апертурного фильтра: создается кольцевой буфер. По мере заполнения подсчитывается сумма. В процессе работы очередной отсчет прибавляется к сумме, отсчет, хранящийся в очередной ячейка кольцевого буфера, вычитается из суммы, после чего на его место кладется очередной отсчет и текущая позиция кольцевого буфера сдвигается на 1. В качестве отфильтрованнго значения берется сумма, домноженная на масштабирующий коэффициент.