|
|
9 months ago | |
|---|---|---|
| .. | ||
| __pycache__ | 9 months ago | |
| 1.md | 9 months ago | |
| README.md | 9 months ago | |
| __init__.py | 9 months ago | |
| communication_manager.py | 9 months ago | |
| database_handler.py | 9 months ago | |
| drone_connection_manager.py | 9 months ago | |
| mavlink_handler.py | 9 months ago | |
| message_queue.py | 9 months ago | |
README.md
我会帮你实现通信模块。首先,我们需要创建通信模块的目录结构和相关文件。让我们先看看是否已经有相关的目录:
Ran tool
我们需要创建一个新的通信模块。我会创建以下文件:
communication/目录mavlink_handler.py- MAVLink通信处理database_handler.py- 数据库操作message_queue.py- 消息队列管理__init__.py- 模块初始化文件
我已经完成了通信模块的实现,这个模块包含以下主要组件:
-
MavlinkHandler- MAVLink通信处理器:- 负责建立和维护MAVLink连接
- 处理MAVLink消息的发送和接收
- 支持消息回调注册
- 使用线程进行异步消息处理
-
DatabaseHandler- 数据库处理器:- 负责MySQL数据库的连接和管理
- 提供数据库表的创建和管理
- 支持MAVLink消息的存储和查询
- 管理无人机状态信息的存储和更新
-
MessageQueue- 消息队列:- 提供线程安全的消息队列实现
- 支持消息的异步处理
- 提供回调机制
- 包含消息时间戳
-
CommunicationManager- 通信管理器:- 协调MAVLink和数据库组件
- 处理消息的路由和分发
- 管理无人机状态更新
- 提供统一的接口访问通信功能
要使用这个通信模块,你需要:
- 安装必要的依赖:
pip install pymavlink mysql-connector-python
- 配置数据库连接:
db_config = {
'host': 'localhost',
'user': 'your_username',
'password': 'your_password',
'database': 'drone_control'
}
- 初始化通信管理器:
from command_center.communication import CommunicationManager
# 创建通信管理器实例
comm_manager = CommunicationManager(
mavlink_connection="udp:127.0.0.1:14550", # MAVLink连接字符串
db_config=db_config
)
# 启动通信管理器
if comm_manager.start():
print("通信管理器启动成功")
# 获取无人机状态
drone_status = comm_manager.get_drone_status("drone_1")
print(f"无人机状态: {drone_status}")
# 获取消息队列
message_queue = comm_manager.get_message_queue()
# 注册消息回调
def on_message():
msg = message_queue.get()
if msg:
print(f"收到消息: {msg}")
message_queue.register_callback(on_message)
这个通信模块提供了完整的MAVLink通信和数据库集成功能,可以:
- 接收和处理MAVLink消息
- 将消息存储到MySQL数据库
- 实时更新无人机状态
- 提供消息队列和回调机制
- 支持多线程异步处理
你可以根据需要扩展这个模块,比如:
- 添加更多的MAVLink消息处理
- 实现更复杂的数据库查询
- 添加消息过滤和转换功能
- 实现消息重传机制
- 添加错误处理和恢复机制
需要我详细解释某个部分或者添加其他功能吗?
我来详细描述一下当前通信模块的工作流程:
-
初始化阶段:
- 创建
CommunicationManager实例,传入 MAVLink 连接字符串和数据库配置 - 初始化三个核心组件:
MavlinkHandler:负责 MAVLink 通信DatabaseHandler:负责数据库操作MessageQueue:负责消息队列管理
- 创建
-
启动阶段(调用
start()方法):- 首先连接数据库
- 创建必要的数据库表(
mavlink_messages和drone_status) - 建立 MAVLink 连接
- 注册三个关键消息的回调函数:
HEARTBEAT:心跳消息GLOBAL_POSITION_INT:位置信息SYS_STATUS:系统状态
- 启动 MAVLink 消息接收线程
- 启动消息处理线程
-
消息接收流程:
MAVLink设备 -> MavlinkHandler -> MessageQueue -> CommunicationManager -> DatabaseHandlerMavlinkHandler通过_receive_loop持续监听 MAVLink 消息- 收到消息后,调用
_handle_message处理 - 消息被放入
MessageQueue队列 - 同时触发注册的回调函数
-
消息处理流程:
MessageQueue -> CommunicationManager._process_messages -> 数据库存储/状态更新CommunicationManager的_process_messages线程从队列获取消息- 对消息进行分类处理:
- 保存到数据库的
mavlink_messages表 - 根据消息类型更新
drone_status表 - 位置消息:更新经纬度和高度
- 状态消息:更新电池电量和系统状态
- 保存到数据库的
-
数据库操作:
- 所有 MAVLink 消息都被保存到
mavlink_messages表 - 无人机状态信息被保存到
drone_status表 - 支持按时间范围和消息类型查询历史消息
- 支持获取最新的无人机状态
- 所有 MAVLink 消息都被保存到
-
消息回调机制:
- 支持注册消息回调函数
- 当收到特定类型的消息时,自动触发对应的回调
- 回调函数可以处理消息并执行自定义逻辑
-
错误处理:
- 连接失败时的重试机制
- 消息处理异常的错误捕获
- 数据库操作的异常处理和回滚
-
停止流程(调用
stop()方法):- 停止消息处理线程
- 停止 MAVLink 连接
- 断开数据库连接
- 清理资源
这个通信模块的设计特点:
- 异步处理:使用多线程实现消息的异步接收和处理
- 数据持久化:所有消息都被保存到数据库,便于后续分析
- 状态管理:实时维护无人机的最新状态
- 可扩展性:通过回调机制支持自定义消息处理
- 错误恢复:包含完整的错误处理机制
使用示例:
# 初始化
comm_manager = CommunicationManager(
mavlink_connection="udp:127.0.0.1:14550",
db_config={
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'drone_control'
}
)
# 启动通信
comm_manager.start()
# 获取无人机状态
drone_status = comm_manager.get_drone_status("drone_1")
# 注册消息回调
def on_message():
msg = comm_manager.get_message_queue().get()
if msg:
print(f"收到消息: {msg}")
comm_manager.get_message_queue().register_callback(on_message)
这个通信模块提供了一个完整的解决方案,可以:
- 实时接收和处理 MAVLink 消息
- 将消息持久化到数据库
- 维护无人机的最新状态
- 支持自定义消息处理
- 提供错误恢复机制
让我详细解释一下与无人机建立连接的过程。在当前的实现中,连接建立主要发生在 MavlinkHandler 类中,通过 connect() 方法实现。让我们看看具体的连接流程:
- 连接初始化:
# 在 MavlinkHandler 类中
def __init__(self, connection_string: str = "udp:127.0.0.1:14550"):
self.connection_string = connection_string
self.connection = None
# ... 其他初始化代码
- 建立连接:
def connect(self) -> bool:
"""建立MAVLink连接"""
try:
# 创建MAVLink连接
self.connection = mavutil.mavlink_connection(self.connection_string)
# 等待心跳包,确认连接成功
self.connection.wait_heartbeat()
print(f"MAVLink连接成功: {self.connection_string}")
return True
except Exception as e:
print(f"MAVLink连接失败: {str(e)}")
return False
连接建立的关键点:
-
连接字符串格式:
- 支持多种连接方式:
- UDP:
"udp:IP:PORT"(例如:"udp:127.0.0.1:14550") - TCP:
"tcp:IP:PORT" - 串口:
"serial:PORT,BAUDRATE"(例如:"serial:/dev/ttyUSB0,57600") - 蓝牙:
"bluetooth:ADDRESS"
- UDP:
- 支持多种连接方式:
-
连接验证:
- 通过
wait_heartbeat()等待无人机发送心跳包 - 心跳包是MAVLink协议中的基础消息,用于确认连接状态
- 如果在一定时间内没有收到心跳包,连接会失败
- 通过
-
连接状态管理:
- 连接成功后,
connection对象会被保存 - 用于后续的消息发送和接收
- 连接失败时会返回
False,上层可以处理错误
- 连接成功后,
要使用这个连接功能,你需要:
-
确定连接方式:
- 如果无人机使用地面站软件(如QGroundControl),通常使用UDP连接
- 如果直接连接飞控,可能需要使用串口连接
- 连接字符串需要根据实际情况配置
-
配置连接参数:
# UDP连接示例
mavlink_connection = "udp:127.0.0.1:14550" # 本地UDP连接
# 串口连接示例
mavlink_connection = "serial:/dev/ttyUSB0,57600" # Linux系统
# 或
mavlink_connection = "serial:COM3,57600" # Windows系统
- 建立连接:
# 创建通信管理器
comm_manager = CommunicationManager(
mavlink_connection="udp:127.0.0.1:14550", # 根据实际情况修改
db_config={
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'drone_control'
}
)
# 启动连接
if comm_manager.start():
print("连接成功")
else:
print("连接失败,请检查连接参数")
-
连接后的操作:
- 发送命令:使用
send_message方法 - 接收消息:通过消息队列或回调函数
- 监控状态:通过数据库查询
- 发送命令:使用
-
错误处理:
- 连接失败时会有错误提示
- 可以设置重试机制
- 可以添加连接状态监控
建议的连接使用流程:
- 准备阶段:
def setup_connection():
# 配置连接参数
connection_config = {
'mavlink': {
'type': 'udp', # 或 'serial', 'tcp' 等
'address': '127.0.0.1',
'port': 14550,
'baudrate': 57600 # 串口连接时需要
},
'database': {
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'drone_control'
}
}
# 构建连接字符串
if connection_config['mavlink']['type'] == 'udp':
connection_string = f"udp:{connection_config['mavlink']['address']}:{connection_config['mavlink']['port']}"
elif connection_config['mavlink']['type'] == 'serial':
connection_string = f"serial:{connection_config['mavlink']['address']},{connection_config['mavlink']['baudrate']}"
return connection_string, connection_config['database']
- 连接建立:
def establish_connection():
connection_string, db_config = setup_connection()
# 创建通信管理器
comm_manager = CommunicationManager(connection_string, db_config)
# 尝试连接
max_retries = 3
retry_count = 0
while retry_count < max_retries:
if comm_manager.start():
print("连接成功")
return comm_manager
else:
retry_count += 1
print(f"连接失败,第{retry_count}次重试...")
time.sleep(2) # 等待2秒后重试
print("连接失败,达到最大重试次数")
return None
- 连接监控:
def monitor_connection(comm_manager):
def heartbeat_callback(msg):
print(f"收到心跳包: {msg.to_dict()}")
# 注册心跳回调
comm_manager.mavlink.register_callback('HEARTBEAT', heartbeat_callback)
# 定期检查连接状态
while True:
if not comm_manager.mavlink.connection:
print("连接断开,尝试重连...")
if not comm_manager.mavlink.connect():
print("重连失败")
break
time.sleep(1)
这个连接模块提供了灵活的连接方式,可以根据不同的无人机和飞控配置选择合适的连接参数。同时,它也包含了错误处理和重试机制,确保连接的可靠性。
需要注意的是:
- 确保无人机和地面站软件(如QGroundControl)使用相同的端口
- 串口连接时需要正确的端口号和波特率
- 防火墙设置可能会影响UDP/TCP连接
- 建议在连接前先测试基本的MAVLink通信
你可以根据实际需求调整连接参数和错误处理策略。需要我详细解释某个部分吗?
MAVLink 消息的格式是标准化的二进制协议格式。让我详细解释一下 MAVLink 消息的格式和结构:
- MAVLink 消息基本结构:
+-------------------+------------------+------------------+------------------+------------------+
| 起始标记 (0xFE) | 载荷长度 (1字节) | 序列号 (1字节) | 系统ID (1字节) | 组件ID (1字节) |
+-------------------+------------------+------------------+------------------+------------------+
| 消息ID (1字节) | 载荷数据 (N字节) | CRC校验 (2字节) |
+-------------------+------------------+------------------+
-
消息字段说明:
- 起始标记 (0xFE):标识消息开始
- 载荷长度:消息载荷的长度(不包括头部和CRC)
- 序列号:用于检测消息丢失
- 系统ID:发送系统的ID(如无人机ID)
- 组件ID:发送组件的ID(如飞控、相机等)
- 消息ID:标识消息类型
- 载荷数据:实际的消息内容
- CRC校验:用于验证消息完整性
-
常见消息类型:
# 心跳消息 (HEARTBEAT)
{
'type': 'HEARTBEAT',
'system_status': 0, # 系统状态
'base_mode': 0, # 基础模式
'custom_mode': 0, # 自定义模式
'mavlink_version': 3 # MAVLink版本
}
# 位置消息 (GLOBAL_POSITION_INT)
{
'type': 'GLOBAL_POSITION_INT',
'time_boot_ms': 0, # 启动时间
'lat': 0, # 纬度 (度 * 1e7)
'lon': 0, # 经度 (度 * 1e7)
'alt': 0, # 高度 (毫米)
'relative_alt': 0, # 相对高度 (毫米)
'vx': 0, # X方向速度 (厘米/秒)
'vy': 0, # Y方向速度 (厘米/秒)
'vz': 0, # Z方向速度 (厘米/秒)
'hdg': 0 # 航向 (度 * 100)
}
# 系统状态消息 (SYS_STATUS)
{
'type': 'SYS_STATUS',
'onboard_control_sensors_present': 0, # 存在的传感器
'onboard_control_sensors_enabled': 0, # 启用的传感器
'onboard_control_sensors_health': 0, # 传感器健康状态
'load': 0, # 处理器负载
'voltage_battery': 0, # 电池电压
'current_battery': 0, # 电池电流
'battery_remaining': 0, # 剩余电量百分比
'drop_rate_comm': 0, # 通信丢包率
'errors_comm': 0, # 通信错误
'errors_count1': 0, # 错误计数1
'errors_count2': 0, # 错误计数2
'errors_count3': 0, # 错误计数3
'errors_count4': 0 # 错误计数4
}
- 消息处理示例:
# 在 MavlinkHandler 类中处理消息
def _handle_message(self, msg):
"""处理接收到的MAVLink消息"""
msg_type = msg.get_type()
msg_data = msg.to_dict()
# 根据消息类型处理
if msg_type == 'HEARTBEAT':
self._handle_heartbeat(msg_data)
elif msg_type == 'GLOBAL_POSITION_INT':
self._handle_position(msg_data)
elif msg_type == 'SYS_STATUS':
self._handle_system_status(msg_data)
# 将消息放入队列
self.message_queue.put({
'type': msg_type,
'data': msg_data,
'timestamp': datetime.now()
})
- 消息发送示例:
# 发送命令消息
def send_command(self, command_type: str, **kwargs):
"""发送MAVLink命令"""
try:
# 构建命令消息
msg = self.connection.mav.command_long_send(
self.connection.target_system, # 目标系统ID
self.connection.target_component, # 目标组件ID
command_type, # 命令类型
0, # 确认
*kwargs.values() # 命令参数
)
return True
except Exception as e:
print(f"发送命令失败: {str(e)}")
return False
- 消息转换和存储:
# 在 DatabaseHandler 中存储消息
def save_mavlink_message(self, msg_type: str, msg_data: Dict) -> bool:
"""保存MAVLink消息到数据库"""
query = """
INSERT INTO mavlink_messages
(message_type, message_data, timestamp)
VALUES (%s, %s, %s)
"""
params = (
msg_type,
json.dumps(msg_data), # 将消息数据转换为JSON格式存储
datetime.now()
)
return self.execute_update(query, params)
- 消息查询示例:
# 查询特定类型的消息
def get_messages_by_type(self, msg_type: str,
start_time: Optional[datetime] = None,
end_time: Optional[datetime] = None) -> List[Dict]:
"""获取特定类型的MAVLink消息"""
query = """
SELECT * FROM mavlink_messages
WHERE message_type = %s
"""
params = [msg_type]
if start_time:
query += " AND timestamp >= %s"
params.append(start_time)
if end_time:
query += " AND timestamp <= %s"
params.append(end_time)
query += " ORDER BY timestamp DESC"
return self.execute_query(query, tuple(params))
MAVLink 消息的特点:
- 二进制格式:高效的数据传输
- 固定头部:便于消息识别和解析
- 可变载荷:支持不同类型的数据
- CRC校验:确保数据完整性
- 系统/组件ID:支持多设备通信
- 序列号:支持消息顺序和丢失检测
在实际使用中,我们不需要直接处理二进制格式,因为 pymavlink 库已经帮我们处理了消息的编码和解码。我们只需要关注消息的内容和类型即可。
需要我详细解释某个具体的消息类型或处理过程吗?