Работа с инфракрасным дальномером Sharp

в 19:45, , рубрики: arduino, DIY, diy или сделай сам, дальномер, робототехника, метки: , , , ,

Добрый день, хочу поделиться своим методом работы с инфракрасными дальномерами Sharp на примере модели Sharp GP2D120 (4 — 40 см).

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

Ваш робот больше не будет терять препятствия.

1 — Читаем документацию

У каждого датчика уже есть замеренная вольт-амперная характеристика, которая находится по названию модели. Учитывая специфику датчиков, производитель поставил в соответствие выходному напряжению расстояние до препятствия:

Работа с инфракрасным дальномером Sharp

Определяем по графику напряжение, соответствующее каждому расстоянию и записываем в два массива:

float voltage[] = {2.7, 2.34, 2.00, 1.78, 1.56, 1.4, 1.265, 1.06, 0.92, 0.8, 0.74, 0.66, 0.52, 0.42, 0.36, 0.32};
float distanse[] = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 35.0, 40.0};
int len = 16;  // количество набранных в массив точек  

2 — Реализуем интерполяцию

Вначале несколько раз (10) опросим датчик и возьмем среднее значение, чтобы избежать случайного шума:

int senPin = 0; // "Analog In", куда подключен датчик
int out = 0;
for (int i = 0; i < 10; i++){
   out += analogRead(senPin);
   delay(8);   // задержка получена опытным путём
}
out = out/10;

Зная, что в Ардуине analogRead() выдает значения от 0 до 1023, а датчики Sharp — от 0 до 5 Вольт, преобразуем out в вольты и найдем положение этого значения в массиве voltage:

int pos = 0;
float volt_read = out * 0.00488758553;  //  5 / 1023 = 0.00488758553
if((voltage[0] > volt_read) && (voltage[N-1] < volt_read)){
    // убедились, что показания принадлежат рабочей области  
    for (int i = 0; i < N-1; i++) { 
        if(volt_read >= voltage[i+1]){
            pos = i;
            break; 
        }
    }
}

Предпоследний шаг.

Интерполировав график, рассчитываем расстояние соответствующее выходному вольтажу.

Работа с инфракрасным дальномером Sharp

float y1 = voltage[pos];
float x1 = distance[pos];
float y2 = voltage[pos + 1];
float x2 = distance[pos + 1];
float distance_out = (x2 - x1)*(y1 - volt_read)/(y1 - y2) + x1;  // следствие из подобия треугольников 123 и 145 

3 — Собираем функцию

float getDistance(int senPin){
    float voltage[] = {2.7, 2.34, 2.00, 1.78, 1.56, 1.4, 1.265, 1.06, 0.92, 0.8, 0.74, 0.66, 0.52, 0.42, 0.36, 0.32};
    float distanse[] = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 35.0, 40.0};
    int len = 16; int out = 0; int pos = 0;

    for (int i = 0; i < 10; i++){
       out += analogRead(senPin);
       delay(8);   
    }
    out = out/10;
    
    float volt_read = out * 0.00488758553;  //  5 / 1023 = 0.00488758553
    if((voltage[0] > volt_read) && (voltage[N-1] < volt_read)){
        for (int i = 0; i < N-1; i++) { 
            if(volt_read >= voltage[i+1]){
                pos = i;
                break; 
            }
        }
        float y1 = voltage[pos];
        float x1 = distance[pos];
        float y2 = voltage[pos + 1];
        float x2 = distance[pos + 1];
        float distance_out = (x2 - x1)*(y1 - volt_read)/(y1 - y2) + x1;  
        return distance_out
    }
    else return -1.0;
}

4 — Правильно используем

Опытным путем я заметил, что функция лучше всего работает, если запускать ее с промежутком в 15 миллисекунд для любого количества дальномеров:

void updateDistance{
    float D1 = getDistance(0);
    delay(15);
    // ...
    float D6 = getDistance(5);
    delay(15);
}

Для ценителей DIY отмечаю, что код тестировался вот на такой установке:

Работа с инфракрасным дальномером Sharp

Спасибо за внимание.

Автор: deQU

Источник

Поделиться