实时追踪的飞机雷达系统,用 JavaScript “搞定”!高度、经纬度等一目了然
摘要:是否还记得上个月数百万人同时围观佩洛西航班轨迹的那个夜晚?当时,飞行跟踪服务 Flightradar24 火了好一把。最近,本文作者 Charlie Gerard 也对这类飞行器雷达系统十分好奇,并尝试用 JavaScript 来构建一个。
原文链接:https://charliegerard.dev/blog/aircraft-radar-system-rtl-sdr-web-usb/
声明:本文为 CSDN 翻译,未经授权,禁止转载。
作者 | Charlie Gerard
几年前,我看了Thomas Waston的演讲,介绍了他构建AirplaneJS的过程。这是一个Web应用,能接收飞机等飞行器的ADS-B雷达信号,然后通过浏览器实时绘制在地图上。我不知道JavaScript还能实现这个功能,所以我仔细研究了一下。
我尝试了这个项目,并思考我能否更进一步。由于AirplaneJS在服务上使用Node.js,我决定试验一下能不能通过WebUSB把它变成一个完全的前端项目。几周前,我终于搞定了。
(注:由于目前我还在学习USB协议以及怎样解码ADS-B信号,所以这篇文章不会在这方面深入探讨。)
先来看一个演示:
演示网站在此:https://aircraft-radar-system.netlify.app/
RTL-SDR适配器
本项目的主要组件包括WebUSB API、一个RTL-SDR适配器加天线,以及一些JavaScript代码。
如今,绝大多数飞行器都会广播ADS-B数据,其全称是Automatic Depedent Surveillance-Broadcast(广播式自动相关监视)。这种监视技术可以让飞行器在不需要地面的问询信号的情况下主动广播其飞行状态,这样就不需要地面的输入了。该数据包括飞行器的位置、经纬度、速度、代码等。飞行器会定期将数据发送给航空控制台,而使用带有天线的信号接收器,你也可以截获这些数据并制作自己的飞行器雷达系统。
由于数据广播频率为1090MHz,偶极子天线的尺寸可以通过以下公式来计算:
总长度=14264 / 频率(MHz)
每侧天线的长度=总长度/2
在该项目中,总长度约为13cm,所以每侧天线的长度应该为6.5cm。
利用WebUSB连接适配器
WebUSB API是一个浏览器API,可以通过USB连接插到电脑上的设备并与之通信。
要使用该API,首先应该检查浏览器是否支持。实现代码如下:
if(navigator.usb){
console.log("The Web USB API is supported!")
} else {
console.log("I'm afraid this won't work")
}
接下来,你需要指定连接到哪个设备。你可以列出所有设备,或者指定一个过滤器,写明设备的制造商ID和产品ID。在Mac上可以通过以下方式找到这些ID:将设备插入电脑,点击苹果图标 > About this Mac > System Report,然后检查 Hardware > USB下的列表。
上面的图片表明,制造商ID为0x0bda,产品ID为0x2838。
出于安全的考虑,WebUSB API必须由用户动作触发,所以我在屏幕上加了一个按钮,来启动连接。
首先调用navigator.usb上的requestDevice方法:
button.onclick = () => {
navigator.usb
.requestDevice({
filters: [
{
vendorId: 0x0bda,
productId: 0x2838,
}
],
})
};
它会返回一个promise,里面包含了列表中选中的设备。接下来,在该设备上开启一个绘画,选择一项配置,然后声明一个接口:
.then((device) => device.open());
.then(() => device.selectConfiguration(1))
.then(() => device.claimInterface(0))
配置和接口是设备特有的。我没有在网上找到该设备的具体信息,所以我尝试了不同的值。
完成这些步骤之后,设备就连接好了。现在需要设置频率和采样率。我使用了Sandeep Mistry的rtlsdrjs库。我使用的频率是 1090000000(1090MHz),采样率是2000000,如果你想尝试类似的项目 ,可以用作参考。
最后,当设备接收到数据时,执行如下transferIn方法:
.transferIn(1, 256000)
.then((result) => {
const data = new Uint8Array(result.data.buffer);
console.log(data);
})
该代码返回的原始数据大致如下:
处理并格式化后如下:
处理原始ADS-B数据
这部分极大依赖于已有的成果。我需要深入研究Mode S通信协议才能解码数据,不过这篇文章(https://mode-s.org/decode/content/ads-b/1-basics.html)可以作为入门。
到目前为止,据我的理解,ADS-B消息包含两个部分:信息头和数据块。数据块包含112比特,分为5个节:
DF:下行格式
CA:应答器功能
ICAO:飞行器地址
ME:消息
PI:校验ID
比特33-38位消息专用。前5个比特是类型代码。如果该代码位于1~4之间,表明ADS-B消息是一条飞行器鉴别信息;如果类型代码位于5~8之间,表明这是一条地面位置消息,等等。类型代码很重要,它决定了消息其余部分的含义。
一条原始ADS-B消息的十六进制如下:
8D4840D6202CC371C32CE0576098
用二进制表示为:
1000110101001000010000001101011000100000001011001100001101110001110000110010110011100000010101110110000010011000
你可以猜一下它一共有多少比特……
112比特!
利用前面的表,可以将该消息分成各个节:
转换成十进制:
消息的前5比特是十进制的4,表示这是一条飞行器鉴别消息。如果我的理解正确,消息的其余部分是关于飞行器类别和呼号的,如下表所示:
你可以利用该数据,使用诸如planespotters.net之类的在线工具,并搜索ICAO代码,来获取有关飞行器的信息。
在处理完数据后,得到的JSON对象包含高度、经纬度等信息。
最终配置
最终的配置如下:
下面是另一段演示:
这篇文章没有涉及深入的细节,但我希望我的实现方法是正确的!很高兴我能用WebUSB实现这个项目。