Направленный Bluetooth-маяк (iBeacon) и полный мобильный факап

    Инверсия — великая вещь! Изобрети что-то одно, а потом возьми и выверни его наизнанку, получишь не менее интересный результат. Я сначала провернул такое с одной штукой, и только потом увидел, что в ТРИЗ (теория решения изобретательских задач) есть такой прием "инверсия или обратная аналогия". Век живи, век учись.


    Но это все теория, а практика ставит всё на свои места...


    Маяки Bluetooth Low Energy или iBeacon теперь не что-то из ряда вон. Их можно встретить на вокзалах, в аэропортах, в музеях и в торговых центрах. Как радио-инженер я участвовал в проектировании маяков и, в особенности, антенн к ним. Дело это, по-началу интересное, потом становится скучным. Нечем выделиться, ничего особо нового не изобретешь. И тут меня осенило!


    Я взял свой пеленгатор (раз и два) и посмотрел на него с обратной стороны. А что, если сделать его маяком? Здесь нужно напомнить читателю, что этот пеленгатор состоит из двух антенн: одна с плавной диаграммой направленности, другая с резко меняющейся.


    image


    Это срез диаграммы направленности. В 3D она выглядит так:



    Пеленгатор "наводит фокус" по разнице уровней этих двух антенн. Если интересно подробно, то можно посмотреть на Github.


    Приведём небольшие фрагменты кода с логикой работы пеленгатора:


    Получаем уровни с обеих антенн. Полученные уровни требуется усреднить, а после этого посчитать разницу. На самом деле это не разница сигналов, а их отношение. Но если измерять в децибелах, то будет разница.


    Запись уровней в буфер
        public boolean handleInfo(WFPacket data)
        {
            if (data.apName.equals(ssid) && data.mac.equals(mac)) {
                int idx = data.antIdx;
                if (0 <= idx && idx <= 1) {
                    mLevels.get(idx).addLast(data.power);
                    while (mLevels.get(idx).size() > avgCount) {
                        mLevels.get(idx).removeFirst();
                    }
                    needRecalc = true;
                    print();
                } else {
                    Log.d(TAG, "LevelCalculator.HandleInfo() Bad rcvIdx: " + data.antIdx);
                }
            } else {
                return false;
            }
            return needRecalc;
        }

    Усреднение и подсчёт разницы
        public double getAvg() {
            if (needRecalc) {
                for (int idx = 0; idx < 2; idx++) {
                    double sum = 0d;
                    for (Double x : mLevels.get(idx)) {
                        sum += x;
                    }
                    int count = mLevels.get(idx).size();
                    if (count != 0) {
                        sum /= count;
                    }
                    avgLevels[idx] = sum;
                }
                avgDiff = Math.pow(10.0, (avgLevels[1] - avgLevels[0]) * 0.1 + 2.5); //Переводим обратно из децибелов
                needRecalc = false;
            }
            return avgDiff;
        }

    Обработка "разницы". Если уровни на обеих антеннах различаются "сильно", то мы с некоторой точностью (плюс минус лапоть) направлены на источник. Чему равно это "сильно" на данный момент определяется методом научного тыка экспериментально.


    private void updateLevelDiff(double levelDiff)
        private void updateLevelDiff(double levelDiff) {
            long deltaTime = System.currentTimeMillis() - lastUpdateTime;
            int progress = (int) Math.floor(100.0 * levelDiff); // Масштабирование для красивого отображения на экране
    
            // Сохраняем пеленг
            if (deltaTime > TIME_PERIOD) { // Мы не хотим сохранять пеленги слишком часто
                if (progress < mThreshold) { // Если разница в уровнях больше порога, то мы как раз направлены на источник сигнала        
                    addBearing();
                    numUpdates++;
                }
                lastUpdateTime = System.currentTimeMillis();
            }
    
            //Далее идёт обновление GUI
        }

    А теперь ИНВЕРТИРУЕМ!


    Пусть на одну антенну будет излучаться маяк iBeacon с одним номером, а на другую — с другим. Тогда на мобильном устройстве можно измерить уровни обоих маяков и по разнице определить насколько близко оно находится к фокусу антенн маяка. Получается позиционирование по направлению прихода волны.


    В стандарте Bluetooth версии 5 даже анонсирован похожий способ высокоточного позиционирования — Angle of Departure. До точного описания этого способа они еще не дошли, обещают в следующих версиях.


    В рафинированном виде работу можно проиллюстрировать роликами: раз и два.


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



    Сам маяк выглядит так:



    А вот рендеры внутренностей:



    Красавец, не правда ли?! Внутри антенна, как в пеленгаторе WiFi, и Bluetooth SoC nRF51822. Но все было тщетно...


    Далее история переходит в факап, который заключается в том, что это работает на смартфоне Nexus 5 и найти другой гаджет, работающий хотя бы так же, оказалось не очень просто. Нет, они есть, Samsung Galaxy S7, Lenovo Phab 2 Pro, и на этом список пока заканчивается. Больше "хороших" гаджетов найти у друзей и знакомых не удалось. Из "плохих" можно отметить Samsung S4 mini.


    Конечно, был проверен маяк. Он излучает пакеты на две антенны по очереди с минимальным интервалом. Маленький интервал нужен, чтобы измерения относились к моментам времени, отстоящим друг от друга незначительно. Иначе нельзя будет соотнести их друг с другом.


    Был записан лог с Bluetooth-снифера с использованием чудесного WireShark. Анализ лога показывает, что излучается все правильно, временные интервалы и уровни в норме. Осциллограф тоже не показал ничего неучтенного на выходе маяка.


    Тем не менее, на большом числе гаджетов работает плохо. Проблема в потерях измерений. В Android-приложение была встроена диагностика приема пар пакетов. Показателем качества был сделан процент парных пакетов. Так вот, показатель от 80 до 100 наблюдался лишь на некоторых гаджетах. На остальной протестированной выборке мобильных устройств показатель был от 20 до 60. В движении соотношение уровней измерялось неточно. Была попытка скомпенсировать это увеличением частоты излучения пакетов, но это результата не дало. Что-то внутри Андроида препятствует нормальным измерениям.


    Исходники всего этого безобразия доступны на Github.


    Есть небольшая надежда, на то, что на iOS ситуация может быть лучше. По крайней мере однороднее на спектре мобильных устройств.


    Есть также надежда, что найдется специалист, который поймет в чем проблема и подскажет решение.


    А мне сейчас очень жаль, что эта идея не работает.

    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 10
    • +1
      Тоже долго сражались с этой проблемой, в Андроиде есть несколько настроек частоты сканирования SCAN_MODE_LOW_LATENCY и настройки как часто вызывать колбэки на пойманый маяк developer.android.com/reference/android/bluetooth/le/ScanSettings.html

      получилось добиться более или менее приемлемого результата… правда тестировалось на galaxy s7
      • +1
        Да, На Galaxy S7 и у нас более-менее работает. Настройки сейчас такие: режим сканирования SCAN_MODE_LOW_LATENCY, режим коллбэков CALLBACK_TYPE_ALL_MATCHES, match mode (не знаю, как по-русски лучше назвать) MATCH_MODE_AGGRESSIVE,
        advertisement MATCH_NUM_MAX_ADVERTISEMENT
      • +1
        Охота на лис выходит на новый уровень, к стандартному набору антенн и trx на 2м и 70см добавлется wi-fi пеленгатор.
        • 0
          Устроим соревнование по охоте на WiFi-лис?
          • +1

            Мы (любители радиво), периодически проводим охоту. Если вам интересно, можно узнать о заинтересованности остальных участников. Как правило, состав почти не меняется в течение многих лет.
            Но за охоту можно намотать не одну сотню километров :) так что, вифи будет актуален на последней стадии обнаружения.

            • 0
              Я подойду к последней стадии :)

              Узнайте, пожалуйста. Конечно, это не лисы получаются, а микро-лисы. Дальность получается не более 50 метров по обычной точке доступа пока.
        • +1
          А если увеличить дистанцию по времени между двумя пакетами? Короче продолжить вашу мысль:
          на данный момент определяется методом научного тыка экспериментально

          Как вариант — увеличить «дистанцию» не только между пакетами одной пары, но и между соседними парами.
          Может Android даже реабилитируется.
          • 0
            К сожалению, и это все пробовали.
          • +2
            Работаю сейчас с bluetooth чипом KW40Z от NXP (Freescale) и заметил что он фильтрует advertising пакеты. Обойти это со стороны маяка удалось изменяя MAC адрес для каждого нового пакета. Со стороны устройства помогает перезапуск процесса сканирования.
            • +1
              Интересное предложение! Большое спасибо!

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