# ULogPilot **Repository Path**: TuringQin/ulog-pilot ## Basic Information - **Project Name**: ULogPilot - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-26 - **Last Updated**: 2026-01-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ULogPilot - PX4 ULog 日志分析助手 基于 MCP (Model Context Protocol) 的 PX4 飞控日志分析服务器,新手友好! ## 🚀 快速开始(新手必读) ### 第一步:安装依赖 ```bash # 激活虚拟环境(如果还没有) source .venv/bin/activate # 安装依赖包 pip install -r requirements.txt ``` **你应该看到什么结果:** ``` Successfully installed fastmcp-xxx pyulog-xxx numpy-xxx matplotlib-xxx ``` ### 第二步:准备测试用 ULog 文件 从 PX4 飞机下载一个 `.ulg` 日志文件,放到项目目录: ```bash # 示例:将日志文件放到项目根目录 /path/to/your/log.ulg # 复制到项目目录 ``` **没有日志?** - 可以从 PX4 官方下载示例日志:https://docs.px4.io/main/en/log/ulog_file_format.html - 或者连接你的 PX4 飞机,用 QGroundControl 下载飞行日志 ### 第三步:启动 MCP Server ```bash python -m ulogpilot.server ``` **你应该看到什么结果:** ``` (没有输出是正常的!MCP 使用 stdio 模式,日志会输出到 stderr) ``` ### 第四步:使用 MCP Inspector 测试工具 在新的终端窗口中: ```bash # 安装 MCP Inspector(如果还没有) npm install -g @modelcontextprotocol/inspector # 启动 Inspector 连接到你的 server mcp-inspector python -m ulogpilot.server ``` **你应该看到什么结果:** ``` 浏览器会自动打开,显示 MCP Inspector 界面 你可以在左侧看到所有可用的 tools ``` ## 📚 工具使用指南 ### 1. `open_ulog` - 打开日志文件 在 Inspector 中调用: ```json { "name": "open_ulog", "arguments": { "path": "/home/qinzihang/Code/ulog-pilot/log.ulg" } } ``` **你应该看到什么结果:** ```json { "session_id": "abc123...", "path": "/home/qinzihang/Code/ulog-pilot/log.ulg", "topics_count": 45 } ``` **保存这个 `session_id`,后面的工具都要用它!** --- ### 2. `flight_summary` - 飞行概览(新手必用!) 一键获取飞行全貌: ```json { "name": "flight_summary", "arguments": { "session_id": "abc123..." } } ``` **你应该看到什么结果:** ```json { "path": "/home/qinzihang/Code/ulog-pilot/log.ulg", "duration_s": 342.5, "arming_state_changes": [ [0.0, 1], // (时间秒, 状态值) [340.2, 0] // 解锁、上锁 ], "nav_state_changes": [ [0.0, 0], [10.5, 4], [320.1, 0] ], "max_altitude_m": 45.6, "max_speed_mps": 15.3, "battery": { "min_voltage_v": 11.2, "max_current_a": 18.5, "min_remaining": 0.15 }, "gps": { "best_fix_type": 3, // 3=3D fix "best_eph_m": 0.8, "best_epv_m": 1.2 }, "ekf": { "topic": "estimator_status", "pos_horiz_reset_counter": 0, "pos_vert_reset_counter": 1, "vel_horiz_reset_counter": 0, "any_filter_fault_flags_nonzero": false } } ``` **解读要点:** - `duration_s`: 飞行时长(秒) - `max_altitude_m`: 最大高度 - `battery.min_remaining`: 电池剩余最低百分比(0.15 = 15%) - `gps.best_eph_m`: GPS 水平精度(越小越好,<2m 为优) - `ekf.pos_vert_reset_counter`: EKF 垂直位置重置次数(0 为最佳) --- ### 3. `event_timeline` - 自动事件时间线 ```json { "name": "event_timeline", "arguments": { "session_id": "abc123...", "max_events": 50 } } ``` **你应该看到什么结果:** ```json { "events": [ { "t_s": 0.0, "kind": "arming_state", "detail": {"arming_state": 1} }, { "t_s": 0.0, "kind": "mode_change", "detail": {"nav_state": 0} }, { "t_s": 10.5, "kind": "mode_change", "detail": {"nav_state": 4} }, { "t_s": 120.3, "kind": "ekf_reset", "detail": {"counter": "pos_vert_reset_counter", "value": 1} }, { "t_s": 320.1, "kind": "mode_change", "detail": {"nav_state": 0} } ], "count": 5 } ``` **事件类型说明:** - `arming_state`: 解锁/上锁 - `mode_change`: 飞行模式切换 - `failsafe`: 保险触发 - `ekf_reset`: EKF 重置(注意!) - `setpoint_step`: 设定点跳跃 --- ### 4. `list_topics` - 列出所有可用的 Topic ```json { "name": "list_topics", "arguments": { "session_id": "abc123...", "limit": 20 } } ``` **你应该看到什么结果:** ```json { "total": 45, "returned": 20, "topics": [ {"topic": "vehicle_status", "multi_instance": 0, "n": 3425}, {"topic": "battery_status", "multi_instance": 0, "n": 3425}, {"topic": "vehicle_local_position", "multi_instance": 0, "n": 3400}, ... ] } ``` --- ### 5. `describe_topic` - 查看 Topic 详情 ```json { "name": "describe_topic", "arguments": { "session_id": "abc123...", "topic": "vehicle_local_position", "multi_instance": 0 } } ``` **你应该看到什么结果:** ```json { "topic": "vehicle_local_position", "multi_instance": 0, "fields": ["timestamp", "x", "y", "z", "vx", "vy", "vz", "ax", "ay", "az"], "samples": 3400, "time_range_s": [0.0, 342.5], "approx_rate_hz": 9.9 } ``` --- ### 6. `query` - 查询时序数据 ```json { "name": "query", "arguments": { "session_id": "abc123...", "topic": "vehicle_local_position", "fields": ["x", "y", "z", "vx"], "t_start_s": 0, "t_end_s": 100, "max_points": 1000 } } ``` **你应该看到什么结果:** ```json { "topic": "vehicle_local_position", "t_s": [0.0, 0.1, 0.2, ..., 100.0], "data": { "x": [0.0, 0.05, 0.1, ...], "y": [0.0, 0.0, 0.01, ...], "z": [-0.5, -0.51, -0.52, ...], "vx": [0.0, 0.2, 0.5, ...] }, "samples": 1000 } ``` --- ### 7. `downsample` - 降采样(快速浏览) ```json { "name": "downsample", "arguments": { "session_id": "abc123...", "topic": "battery_status", "fields": ["voltage_v", "current_a"], "target_points": 500 } } ``` --- ### 8. `plot_timeseries` - 绘制时序图 ```json { "name": "plot_timeseries", "arguments": { "session_id": "abc123...", "topic": "vehicle_local_position", "fields": ["z"], "t_start_s": 0, "t_end_s": 100, "target_points": 1000 } } ``` **你应该看到什么结果:** ```json { "path": "/tmp/ulogpilot_plots/abc123...png", "topic": "vehicle_local_position", "fields": ["z"], "points": 1000 } ``` 然后你可以打开这个图片文件查看图表: ```bash # 在 Inspector 中复制 path 的值,然后在终端 eog /tmp/ulogpilot_plots/abc123...png # 或者 xdg-open /tmp/ulogpilot_plots/abc123...png ``` --- ### 9. `close_session` - 关闭会话 ```json { "name": "close_session", "arguments": { "session_id": "abc123..." } } ``` --- ## 🔍 新手常见问题诊断 ### 问题 1:飞行高度不稳定 / 抖动 1. 先运行 `flight_summary`,看 `ekf.pos_vert_reset_counter` 是否 > 0 2. 运行 `plot_timeseries` 绘制 `vehicle_local_position.z` 3. 运行 `plot_timeseries` 绘制 `estimator_status` 的相关字段 ### 问题 2:GPS 信号差 1. 运行 `flight_summary`,看 `gps.best_eph_m`(应该 < 2m) 2. 运行 `plot_timeseries` 绘制 `vehicle_gps_position.eph` 和 `epv` 3. 查看 `event_timeline` 中是否有 `failsafe` 事件 ### 问题 3:电池掉电过快 1. 运行 `flight_summary`,看 `battery.max_current_a` 2. 运行 `plot_timeseries` 绘制 `battery_status.voltage_v` 和 `current_a` ### 问题 4:降落不准 1. 运行 `event_timeline`,看降落时的 `mode_change` 和 `ekf_reset` 2. 运行 `plot_timeseries` 绘制 `vehicle_local_position.x` 和 `y`(降落阶段) --- ## 📂 项目结构 ``` ulog-pilot/ ├── ulogpilot/ │ ├── __init__.py # 包初始化 │ └── server.py # MCP Server 核心代码 ├── requirements.txt # 依赖包列表 ├── README.md # 本文件 └── .gitignore # Git 忽略规则 ``` --- --- ### 9. `close_session` - 关闭会话 ```json { "name": "close_session", "arguments": { "session_id": "abc123..." } } ``` --- ## 🎯 第二阶段:智能诊断向导(已实现!) ### `list_available_diagnostic_symptoms` - 列出可诊断的症状 ```json { "name": "list_available_diagnostic_symptoms", "arguments": {} } ``` **你应该看到什么结果:** ```json { "available_symptoms": { "drift": "位置漂移检测", "jitter": "传感器/位置抖动检测", "altitude_fluctuation": "高度波动检测", "landing_inaccuracy": "降落精度检测", "gps_poor": "GPS 信号质量检测", "battery_issue": "电池状态检测", "ekf_fault": "EKF 故障检测" }, "total": 7 } ``` --- ### `diagnose(symptom)` - 智能诊断 ⭐新手必用! 新手最友好的工具!只需描述问题,自动分析并给出建议。 #### 示例 1: 诊断高度波动 ```json { "name": "diagnose", "arguments": { "session_id": "abc123...", "symptom": "altitude_fluctuation" } } ``` **你应该看到什么结果:** ```json { "has_fluctuation": true, "max_fluctuation_m": 45.6, "fluctuation_std_m": 0.32, "ekf_resets": 1, "evidence": [ "⚠️ EKF 垂直位置重置 1 次", "⚠️ 高度标准差 0.32m,可能存在异常波动" ], "severity": "high", "formatted": "⚠️ 检测到高度波动:标准差 0.32m,EKF重置 1 次", "recommendations": [ "1. 检查气压计安装位置(远离螺旋桨气流)", "2. 降低飞行速度,减少高度变化率", "3. 检查是否有遮挡影响气压计", "4. 考虑使用 GPS 辅助高度测量" ] } ``` --- #### 示例 2: 诊断 GPS 质量 ```json { "name": "diagnose", "arguments": { "session_id": "abc123...", "symptom": "gps_poor" } } ``` **你应该看到什么结果:** ```json { "has_issue": false, "best_fix_type": 3, "avg_eph_m": 0.8, "sat_count_avg": 12.5, "evidence": [], "formatted": "✅ GPS 信号良好:定位 3,平均精度 0.80m", "recommendations": [ "✓ 检测正常,继续飞行前请确认传感器标定" ] } ``` --- #### 示例 3: 诊断电池状态 ```json { "name": "diagnose", "arguments": { "session_id": "abc123...", "symptom": "battery_issue" } } ``` **你应该看到什么结果:** ```json { "has_issue": true, "min_voltage_v": 10.8, "max_current_a": 25.3, "min_remaining_pct": 8.5, "evidence": [ "⚠️ 最低电压过低:10.80V(理想 > 11.1V)", "⚠️ 电量过低:8.5%(理想 > 15%)" ], "severity": "high", "formatted": "⚠️ 电池异常:最低 10.80V,最大电流 25.30A,剩余电量 8.5%", "recommendations": [ "1. 检查电池老化情况(内阻升高)", "2. 确认电池电量充足再起飞(> 50%)", "3. 检查电机和电调是否工作正常", "4. 降低最大飞行速度以减少电流消耗" ] } ``` --- #### 示例 4: 诊断 EKF 故障 ```json { "name": "diagnose", "arguments": { "session_id": "abc123...", "symptom": "ekf_fault" } } ``` **你应该看到什么结果:** ```json { "has_issue": true, "resets": { "pos_vert_reset_counter": 2, "yaw_reset_counter": 1 }, "fault_flags": false, "evidence": [ "⚠️ pos_vert_reset_counter: 2 次重置", "⚠️ yaw_reset_counter: 1 次重置" ], "severity": "critical", "formatted": "⚠️ EKF 故障:重置 2 种,故障标志 False", "recommendations": [ "1. 确保起飞前有充足的 GPS 定位(> 8 颗星)", "2. 避免快速机动(加速、转弯)", "3. 检查磁力计是否需要重新校准", "4. 避免在有强磁场干扰的环境飞行" ] } ``` --- ## 🔧 扩展诊断规则 如果你想添加新的诊断规则,编辑 `ulogpilot/diagnose.py`: ```python class MyDiagnostic(DiagnosticRule): """自定义诊断规则""" def __init__(self): super().__init__( name="我的诊断", description="描述这个诊断做什么", severity="medium" ) def check(self, ulog: ULog, session_id: str) -> Dict[str, Any]: results = { "has_issue": False, "evidence": [] } # 1. 查询相关数据 # 2. 执行分析逻辑 # 3. 填充 results return results def format_result(self, result: Dict[str, Any]) -> str: if result["has_issue"]: return "⚠️ 检测到问题" else: return "✅ 未检测到问题" # 注册到 DIAGNOSTIC_RULES DIAGNOSTIC_RULES: Dict[str, DiagnosticRule] = { # ... 现有规则 ... "my_diagnostic": MyDiagnostic(), } ``` --- ## ⚠️ 注意事项 1. **日志输出**:MCP Server 使用 stdio 模式,日志输出到 stderr(避免污染 MCP 通信) 2. **绘图**:使用非交互模式 `matplotlib.use("Agg")`,图片保存到 `/tmp/ulogpilot_plots/` 3. **内存管理**:使用完后记得 `close_session` 释放内存 4. **数据量**:`query` 默认限制 20000 点,防止 JSON 过大 --- ## 📖 参考资源 - **完整测试指南**: [TESTING_GUIDE.md](TESTING_GUIDE.md) - MCP Inspector 详细使用教程 - PX4 ULog 文档: https://docs.px4.io/main/en/log/ulog_file_format.html - PX4 Topic 列表: https://docs.px4.io/main/en/advanced_config/parameter_reference.html - MCP Inspector 使用: https://modelcontextprotocol.io/quickstart/ --- ## 🏁 MVP 完成状态 ### ✅ 已完成的功能 | 功能 | 状态 | 说明 | |------|------|------| | 基础 MCP Server | ✅ | stdio transport,FastMCP 框架 | | open_ulog / close_session | ✅ | 会话管理 | | flight_summary | ✅ | 飞行概览(时长、模式、高度、速度、电池、GPS、EKF) | | event_timeline | ✅ | 自动事件时间线(arming、mode、failsafe、EKF、setpoint) | | list_topics / describe_topic | ✅ | Topic 浏览 | | query / downsample | ✅ | 时序数据查询 | | plot_timeseries | ✅ | 绘图功能 | | list_available_diagnostic_symptoms | ✅ | 列出可诊断症状 | | diagnose(symptom) | ✅ | 现象驱动诊断向导(7种症状) | ### 🎯 诊断规则清单 | 症状 | 状态 | 检测内容 | |------|------|----------| | drift | 🟡 基础 | 位置漂移检测(框架已实现) | | jitter | 🟡 基础 | 传感器/位置抖动检测(框架已实现) | | altitude_fluctuation | ✅ 完整 | 高度波动检测(已实现) | | landing_inaccuracy | 🟡 基础 | 降落精度检测(框架已实现) | | gps_poor | ✅ 完整 | GPS 信号质量检测(已实现) | | battery_issue | ✅ 完整 | 电池状态检测(已实现) | | ekf_fault | ✅ 完整 | EKF 故障检测(已实现) | --- ## 🚀 快速开始(3 分钟上手) ```bash # 1. 安装依赖 pip install -r requirements.txt # 2. 启动 MCP Server(终端 1) python -m ulogpilot.server # 3. 启动 MCP Inspector(终端 2) mcp-inspector python -m ulogpilot.server # 4. 在浏览器中测试工具 # - open_ulog: 打开日志文件 # - flight_summary: 查看飞行概览 # - diagnose(symptom): 智能诊断 ``` 详细步骤请查看 [TESTING_GUIDE.md](TESTING_GUIDE.md) --- ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! 如果你想贡献代码: 1. Fork 项目 2. 创建特性分支 3. 提交更改 4. 推送到分支 5. 创建 Pull Request --- ## 📝 更新日志 ### v1.0.0 (2026-01-26) #### 新增功能 - ✅ 基础 MCP Server(stdio transport) - ✅ 会话管理(open_ulog / close_session) - ✅ 飞行概览(flight_summary) - ✅ 事件时间线(event_timeline) - ✅ Topic 浏览(list_topics / describe_topic) - ✅ 时序数据查询(query / downsample) - ✅ 绘图功能(plot_timeseries) - ✅ 智能诊断向导(diagnose) - ✅ 7 种诊断规则 #### 诊断规则 - ✅ 高度波动检测(altitude_fluctuation) - ✅ GPS 信号质量检测(gps_poor) - ✅ 电池状态检测(battery_issue) - ✅ EKF 故障检测(ekf_fault) - 🟡 位置漂移检测(drift - 框架已实现) - 🟡 传感器抖动检测(jitter - 框架已实现) - 🟡 降落精度检测(landing_inaccuracy - 框架已实现) #### 文档 - ✅ README.md - 使用指南 - ✅ TESTING_GUIDE.md - 详细测试教程 - ✅ diagnose.py - 诊断规则框架 --- ## 📄 许可证 MIT License --- ## 🙏 致谢 - PX4 Autopilot - 飞控日志格式和工具 - FastMCP - MCP 框架 - pyulog - ULog 解析库