航空機のADS-B信号を捉える「ADS-B Feeder Image」をラズパイPVE環境のLXCコンテナで動かす

航空機のADS-B信号を捉える「ADS-B Feeder Image」をラズパイPVE環境のLXCコンテナで動かす
Page content

機運

航空機は、自機の位置情報などをADS-B信号 (Automatic Dependent Surveillance-Broadcast Signal) で送信している。その信号を受信してデータをFlightradar24などにシェアできる「ADS-B Feeder」なるものを、私は3年ほど前に知ったようだ。

この「ADS-B Feeder」のことを最近また思い出し、かつ、私も子どもも程々にFlightradar24が好きで、利用プランをContributorsにアップグレードしてみたくもあり。いわば機運を感じてやる気も出して、1090MHzのADS-B信号を受信できる受信機、実際にはDVB-T規格のTVチューナーをAliExpressで購入した。

ラズパイをADS-B信号の受信専用機に仕立てる方法は多くのウェブ記事で紹介されているものの、

私は家の中で物理サーバを増やしたくない。そこで別の構築方法を考えた。自宅ITの中核となっている既存のラズパイのPVE環境の中で、「ADS-B Feeder Image」を動かすことができるのか、挑戦することにした。

今回の目標

Proxmox VE (PxVirt) の仮想化ホストとして稼働中のRaspberry Pi 4がある。その仮想化ゲストとしてLXCコンテナを作成し、その中で「ADS-B Feeder Image」の公式Dockerコンテナを動作させる。ポイントになりそうなのは、USB接続する受信機を、LXCコンテナから利用可能にできるのかどうかだ。

目指す構成

新規のADS-B Feeder Image (LXC) を、既存の、USB接続でBluetoothを利用しているHome Assitant (VM) やAsterisk (LXC) などと同居させる。

graph TD
    subgraph HW ["Raspberry Pi 4 B+ (Physical)"]
        subgraph PVE ["Proxmox VE / PxVirt (Hypervisor)"]
            
            direction TB
            
            subgraph LXC_ADSB ["LXC (Privileged) for ADS-B"]
                subgraph Docker ["Docker"]
                    App["ADS-B Feeder"]
                end
            end

            subgraph LXC_VoIP ["LXC: Asterisk"]
            end

            subgraph LXC_Others ["LXC: others"]
            end

            subgraph VM_HA ["VM: Home Assistant"]
            end
            
        end
    end

    NIC1(["🌐 Ethernet Port (NIC1)"]) ---|Network Bridge| PVE
    NIC2(["🌐 USB NIC (NIC2)"]) ---|Specific Bridge| LXC_VoIP

    USB(["📡 USB Dongle<br/>(RTL2838)"]) -.->|USB Passthrough| LXC_ADSB
    BT(["🔹 Bluetooth Dongle"]) -.->|USB Passthrough| VM_HA

    %% Styling for a premium look
    style HW fill:#f9f9f9,stroke:#333,stroke-width:2px
    style PVE fill:#eceff1,stroke:#607d8b,stroke-width:2px
    style LXC_ADSB fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
	style LXC_VoIP fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
    style VM_HA fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
    style Docker fill:#e8f5e9,stroke:#43a047,stroke-width:2px
    style App fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,font-weight:bold

参考) 標準的な構成

参考として。ラズパイと公式のADS-B Feeder Imageを組み合わせた場合はこの構成になる。

graph TD
    subgraph HW ["Raspberry Pi (Physical)"]
        subgraph Image ["ADS-B Feeder Image (All-in-one)"]
            direction TB
            OS["Minimal OS"]
            App["ADS-B Feeder"]
            OS --- App
        end
    end

    NIC1(["🌐 Ethernet Port (NIC1)"]) --- HW
    USB(["📡 USB Dongle<br/>(RTL2838)"]) -.->|Direct Access| Image

    %% Styling
    style HW fill:#f9f9f9,stroke:#333,stroke-width:2px
    style Image fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style App fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,font-weight:bold

「ADS-B Feeder Image」LXCコンテナの構築方法

Step-1. 機器を用意する

項目内容価格備考
受信機Digital USB 2.0 TV Receiver Stick USB2.0 DVB-T SDR DAB FM HDTV TV Tuner Stick RTL2832U R820T2 Antenna Remote Control For laptop - AliExpress 443,287円購入日: 2026-04-27
アンテナ上記受信機に付属の物
サーバ筐体Raspberry Pi 4 Model B Rev 1.4 (8GB)

AliExpressで購入した受信機は上記の写真のUSBドングルタイプで、アンテナ端子の形状はMCX。Linux環境からはUSBデバイスとして次のようにみえる。

$ lsusb | grep RTL
Bus 001 Device 007: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T

$ lsusb -t
/:  Bus 001.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/1p, 480M
    |__ Port 001: Dev 002, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 001: Dev 003, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 003: Dev 005, If 0, Class=Hub, Driver=hub/4p, 480M
                |__ Port 001: Dev 007, If 0, Class=Vendor Specific Class, Driver=dvb_usb_rtl28xxu, 480M
                |__ Port 001: Dev 007, If 1, Class=Vendor Specific Class, Driver=[none], 480M
(snip)

Step-2. PVE環境とLXCコンテナの準備を行う

  1. 適当なPCにUSBドングルを接続して、実際のIDを念のため確認しておく (idVendor=“0bda”, idProduct=“2838” となるはず)
  2. PVE環境にて次の2つのファイルを用意する
    • /etc/modprobe.d/blacklist-rtl_adsb.conf は、PVE環境にUSBドングル (Realtek RTL2838) を認識させないようにドライバをブラックリスト化するもの。
    • /etc/udev/rules.d/99-rtl-sdr.rules は、USBドングル (Realtek RTL2838) への一般ユーザへのアクセス権限付与と、HIDドライバの解放を意図するもの。なぜTV受信機なのに「HIDドライバ」が関係してくるかと言うと、このUSBドングルには赤外線受光部が備わっていて、PCのリモコンにもなりうるため。なお、HIDドライバをblacklistに追加するとUSBデバイス全般に影響してそれは困るので、このUSBドングルだけに作用するrulesを用意した。
    $ cat /etc/modprobe.d/blacklist-rtl_adsb.conf
    blacklist dvb_usb_rtl28xxu
    blacklist rtl2832
    blacklist rtl2830
    
    $ cat /etc/udev/rules.d/99-rtl-sdr.rules
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666", RUN+="/bin/sh -c 'echo -n $kernel > /sys/bus/usb/drivers/usbhid/unbind || true'"
  3. PVE環境にて次のLXCコンテナを作成する
    • Template: Debian (trixie)
    • Unprivileged container: No (非特権コンテナではなく特権コンテナへ切り替える)
  4. ちなみに、LXCコンテナのIPアドレスがPVE環境で固定したものだけではなく、DHCP取得も行われてしまう問題は、次のサービスの停止で一応解決できる
    systemctl stop systemd-networkd
    systemctl disable systemd-networkd
  5. LXCコンテナにSSHサーバを導入する: sudo apt install openssh-server
  6. PVE環境にて、LXCコンテナの設定ファイル /etc/pve/lxc/<LXCコンテナID>.conf の最後に次の2行を追加し、LXCコンテナからUSBドングルが見えてかつアクセス可能な状態にする。「bus/usb/001」の001は、Busの001側につないでいることを意味する (実際の環境に合わせた数値にすること)。Devの番号はUSBデバイスの差し替えで変化するので、本設定ではDev番号の指定までは行っていない。
    lxc.cgroup2.devices.allow: c 189:* rwm
    lxc.mount.entry: /dev/bus/usb/001 dev/bus/usb/001 none bind,optional,create=dir
  7. LXCコンテナを再起動し、その後、USBドングルの見え方とrtl_testの実行結果を確認する
    $ sudo apt install usbutils rtl-sdr
    
    $ ls -al /dev/bus/usb/001/007
    crw-rw-rw- 1 root plugdev 189, 6 May 11 01:05 /dev/bus/usb/001/007
    
    $ lsusb | grep RTL
    Bus 001 Device 007: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T
    
    $ rtl_test -t
    Found 1 device(s):
    0:  Realtek, RTL2838UHIDIR, SN: 00000001
    
    Using device 0: Generic RTL2832U OEM
    Detached kernel driver
    Found Rafael Micro R820T tuner
    Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 
    [R82XX] PLL not locked!
    Sampling at 2048000 S/s.
    No E4000 tuner found, aborting.
    Reattached kernel driver

上記のように、LXCコンテナからUSBデバイスが認識されて「0: Realtek, RTL2838UHIDIR, SN: 00000001」のようにデバイス情報の取得まで正常に行えるならば、Step-2は成功だ。

参考情報として、今回の試行錯誤の途中で遭遇した失敗の例を2つ、挙げておく。表示されるエラー番号は、libusbenum libusb_errorでの定義に対応しているらしい。

## デバイス情報が正しく読み取れない例
$ rtl_test -t
Found 1 device(s):
  0:  b, x, SN: ?

Using device 0: Generic RTL2832U OEM
usb_open error -4
Failed to open rtlsdr device #0.
## デバイスがすでに専有されてBUSYな例
$ rtl_test -t
Found 1 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
usb_claim_interface error -6
Failed to open rtlsdr device #0.

Step-3. ADS-B Feederを導入する

LXCコンテナのOS (Debian) にログインして、以下の操作を行う。

  1. ADS-B Feeder Imageのインストーラーの実行に必要なツールを事前導入する: sudo apt install curl jq
  2. ADSB.imにて、「How to Install」 > 「Linux (more advanced)」にある次の記載を見つける
    • On most recent Debian / Ubuntu based Linux systems running on ARM64 or x86 systems, you can install the ADS-B Feeder Image as an app
  3. 記載部分に書かれた次のコマンドで、インストーラーを実行する: curl https://raw.githubusercontent.com/dirkhh/adsb-feeder-image/main/src/tools/app-install.sh | sudo bash
    • 最初は次のものをインストールせよと表示されるので従って実行する: sudo apt-get install -y python3 python3-flask python3-requests python3-cryptography git docker.io docker-compose
    • 再度、curl ... を実行すると、次のような処理が行われて正常終了するはず。
      $ curl https://raw.githubusercontent.com/dirkhh/adsb-feeder-image/main/src/tools/app-install.sh | sudo bash
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                      Dload  Upload   Total   Spent    Left  Speed
      100  8092  100  8092    0     0   1591      0  0:00:05  0:00:05 --:--:--  1871
      You appear to be on a debian-style distribution
      Cloning into '/tmp/tmp.m32B5HCAHy/adsb-feeder'...
      remote: Enumerating objects: 42008, done.
      remote: Counting objects: 100% (4082/4082), done.
      remote: Compressing objects: 100% (664/664), done.
      remote: Total 42008 (delta 3655), reused 3480 (delta 3394), pack-reused 37926 (from 5)
      Receiving objects: 100% (42008/42008), 6.89 MiB | 12.02 MiB/s, done.
      Resolving deltas: 100% (21636/21636), done.
      Already on 'main'
      Your branch is up to date with 'origin/main'.
      Created symlink '/etc/systemd/system/multi-user.target.wants/adsb-docker.service' → '/usr/lib/systemd/system/adsb-docker.service'.
      Created symlink '/etc/systemd/system/default.target.wants/adsb-early-boot.service' → '/usr/lib/systemd/system/adsb-early-boot.service'.
      Created symlink '/etc/systemd/system/multi-user.target.wants/adsb-setup.service' → '/usr/lib/systemd/system/adsb-setup.service'.
      Created symlink '/etc/systemd/system/timers.target.wants/adsb-update.timer' → '/usr/lib/systemd/system/adsb-update.timer'.
      Running as unit: adsb-docker-pull.service; invocation ID: 0123456789abcdef0123456789abcdef
      done installing
      you can uninstall this software by running
      sudo bash /opt/adsb/app-uninstall
      
      you can access the web interface at http://localhost:1099 or http://192.168.1.20:1099
  4. 実行結果の最後に表示されているURL http://<LXCコンテナのIPアドレス>:1099 をウェブブラウザで開く

Step-4. GUIでの設定, 動作確認

ADS-B Feeder Imageの設定方法については、今回のPVE/LXC環境とは直接関係しない内容となるので、ここでは省略する。たとえば、【特集】眠っていたRaspberry Piが“航空情報局”に!Flightradar24有料プランを無料で楽しむ裏ワザ - PC Watch > 「ADS-B Feederの初期設定」を参考にして進めればよい。参考程度の画面キャプチャを以下に示す。

  1. Basic SetupとSupport Info:
    • Basic Setup: 自局の緯度・経度・高度を入力し、ADS-BのチェックをONにして、APPLYする
    • Support Info: 項目「SDR(s)」にてUSBドングルが認識されていることがわかる
  2. 1週間ほど運用すると次のような記録が得られる
    • Map: 捉えたADS-B信号の範囲が地図上にプロットされる。円形とはかけ離れたかなり歪な形となっているのは、周りに障害物が多い、今回のアンテナ設置状況の影響を多分に受けているのだろうと推測する。
    • Performance Graphs: 例えば夜間は激減するなど、日々の時間帯によってADS-B信号の受信レートに周期的な変動があることが分かる。

参考リンク