如何用MAVLink/MAVProxy检测无人机解锁状态并启停Python脚本?
无人机解锁状态检测问题及解决方案
你遇到的核心问题是解锁状态检测不稳定,明明无人机处于解锁状态,代码却误判为上锁。结合你提供的两段代码,先分析问题根源,再给出修复后的实现方案:
原代码问题分析
CODE 1 问题
- 循环内重复调用
master.wait_heartbeat():该函数会阻塞直到收到下一个心跳包,再加上time.sleep(2),导致状态检测间隔过长,且内部状态缓存无法及时更新。 - 未持续接收MAVLink消息:
master.motors_armed()依赖内部缓存的状态数据,若不主动接收消息,缓存会过期,导致判断错误。
CODE 2 问题
- 缩进错误:部分代码缩进层级混乱,会导致逻辑执行顺序出错(比如
armed = False的位置会覆盖后续判断结果)。 - 状态判断不严谨:位与操作后未显式判断结果是否非零,虽然Python中非零值会被视为True,但显式判断能避免潜在的逻辑歧义。
- 仅监听HEARTBEAT消息:单一消息源可能错过状态更新,导致判断不准。
关键注意事项(针对MAVProxy场景)
不要让脚本直接连接无人机串口(/dev/ttyACM0),因为MAVProxy已经占用了该串口,同时访问会导致消息冲突。正确做法是:
- 启动MAVProxy时指定输出端口:
mavproxy.py --master /dev/ttyACM0 --baud 57600 --out udp:127.0.0.1:14550
- 脚本连接MAVProxy的UDP端口,而非直接连串口。
修复后的代码实现
方案一:使用封装好的motors_armed()方法(推荐)
该方法由pymavutil封装,会自动处理MAVLink消息更新状态,代码更简洁可靠:
from pymavlink import mavutil import time # 若需要启停外部脚本,导入subprocess # import subprocess # 连接MAVProxy的UDP端口,而非直接连串口 master = mavutil.mavlink_connection('udp:127.0.0.1:14550') # 等待首次心跳,确认连接成功 master.wait_heartbeat() print(f"已连接到系统 {master.target_system},组件 {master.target_component}") # 记录当前解锁状态,避免重复执行启停逻辑 current_armed = None # 用于保存外部脚本进程(如果需要) # script_process = None while True: # 非阻塞接收所有MAVLink消息,更新内部状态缓存 msg = master.recv_match(blocking=False) if msg: pass # 无需处理具体消息,master会自动更新状态 # 获取当前解锁状态 is_armed = master.motors_armed() # 仅在状态变化时执行操作 if is_armed != current_armed: current_armed = is_armed if is_armed: print("无人机已解锁,启动目标脚本") # 启动外部脚本示例 # script_process = subprocess.Popen(["python3", "your_target_script.py"]) else: print("无人机已上锁,停止目标脚本") # 停止外部脚本示例 # if script_process: # script_process.terminate() # script_process.wait() # script_process = None time.sleep(0.1) # 缩短检测间隔,提升响应速度
方案二:直接解析MAVLink消息(底层实现)
如果需要更精细的控制,可以直接监听HEARTBEAT消息并解析状态:
from pymavlink import mavutil import time # import subprocess master = mavutil.mavlink_connection('udp:127.0.0.1:14550') master.wait_heartbeat() print(f"已连接到系统 {master.target_system},组件 {master.target_component}") current_armed = None # script_process = None while True: # 阻塞接收HEARTBEAT消息,确保实时获取状态 msg = master.recv_match(type='HEARTBEAT', blocking=True) if not msg: continue # 解析解锁状态:位与操作后判断是否非零 is_armed = (msg.base_mode & mavutil.mavlink.MAV_MODE_FLAG_SAFETY_ARMED) != 0 if is_armed != current_armed: current_armed = is_armed if is_armed: print("无人机已解锁,启动目标脚本") # script_process = subprocess.Popen(["python3", "your_target_script.py"]) else: print("无人机已上锁,停止目标脚本") # if script_process: # script_process.terminate() # script_process.wait() # script_process = None
内容的提问来源于stack exchange,提问作者SAFIYA ATEEQ
相关产品推荐
相关产品推荐

