TinyPilot: Build a KVM Over IP for Under $100

Michael Lynch

TinyPilot: 100ドル以下で作るKVM over IP

原文は Michael Lynch により に公開されました。 このブログを購読する

TinyPilotは、コンピュータを遠隔操作するための安価でオープンソースのデバイスです。OSが起動する前から動作するので、ベアメタルのホームラボサーバーで新しいOSをインストールしたり、起動時のトラブルをデバッグしたりするのに使っています。

この記事では、TinyPilotを作ったときの体験を詳しく紹介し、Raspberry Piを使って100ドル以下で自作する方法を解説します。

2台のコンピュータを接続するTinyPilotの写真

Microsoft Surface上のChromeからTinyPilotを使ってUbuntuノートPCを操作している様子

前置きはいいから作り方だけ教えて

もしあなたが、TinyPilot開発における私の栄光と苦悩の物語を飛ばしたいひねくれ者なら、「自作TinyPilotの作り方」のセクションまで直接飛んでください。

デモ

なぜTinyPilotなのか?

数年前、ソフトウェアのテスト用に自宅サーバーを自作しました。価値ある投資で、今では毎日使っています。

私のホームラボVMサーバーの写真

2017年に仮想マシン用に自作したホームラボサーバー

このサーバーにはキーボードもモニターもつながっていません。sshやウェブインターフェース経由でアクセスしているからです。便利な構成ですが、小さな問題がとてつもなく面倒な事態に変わります。

数ヶ月に一度、何かをやらかしてサーバーが起動しなくなったりネットワークに接続できなくなったりして、事実上マシンを締め出されてしまいます。復旧するには、すべての配線を外し、サーバーを机まで引きずってきて、デスクトップのキーボードやモニターに接続するためにケーブルをあちこち繋ぎ直さなければなりません。

市販のソリューション

友人たちはDellサーバーに搭載されているiDRACを絶賛しています。システムの電源が入った瞬間から仮想コンソールを提供するチップです。次のホームサーバー用にiDRACを一瞬検討しましたが、べらぼうに高い値段ですぐに断念しました。ライセンスだけで300ドルかかり、しかも高価な専用ハードウェアが必要です。

iDRAC 9 Enterpriseライセンスが300ドルであることを示すスクリーンショット

DellのiDRAC技術のライセンスは、ハードウェア代とは別に1台あたり300ドルかかります

次に、市販のKVM over IPソリューションを調べました。DellのiDRACと似た機能を提供しますが、コンピュータのキーボード、映像、マウス端子に接続する外付けデバイスです(だからKVMという名前です)。残念ながらさらに高価で、1台あたり500〜1,000ドルします。

Raritan Dominion KVM over IPの購入ページのスクリーンショット

市販のKVM over IPデバイスは1台500〜1,000ドルします。

サーバーを引きずり回すのが面倒だといっても、年に数回ケーブルを繋ぎ替える手間を省くためだけに500ドルも払う気にはなれませんでした。

そこで、まっとうに非合理的なプログラマーなら誰でもやることをしました。何百時間もかけて自分でKVM over IPを作ることにしたのです。

Raspberry PiでKVM over IPを作る

Raspberry Piは、小さくて安価なシングルボードコンピュータです。フル機能のデスクトップOSを動かせるほど高性能でありながら、30〜60ドルという価格のため、愛好家やプログラマーの間で人気の道具となっています。

手のひらに載せたRaspberry Pi

Raspberry Piは、1枚の基板に収まるフル機能のコンピュータで、わずか30〜60ドルです。

最近のPiはUSB On-The-Go(USB OTG)に対応しており、キーボードやUSBメモリ、マイクなどのUSBデバイスになりすますことができます。

PiをKVMとして使うというアイデアの概念実証として、Key Mime Piというシンプルなウェブアプリを作りました。

Key Mime Piのウェブインターフェースのスクリーンショット

Key Mime Pi。キーボード転送のみに対応したTinyPilotの初期の前身です。

Key Mime PiはUSB経由で別のコンピュータに接続し、USBキーボードとして認識されます。ウェブページを表示してJavaScriptのキーイベントを待ち受け、ユーザーが入力するとキーイベントを捕捉し、仮想USBキーボードを通じてキーストロークに変換します。その結果、入力はターゲットコンピュータに現れます。この動作については以前の投稿で詳しく説明しました。

映像キャプチャという課題

画面に何が表示されているか見えなければ、キーボード転送だけではあまり役に立ちません。次の当然のステップは、サーバーの映像出力をPiでキャプチャしてブラウザに表示する方法を見つけることでした。

映像キャプチャの最初の試みでは、Lenkeng LKV373A HDMIエクステンダーを使いました。Daniel Kučera氏(別名danman)がこのデバイスを素晴らしくリバースエンジニアリングしてくれています。eBayで中国の業者から約40ドルで入手できたので、最良の選択肢に思えました。

Lenkeng LKV373A HDMIエクステンダーの写真

Lenkeng LKV373A HDMIエクステンダーは、HDMI映像キャプチャの最初の試みでした。

映像のキャプチャは厄介でした。というのも、LKV373Aのトランスミッターはそもそも映像キャプチャデバイスではないからです。本来の用途は、ネットワークストリームを再びHDMI出力に変換するLKV373Aレシーバーとペアで使うことです。danman氏の調査で、映像ストリームを傍受してキャプチャする方法が発見されましたが、LKV373Aはほとんどの映像ツールが理解できない非標準のRTPプロトコル変種を喋ります。

幸い、danman氏がffmpegにパッチを提供してくれたおかげで、LKV373Aの奇妙な挙動にも対応できるようになり、ffmpegのビデオプレーヤーでストリームを再生できました。

ffplay -i udp://239.255.42.42:5004
LKV373Aからの映像ストリームをffplayで表示しているスクリーンショット

LKV373Aからの映像ストリームをffplayで表示しているところ

ここで、このプロジェクト全体を通して付きまとうことになる問題を初めて味わいました。遅延です。ターゲットコンピュータとデスクトップでの映像再生の間に、ほぼ1秒の遅れがありました。

Lenkeng LKV373A HDMIエクステンダーの写真

LKV373Aは、再エンコードする前ですでに838ミリ秒の遅延を生じさせていました。

ffplayの豊富なコマンドラインオプションをいろいろ試してストリームを高速化しようとしましたが、800ミリ秒を切ることはできませんでした。しかもそれは高性能なGPUとCPUを積んだデスクトップでの結果です。非力なRaspberry Piでは性能的に期待できそうにありませんでした。

幸い、まったくの偶然からより良い解決策を見つけました。

HDMI - USBドングル

Twitterをぼんやり眺めていたとき、たまたまArsenio Dev氏によるツイートを見かけました。格安のHDMI - USBドングルを買ったという内容でした。

ツイートのスクリーンショット

Arsenio Dev氏のツイートが、より良い映像キャプチャ手段を教えてくれました。

1080p解像度で30フレーム/秒の映像キャプチャができるとは、あまりにうますぎる話に思えたので、eBayで注文してみました。送料込みでわずか11ドルでした。これが何という名前なのかも分かりません。ブランド名すらなく、単に「HDMIドングル」と呼ぶことにします。いくつかバリエーションがありますが、中身はどれも同じMacroSilicon MS2109チップを異なるケースに入れただけです。

eBayで11.20ドルで販売されているHDMIのスクリーンショット

eBayで送料無料11.20ドルで販売されているHDMI - USBドングル

数日後にデバイスが届くと、驚かされました。Raspberry Piに挿すだけで、何の設定もなくUVC映像キャプチャデバイスとして認識されたのです。

$ sudo v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
        /dev/video10
        /dev/video11
        /dev/video12

UVC Camera (534d:2109): USB Vid (usb-0000:01:00.0-1.4): <<< HDMI capture dongle
        /dev/video0
        /dev/video1

数分のうちにHDMI映像をキャプチャして再配信できるようになりました。

# On the Pi
ffmpeg \
  -re \
  -f v4l2 \
  -i /dev/video0 \
  -vcodec libx264 \
  -f mpegts udp://10.0.0.100:1234/stream

# On my Windows desktop
ffplay.exe -i udp://@10.0.0.100:1234/stream

しかも驚くほど手軽でした。LKV373Aはレンガほどの大きさで、専用の電源とEthernetケーブルが必要でした。一方、HDMIドングルは親指ほどの大きさで、USBポートに挿すだけで済みます。

Lenkeng LKV373AとHDMIドングルの比較

Lenkeng LKV373A HDMIエクステンダー(左)は、HDMIドングル(右)よりも大きく、必要な接続も多くなります。

唯一の問題は、やはり遅延でした。Piが再配信する映像ストリームは、元のコンピュータより7〜10秒も遅れていました。

Lenkeng LKV373AとHDMIドングルの比較

ffmpegを使ってPiから映像を配信すると、映像に最大10秒の遅延が生じました。

この遅延がドングル自体に起因するのか、Pi上のffmpegなのか、デスクトップのffplayなのかは分かりませんでした。Arsenio Dev氏は遅延が20msだと報告していたので、ffmpegの難解で神秘的なコマンドラインオプションを掘り下げれば、より高速化できる可能性はありそうでした。

またしても幸運が、その苦行から私を救ってくれました。

類似プロジェクトからのヒント

以前のブログ記事をKey Mime Piについて公開したとき、Max Devaev氏からコメントをもらいました。彼のプロジェクトであるPi-KVMをチェックしてみるよう勧められたのです。

Max氏のコメントのスクリーンショット: Hi:) Take a look at this project: https://github.com/pikvm/pikvm We have already done and debugged many things

Max Devaev氏が、自身のPi-KVMプロジェクトを教えてくれました。

GPIOピン

私のブレッドボードに関する以前の経験といえば、うっかり溶かしてしまったことです。

Pi-KVMは以前にも見たことがありましたが、ブレッドボードやハンダ付けが必要という要件に尻込みしていました。

Max氏に勧められてPi-KVMをもう一度よく見てみると、特に映像遅延をどう解決しているかに興味が湧きました。彼がuStreamerというツールで映像をキャプチャしていることに気づきました。

注記:Max氏とのその後のやり取りで、Pi-KVMはハンダ付けやブレッドボードなしでも構築できることを知りました。

uStreamer: 超高速な映像ストリーマー

まだ予想もしていなかった問題まで解決してくれるような、素晴らしいツールに出会ったことはありますか?

uStreamerは、何の設定もなしに遅延を8秒から500〜600ミリ秒に短縮してくれました。しかも、一連の余計な作業まで不要にしてくれたのです。

HDMIドングルとuStreamerで500msの遅延

uStreamerにより遅延は15分の1になりました。

uStreamer以前は、ffmpegからの映像をどうやってユーザーのブラウザに届けるか見当もつきませんでした。ほぼ正確なチュートリアルを試してffmpegからnginxへHLSで映像を流してみましたが、遅延がさらに増えるだけでした。しかも、HDMIケーブルの抜き差しでストリーミングを開始・停止する方法や、映像をブラウザが扱える形式に変換する方法といった問題も未解決のままでした。

uStreamerはこれらすべてを解決してくれました。Motion JPEGというブラウザがネイティブに再生できる形式で映像を配信する、最小限のHTTPサーバー自体を内蔵していたのです。HLSストリームやffmpegとnginxの連携に悩む必要はなくなりました。

このツールはあまりにも高機能だったので、Max氏が成熟した別プロジェクトをフォークしたのだろうと思い込みましたが、間違いでした。この猛者は、Piのハードウェアから最大限の性能を引き出すために、自作のビデオエンコーダをC言語で書いたのです。私はすぐにMax氏に寄付し、このソフトウェアを使うすべての人に同じことを勧めます。

映像の遅延をさらに改善する

uStreamerにより遅延は10秒から約600ミリ秒まで縮まりました。大きな前進でしたが、まだはっきり分かる遅れでした。さらに性能を改善できるならuStreamerへの資金提供にも興味があるとMax氏に伝え、話し込むようになりました。

Max氏は私が使っているHDMIドングルに興味を持ちました。彼はその特定のデバイスを見たことがなかったのです。彼はtmateを使って共有シェルセッションを作り、Piにリモートアクセスさせてほしいと誘ってくれました。

Max氏がtmate経由でサポートを申し出ている会話のスクリーンショット

Max氏は、遅延の改善を手伝うか、私を連邦犯罪で陥れるかのどちらかを申し出てくれました。幸い、前者をやってくれました。

私のハードウェアでuStreamerがどう動くかを数分テストした後、Max氏はv4l2-ctlユーティリティを実行し、私にはさっぱり分からない一行に魅了されました。

$ sudo v4l2-ctl --all
Driver Info:
        Driver name      : uvcvideo
        Card type        : UVC Camera (534d:2109): USB Vid
...
Format Video Capture:
        Width/Height      : 1280/720
        Pixel Format      : 'MJPG' (Motion-JPEG)
...
Streaming Parameters Video Capture:
        Capabilities     : timeperframe
        Frames per second: 30.000 (30/1)

HDMIドングルはMotion JPEG形式で映像ストリームを送ってきていたのです!uStreamerのハードウェア支援エンコードは高速でしたが、そもそも不要でした。なぜなら最近のブラウザはMotion JPEGをネイティブに再生できるからです。

私たちはuStreamerを再エンコードをスキップして映像ストリームをそのままパススルーするように設定しました。

再エンコードを省いたことで遅延が200msになったことを示す写真

Piでの余計な再エンコードを省くことで、遅延は600msから200msに縮まりました。

遅延は600ミリ秒から200ミリ秒まで一気に縮まりました。瞬時というわけではありませんが、数分使えば遅れを忘れられる程度には低くなりました。

TinyPilotの実践

この記事の冒頭で、ヘッドレスのVMサーバーに起動前からアクセスするためにTinyPilotが欲しいと言ったのを覚えているでしょうか?実際に動きますし、私は使っています!

Key Mime Piを改良して、映像キャプチャ機能を統合した新しいウェブインターフェースを作りました。

今年、新しいヘッドレスVMサーバーを自作し、TinyPilotを使ってProxmoxというオープンソースのハイパーバイザー兼VM管理用ウェブインターフェースをインストールしました。

TinyPilotのおかげで、インストール全体をブラウザから管理できました。コンピュータを引きずり回したりケーブルを何度も繋ぎ替えたりしていた昔のやり方より、ずっと快適でした。

自作TinyPilotの作り方

パーツリスト

Raspberry Pi OS Liteをインストールする

まずは、microSDカードにRaspberry Pi OS Lite(旧称Raspbian)をインストールします。

Rufusのスクリーンショット

私はPi用のmicroSDカードの書き込みにRufusを使っていますが、どのディスクイメージ書き込みツールでもかまいません。

microSDカードのbootパーティションにsshという名前のファイルを置くことで、SSHアクセスを有効にしてください。無線で接続する場合は、wpa_supplicant.confファイルも必要です。

microSDカードの準備ができたら、Piデバイスに挿入してください。

ケースを取り付ける(任意)

Raspberry Pi 4は発熱が大きいことで有名です。冷却なしでも動作はしますが、時間が経つと安定性に問題が出る可能性があります。

私はこのミニマルなケースが気に入っています。安価で、電源付きファンのような複雑さもなく、Piをパッシブ冷却してくれるからです。

Raspberry Pi用のミニマルなアルミケース

このミニマルなアルミケースは、ファンの複雑さなしにPiをしっかり冷やしてくれます。

USBでマシンに接続する

TinyPilotが仮想キーボードとして機能するように、PiのUSB-CポートをターゲットマシンのUSB-Aポートに接続してください。

Raspberry PiへのUSB接続ターゲットコンピュータへのUSB接続

USB-C - USB-Aケーブルで、USB-C側をPiのUSB-Cポートに、USB-A側をターゲットコンピュータに接続します。

注記:できればUSB 3.0ポートを使ってください。Piにより多くの電力を供給できます。

HDMIキャプチャドングルを取り付ける

物理的な組み立てを完了するには、HDMIドングルをPiのUSBポートの1つに挿入します。次に、HDMIケーブルをドングルに接続し、もう一方の端をターゲットコンピュータの映像出力端子につなぎます。

Raspberry PiへのHDMI入力接続ターゲットコンピュータからのHDMI出力接続

ターゲットコンピュータの映像出力をHDMIドングルに接続し、PiのUSBポートに挿入します。

注記:接続先のコンピュータにHDMI出力がない場合は、DisplayPort - HDMIケーブルDVI - HDMIケーブルが使えるはずですが、私自身は試していません。

Ethernetケーブルを接続する

Piに有線LANで接続する場合は、ネットワークケーブルをPiのEthernetポートに接続してください。

Piデバイスに接続されたEthernetケーブルの写真

EthernetケーブルをPiに接続します。

注記上記wpa_supplicant.confファイルを追加して無線アクセスを設定した場合は、この手順をスキップできます。

TinyPilotソフトウェアをインストールする

PiデバイスにSSHで接続し(Raspberry Pi OSのデフォルト認証情報はpi / raspberryです)、次のコマンドを実行してください。

curl -sS https://raw.githubusercontent.com/tiny-pilot/tinypilot/master/quick-install \
  | bash -
sudo reboot

もし無作為なウェブ上のスクリプトをシェルにパイプすることに当然の疑念を抱くなら、ソースを確認することをお勧めします。

このスクリプトは、私のTinyPilot Ansibleロールを使って自己完結型のAnsible環境をブートストラップします。起動時に毎回実行される4つのサービスをインストールします。

  • nginx:人気のオープンソースウェブサーバー
  • ustreamer:軽量なHTTP映像ストリーミングサーバー
  • usb-gadget:Piの「USBガジェットモード」を有効にするスクリプト。これによりPiがUSBデバイスになりすますことができます
  • tinypilot:私がTinyPilot用に作成したウェブインターフェース

TinyPilotの使い方

インストールスクリプトを実行すると、TinyPilotは次のアドレスで利用できるようになります。

TinyPilotウェブインターフェースのスクリーンショット

セットアップが完了すると、ローカルネットワーク上のhttp://raspberrypi/でTinyPilotのウェブインターフェースにアクセスできます。

電源の問題

この構成の最大の制約は電源です。ターゲットコンピュータから電源を取ることに依存しているため、ターゲットがシャットダウンするとPiは突然電源を断たれることになります。

さらに、Pi 4は安定動作のために3Aを必要としますが、より低い電力でも動作は可能です。コンピュータのUSB 3.0ポートは0.9Aしか供給できず、USB 2.0では0.5Aしか供給できないため、Piのシステムログに次のような警告が表示されることがあります。

 $ sudo journalctl -xe | grep "Under-voltage"
Jun 28 06:23:15 tinypilot kernel: Under-voltage detected! (0x00050005)

この問題を解決するため、エンジニアリング会社と協力して、PiのUSB-Cポートを2つに分岐するカスタム基板を作成しました。1つ目のポートはUSB電源を受け付けるので、Piに引き続き3Aをフルに供給できます。2つ目はUSBデータ出力を担うので、PiはUSBキーボードになりすましたままにできます。

電源コネクタのクローズアップRaspberry PiとmicroUSBケーブルに接続された電源コネクタ

TinyPilot Power Connectorにより、PiはUSB OTG機能を失うことなく、USB-Cポート経由で3Aの電源を受け取ることができます。

重要なことに、この電源コネクタのデータポートはUSBの電源ラインを除外しています。これにより、コンピュータ側の電源とPi側の電源の電圧差によって好ましくない逆流が起こるのを防ぎます。

注記:適切なコネクタなしで、コンピュータに接続したまま外部電源からPiに給電すると、ハードウェアを損傷する恐れがあります。詳細はTinyPilot wikiを参照してください。

ソースコード

TinyPilotのソフトウェアは、寛容なMITライセンスの下でオープンソースとして公開されています。

  • tinypilot:TinyPilotのウェブインターフェースとバックエンド。
  • ansible-role-tinypilot:TinyPilotとその依存関係をsystemdサービスとしてインストールするためのAnsibleロール。

完成品のTinyPilotデバイス

完成品のTinyPilotデバイスはTinyPilotのウェブサイトで購入できます。私はTinyPilotという会社の最初の創業者でしたが、2024年4月に事業を売却し、現在は熱心なユーザーの一人として以外、会社とは関係がありません。


Max Devaev氏によるuStreamerでの素晴らしい仕事と、TinyPilotへの貢献に特別な感謝を捧げます。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。

コメント