用 JavaScript 构建飞机雷达系统

发布于:2022-12-21 ⋅ 阅读:(466) ⋅ 点赞:(0)

几年前,我看到了Thomas Watson的精彩演讲,他在演讲中谈到了他是如何构建AirplaneJS的,这是一个网络应用程序,可以从飞机上接收ADS-B无线电信号,并在浏览器的地图上实时绘制它们。我不知道这在 JavaScript 中是可能的,所以我开始研究它。

我玩弄了这个项目,并开始想知道是否有办法可以将它推得更远一些。考虑到 AirplaneJS 在服务器上使用 Node.js,我决定进行实验,看看是否可以使用 Web USB 使其工作,从而将其变成仅前端的项目。几周前我终于让它工作了🥳所以决定写下来。

我还在学习很多关于 USB 协议以及如何解码 ADS-B 信号的知识,所以这篇文章不会深入探讨这个主题。

在我开始之前,这里有一个演示:

动图

这是演示站点的链接

RTL-SDR 加密狗

该项目的主要组件包括Web USB APIRTL-SDR 加密狗 + 天线和一些 JavaScript 代码。

如今,大多数飞机都广播 ADS-B 数据,即自动相关监视广播。这是一种监视技术,允许飞机在不被询问的情况下广播其飞行状态,这意味着它不需要飞行员的输入。
此数据指示飞机的位置、纬度、经度、速度、代码等。
他们会定期将此数据传输给空中交通管制员,但是,使用带有天线的软件定义无线电加密狗,您可以拦截这些消息以制作您自己的飞机雷达系统📡。

您可以购买或制造不同类型的天线,但我个人使用的是偶极天线。

由于数据以 1090 MHz 的频率广播,因此偶极子的大小需要使用以下公式计算:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">In</span> <span style="color:var(--syntax-name-color)">feet</span><span style="color:var(--syntax-text-color)">:</span>

<span style="color:var(--syntax-name-color)">Total</span> <span style="color:var(--syntax-name-color)">length</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">468</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-name-color)">Frequency</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-name-color)">MHz</span> <span style="color:var(--syntax-comment-color)">// Gives the total lengh of the dipole</span>

<span style="color:var(--syntax-name-color)">Length</span> <span style="color:var(--syntax-declaration-color)">of</span> <span style="color:var(--syntax-name-color)">each</span> <span style="color:var(--syntax-name-color)">branch</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Total</span> <span style="color:var(--syntax-name-color)">length</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">2</span>

<span style="color:var(--syntax-error-color)">---</span>

<span style="color:var(--syntax-name-color)">In</span> <span style="color:var(--syntax-name-color)">cm</span><span style="color:var(--syntax-text-color)">:</span>

<span style="color:var(--syntax-name-color)">Total</span> <span style="color:var(--syntax-name-color)">length</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">14264</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-name-color)">Frequency</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-name-color)">MHz</span> <span style="color:var(--syntax-comment-color)">// Gives the total lengh of the dipole</span>

<span style="color:var(--syntax-name-color)">Length</span> <span style="color:var(--syntax-declaration-color)">of</span> <span style="color:var(--syntax-name-color)">each</span> <span style="color:var(--syntax-name-color)">branch</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Total</span> <span style="color:var(--syntax-name-color)">length</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">2</span>
</code></span></span></span>

如果更简单,可以使用在线计算器。

对于这个项目,它给了我大约 13 厘米的总长度,所以偶极子的每个部分应该是大约 6.5 厘米。

通过 Web USB 连接到加密狗

Web USB API是一种浏览器 API,可让您通过USB 与插入计算机的设备进行连接和通信。

要使用它,您需要首先检查您的浏览器是否支持它。您可以使用以下代码执行此操作:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">if</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">navigator</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">usb</span><span style="color:var(--syntax-text-color)">){</span>
    <span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">The Web USB API is supported!</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">I'm afraid this won't work</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span>

然后,您需要指明您希望应用程序连接到哪个设备。您可以列出所有当前连接的设备,也可以指定一个过滤器,在其中传递设备的供应商 ID 和产品 ID。
在 Mac 上,您可以通过将设备插入计算机、单击苹果图标 > 关于本机 > 系统报告并查看硬件 > USB 下的列表来找到这些 ID。

上图表明供应商 ID 是0x0bda,产品 ID 是0x2838,所以我可以在代码中使用它。

出于安全原因,Web USB API 需要由用户交互触发,所以我在屏幕上有一个按钮来启动连接过程。

第一个调用方法navigator.usbrequestDevice

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">onclick</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">navigator</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">usb</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">requestDevice</span><span style="color:var(--syntax-text-color)">({</span>
      <span style="color:var(--syntax-name-color)">filters</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">[</span>
        <span style="color:var(--syntax-text-color)">{</span>
          <span style="color:var(--syntax-name-color)">vendorId</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">0x0bda</span><span style="color:var(--syntax-text-color)">,</span>
          <span style="color:var(--syntax-name-color)">productId</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">0x2838</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">}</span>
      <span style="color:var(--syntax-text-color)">],</span>
    <span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span></span>

它返回一个带有在列表中选择的设备的承诺。接下来的步骤是打开与此设备的会话,选择配置并声明接口:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">device</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">device</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">open</span><span style="color:var(--syntax-text-color)">());</span>
<span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">device</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">selectConfiguration</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">device</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">claimInterface</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">))</span> 
</code></span></span></span>

配置和接口是特定于设备的。我在网上找不到关于我正在使用的特定设备的信息,所以我尝试了不同的值,直到它起作用......

成功执行这些步骤后,应连接设备。现在,需要设置频率和采样率。
为此,我依靠Sandeep Mistry的rtlsdrjs库。如果你决定用它来创建一个类似的项目,我用它作为频率(对于 1090MHz)和采样率。10900000002000000

最后,该transferIn方法在从设备接收到数据时执行。

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">transferIn</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">256000</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">result</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">data</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Uint8Array</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">result</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">buffer</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">})</span>
</code></span></span></span>

此代码返回如下所示的原始数据:

动图

处理和格式化后,它看起来像这样:

处理原始 ADS-B 数据

该项目的这一部分很大程度上依赖于现有的工作。我需要更深入地研究 S 模式通信协议如何工作以解码数据,但本指南解码 S 模式和 ADS-B 信号似乎是一个非常好的开始。

到目前为止,据我了解,ADS-B 消息有两个主要部分,一个前导码和一个数据块。数据块由 112 位组成,分为 5 个部分:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>+----------+----------+-------------+------------------------+-----------+
|  DF (5)  |  CA (3)  |  ICAO (24)  |         ME (56)        |  PI (24)  |
+----------+----------+-------------+------------------------+-----------+
</code></span></span></span>
  • DF:下行格式
  • CA:转发器能力
  • ICAO 飞机地址
  • 我:留言
  • PI:奇偶校验 ID

位 33-88 专用于消息。无需过多介绍,本节的前 5 位表示类型代码。如果此类型代码在 1 和 4 之间,ADS-B 消息是飞机识别消息,如果类型代码在 5-8 之间,则消息是表面位置消息,等等。
这个类型代码很重要,因为它表明了消息的其余部分涉及。

十六进制格式的原始 ADS-B 消息示例如下所示:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-literal-color)">8</span><span style="color:var(--syntax-name-color)">D4840D6202CC371C32CE0576098</span>
</code></span></span></span>

在二进制中,它转换为:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-literal-color)">1000110101001000010000001101011000100000001011001100001101110001110000110010110011100000010101110110000010011000</span>
</code></span></span></span>

如果您正在关注,您可能会猜到这是多少位......

...

...

...

112!

如果我们使用前面显示的表格,我们可以将此二进制文件拆分为相应的部分:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>+--------+--------+--------------+-------------------------+-------------------+
| DF (5) | CA (3) |   ICAO (24)  |         ME (56)         |      PI (24)      |
+--------+--------+--------------+-------------------------+-------------------+
| 10001  | 101    | 010010000100 | 00100000001011001100001 | 01010111011000001 |
|        |        | 000011010110 | 10111000111000011001011 | 0011000           |
|        |        | 000011010110 | 0011100000              |                   |
|        |        |              |                         |                   |
+--------+--------+--------------+-------------------------+-------------------+
</code></span></span></span>

它使它更容易阅读,但现在我们也可以将它们中的每一个转换为十进制:

<span style="color:#171717"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>+--------+--------+--------------+-------------------------+-------------------+
| DF (5) | CA (3) |   ICAO (24)  |         ME (56)         |      PI (24)      |
+--------+--------+--------------+-------------------------+-------------------+
| 17     | 5      | 4735190      | [4]...                  | ...               |
+--------+--------+--------------+-------------------------+-------------------+
</code></span></span></span>

消息的前 5 位给出十进制值 4,这意味着这是一个飞机识别消息。从那里,如果我理解得很好,消息的其余部分应该包含有关飞机类别及其呼号的数据,根据我找到的这张表。

使用这些数据,您可以使用planespotters.net等在线工具并搜索 ICAO 代码以获取有关您正在跟踪的飞机的更多信息。

处理完所有这些数据后,结果是一个 JSON 对象,其中包含高度、纬度、经度等信息。

如果需要,请查看repo 。

最终设置

最后,这就是我的设置:

——

这篇文章不是深入探讨,但希望它有意义!

我真的非常高兴我能够使用 Web USB 让这个项目工作,这是我多年来一直想做的事情!

我仍然需要了解更多关于它的信息,但我有一些其他的想法,我想围绕相同的技术构建项目,我非常兴奋!潜入我一无所知的事情只需要很多时间😅...

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到