matlab-connect-mavlink について
MATLABからUDP経由でPX4またはArduPilotのフライトコントローラーに接続するスキルです。地上局やSITLでの利用を想定し、MAVLink設定とハートビートの順序を示して接続時の誤りを防ぎます。
主な機能
- 01UDPによるMAVLink通信の確立
- 02MAVLink方言とインターフェースの設定
- 03地上局ハートビートの送信
- 04オートパイロットクライアントの検出と接続
- 05MAVLinkメッセージの購読
活用シーン
- 01MATLABとPX4 SITLの接続
- 02MATLABの地上局としての設定
- 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.