ブラウザからドローンにアクセス?Web Serial APIでPixhawkと繋いでみた

はじめに
ドローンや無人移動体のフライトコントローラーとして世界中で使われている「Pixhawk」。
通常、そのデータを確認するには専用ソフト(Mission PlannerやQGroundControl)をPCにインストールします。

しかし最近、「ブラウザ(ChromeやEdge)から直接シリアル通信ができる」というWeb Serial APIの存在を知り、ふと思いました。

「これを使えば、ブラウザだけでPixhawkの中身が覗けるんじゃね?」

今回はその検証の第1弾として、インストール不要・ブラウザのみでPixhawkの生データを受信するところまでを実践してみます。


Web Serial APIとは
ひとことで言えば、「OSの壁を越えて、ブラウザからハードウェアを直接制御できる技術」です。
これまではセキュリティの観点からブラウザがPCのハードウェアに直接触れることは制限されてきましたが、このAPIの登場により、WebアプリからArduinoやPixhawkといったデバイスを制御することが可能になりました。


実装:最小限のコードで繋いでみる
まずは、Pixhawkから送られてくる「生データ」を表示するための、シンプルなHTMLとJavaScriptを準備しました。

実装のポイント
1.ボーレートの設定: PixhawkのUSBポートは通常 115200 で通信しています。
2.バイナリの可視化: Pixhawkはデータをバイナリ(数値の列)で送ってくるため、JavaScriptで16進数の文字列に変換して表示させています。




<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Pixhawk Web Serial Connect</title>
    <style>
        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f4f4f9; padding: 30px; }
        .card { background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 20px; max-width: 800px; margin: auto; }
        h1 { color: #333; font-size: 1.5rem; }
        .controls { margin: 20px 0; display: flex; gap: 10px; align-items: center; }
        button { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; transition: 0.3s; }

        /* 接続ボタンのスタイル */
        .btn-primary { background: #007bff; color: white; }
        .btn-primary:hover { background: #0056b3; }

        /* 切断ボタンのスタイル */
        .btn-danger { background: #dc3545; color: white; }
        .btn-danger:hover { background: #a71d2a; }

        #clearBtn { background: #6c757d; color: white; }
        .status { font-weight: bold; margin-left: 10px; }
        .status.connected { color: #28a745; }
        .status.disconnected { color: #dc3545; }
        #console { background: #1e1e1e; color: #00ff00; padding: 15px; height: 400px; 
                   overflow-y: scroll; font-family: 'Consolas', monospace; font-size: 13px; border-radius: 4px; }
        .info { font-size: 0.9rem; color: #666; margin-top: 10px; }
    </style>
</head>
<body>

<div class="card">
    <h1>Pixhawk 接続テスト (Web Serial API)</h1>

    <div class="controls">
        <button id="connectBtn" class="btn-primary">Pixhawkに接続</button>
        <button id="clearBtn">表示をクリア</button>
        <span id="statusLabel" class="status disconnected">未接続</span>
    </div>

    <div id="consoleText">受信待機中...</div>
    <div id="console"></div>

    <div class="info">
        ※PixhawkをUSBで繋ぎ、Mission Planner等を閉じてから「接続」を押してください。<br>
        ※115200bpsで通信を開始します。
    </div>
</div>

<script>
    const connectBtn = document.getElementById('connectBtn');
    const clearBtn = document.getElementById('clearBtn');
    const consoleDiv = document.getElementById('console');
    const statusLabel = document.getElementById('statusLabel');

    let port;
    let reader;
    let keepReading = true;

    // ボタン1つで接続と切断を切り替える
    connectBtn.addEventListener('click', async () => {
        if (port) {
            // 切断処理
            keepReading = false;
            if (reader) await reader.cancel();
            await port.close();
            port = null;

            // UIを元に戻す
            statusLabel.innerText = "未接続";
            statusLabel.className = "status disconnected";
            connectBtn.innerText = "Pixhawkに接続";
            connectBtn.className = "btn-primary";
            return;
        }

        try {
            port = await navigator.serial.requestPort();
            await port.open({ baudRate: 115200 });
            statusLabel.innerText = "接続済み";
            statusLabel.className = "status connected";
            connectBtn.innerText = "切断する";
            connectBtn.className = "btn-danger";

            keepReading = true;
            readLoop(); 
        } catch (err) {
            console.error(err);
            alert("接続に失敗しました: " + err.message);
        }
    });

    async function readLoop() {
        while (port && port.readable && keepReading) {
            reader = port.readable.getReader();
            try {
                while (true) {
                    const { value, done } = await reader.read();
                    if (done) break;

                    const hexString = Array.from(value)
                        .map(b => b.toString(16).padStart(2, '0').toUpperCase())
                        .join(' ');

                    const span = document.createElement('div');
                    span.textContent = `[${new Date().toLocaleTimeString()}] ${hexString}`;
                    consoleDiv.appendChild(span);

                    if (consoleDiv.childNodes.length > 100) {
                        consoleDiv.removeChild(consoleDiv.firstChild);
                    }
                    consoleDiv.scrollTop = consoleDiv.scrollHeight;
                }
            } catch (err) {
                console.error("読み取りエラー:", err);
            } finally {
                reader.releaseLock();
            }
        }
    }

    clearBtn.addEventListener('click', () => {
        consoleDiv.innerHTML = '';
    });
</script>

</body>
</html>


動作確認:ブラウザに流れる「生データ」
PixhawkをUSBでPCに繋ぎ、作成したページで「接続」ボタンを押すと……。

出ました!
黒いコンソール画面に、16進数の数字がザーッと流れ始めました。
この中には、機体の傾き、高度、GPSの状態といったあらゆる情報が詰まっています。

よく見るとデータの先頭に FD という文字が混ざっているのがわかります。これは MAVLink v2 という通信プロトコルの開始合図。ブラウザが正しくPixhawkの信号を捉えている証拠です。


まとめ
専用ソフトを一切立ち上げることなく、「ただWebページを開くだけ」でPixhawkとの通信に成功しました。
「ブラウザだけで動く」ということは、OSを問わず、URLを共有するだけで誰でも同じ解析ツールが使えるようになるということです。

注意点
1.ブラウザの制限(Safariは未対応)
  ここが一番のポイントです。Mac標準の Safariは、Web Serial APIをサポートしていません。Macユーザーには「ChromeかEdgeを使ってください」と伝える必要があります。

2.ドライバー不要だが「認識名」が違う
  Windowsでは「COM3」のように表示されますが、Macでは /dev/cu.usbmodem… のような名前で認識されます。Web Serial APIの選択ダイアログにはちゃんと出てくるので、それを選択すればOKです。

ブラウザOS (Windows/Mac/Linux)対応状況
Google ChromeWindows / MacOK
Microsoft EdgeWindows / MacOK
FirefoxWindows / MacNG (非対応)
SafariMacNG (非対応)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA