Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

w4_request_message.py

W4 實驗:REQUEST_MESSAGE(指令 512)只要一次,不會持續推送。

檔案位置:scripts/w4_request_message.py

"""W4 實驗:REQUEST_MESSAGE(指令 512)只要一次,不會持續推送。

先把 ATTITUDE 停掉,再各送 REQUEST_MESSAGE 一次,觀察 COMMAND_ACK 與收到的訊息筆數;
另外要一次平常不會主動送的 AUTOPILOT_VERSION(固件版本)。
先執行 scripts/sitl.sh;用法:vendor/venv/bin/python -u -I scripts/w4_request_message.py
"""
import time

from pymavlink import mavutil

mav = mavutil.mavlink  # MAVLink 的常數與訊息編號都在這個模組裡
WINDOW = 3.0  # 每次觀察的秒數

# m:MAVLink 連線;m.mav.*_send 送出訊息,m.recv_match 接收訊息
m = mavutil.mavlink_connection("tcp:127.0.0.1:5762")
m.wait_heartbeat(timeout=10)


def command(cmd, *params):
    """送 COMMAND_LONG;params 最多 7 個,不足補 0。"""
    m.mav.command_long_send(m.target_system, m.target_component, cmd, 0,
                            *(list(params) + [0] * (7 - len(params))))


def message_id(name):
    return getattr(mav, f"MAVLINK_MSG_ID_{name}")  # 訊息編號


def observe(name):
    """觀察 WINDOW 秒,回傳 (COMMAND_ACK 的結果或 None, 收到的 name 訊息列表, 第一筆延遲秒數)。"""
    acks, got, first = [], [], None
    start = time.time()
    while time.time() - start < WINDOW:
        msg = m.recv_match(type=["COMMAND_ACK", name], blocking=True, timeout=0.5)
        if msg is None:
            continue
        if msg.get_type() == "COMMAND_ACK":
            acks.append(msg)
        else:
            got.append(msg)
            first = first if first is not None else time.time() - start
    return acks, got, first


def request_once(name):
    command(mav.MAV_CMD_REQUEST_MESSAGE, message_id(name))
    return observe(name)


# 停掉所有持續推送,讓「收到幾筆」只反映 REQUEST_MESSAGE
m.mav.request_data_stream_send(m.target_system, m.target_component, mav.MAV_DATA_STREAM_ALL, 0, 0)
command(mav.MAV_CMD_SET_MESSAGE_INTERVAL, message_id("ATTITUDE"), -1)  # -1 表示停止
time.sleep(1)
while m.recv_match(blocking=False):  # 丟掉緩衝區裡剩下的
    pass

print("== 沒要求時:觀察 3 秒 ==")
_, got, _ = observe("ATTITUDE")
print(f"ATTITUDE 收到 {len(got)} 筆")

print("\n== REQUEST_MESSAGE ATTITUDE 一次 ==")
acks, got, first = request_once("ATTITUDE")
print(f"COMMAND_ACK:{[(a.command, a.result) for a in acks]}(result 0 = ACCEPTED)")
print(f"ATTITUDE 收到 {len(got)} 筆,第一筆在 {first:.3f} 秒後" if got else "ATTITUDE 收到 0 筆")

print("\n== 再要一次 ==")
acks, got, _ = request_once("ATTITUDE")
print(f"COMMAND_ACK {len(acks)} 個;ATTITUDE 收到 {len(got)} 筆")

print("\n== REQUEST_MESSAGE AUTOPILOT_VERSION(平常不會主動送)==")
acks, got, _ = request_once("AUTOPILOT_VERSION")
print(f"COMMAND_ACK:{[(a.command, a.result) for a in acks]}")
if got:
    v = got[0].flight_sw_version  # v:固件版本,4 個位元組,依序是 major、minor、patch、type
    print(f"固件版本 {v >> 24}.{(v >> 16) & 0xFF}.{(v >> 8) & 0xFF}(type 位元組 {v & 0xFF})")
else:
    print("沒收到 AUTOPILOT_VERSION")