Создание радарной системы для самолетов на JavaScript

Несколько лет назад я наткнулся на потрясающий доклад Томаса Уотсона, в котором он рассказывает о том, как он создал AirplaneJS, веб-приложение, которое принимает радиосигналы ADS-B от самолетов и отображает их в режиме реального времени на карте в браузере. Я не знал, что такое возможно на JavaScript, поэтому начал изучать этот вопрос.

Я поиграл с проектом и начал думать, есть ли способ продвинуть его немного дальше. Учитывая, что AirplaneJS использует Node.js на сервере, я решил поэкспериментировать и посмотреть, смогу ли я заставить его работать с помощью Web USB, чтобы превратить его только во внешний проект. Несколько недель назад у меня наконец-то получилось 🥳 и я решил написать об этом.

Я все еще много узнаю о протоколе USB и о том, как декодировать сигналы ADS-B, поэтому в этом посте я не буду слишком глубоко погружаться в тему.

Прежде чем я начну, вот демонстрация:

Вот ссылка на демонстрационный сайт

RTL-SDR dongle

Основными компонентами этого проекта являются Web USB API, RTL-SDR донгл + антенна и немного JavaScript кода.

В настоящее время большинство самолетов передают данные ADS-B, что расшифровывается как Automatic Dependent Surveillance-Broadcast. Это технология наблюдения, которая позволяет самолетам передавать данные о состоянии своего полета без опроса, то есть не требует участия пилотов.
Эти данные указывают местоположение самолета, широту, долготу, скорость, код и т. д.
Они периодически передают эти данные авиадиспетчерам, однако, используя Software Defined Radio dongle с антенной, вы можете перехватывать эти сообщения, чтобы сделать свою собственную систему авиационного радара 📡.

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

Поскольку данные передаются на частоте 1090 МГц, размер диполя необходимо рассчитать по следующей формуле:

In feet:

Total length = 468 / Frequency in MHz // Gives the total lengh of the dipole

Length of each branch = Total length / 2

---

In cm:

Total length = 14264 / Frequency in MHz // Gives the total lengh of the dipole

Length of each branch = Total length / 2
Войти в полноэкранный режим Выйти из полноэкранного режима

Есть онлайн-калькулятор, если это проще.

Для данного проекта он дает общую длину примерно 13 см, поэтому каждая часть диполя должна быть около 6,5 см.

Подключение к диполю через Web USB

Web USB API — это API браузера, который позволяет подключаться и взаимодействовать с устройствами, подключенными к компьютеру через USB.

Чтобы воспользоваться им, необходимо проверить, поддерживает ли его ваш браузер. Это можно сделать с помощью следующего кода:

if(navigator.usb){
    console.log("The Web USB API is supported!")
} else {
    console.log("I'm afraid this won't work")
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем необходимо указать, к какому устройству вы хотите подключить приложение. Вы можете перечислить все подключенные в данный момент устройства или задать фильтр, в котором вы передадите ID производителя и ID продукта устройства.
На компьютере Mac эти идентификаторы можно найти, подключив устройство к компьютеру, нажав на значок яблока > About this Mac > System Report, и посмотрев в списке в разделе Hardware > USB.

Изображение выше показывает, что ID производителя — 0x0bda, а ID продукта — 0x2838, поэтому я могу использовать это в коде.

По соображениям безопасности Web USB API должен запускаться при взаимодействии с пользователем, поэтому у меня есть кнопка на экране для запуска процесса подключения.

Первый метод, вызываемый в navigator.usbrequestDevice:

button.onclick = () => {
  navigator.usb
    .requestDevice({
      filters: [
        {
          vendorId: 0x0bda,
          productId: 0x2838,
        }
      ],
    })
};
Войти в полноэкранный режим Выйти из полноэкранного режима

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

.then((device) => device.open());
.then(() => device.selectConfiguration(1))
.then(() => device.claimInterface(0)) 
Войти в полноэкранный режим Выход из полноэкранного режима

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

После успешного выполнения этих шагов устройство должно быть подключено. Теперь необходимо установить частоту и частоту дискретизации.
Для этого я воспользовался замечательной библиотекой rtlsdrjs Сандипа Мистри. Если вы решите использовать ее для создания подобного проекта, я использовал 1090000000 в качестве частоты (для 1090 МГц) и 2000000 в качестве частоты дискретизации.

Наконец, метод transferIn выполняется при получении данных от устройства.

.transferIn(1, 256000)
.then((result) => {
    const data = new Uint8Array(result.data.buffer);
    console.log(data);
})
Вход в полноэкранный режим Выход из полноэкранного режима

Этот код возвращает необработанные данные, которые выглядят следующим образом:

После обработки и форматирования они выглядят следующим образом:

Обработка необработанных данных ADS-B

Эта часть проекта во многом опирается на существующую работу. Мне нужно глубже изучить, как работает протокол связи Mode S для декодирования данных, но это руководство по декодированию сигналов Mode-S и ADS-B кажется очень хорошим началом.

Пока, насколько я понимаю, сообщения ADS-B состоят из двух основных частей: преамбулы и блока данных. Блок данных состоит из 112 битов, организованных в 5 секций:

+----------+----------+-------------+------------------------+-----------+
|  DF (5)  |  CA (3)  |  ICAO (24)  |         ME (56)        |  PI (24)  |
+----------+----------+-------------+------------------------+-----------+
Вход в полноэкранный режим Выход из полноэкранного режима
  • DF: Формат нисходящей линии связи
  • CA: Возможность транспондера
  • ICAO Адрес воздушного судна
  • ME: Сообщение
  • PI: Идентификатор четности

Биты 33-88 отведены под сообщение. Не вдаваясь в излишние подробности, первые 5 битов этой секции указывают код типа. Если код типа находится в диапазоне от 1 до 4, то сообщение ADS-B является сообщением идентификации воздушного судна, если код типа находится в диапазоне 5-8, то сообщение является сообщением о положении над поверхностью и т.д.
Этот код типа имеет значение, поскольку он указывает, к чему относится остальная часть сообщения.

Пример необработанного сообщения ADS-B в шестнадцатеричном формате выглядит следующим образом:

8D4840D6202CC371C32CE0576098
Войти в полноэкранный режим Выйти из полноэкранного режима

В двоичном формате это переводится как:

1000110101001000010000001101011000100000001011001100001101110001110000110010110011100000010101110110000010011000
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы следите за этим, вы можете догадаться, сколько это бит…

112!

Если мы воспользуемся таблицей, показанной ранее, то сможем разбить этот двоичный код на соответствующие секции:

+--------+--------+--------------+-------------------------+-------------------+
| DF (5) | CA (3) |   ICAO (24)  |         ME (56)         |      PI (24)      |
+--------+--------+--------------+-------------------------+-------------------+
| 10001  | 101    | 010010000100 | 00100000001011001100001 | 01010111011000001 |
|        |        | 000011010110 | 10111000111000011001011 | 0011000           |
|        |        | 000011010110 | 0011100000              |                   |
|        |        |              |                         |                   |
+--------+--------+--------------+-------------------------+-------------------+
Вход в полноэкранный режим Выход из полноэкранного режима

Это немного облегчает чтение, но теперь мы также можем перевести каждое из них в десятичную систему:

+--------+--------+--------------+-------------------------+-------------------+
| DF (5) | CA (3) |   ICAO (24)  |         ME (56)         |      PI (24)      |
+--------+--------+--------------+-------------------------+-------------------+
| 17     | 5      | 4735190      | [4]...                  | ...               |
+--------+--------+--------------+-------------------------+-------------------+
Войти в полноэкранный режим Выход из полноэкранного режима

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

Используя эти данные, вы можете использовать онлайн-инструменты, такие как planespotters.net, и искать код ICAO, чтобы получить больше информации о самолетах, которые вы отслеживаете.

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

Посмотрите репозиторий, если хотите.

Окончательная настройка

В итоге, вот как выглядит моя установка:

Этот пост не был глубоким погружением, но, надеюсь, он был понятен!

Я очень рад, что мне удалось заставить этот проект работать с помощью Web USB, это то, что я хотел сделать уже много лет!

Мне еще предстоит узнать об этом больше, но у меня есть еще несколько идей проектов, которые я хочу построить на основе той же технологии, я очень взволнован! Просто нужно много времени, чтобы погрузиться в то, о чем я ничего не знаю 😅…

Дополнительные ресурсы

  • The 1090 Megahertz Riddle (2-е издание) — удивительный онлайн-ресурс, позволяющий узнать, как декодировать данные Mode S.

  • Технический паспорт RTL-SDR v3

  • Узнайте больше о RTL-SDR

  • AirplaneJS

  • Интересная статья об атаках на спуфинг ADS-B

  • История режима S

  • Декодер Mode S

  • dump1090

  • Руководство по декодированию ADS-B

  • Радиоприемник

Оцените статью
devanswers.ru
Добавить комментарий