mcpField
M
matlab-connect-mavlink

matlab-connect-mavlink

github.com/matlab開発1.2k62 回インストール1 日前に更新
リポジトリ

matlab-connect-mavlink について

MATLABからUDP経由でPX4またはArduPilotのフライトコントローラーに接続するスキルです。地上局やSITLでの利用を想定し、MAVLink設定とハートビートの順序を示して接続時の誤りを防ぎます。

主な機能

  1. 01UDPによるMAVLink通信の確立
  2. 02MAVLink方言とインターフェースの設定
  3. 03地上局ハートビートの送信
  4. 04オートパイロットクライアントの検出と接続
  5. 05MAVLinkメッセージの購読

活用シーン

  1. 01MATLABとPX4 SITLの接続
  2. 02MATLABの地上局としての設定
  3. 03検出したオートパイロットのメッセージ監視

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-connect-mavlink

インストール後、Claude Code で/matlab-connect-mavlinkを入力して読み込まれたか確認します。

同梱ファイルmanifest.yaml

詳細

MAVLink 接続のセットアップ

MATLAB をグラウンドコントロールステーション(GCS)として使用し、MATLAB から PX4 または ArduPilot のフライトコントローラーへの MAVLink UDP 接続を確立します。このスキルでは、エージェントが一貫して誤るプロトコルシーケンスとハートビートのパターンを正しく定義します。

使用する場合

  • UDP 経由で MATLAB を PX4 または ArduPilot のオートパイロットに接続したい場合
  • MATLAB でグラウンドコントロールステーションを構築している場合
  • SITL またはネットワーク接続されたオートパイロットとの MAVLink 通信を設定する必要がある場合
  • ハートビートの交換やクライアントの検出について質問された場合
  • mavlinkio、mavlinkdialect、または sendudpmsg に言及された場合

使用しない場合

  • すでに確立された接続を介してパラメーターの読み取り/設定、ミッションのアップロード、ログのダウンロードをしたい場合 — これらはこのスキルなしで問題なく実行できます
  • Simulink の MAVLink ブロックを使用している場合(ワークフローが異なります)
  • .ulg ログファイルをオフラインで解析したいだけの場合 — ulogreader を直接使用してください
  • MAVLink メッセージのシリアライズ/デシリアライズのみについて質問された場合

ワークフロー

次の順序を正確に守ってください。順番が重要です — 手順を省略したり順序を変えたりすると、何も通知されないまま失敗します。

1. ダイアレクトを作成する
dialect = mavlinkdialect("common.xml", 2);

PX4 と ArduPilot の両方で "common.xml" を使用してください(標準メッセージすべてに対応しています)。 ArduPilot 固有の拡張メッセージが必要な場合にのみ、"ardupilotmega.xml" を使用してください。 2 は MAVLink プロトコルのバージョン 2 を指定します。

利用可能なダイアレクト:common.xml、ardupilotmega.xml、standard.xml、minimal.xml

2. MAVLink IO インターフェイスを作成する
mavlink = mavlinkio(dialect, 'SystemID', 255, 'ComponentID', 1);
  • SystemID 255、ComponentID 1 は標準の GCS ID です
  • 接続確認のために mavlinksub(mavlink, "HEARTBEAT") を作成しないでください。 mavlinkio には、listClients() に情報を渡す組み込みのハートビートサブスクライバーがあります。 HEARTBEAT サブスクライバーを手動で作成するのは重複であり、無駄です。
3. UDP トランスポートに接続する
connect(mavlink, "UDP", LocalPort=14550);

トランスポートオプションはすべて名前と値のペアです。位置引数は使用しないでください。

名前と値のオプション:LocalPort(既定値 0)、ConnectionName(既定値 "Connection#")

4. GCS ハートビートメッセージを作成する

createmsg のシグネチャ:createmsg(dialect, msgName) — ダイアレクトオブジェクトが常に最初の引数、メッセージ名の文字列が 2 番目の引数です。mavlinkio オブジェクトを createmsg に渡さないでください。

hbMsg = createmsg(dialect, "HEARTBEAT");
hbMsg.Payload.type(:) = dialect.enum2num("MAV_TYPE", "MAV_TYPE_GCS");
hbMsg.Payload.autopilot(:) = dialect.enum2num("MAV_AUTOPILOT", "MAV_AUTOPILOT_INVALID");
hbMsg.Payload.base_mode(:) = 0;
hbMsg.Payload.custom_mode(:) = 0;
hbMsg.Payload.system_status(:) = 0;  % GCS has no vehicle state

重要:フィールドには必ず msg.Payload.fieldname(:) 経由でアクセスしてください — msg.fieldname(:) は使用しないでください。メッセージ構造体には .Payload サブ構造体があり、すべてのプロトコルフィールドが含まれています。hbMsg.type(:) = ... と記述すると、type はトップレベルのフィールドではなく hbMsg.Payload.type にあるため失敗します。

重要:ペイロードフィールドへの代入では、必ず (:) インデックスを使用してください。 msg.Payload.type = 6((:) なし)と記述すると、ワイヤー型(uint8)が double に無言で置き換わり、MAVLink パケットが破損します。(:) を使用することで、元のデータ型が保持されます。

5. 定期的なハートビートを開始する

オートパイロットがすでにブロードキャストしているかどうかによって、ワークフローが 2 つあります。

ワークフロー A:自動検出(オートパイロットがすでにハートビートをブロードキャストしている場合)

PX4 SITL が mavlink メッセージをブロードキャストするように設定されている場合、オートパイロットのハートビートは自動的に届きます。まず listClients をポーリングし、検出されたクライアントにハートビートを返送します。

% Wait for autopilot to appear
timeout = 10;
tic;
discovered = false;
while toc < timeout
    clients = listClients(mavlink);
    if height(clients) > 1
        discovered = true;
        break;
    end
    pause(0.5);
end

if discovered
    % Use SystemID/ComponentID from listClients output
    remoteClient = clients(clients.SystemID ~= 255, :);  % exclude local GCS
    autopilot = mavlinkclient(mavlink, remoteClient.SystemID, remoteClient.ComponentID);
    hbTimer = timer('ExecutionMode', 'fixedRate', 'Period', 1, ...
        'TimerFcn', @(~,~) sendmsg(mavlink, hbMsg, autopilot));
    start(hbTimer);
end

ワークフロー B:手動で開始(オートパイロットがまだブロードキャストしていない場合)

オートパイロットが応答する前に GCS のハートビートを必要とする場合は、オートパイロットの待ち受けポートを指定して sendudpmsg を使用してください。PX4 SITL では、ビルドログで確認できます: [mavlink] ... on udp port <SITL_PORT> remote port 14550。不明な場合は、このポートをユーザーに確認してください。

sitlHost = "172.x.x.x";  % IP of SITL instance (use "ip a" in WSL to find it)
sitlPort = 18570;         % PX4 SITL listening port (from SITL build log "udp port" line)
hbTimer = timer('ExecutionMode', 'fixedRate', 'Period', 1, ...
    'TimerFcn', @(~,~) sendudpmsg(mavlink, hbMsg, sitlHost, sitlPort));
start(hbTimer);
  • sendudpmsg(io, msg, host, port) は特定の UDP エンドポイントに送信します — クライアントがまだ検出されていない場合に使用します
  • sendmsg(io, msg, client) は検出済みのクライアントに送信します — listClients にオートパイロットが表示された後に使用します
  • MAVLink の標準ハートビートレートは 1 Hz です
  • リモートポートに 14550 を使用しないでください — これは GCS のローカルポートです。 オートパイロットの待ち受けポートは別のポートです(例:PX4 SITL の -u ポート)。
6. クライアントの検出を確認する(ワークフロー B のみ)

sendudpmsg でハートビートを開始した後、自動操縦装置から応答があるまでポーリングします。

timeout = 10;
tic;
discovered = false;
while toc < timeout
    clients = listClients(mavlink);
    if height(clients) > 1  % local GCS client is always listed
        discovered = true;
        break;
    end
    pause(0.5);
end

if discovered
    disp(clients);
else
    error("Autopilot not discovered within %d seconds.", timeout);
end

listClients(mavlink) は組み込みのハートビートサブスクライバーを使用するため、mavlinksub を手動で実行する必要はありません。ワークフロー A では、ステップ 5 ですでに検出が完了しています。

7. 完了時にクリーンアップする
stop(hbTimer);
delete(hbTimer);
disconnect(mavlink);

孤立したタイマーが残らないよう、切断する前に必ずタイマーを停止して削除してください。

主な関数

関数シグネチャ目的
mavlinkdialect(xmlFile, version)ダイアレクト XML を解析し、メッセージ定義を作成します
mavlinkio(dialect, 'SystemID', N, 'ComponentID', N)I/O インターフェースを作成します
connect(io, "UDP", LocalPort=N)UDP トランスポートを開きます
mavlinkclient(io, systemID, componentID)リモートシステム用のクライアントハンドルを作成します
createmsg(dialect, msgType)メッセージ構造体を作成します — io ではなく、dialect を先に指定します
sendudpmsg(io, msg, remoteHost, remotePort)指定した UDP エンドポイントにメッセージを送信します
sendmsg(io, msg) または (io, msg, client)すべてのクライアント、または検出済みのクライアントに送信します
listClients(io)検出済みのすべてのクライアントを一覧表示します(組み込みサブスクライバーを使用)
listTopics(io)受信したすべてのメッセージトピックを一覧表示します
listConnections(io)アクティブなトランスポート接続を一覧表示します
mavlinksub(io, topic) または (io, client, topic)メッセージをサブスクライブします
latestmsgs(subscriber, count)サブスクライバーから最新のメッセージを読み取ります
disconnect(io)すべての接続を閉じます

パターン

PX4 SITL への UDP 接続(自動検出)

PX4 SITL は GCS ポート 14550 にブロードキャストするよう設定されています(ビルドログで remote port 14550 を確認してください)。自動操縦装置は listClients に自動的に表示されます。

% Setup
dialect = mavlinkdialect("common.xml", 2);
mavlink = mavlinkio(dialect, 'SystemID', 255, 'ComponentID', 1);
connect(mavlink, "UDP", LocalPort=14550);

% Build GCS heartbeat
hbMsg = createmsg(dialect, "HEARTBEAT");
hbMsg.Payload.type(:) = dialect.enum2num("MAV_TYPE", "MAV_TYPE_GCS");
hbMsg.Payload.autopilot(:) = dialect.enum2num("MAV_AUTOPILOT", "MAV_AUTOPILOT_INVALID");
hbMsg.Payload.base_mode(:) = 0;
hbMsg.Payload.custom_mode(:) = 0;
hbMsg.Payload.system_status(:) = 0;

% Wait for autopilot to be discovered
timeout = 10;
tic;
while toc < timeout
    clients = listClients(mavlink);
    if height(clients) > 1
        break;
    end
    pause(0.5);
end
disp(clients);

% Start GCS heartbeat back to the discovered autopilot
remoteClient = clients(clients.SystemID ~= 255, :);
autopilot = mavlinkclient(mavlink, remoteClient.SystemID, remoteClient.ComponentID);
hbTimer = timer('ExecutionMode', 'fixedRate', 'Period', 1, ...
    'TimerFcn', @(~,~) sendmsg(mavlink, hbMsg, autopilot));
start(hbTimer);

% ... perform operations ...

% Clean up
stop(hbTimer);
delete(hbTimer);
disconnect(mavlink);
特定のメッセージのサブスクライブ

接続確認以外に、特定のメッセージタイプを監視する必要がある場合:

% Subscribe to all messages of a type
sub = mavlinksub(mavlink, "GLOBAL_POSITION_INT");

% Subscribe to messages from a specific discovered client
remoteClient = clients(clients.SystemID ~= 255, :);
autopilot = mavlinkclient(mavlink, remoteClient.SystemID, remoteClient.ComponentID);
sub = mavlinksub(mavlink, autopilot, "ATTITUDE");

% Read the latest message(s)
msgs = latestmsgs(sub, 1);
if ~isempty(msgs)
    disp(msgs.Payload);
end
検出後のコマンド送信

listClients でクライアントが検出されたら、sendmsg でそのクライアントを指定できます。

% After discovery, send to specific client
clients = listClients(mavlink);
if height(clients) > 1
    remoteClient = clients(clients.SystemID ~= 255, :);
    autopilot = mavlinkclient(mavlink, remoteClient.SystemID, remoteClient.ComponentID);

    % Create command message
    cmdMsg = createmsg(dialect, "COMMAND_LONG");
    cmdMsg.Payload.target_system(:) = remoteClient.SystemID;
    cmdMsg.Payload.target_component(:) = remoteClient.ComponentID;
    cmdMsg.Payload.command(:) = 400;  % MAV_CMD_COMPONENT_ARM_DISARM
    cmdMsg.Payload.param1(:) = 1;     % arm

    sendmsg(mavlink, cmdMsg, autopilot);
end
エラー処理を備えたハートビートタイマー

堅牢なアプリケーションでは、タイマーのコールバックをラップして、エラーが気づかれないままになるのを防ぎます。

% Using sendudpmsg (pre-discovery, to known SITL endpoint)
hbTimer = timer('ExecutionMode', 'fixedRate', 'Period', 1, ...
    'ErrorFcn', @(~,evt) warning("Heartbeat error: %s", evt.Data.message), ...
    'TimerFcn', @(~,~) sendudpmsg(mavlink, hbMsg, sitlHost, sitlPort));
start(hbTimer);

注意点

  • ポート 14550 は GCS のローカルポートであり、オートパイロットのポートではありません。 sendudpmsg を使用する場合、リモートポートには 14550 ではなく、オートパイロットのリッスンポート(PX4 SITL の -u フラグ)を指定する必要があります。オートパイロットがすでに listClients で検出されている場合は、代わりに sendmsg(io, msg, client) を使用してください。自動的にルーティングされます。
  • 検出前のメッセージには sendmsg ではなく sendudpmsg を使用してください。 クライアントがまだ検出されていない状態で sendmsg(io, msg, client) を呼び出すと、エラーが発生します。ハートビートや検出前の通信には sendudpmsg(io, msg, host, port) を使用してください。
  • すべてのメッセージフィールドは .Payload の下にあります。 msg.Payload.type(:) = ... と記述し、msg.type(:) = ... とは記述しないでください。最上位のメッセージ構造体にはメタデータが含まれ、プロトコルフィールドは常に msg.Payload.fieldname にあります。
  • ペイロードフィールドへの代入には、必ず (:) を使用してください。 msg.Payload.field(:) = value とすると、ワイヤー上の型(uint8、uint16、int32 など)が保持されます。(:) を付けないと、MATLAB がフィールドを double に置き換えるため、ワイヤー上で MAVLink パケットが破損します。このバグはエラーも警告もなく、相互運用時にのみ発生します。
  • createmsg(dialect, msgName) — dialect は第 1 引数です。 createmsg に mavlinkio を渡さないでください。メッセージを送信するのは io オブジェクトであり、メッセージを作成するのは dialect です。
  • connect() は名前と値のペアのみを使用します。 connect(io, "UDP", LocalPort=14550) のように指定し、connect(io, "udpin", "0.0.0.0", 14550) とは指定しません。
  • 接続確認のために mavlinksub(mavlink, "HEARTBEAT") を作成しないでください。 mavlinkio には listClients() を更新するハートビートサブスクライバーが組み込まれています。手動で HEARTBEAT サブスクライバーを作成する必要はありません。mavlinksub は、ハートビート以外のメッセージタイプ(例:"GLOBAL_POSITION_INT"、"ATTITUDE")にのみ使用してください。
  • listClients には常にローカルの GCS クライアントが含まれます。 リモートシステムが検出されたことを確認するには、height(clients) > 0 ではなく height(clients) > 1 を確認してください。
  • mavlinkclient(io, sysID, compID) はコンストラクターであり、一覧表示関数ではありません。 ハンドルを作成しますが、クライアントの存在は確認しません。検出済みクライアントを確認するには、listClients(io) を使用してください。
  • サブスクライバーの読み取りメソッドは latestmsgs(sub, count) です。 read()、receive()、next() ではありません。
  • タイマーは必ず停止して削除してください。 孤立したタイマーは disconnect の後も実行され続け、MATLAB の不安定化を引き起こす場合があります。stop(t); delete(t) を使用するか、onCleanup でラップしてください。

規約

  • GCS の ID:SystemID 255、ComponentID 1
  • GCS のローカルポート(GCS がバインドするポート):14550
  • PX4 SITL のリッスンポート:変動します(SITL のビルドログで udp port <N> を確認してください。例:18570)
  • ArduPilot SITL の GCS 向けデフォルト送信ポート:14550
  • 一般的なオートパイロットの ID:SystemID 1、ComponentID 1
  • ハートビートのレート:1 Hz(MAVLink 標準)
  • ArduPilot 固有の拡張機能が必要でない限り、"common.xml" dialect を使用してください

Copyright 2026 The MathWorks, Inc.

コメント