数据起飞了?当无人机仿真遇上 KaiwuDB

本篇内容出自「码」上数据库——KaiwuDB 社区第二届征文大赛优秀作品:《KaiwuDB 社区版在 PX4-ROS2 无人机飞行仿真中的落地实践,加速仿真时序数据的高效存取与智能分析》,作者: 富贵儿 998



 

一、前言

无人机作为智能移动机器人的重要分支,已广泛应用于巡检、测绘、物流、应急救援等众多领域。在无人机系统的研发与测试中,飞行控制仿真是不可或缺的关键环节。通过仿真,开发者可以在安全、低成本的环境中验证算法、调试逻辑并评估性能,大幅缩短从设计到实飞的周期。

当前,开源飞控软件 PX4 与机器人操作系统 ROS2 已成为无人机仿真与二次开发的主流技术栈。PX4 提供专业的飞控核心算法(如姿态解算、导航滤波、混控输出),而 ROS2 则为其带来了模块化、分布式通信和丰富的生态工具。两者通过 PX4‑Gazebo‑ROS2 框架紧密耦合,构成了一个完整的软件在环(SITL)仿真环境。在该框架中,PX4 通过 RTPS(Real‑Time Publish‑Subscribe)协议将飞控内部状态、传感器数据、控制指令等以 Topic 的形式发布到 ROS2 网络,同时接收来自 ROS2 节点的外部控制命令(Off‑Board Control)。

仿真过程中产生的数据本质上是高并发、强时序的流式数据。这些数据主要包括:

•  传感器原始数据:IMU 测量值、GPS 位置、气压计高度等,通常以数百赫兹的频率输出。

•  状态估计数据:EKF 滤波后的姿态、位置、速度等状态量。

•  控制指令数据:油门、舵面指令、期望姿态/位置等。

•  系统状态数据:电池电压、模式切换、错误标志等。

在传统的仿真流程中,这些数据往往以 ULOG(PX4 专用二进制日志)或 CSV 文件的形式暂存于本地磁盘。随着仿真规模扩大(如多机编队、长时测试)、数据频率提升(如视觉/激光雷达数据接入)以及实时性要求加强(如硬件在环 HIL),传统文件存储方式在写入吞吐量、实时查询、长期归档与在线分析等方面面临显著挑战。如何高效地管理、存储和利用这些海量时序数据,已成为提升无人机仿真效能的关键问题。

在此背景下,面向 AIoT 场景的分布式多模数据库 KaiwuDB 社区版提供了新的解决方案。 KaiwuDB  定位为“时序引擎、通用事务引擎、分析引擎、内存实时引擎等多引擎架构”的融合数据库,具备 百万级数据秒级写入、毫秒级查询响应、高压缩比(5‑30 倍)以及云边端一体化部署 等特性。其兼容 PostgreSQL 协议、提供 RESTful API 及多种编程语言接口的设计,使得与 ROS2 节点的集成尤为便捷。

本文将聚焦于 PX4 仿真场景下  KaiwuDB  与 ROS2 的结合应用。通过 ROS2 节点订阅 PX4 发布的各类 Topic,将实时流式数据持续写入   KaiwuDB  的时序表中;利用  KaiwuDB  的高性能写入与实时查询能力,实现仿真数据的 在线持久化、秒级回溯与即时分析 ;进一步结合其跨模计算(时序+关系)特性,可支持复杂的业务查询与决策分析,为无人机仿真的数据驱动优化、智能算法训练与全生命周期测试验证提供坚实的数据底座。

undefined


二、时序数据增长下的业务痛点分析:MySQL 在 PX4-ROS2 无人机仿真中的瓶颈

在 PX4-ROS2 无人机飞行仿真的研发与测试流程中,海量、高频的时序数据是算法验证和系统分析的血液。传统上,团队可能选择使用MySQL 这类成熟的关系型数据库进行数据记录,因为它通用、稳定且生态完善。然而,随着仿真规模从单机向机群、从短时测试向全天候压力测试演进,数据的规模与复杂性呈指数级增长,MySQL 的架构特性在面对这种纯粹的时序数据写入与查询场景时,逐渐暴露出以下核心痛点:




2.1 高并发写入瓶颈与仿真中断风险


•  场景 :在仿真中,单个无人机节点可能同时发布数十个 Topic(如/fmu/vehicle_imu/data、/fmu/vehicle_gps_position/data 等),每个 Topic 的发布频率在 50Hz 至数百 Hz 不等。一个包含 10 架无人机的仿真集群,每秒产生的数据点轻松超过 10 万个。

•  MySQL痛点 :MySQL 的 InnoDB 引擎基于 B+ 树索引,擅长处理复杂的 OLTP 事务,但面对每秒数十万次的简单 INSERT 操作时,会迅速成为瓶颈。频繁的磁盘 I/O、索引维护开销以及行级锁竞争,会导致数据写入队列阻塞。在实时仿真中,这直接表现为数据记录延迟,严重时甚至因写入超时导致 ROS2 节点阻塞,引发整个仿真链路的中断或丢帧,破坏了仿真的实时性与连续性。




2.2 查询性能低下,严重拖慢研发调试效率


  场景 :工程师需要快速查询某架无人机在特定时间区间(如仿真第 120-130 秒)的俯仰角变化,或关联分析同一时刻 IMU 数据与 EKF 估计状态的差异。

•  MySQL痛点

时间区间查询慢:即使对时间戳字段建立了索引,在亿级数据表中进行范围扫描,性能衰减依然明显。SELECT * FROM imu_data WHERE drone_id = 1 AND timestamp BETWEEN ‘2023-10-01 10:00:00’ AND ‘2023-10-01 10:00:10’ 这类查询会变得异常缓慢。

聚合分析吃力:对海量时序数据进行降采样(Downsampling)、统计每架无人机的最大转速或计算平均轨迹偏差等操作,需要执行全表扫描或复杂的联表查询,耗时可能长达数分钟甚至小时,使交互式分析变得几乎不可能,打断了工程师的思路流。




2.3 存储成本急剧膨胀,管理负担沉重


  场景 :为进行长期趋势分析和算法回归测试,需要保留数月至数年的仿真历史数据。原始数据以每秒 10 万点的速度涌入。

  MySQL痛点

存储效率低:MySQL 按行存储,每条记录都包含完整的列头信息和索引开销。对于结构简单的传感器数据(时间戳、设备 ID、几个浮点数值),其有效数据占比(压缩前)可能低于 50%,造成存储空间的巨大浪费。

分区维护复杂:为缓解性能问题,通常需要对表按时间进行分区(Partitioning)。然而,MySQL 分区的创建、维护(如定期删除旧分区)和优化需要繁琐的 DBA 手工操作或脚本维护,自动化程度低,容易出错,且分区数量存在上限,不适合超长期存储。




2.4 数据模型与业务场景错配,开发复杂度高


  场景 :仿真中除了数值型的传感器数据,还有事件型数据(如模式切换、指令下发)和半结构化数据(如飞控参数快照)。

  MySQL痛点

Schema僵化:增加一个新的传感器类型或 Topic 需要执行 ALTER TABLE 操作,在大表上这会引发锁表,导致服务中断。仿真系统的快速迭代特性与数据库 Schema 的刚性变更要求产生直接矛盾。

复杂查询代码冗长:实现时序数据常见的“按时间线对齐”、“最新值查询”等操作,需要编写复杂且低效的SQL语句,增加了业务代码的复杂度和维护成本。




2.5 总结:业务发展的核心制约


在 PX4-ROS2 无人机仿真这一追求高效率、高保真、高迭代速度的业务场景下,MySQL 的上述痛点已从技术问题上升为业务发展的制约:

  拖慢研发周期 :工程师将大量时间耗费在等待查询结果和数据导出上。

  限制仿真规模 :为避免系统崩溃,被迫降低仿真频率、减少无人机数量或缩短测试时长,影响了测试的覆盖度和真实性。

  推高运维与硬件成本 :为支撑存储和性能,需要不断进行分库分表或升级硬件,总拥有成本(TCO)居高不下。

因此,仿真数据平台迫切需要一种能够 原生适配时序数据特性 ,具备 超高吞吐写入、低成本存储、毫秒级时序查询能力 的数据基础设施。

面对海量时序数据带来的挑战,专业时序数据库(Time-Series Database, TSDB) 应运而生。它专为处理带时间戳的数据而设计,采用列式存储、高效压缩、时序索引等核心技术,天然适合无人机仿真这类高频率、强时序的场景。作为面向 AIoT 场景的代表,KaiwuDB 不仅能提供上述时序数据库的核心优势,更以其独特的“分布式多模”架构,为复杂仿真系统提供了更全面的数据管理方案。


对比维度

传统关系型数据库 (如 MySQL) 的瓶颈

KaiwuDB 的针对性优势与解决方案

写入与并发性能

高并发写入时存在锁竞争与 I/O 瓶颈,易导致仿真数据记录延迟或丢失。

采用 “就地计算” 等核心技术,具备每秒百万级数据点的高性能写入能力,能轻松应对多架无人机高频数据的实时入库,保障仿真连续性。

查询与实时分析

海量数据下时间范围查询慢,聚合分析吃力,无法支持交互式调试。

实现毫秒级查询响应,并支持在流式数据上进行实时计算与连续查询。工程师可即时查询任意时间段的飞行参数,进行实时分析与回溯。

存储与成本效率

按行存储,冗余多,压缩率低,长期存储成本高昂。

为时序数据提供 5 至 30 倍的高压缩比,可节省 90% 以上的存储空间。支持数据生命周期管理,自动将冷热数据分级存储,进一步降低成本。

数据模型与扩展性

Schema 僵化,变更困难;扩展时通常需要复杂的分库分表。

原生多模融合,支持在同一数据库实例内同时处理时序数据、关系型数据甚至非结构化数据。采用分布式架构,可在线水平扩展,轻松应对仿真规模从单机到集群的增长。

生态与集成

与物联网生态集成需要大量开发工作。

兼容 PostgreSQL 协议与语法,现有工具和 SQL 技能可平滑迁移。提供云边端一体化部署支持,并能与 ROS2 等系统高效集成,易于构建从边缘(机载)到云端的全链路数据管道。




2.6 超越单纯存储:赋能仿真智能化


除了解决存储与性能的燃眉之急,KaiwuDB 的“多模”与“AIoT”基因还为其在无人机仿真中扮演更智能的角色提供了可能:

  跨模关联分析 :不仅能存储传感器时序流,还能在同一平台上管理飞控参数表(关系型)、飞行事件日志(文档型),并通过跨模计算能力进行关联分析。例如,将某一时刻的异常震动数据(时序)与当时执行的飞行动作指令(关系)进行即时关联分析。

  面向未来的智能集成 :其多模架构为集成高级分析框架奠定了基础。这意味着,未来可以基于 KaiwuDB 中沉淀的高质量仿真数据,更方便地训练和集成 AI 模型,用于飞控算法的异常检测、自主飞行策略优化等,真正实现数据驱动的仿真智能化。


undefined


综上所述,KaiwuDB 凭借其高性能写入、低成本存储、毫秒级查询、多模融合以及云边端协同的核心优势,不仅能够直接解决 PX4-ROS2 无人机仿真中由海量时序数据引发的核心痛点,更能为仿真测试平台提供面向未来的、支持智能分析的数据底座。


三、实践过程



3.1 准备工作:


KaiwuDB 社区版支持用户根据自己的需求来选择安装的方式,分为单节点部署和集群部署两种方式,这里以个人常用的单节点裸机部署的方式来进行部署与使用(此处列举简单步骤,具体过程及其余方式可参考 KaiwuDB 官方文档及相关论坛):


3.1.1 安装 KaiwuDB 社区版


本实践使用的操作系统为 Ubuntu22.04,安装包下载链接: https://gitee.com/kwdb/kwdb/releases,并使用脚本部署 KaiwuDB。

① 登录待部署节点,编辑安装包目录下的 deploy.cfg 配置文件,设置安全模式、管理用户、服务端口等信息。


[global]


# Whether to turn on secure mode
secure_mode=tls
# Management KaiwuDB user
management_user=kaiwudb
# KaiwuDB cluster http port
rest_port= 8080
# KaiwuDB service port
kaiwudb_port= 26257
# KaiwuDB brpc port
brpc_port= 27257
# KaiwuDB data directory
data_root=/ var /lib/kaiwudb
# CPU usage[ 0 - 1 ]
# cpu= 1

[local]
# local node configuration
node_addr= 127.0 .0 .1

# [cluster]
# remote node addr,split by  ','
# node_addr= 127.0 .0 .2
# ssh info
# ssh_port= 22
# ssh_user=admin

# [additional]
# IPs= 127.0 .0 .3 , 127.0 .0 .4

② 执行单机部 署安装命令

./deploy.sh install --single

③ 检查配置无误后输入 Y 或 y,如需返回修改 deploy.cfg 配置文件,输入 N 或 n。


================= KaiwuDB Basic Info =================


Deploy Mode: bare-metal
Start Mode: single
RESTful Port: 8080
KaiwuDB Port: 26257
BRPC Port: 27257
Data Root: /var/lib/kaiwudb
Secure Mode: tls
CPU Usage Limit: unlimited
Local Node Address: 127.0.0.1
======================================================
Please confirm the installation information above(Y/n):

行成功后,控制 台输出以下信息:

[INSTALL COMPLETED]:KaiwuDB has been installed successfully! ...

④ 启动 KaiwuDB 节点。

./deploy.sh start

⑤ 使用以下任 一方式查看节点状态:

  在当前目录使用部署脚

./deploy.sh status

•  在任一目录下使用 systemctl 命令

systemctl status kaiwudb

•  在任一目录下使用便捷脚本(推荐)

 kw-status


⑥ (可选)配置 KaiwuDB 开机自启动。

配置 KaiwuDB 开机自启动后,如果系统重启,则自动启动 KaiwuDB。


systemctl enable kaiwudb

⑦ 部署完成截图如下:


undefined



3.1.2 使用 KaiwuDB 开发者中心连接 KaiwuDB


① KaiwuDB 开发者中心下载链接: https://gitee.com/kwdb/kwdb/releases


② 合并解压缩安装包,文件目录如下:


undefined


③ 双击运行 KaiwuDB 开发者中心应用程序。


④ 连接 KaiwuDB 数据库。

建立连接。第一次建立连接或软件中的所有连接都被删除后,软件启动后会自动弹出 新建连接 向导,引导用户建立连接。


undefined


以下步骤以初次建立连接为例,说明如何连接数据库。

•  创建新连接 窗口,选择 KaiwuDB 驱动,然后单击 下一步


undefined


•  常规 页签,设置主机、端口、数据库。根据需要选择数据库认证方式(默认为数据库原生认证方式),然后完成对应的用户、密码(如果采用非安全模式,则无需设置密码)等设置。


undefined

(可选) 单击 测试链接 ,检查连接是否成功。连接成功后,将显示以下信息:


undefined


•  单击 确定

数据库导航区将自动更新,显示用户具有权限的数据库。


undefined


其他连接方式。其他情况下,如需创建连接,可以选择以下任一操作:

•  击工具栏或 数据库导航区工具栏中的 新建连接 按钮。


undefined


•  在菜单栏中,单击 数据库 ,然后从下拉菜单中选择 新建连接


undefined



⑤ 创建时序数据库。

前提条件

用户是  admin  角色的成员。默认情况下, root  用户属于  admin  角色。


步骤

•  在数据库导航区,右键单击 时序数据库 ,选择 新建时序数据库


undefined


•  创建时序数据库 窗口,填写数据库名称,单击 确定


undefined


创建成功后,新建数据库将自动显示在数据库导航区内,继承 KaiwuDB 数据库系统的角色和用户设置。


3.1.3 连接数据库


大部分仿真代码基于 C++ 语言开发, KaiwuDB  提供了 PostgreSQL ODBC 连接 KaiwuDB 数据库的方法。

开放数据库连接(Open Database Connectivity,ODBC)是一种应用程序编程接口(Application Programming Interface,API),为应用程序访问数据库存储的信息提供了一种标准。ODBC 为异构数据库访问提供统一接口,实现异构数据库间的数据共享。使用 ODBC API 的应用程序可以访问任何符合 ODBC 标准的数据库中的数据,通常无需修改应用程序代码。


undefined


① 安装 PostgreSQL ODBC 驱动。

前提条件

•  下载软件依赖包。

libgc c(9.4.0  及以上版本)

postgresql-devel(10.5 及以上版本)

unixODBC-devel(2.3.7 及以上版本)


② 安装 KaiwuDB 数据库、配置数据库认证方式、创建数据库。

postg resql-deve l

yum install postgresql-devel

unixODBC-devel

yum install unixODBC-devel



③ 安装 PostgreSQL ODBC 驱动下载并安装 PostgreSQL ODBC 驱动。


wget https://update.cs2c.com.cn/NS/V10/V10SP3-2403/os/adv/lic/base/x86_64/Packages/postgresql-odbc-13.00.0000-1.ky10.x86_64.rpm


sudo rpm -ivh postgresql-odbc-13.00.0000-1.ky10.x86_64.rpm

验证是否成功安装 unixODBC。

odbcinst -j

验证是否成功安装 PostgreSQL ODBC 驱动。

odbcinst -q -d

④ 配置 ODBC 数据源。

•  打开 OD BC 配置文件(odbc.ini)

sudo gedit /etc/odbc.ini

•  参数配置示例:


[kwdb]


Description = PostgreSQL
Driver = PostgreSQL Unicode
Trace = No
TraceFile = /tmp/pgodbc.log
Database = px4_simulation
Servername = 10.195.165.24
UserName = yfl
Password = yfl123456..
Port = 26257
SSLMode = require

验证 unixODBC 是否识别配置的数据源。

odbcinst -q -s

执行成功后,控制台输出以下信息:

[kwdb]





3.2 实践过程


仿真环境基于 Ubuntu 22.04 操作系统构建,以 PX4 v1.14 自动驾驶软件为核心,通过 Micro XRCE-DDS Agent 实现与 ROS 2 (Humble) 的实时通信。仿真可视化与动力学模型由 Gazebo classic 提供,整个系统的监控、参数调试与任务规划则通过 QGroundControl (QGC) 地面站完成。此处仿真环境搭建不做演示,可根据个人兴趣及配置参考链接  https://blog.csdn.net/weixin_55944949/article/details/140627640 完成相关环境配置。


3.2.1 数据库连接


① 数据库连接架构设计:

ODBC 采用经典的三层句柄架构,确保资源的有序管理


// 数据库连接变量定义 - 三层句柄设计



private
:
    // 第一层:环境句柄 - 管理ODBC环境

    SQLHENV env_{ nullptr };
    
    // 第二层:连接句柄 - 管理数据库连接  

    SQLHDBC dbc_{ nullptr };
    
    // 第三层:语句句柄 - 执行SQL语句

    SQLHSTMT stmt_{ nullptr };
    
    // 数据库连接参数

    std::string dsn_{ "kwdb" };
    std::string user_{ "yfl" };
    std::string password_{ "yfl123456.." };

②  配置驱动的连接管理:


// 构造函数中的参数配置


ParamCollectorNode:: ParamCollectorNode ( const  rclcpp::NodeOptions& options)
    :  Node ( "px4_param_collector" , options) {
    
    // 声明可配置的数据库参数

    this
-> declare_parameter ( "dsn" ,  "kwdb" );
    this
-> declare_parameter ( "user" ,  "yfl" );
    this
-> declare_parameter ( "password" ,  "yfl123456.." );
    this
-> declare_parameter < bool >( "enable_database" ,  true );
    
    // 获取运行时参数值

    dsn_ =  this -> get_parameter ( "dsn" ). as_string ();
    user_ =  this -> get_parameter ( "user" ). as_string ();
    password_ =  this -> get_parameter ( "password" ). as_string ();
    enable_database_ =  this -> get_parameter ( "enable_database" ). as_bool ();
    
    // 根据配置决定是否启用数据库

    if
 (enable_database_) {
        initializeDatabase
();   // 初始化数据库连接
    }  else  {
        RCLCPP_WARN
( this -> get_logger (),  "数据库功能已禁用" );
    }
}

③ 错误处理机制,包含详细的错误诊断和异常处理:


// 连接数据库时的错误处理


ret = SQLConnect(dbc_, 
                (SQLCHAR*)dsn_.c_str(), SQL_NTS,
                (SQLCHAR*)user_.c_str(), SQL_NTS,
                (SQLCHAR*)password_.c_str(), SQL_NTS);
 
if
 (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
    // 获取详细的ODBC错误信息

    SQLCHAR sqlState[ 6 ] = { 0 };   // SQL状态码(5字符+终止符)
    SQLCHAR message[SQL_MAX_MESSAGE_LENGTH] = { 0 };
    SQLSMALLINT
 length  =  0 ;
    SQLINTEGER
 nativeError  =  0 ;
    
    // 提取诊断信息

    SQLGetDiagRec(SQL_HANDLE_DBC, dbc_,  1 , sqlState, &nativeError, 
                 message, sizeof(message), &length);
    
    // 记录详细的错误信息

    RCLCPP_ERROR( this ->get_logger(),  
                "数据库连接失败: %s (SQL状态: %s, 原生错误码: %d)"

                message, sqlState, nativeError);
    
    enable_database_ =  false ;   // 优雅降级:禁用数据库功能
    return
;
}
 
// 异常处理包装

try
 {
    // 数据库操作代码...

}  catch  (const std::exception& e) {
    RCLCPP_ERROR( this ->get_logger(),  
                "数据库操作异常: %s。已禁用数据库功能。"

                e.what());
    enable_database_ =  false ;
}

④ 资源生命周期管理:

严格按照 RAII 原则管理 ODBC 资源:


// 析构函数中的资源清理


ParamCollectorNode::~ ParamCollectorNode () {
    stopCollection
();
    
    // 逆序释放ODBC资源(语句→连接→环境)

    if
 (stmt_) {
        SQLFreeHandle
(SQL_HANDLE_STMT, stmt_);
        RCLCPP_DEBUG
( this -> get_logger (),  "SQL语句句柄已释放" );
    }
    if
 (dbc_) {
        SQLDisconnect
(dbc_);       // 断开连接
        SQLFreeHandle
(SQL_HANDLE_DBC, dbc_);   // 释放连接句柄
        RCLCPP_DEBUG
( this -> get_logger (),  "数据库连接已断开" );
    }
    if
 (env_) {
        SQLFreeHandle
(SQL_HANDLE_ENV, env_);   // 释放环境句柄
        RCLCPP_DEBUG
( this -> get_logger (),  "SQL环境句柄已释放" );
    }
    
    RCLCPP_INFO
( this -> get_logger (),  "参数采集器已关闭" );
}

⑤ 连接优化措施:


void
 ParamCollectorNode
::
initializeDatabase
() {



    // 设置ODBC 3.0版本

    ret =  SQLSetEnvAttr (env_,  
                       SQL_ATTR_ODBC_VERSION

                       ( void *) SQL_OV_ODBC3 ,  
                       0
);
    
    // 设置5秒连接超时

    SQLSetConnectAttr
(dbc_,  
                     SQL_LOGIN_TIMEOUT

                     ( SQLPOINTER ) 5 ,  
                     0
);
    
    RCLCPP_INFO
( this -> get_logger (),  
               "ODBC 3.0已启用,连接超时设置为5秒"
);
}


3.2.2 表格设计与创建


•  创建表格:

①  参数调优表 (parameter_tuning)

作用:记录飞行控制器参数的变化历史,用于参数调优和性能分析。

普通列:

ts - 时间戳(主键)
parameter_name - 参数名称(如:MC_PITCH_P, MC_ROLL_P)
parameter_value - 参数值
tuning_session_id - 调优会话 ID
commit_hash - Git 提交哈希
tuner_name - 调优者姓名
performance_score - 调优后的性能评分

TAGS列(元数据):

simulation_id - 仿真 ID(主TAG)
airframe_type - 机架类型(如:iris)
controller_type - 控制器类型(如:px4)
test_scenario - 测试场景(如:ros2_simulation)


② 模式切换表 (mode_transition)

作用:记录飞行模式切换事件,分析模式切换时的飞行状态。

普通列:

ts - 时间戳
transition_id - 切换事件 ID
from_mode - 源模式(如:MANUAL, POSCTL)
to_mode - 目标模式
altitude - 切换时高度
velocity_ned_x/y/z - NED 坐标系速度分量
roll/pitch/yaw - 切换时姿态角

TAGS列:

simulation_id - 仿真 ID
airframe_type - 机架类型
transition_type - 切换类型(manual/auto/emergency)


③  性能指标表 (performance_metrics)

作用:记录飞行性能指标,用于评估控制系统性能。

普通列:

ts - 时间戳
roll_error/pitch_error/yaw_error - 姿态角误差
pos_error/vel_error - 位置/速度误差
control_effort - 控制努力度
performance_score - 综合性能评分

TAGS列:

simulation_id - 仿真 ID
airframe_type - 机架类型
controller_type - 控制器类型
metric_type - 指标类型(如:periodic_metrics)


④  飞行性能基准测试表 (flight_performance_baseline)

作用:记录详细的飞行性能基准数据,用于系统性能评估和对比。

普通列:

ts - 时间戳
position_error_xy/z - XY 平面和垂直方向位置误差
attitude_error_roll/pitch/yaw - 姿态角误差
velocity_response_time - 速度响应时间
max_acceleration - 最大加速度
hover_stability_index - 悬停稳定性指数

TAGS列:

simulation_id - 仿真 ID
drone_type - 无人机类型
flight_mode - 飞行模式
payload_config - 载荷配置


⑤ 振动监测表 (vibration_monitoring)

作用:监测无人机振动水平,检测机械故障和异常。

普通列:

ts - 时间戳
accel_rms_x/y/z - 加速度计 XYZ 轴的 RMS 值
gyro_rms_x/y/z - 陀螺仪 XYZ 轴的 RMS 值
dominant_frequency_hz - 主振动频率
vibration_severity_index - 振动严重性指数

TAGS列:

simulation_id - 仿真 ID
component_id - 组件标识(如:motor_1)
component_type - 组件类型(如:motor)


⑥ 通信质量监测表 (communication_quality)

作用:监控无人机与地面站之间的通信质量。

普通列:

ts - 时间戳
rssi_dbm - 接收信号强度指示(dBm)
packet_loss_rate - 丢包率
latency_ms - 延迟(毫秒)
jitter_ms - 抖动(毫秒)
retransmission_count - 重传次数
link_margin_db - 链路余量(dB)

TAGS列:

simulation_id - 仿真 ID
link_type - 链路类型(如:UART, Radio)
transmitter_id - 发/射器标识
receiver_id - 接收器标识
distance_m - 通信距离(米)


⑦ PID 参数调优历史表 (pid_tuning_history)

作用:记录 PID 参数调优的历史记录和调优效果。

普通列:

ts - 时间戳
parameter_group - 参数组(如:Attitude, Position)
parameter_name - 具体参数名
old_value/new_value - 调优前后的参数值
overshoot_percentage - 超调百分比
settling_time_ms - 调节时间(毫秒)
steady_state_error - 稳态误差
rmse_error - 均方根误差
stability_margin - 稳定裕度

 

TAGS列:

 

simulation_id - 仿真 ID
tuning_session_id - 调优会话 ID
tuning_method - 调优方法(如:manual, Ziegler-Nichols)
flight_condition - 飞行条件

 


⑧ 环境适应能力表 (environmental_adaptation)

作用:评估无人机在不同环境条件下的适应能力。

普通列:

ts - 时间戳
wind_speed_estimated - 估计风速
wind_direction_estimated - 估计风向
turbulence_intensity - 湍流强度
temperature/humidity - 温湿度
air_density - 空气密度
position_hold_error - 位置保持误差
attitude_correction_roll/pitch - 姿态修正量
power_consumption_factor - 功耗因子

TAGS列:

simulation_id - 仿真 ID
environment_type - 环境类型(如:simulation, outdoor)
altitude_range - 高度范围

•  参数调优表 (parameter_tuning)创建代码示例:


// ========== 创建表函数 ==========



void
 ParamCollectorNode::createTables() {
    try
 {
        RCLCPP_INFO( this ->get_logger(),  "正在创建数据库表..." );
        
        if
 (!stmt_) {
            RCLCPP_ERROR( this ->get_logger(),  "数据库语句句柄无效" );
            return
;
        }
        
        // 先创建TS数据库(如果需要)

        const  char * createDatabaseSQL =  "CREATE TS DATABASE IF NOT EXISTS px4_simulation" ;
        SQLRETURN
 ret  =  SQLExecDirect(stmt_, (SQLCHAR*)createDatabaseSQL, SQL_NTS);
        if
 (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
            // 数据库可能已存在,忽略错误

            SQLCHAR sqlState[ 6 ] = { 0 };
            SQLCHAR message[SQL_MAX_MESSAGE_LENGTH] = { 0 };
            SQLSMALLINT
 length  =  0 ;
            SQLINTEGER
 nativeError  =  0 ;
            
            if
 (SQLGetDiagRec(SQL_HANDLE_STMT, stmt_,  1 , sqlState, &nativeError, 
                             message, sizeof(message), &length) == SQL_SUCCESS) {
                RCLCPP_DEBUG( this ->get_logger(),  "数据库创建消息: %s" , message);
            }
        }
        
        // 在每个表创建之间重置语句句柄状态

        SQLFreeStmt(stmt_, SQL_CLOSE);
        
        // ========== 创建参数调优表 ==========

        const  char * createParamTableSQL = R "(
            CREATE TABLE px4_simulation.parameter_tuning (
                ts TIMESTAMP NOT NULL,
                parameter_name VARCHAR(100),
                parameter_value DOUBLE PRECISION,
                tuning_session_id VARCHAR(50),
                commit_hash VARCHAR(40),
                tuner_name VARCHAR(50),
                performance_score DOUBLE PRECISION
            ) TAGS (
                simulation_id INTEGER NOT NULL,
                airframe_type VARCHAR(50),
                controller_type VARCHAR(50),
                test_scenario VARCHAR(100)
            ) PRIMARY TAGS (simulation_id)
        )"
;
        
        ret = SQLExecDirect(stmt_, (SQLCHAR*)createParamTableSQL, SQL_NTS);
        // ... 错误处理代码 ...

        
        SQLFreeStmt(stmt_, SQL_CLOSE);
        
        // ========== 创建其他表 ==========


        
        
        RCLCPP_INFO( this ->get_logger(),  "所有数据库表创建完成" );
        
    }  catch  (const std::exception& e) {
        RCLCPP_ERROR( this ->get_logger(),  "创建表异常: %s" , e.what());
    }
}



3.2.3 数据采集、插入、保存


① 数据采集回调函数:

这些函数由 ROS2 订阅器触发,实时采集各种飞行数据:

回调函数

数据来源

采集的数据

处理方式

onParameterUpdate

/fmu/out/parameter_update

参数更新通知

记录日志文件

onVehicleStatus

/fmu/out/vehicle_status

飞行模式、解锁状态

检测模式切换,触发insertModeTransition

onVehicleControlMode

/fmu/out/vehicle_control_mode

控制模式(如Offboard)

记录控制模式变化

onVehicleAttitude

/fmu/out/vehicle_attitude

四元数姿态

转换为欧拉角,更新性能指标

onVehicleLocalPosition

/fmu/out/vehicle_local_position

位置、速度、加速度

更新性能指标,计算位置/速度误差

onSensorCombined

/fmu/out/sensor_combined

加速度计、陀螺仪原始数据

收集数据用于振动分析

onActuatorOutputs

/fmu/out/actuator_outputs

电机输出值

计算方差,检测振动异常,触发saveActuatorVariance

onTrajectorySetpoint

/fmu/in/trajectory_setpoint

期望位置和速度

用于性能计算对比


② 定时器处理函数:

这些函数由定时器定期触发,执行计算和分析任务:


定时器函数

触发间隔

主要功能

关联的保存函数

calculatePerformanceMetrics

2秒

计算飞行性能指标

insertFlightPerformance

analyzeVibrationData

1秒

分析振动数据

saveVibrationMetrics

monitorCommunication

3秒

监控通信质量

saveCommunicationQuality

monitorEnvironment

1 0秒

监控环境适应能力

saveEnvironmentalData

savePerformanceMetrics

可配置(默认2秒)

保存基础性能指标

自身执行数据库插入


③ 数据处理流程:

ROS2 消息订阅 → 回调函数采集 → 数据缓存/处理 → 定时器分析 → 数据库保存

  1. 1. 实时数据采集:ROS2 订阅器接收 PX4 飞控的各类消息
  2. 2. 数据预处理
    • 姿态四元数转换为欧拉角
    • NED 坐标系转换(z 轴取负得到高度)
    • 数据有效性检查
  3. 3. 缓存管理
    • 传感器数据缓冲区(限制大小)
    • 性能计算数据缓存
  4. 4. 定时分析
    • 性能指标计算(位置误差、姿态误差、响应时间等)
    • 振动分析(RMS 值、主频、严重性指数)
    • 电池健康分析(SOH 计算)
    • 组件寿命预测(磨损率计算)
  5. 5. 数据库保存
    • 检查数据库连接状态
    • 准备 SQL 语句和参数绑定
    • 执行插入操作
    • 错误处理和日志记录


④ 代码示例:


// ========== 参数采集相关的回调函数 ==========



 
// 1. 参数更新回调函数

void  ParamCollectorNode::onParameterUpdate ( const  px4_msgs::msg::ParameterUpdate::SharedPtr msg)  
{
    // parameter_update消息只是一个通知,表明参数有更新

    // 但PX4的ROS2消息中不包含具体的参数名和值

    
    RCLCPP_DEBUG
( this -> get_logger (),  
                "参数更新通知接收时间戳: %lu"

                msg->timestamp);
    
    // 记录通知事件

    if
 (enable_file_log_ && log_file_. is_open ()) {
        rclcpp::Time timestamp =  px4TimeToRosTime (msg->timestamp);
        log_file_ << std::fixed << std:: setprecision ( 6 )
                 << timestamp. seconds () <<  ", "
                 <<  "PARAM_UPDATE_NOTIFICATION"  <<  ", "
                 <<  "0"  <<  ", "
                 <<  "uXRCE-DDS"  << std::endl;
    }
}
 
// ========== 其他回调函数 ==========

 
 
 
// ========== 定时器触发的处理函数 ==========

 
// 10. 性能计算函数(定时器触发)

void  ParamCollectorNode::calculatePerformanceMetrics ()  
{
    std::lock_guard  lock (data_mutex_)
;
    
    // 检查是否有足够的数据进行计算

    if
 (!vehicle_local_position_ || !vehicle_attitude_) {
        static
 int  missing_count =  0 ;
        missing_count++;
        if
 (missing_count %  50  ==  0 ) {
            RCLCPP_WARN
( this -> get_logger (),  
                "数据不完整无法计算性能: loc_pos=%d, attitude=%d"
,
                vehicle_local_position_ !=  nullptr ,
                vehicle_attitude_ !=  nullptr );
        }
        return
;
    }
    
    // 如果没有设定点数据,创建一个默认的设定点(当前位置)

    std::shared_ptr setpoint;
    if
 (!trajectory_setpoint_) {
        // 创建基于当前位置的设定点

        setpoint = std:: make_shared ();
        setpoint->position[ 0 ] = vehicle_local_position_->x;
        setpoint->position[ 1 ] = vehicle_local_position_->y;
        setpoint->position[ 2 ] = vehicle_local_position_->z;
        setpoint->velocity[ 0 ] =  0 ;
        setpoint->velocity[ 1 ] =  0 ;
        setpoint->velocity[ 2 ] =  0 ;
        trajectory_setpoint_ = setpoint;
        has_setpoint_ =  true ;   // 标记已有设定点
        RCLCPP_INFO
( this -> get_logger (),  "使用当前位置作为设定点: [%.2f, %.2f, %.2f]"
                   setpoint->position[ 0 ], setpoint->position[ 1 ], setpoint->position[ 2 ]);
    }  else  {
        setpoint = trajectory_setpoint_;
    }
    
    // 检查是否有设定点数据

    if
 (!has_setpoint_) {
        static
 int  missing_setpoint_count =  0 ;
        missing_setpoint_count++;
        if
 (missing_setpoint_count %  10  ==  0 ) {
            RCLCPP_WARN
( this -> get_logger (),  "没有设定点数据,无法计算性能" );
        }
        return
;
    }
    
    // 使用更安全的方式检查时间,避免使用时间减法

    // 获取当前时间戳

    auto
 now_ms = std::chrono:: duration_cast (
        std::chrono::system_clock:: now (). time_since_epoch ()). count ();
    
    // 简单的频率控制:每2秒计算一次性能指标

    static
 int64_t  last_calc_time =  0 ;
    int64_t
 current_time = now_ms;
    
    if
 (last_calc_time ==  0 ) {
        last_calc_time = current_time;
    }
    
    // 如果距离上次计算不足2秒,跳过

    if
 (current_time - last_calc_time <  2000 ) {
        return
;
    }
    
    last_calc_time = current_time;
    
    // 计算性能指标

    try
 {
        auto
 metrics = performance_calculator_-> calculate (
            *vehicle_local_position_, 
            *vehicle_attitude_,
            *setpoint);
        
        // 更新性能评分

        current_legacy_performance_.performance_score =  100.0  - 
            (metrics.position_error_xy *  10.0  + 
             metrics.position_error_z *  5.0  + 
             metrics.attitude_error_roll + 
             metrics.attitude_error_pitch + 
             metrics.attitude_error_yaw);
        
        // 确保评分在合理范围内

        current_legacy_performance_.performance_score = 
            std:: max ( 0.0 , std:: min ( 100.0 , current_legacy_performance_.performance_score));
        
        // 检查是否有有效的数据需要保存

        if
 (std:: isfinite (metrics.position_error_xy) && 
            std:: isfinite (metrics.position_error_z) &&
            metrics.position_error_xy <  1000.0  &&   // 合理范围检查
            metrics.position_error_z <  1000.0 ) {
            
            // 保存到数据库

            insertFlightPerformance
(metrics);
            
            // 更新当前性能评分

            current_performance_ = metrics;
            
            RCLCPP_INFO
( this -> get_logger (),  
                       "性能计算完成: 位置误差XY=%.3fm, 位置误差Z=%.3fm, 响应时间=%.3fs, 评分=%.1f"

                       metrics.position_error_xy, metrics.position_error_z, 
                       metrics.velocity_response_time, current_legacy_performance_.performance_score);
        }  else  {
            RCLCPP_WARN
( this -> get_logger (),  "无效的性能指标数据,跳过保存: pos_xy=%.3f, pos_z=%.3f" ,
                       metrics.position_error_xy, metrics.position_error_z);
        }
        
    }  catch  ( const  std::exception& e) {
        RCLCPP_ERROR
( this -> get_logger (),  "性能计算异常: %s" , e. what ());
    }
}
// ========== 其他处理函数 ==========


3.2.4 查询与分析


完成上述工作后,在进行 PX4 仿真时运行数据采集节点,即可收集所需数据,对于采集数据采用以下代码进行查询与分析:

•  核心监控与概览 :查询仿真活跃度(查询 1)、性能评分分布(查询 4)及关键飞行指标(查询 5),快速掌握系统整体运行状态。

•  异常与安全告警 :实时筛查电池、振动、性能等方面的紧急异常(查询 6),并对各类告警进行统计分析(查询 3),确保仿真安全与问题可追溯。

•  深度诊断与分析 :深入分析飞行失败的根本原因(查询 7)和异常问题的处理效率(查询 9),助力问题定位与流程优化。

•  运维与健康管理 :评估电池健康(查询 2)、预测组件寿命并生成维护计划(查询 8),实现预防性维护。

•  多维度性能评估 :从通信链路质量(查询 11)、环境适应能力(查询 12)、参数调优历史(查询 13)及时间趋势(查询 10)等多个维度,全面评估无人机系统性能。


-- 1. 查询最近24小时各仿真ID的飞行性能记录数量TOP10(保持不变)



SELECT
 
    simulation_id,
    COUNT
( * )  as  flight_count,
    AVG
(performance_score)  as  avg_performance,
    MIN
(ts)  as  first_flight_time,
    MAX
(ts)  as  last_flight_time
FROM
 px4_simulation.performance_metrics
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  simulation_id
ORDER
 BY  flight_count  DESC
LIMIT  10 ;
 
-- 2. 查询不同电池的健康状态统计(保持不变)

SELECT

    battery_id,
    battery_type,
    COUNT
( * )  as  record_count,
    ROUND( AVG (state_of_health):: numeric ,  2 )  as  avg_soh,
    ROUND( AVG (remaining_capacity):: numeric ,  2 )  as  avg_remaining,
    ROUND( MIN (remaining_capacity):: numeric ,  2 )  as  min_remaining
FROM
 px4_simulation.battery_health_monitoring
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  battery_id, battery_type
ORDER
 BY  avg_soh  DESC
LIMIT  100 ;
 
-- 3. 查询各仿真ID的告警/异常统计

WITH
 alert_data  AS  (
    -- 电池异常

    SELECT
 simulation_id,  'battery_low'  as  alert_type,  COUNT ( * )  as  alert_count
    FROM
 px4_simulation.battery_health_monitoring
    WHERE
 remaining_capacity  <  0.2
    AND
 ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  simulation_id
    
    UNION
 ALL
    
    -- 振动异常

    SELECT
 simulation_id,  'vibration_high'  as  alert_type,  COUNT ( * )  as  alert_count
    FROM
 px4_simulation.vibration_monitoring
    WHERE
 vibration_severity_index  >  0.5
    AND
 ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  simulation_id
    
    UNION
 ALL
    
    -- 姿态误差过大

    SELECT
 simulation_id,  'attitude_error'  as  alert_type,  COUNT ( * )  as  alert_count
    FROM
 px4_simulation.performance_metrics
    WHERE
 roll_error  >  10.0  OR  pitch_error  >  10.0  OR  yaw_error  >  10.0
    AND
 ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  simulation_id
)
SELECT

    simulation_id,
    alert_type,
    SUM
(alert_count)  as  total_alerts
FROM
 alert_data
GROUP
 BY  simulation_id, alert_type
ORDER
 BY  total_alerts  DESC
LIMIT  100 ;
 
-- 4. 查询飞行性能分数分布(修正:移除ORDER BY中的CASE,使用别名)

SELECT

    score_range,
    COUNT
( * )  as  count,
    ROUND( MIN (performance_score):: numeric ,  2 )  as  min_score,
    ROUND( MAX (performance_score):: numeric ,  2 )  as  max_score,
    ROUND( AVG (performance_score):: numeric ,  2 )  as  avg_score
FROM
 (
    SELECT

        performance_score,
        CASE
 
            WHEN
 performance_score  >=  0  AND  performance_score  <  10  THEN  '0-9'
            WHEN
 performance_score  >=  10  AND  performance_score  <  20  THEN  '10-19'
            WHEN
 performance_score  >=  20  AND  performance_score  <  30  THEN  '20-29'
            WHEN
 performance_score  >=  30  AND  performance_score  <  40  THEN  '30-39'
            WHEN
 performance_score  >=  40  AND  performance_score  <  50  THEN  '40-49'
            WHEN
 performance_score  >=  50  AND  performance_score  <  60  THEN  '50-59'
            WHEN
 performance_score  >=  60  AND  performance_score  <  70  THEN  '60-69'
            WHEN
 performance_score  >=  70  AND  performance_score  <  80  THEN  '70-79'
            WHEN
 performance_score  >=  80  AND  performance_score  <  90  THEN  '80-89'
            WHEN
 performance_score  >=  90  AND  performance_score  <=  100  THEN  '90-100'
            ELSE
 '其他'
        END
 as  score_range
    FROM
 px4_simulation.performance_metrics
    WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
)  as  subquery
GROUP
 BY  score_range
ORDER
 BY  
    CASE
 score_range
        WHEN
 '0-9'  THEN  0
        WHEN
 '10-19'  THEN  1
        WHEN
 '20-29'  THEN  2
        WHEN
 '30-39'  THEN  3
        WHEN
 '40-49'  THEN  4
        WHEN
 '50-59'  THEN  5
        WHEN
 '60-69'  THEN  6
        WHEN
 '70-79'  THEN  7
        WHEN
 '80-89'  THEN  8
        WHEN
 '90-100'  THEN  9
        ELSE
 10
    END

LIMIT  100 ;
 
 
-- 5. 查询关键性能指标统计(保持不变)

SELECT

    simulation_id,
    COUNT
( * )  as  total_flights,
    ROUND( AVG (position_error_xy):: numeric ,  4 )  as  avg_position_error_xy,
    ROUND( AVG (position_error_z):: numeric ,  4 )  as  avg_position_error_z,
    ROUND( AVG (attitude_error_roll):: numeric ,  4 )  as  avg_attitude_error_roll,
    ROUND( AVG (attitude_error_pitch):: numeric ,  4 )  as  avg_attitude_error_pitch,
    ROUND( AVG (attitude_error_yaw):: numeric ,  4 )  as  avg_attitude_error_yaw,
    ROUND( AVG (velocity_response_time):: numeric ,  4 )  as  avg_response_time,
    ROUND( AVG (max_acceleration):: numeric ,  4 )  as  avg_max_acceleration
FROM
 px4_simulation.flight_performance_baseline
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  simulation_id
ORDER
 BY  avg_position_error_xy  DESC
LIMIT  10 ;
 
 
 
-- 6.查询未处理的高优先级异常(修正版)

WITH
 battery_critical  AS  (
    SELECT
 
        'battery_critical'
 as  alert_type,
        '紧急'
 as  alert_level,
        '电池电量严重不足'
 as  alert_description,
        battery_id,
        remaining_capacity,
        ts
    FROM
 px4_simulation.battery_health_monitoring
    WHERE
 remaining_capacity  <  0.15
    AND
 ts  >=  NOW()  -  INTERVAL  '1 hour'
),
vibration_critical  AS  (
    SELECT
 
        'vibration_critical'
 as  alert_type,
        '紧急'
 as  alert_level,
        '振动严重异常'
 as  alert_description,
        component_id,
        vibration_severity_index,
        ts
    FROM
 px4_simulation.vibration_monitoring
    WHERE
 vibration_severity_index  >  0.8
    AND
 ts  >=  NOW()  -  INTERVAL  '1 hour'
),
performance_critical  AS  (
    SELECT
 
        'performance_critical'
 as  alert_type,
        '高'
 as  alert_level,
        '飞行性能严重下降'
 as  alert_description,
        CAST
(simulation_id  AS  VARCHAR )  as  simulation_id_str,
        performance_score,
        ts
    FROM
 px4_simulation.performance_metrics
    WHERE
 performance_score  <  60
    AND
 ts  >=  NOW()  -  INTERVAL  '1 hour'
),
-- 注意:从performance_metrics表查询时,需要确保列名和数据类型与其他子查询一致

performance_critical_fixed  AS  (
    SELECT

        alert_type,
        alert_level,
        alert_description,
        -- 使用空字符串作为占位符,因为其他表有battery_id/component_id,但performance_metrics没有

        ''
 as  component_id,
        performance_score  as  severity_value,   -- 重命名以统一
        ts
    FROM
 performance_critical
),
-- 统一所有子查询的列

battery_critical_fixed  AS  (
    SELECT

        alert_type,
        alert_level,
        alert_description,
        battery_id  as  component_id,
        remaining_capacity  as  severity_value,
        ts
    FROM
 battery_critical
),
vibration_critical_fixed  AS  (
    SELECT

        alert_type,
        alert_level,
        alert_description,
        component_id,
        vibration_severity_index  as  severity_value,
        ts
    FROM
 vibration_critical
)
-- 合并所有警报

SELECT
 *  FROM  battery_critical_fixed
UNION
 ALL
SELECT
 *  FROM  vibration_critical_fixed
UNION
 ALL
SELECT
 *  FROM  performance_critical_fixed
ORDER
 BY  
    CASE
 alert_type
        WHEN
 'battery_critical'  THEN  1
        WHEN
 'vibration_critical'  THEN  2
        WHEN
 'performance_critical'  THEN  3
        ELSE
 4
    END
,
    severity_value,   -- 按严重程度排序(值越小/越大表示越严重)
    ts  DESC ;
 
 
 
 
-- 7. 查询飞行失败原因分析(修正:使用正确的表和列)

SELECT

    failure_reason,
    SUM
(failure_count)  as  total_failures,
    ROUND( AVG (avg_performance):: numeric ,  2 )  as  avg_failure_score,
    COUNT
( DISTINCT  simulation_id)  as  affected_simulations
FROM
 (
    SELECT

        simulation_id,
        CASE
 
            -- 使用performance_metrics表中的列

            WHEN
 pos_error  >  1.0  THEN  '位置控制误差过大'
            WHEN
 vel_error  >  0.5  THEN  '速度控制误差过大'
            WHEN
 roll_error  >  15.0  THEN  '滚转角不稳定'
            WHEN
 pitch_error  >  15.0  THEN  '俯仰角不稳定'
            WHEN
 yaw_error  >  20.0  THEN  '偏航角不稳定'
            WHEN
 control_effort  >  2.0  THEN  '控制努力度过大'
            ELSE
 '其他原因'
        END
 as  failure_reason,
        COUNT
( * )  as  failure_count,
        AVG
(performance_score)  as  avg_performance
    FROM
 px4_simulation.performance_metrics   -- 修改为performance_metrics表
    WHERE
 performance_score  <  70
    AND
 ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  simulation_id, pos_error, vel_error, roll_error, 
             pitch_error, yaw_error, control_effort
)  as  subquery
GROUP
 BY  failure_reason
ORDER
 BY  total_failures  DESC
LIMIT  100 ;
 
 
-- 8. 查询无人机组件维护计划(保持不变)

SELECT

    component_id,
    component_type,
    total_operating_hours,
    predicted_remaining_life_hours,
    ROUND((total_operating_hours  /
          (total_operating_hours  +  predicted_remaining_life_hours)):: numeric ,  4 )  as  wear_percentage,
    maintenance_recommendation,
    CASE
 
        WHEN
 predicted_remaining_life_hours  <  24  THEN  '紧急维护'
        WHEN
 predicted_remaining_life_hours  <  72  THEN  '近期维护'
        ELSE
 '计划维护'
    END
 as  maintenance_priority,
    CASE
 
        WHEN
 predicted_remaining_life_hours  <  24  THEN  NOW()
        WHEN
 predicted_remaining_life_hours  <  72  THEN  NOW()  +  INTERVAL  '7 days'
        ELSE
 NOW()  +  INTERVAL  '30 days'
    END
 as  suggested_maintenance_time
FROM
 px4_simulation.component_life_prediction
WHERE
 ts  >=  NOW()  -  INTERVAL  '1 hour'
ORDER
 BY  maintenance_priority, predicted_remaining_life_hours
LIMIT  100 ;
 
-- 9. 查询异常处理效率分析(修正:使用正确的列名)

WITH
 battery_exceptions  AS  (
    SELECT
 
        'battery'
 as  exception_type,
        b1.battery_id  as  component,
        b1.ts  as  detection_time,
        MIN
(b2.ts)  as  resolution_time
    FROM
 px4_simulation.battery_health_monitoring b1
    LEFT
 JOIN  px4_simulation.battery_health_monitoring b2  
        ON
 b1.battery_id  =  b2.battery_id  
        AND
 b2.ts  >  b1.ts  
        AND
 b2.remaining_capacity  >  b1.remaining_capacity
    WHERE
 b1.remaining_capacity  <  0.2
    AND
 b1.ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  b1.battery_id, b1.ts
),
vibration_exceptions  AS  (
    SELECT
 
        'vibration'
 as  exception_type,
        v1.component_id  as  component,
        v1.ts  as  detection_time,
        MIN
(v2.ts)  as  resolution_time
    FROM
 px4_simulation.vibration_monitoring v1
    LEFT
 JOIN  px4_simulation.vibration_monitoring v2  
        ON
 v1.component_id  =  v2.component_id  
        AND
 v2.ts  >  v1.ts  
        AND
 v2.vibration_severity_index  <  v1.vibration_severity_index   -- 修正:使用正确的列名
    WHERE
 v1.vibration_severity_index  >  0.5   -- 修正:使用正确的列名
    AND
 v1.ts  >=  NOW()  -  INTERVAL  '24 hours'
    GROUP
 BY  v1.component_id, v1.ts
),
all_exceptions  AS  (
    SELECT
 exception_type, component, detection_time, resolution_time
    FROM
 battery_exceptions
    UNION
 ALL
    SELECT
 exception_type, component, detection_time, resolution_time
    FROM
 vibration_exceptions
)
SELECT

    exception_type,
    COUNT
( * )  as  total_exceptions,
    COUNT
(resolution_time)  as  handled_exceptions,
    ROUND( AVG (
        CASE
 
            WHEN
 resolution_time  IS  NOT NULL  
            THEN
 EXTRACT (EPOCH  FROM  (resolution_time  -  detection_time))
            ELSE
 NULL  
        END

    ):: numeric ,  2 )  as  avg_handling_time_seconds,
    ROUND( MIN (
        CASE
 
            WHEN
 resolution_time  IS  NOT NULL  
            THEN
 EXTRACT (EPOCH  FROM  (resolution_time  -  detection_time))
            ELSE
 NULL  
        END

    ):: numeric ,  2 )  as  min_handling_time,
    ROUND( MAX (
        CASE
 
            WHEN
 resolution_time  IS  NOT NULL  
            THEN
 EXTRACT (EPOCH  FROM  (resolution_time  -  detection_time))
            ELSE
 NULL  
        END

    ):: numeric ,  2 )  as  max_handling_time,
    ROUND(( COUNT (resolution_time):: float  /  NULLIF ( COUNT ( * ),  0 )  *  100 ):: numeric ,  2 )  as  handling_rate_percent
FROM
 all_exceptions
GROUP
 BY  exception_type
ORDER
 BY  avg_handling_time_seconds
LIMIT  100 ;
 
-- 10. 查询测试记录的时间分布和性能趋势(保持不变)

-- 查询测试记录的时间分布和性能趋势(修正版)

SELECT

    DATE_TRUNC( 'hour' , ts)  as  hour_bucket,
    COUNT
( * )  as  test_count,
    ROUND( AVG (hover_stability_index):: numeric ,  2 )  as  avg_stability,
    ROUND( AVG (position_error_xy):: numeric ,  4 )  as  avg_position_error_xy,
    ROUND( AVG (position_error_z):: numeric ,  4 )  as  avg_position_error_z,
    ROUND( AVG (attitude_error_roll):: numeric ,  4 )  as  avg_attitude_error_roll,
    ROUND( AVG (attitude_error_pitch):: numeric ,  4 )  as  avg_attitude_error_pitch,
    ROUND( AVG (attitude_error_yaw):: numeric ,  4 )  as  avg_attitude_error_yaw,
    ROUND( AVG (velocity_response_time):: numeric ,  4 )  as  avg_response_time
FROM
 px4_simulation.flight_performance_baseline
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  DATE_TRUNC( 'hour' , ts)
ORDER
 BY  hour_bucket  DESC
LIMIT  100 ;
 
 
-- 11. 查询通信质量分析(保持不变)

SELECT

    simulation_id,
    link_type,
    COUNT
( * )  as  sample_count,
    ROUND( AVG (rssi_dbm):: numeric ,  2 )  as  avg_rssi_dbm,
    ROUND( AVG (packet_loss_rate):: numeric ,  4 )  as  avg_packet_loss,
    ROUND( AVG (latency_ms):: numeric ,  2 )  as  avg_latency_ms,
    ROUND( AVG (jitter_ms):: numeric ,  2 )  as  avg_jitter_ms,
    ROUND( MIN (link_margin_db):: numeric ,  2 )  as  min_link_margin,
    ROUND( MAX (link_margin_db):: numeric ,  2 )  as  max_link_margin,
    SUM
( CASE  WHEN  packet_loss_rate  >  0.1  THEN  1  ELSE  0  END )  as  high_loss_samples
FROM
 px4_simulation.communication_quality
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  simulation_id, link_type
ORDER
 BY  avg_packet_loss  DESC
LIMIT  100 ;
 
-- 12. 查询环境适应能力分析(保持不变)

SELECT

    simulation_id,
    environment_type,
    COUNT
( * )  as  sample_count,
    ROUND( AVG (wind_speed_estimated):: numeric ,  2 )  as  avg_wind_speed,
    ROUND( AVG (turbulence_intensity):: numeric ,  4 )  as  avg_turbulence,
    ROUND( AVG (position_hold_error):: numeric ,  4 )  as  avg_position_error,
    ROUND( AVG (power_consumption_factor):: numeric ,  4 )  as  avg_power_factor,
    ROUND( AVG (attitude_correction_roll):: numeric ,  4 )  as  avg_roll_correction,
    ROUND( AVG (attitude_correction_pitch):: numeric ,  4 )  as  avg_pitch_correction
FROM
 px4_simulation.environmental_adaptation
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  simulation_id, environment_type
ORDER
 BY  avg_position_error  DESC
LIMIT  100 ;
 
-- 13. 查询参数调优历史分析(修正:添加GROUP BY中的performance_score或使用聚合函数)

SELECT

    simulation_id,
    parameter_name,
    COUNT
( * )  as  tuning_count,
    ROUND( MIN (parameter_value):: numeric ,  4 )  as  min_value,
    ROUND( MAX (parameter_value):: numeric ,  4 )  as  max_value,
    ROUND( AVG (parameter_value):: numeric ,  4 )  as  avg_value,
    ROUND( AVG (performance_score):: numeric ,  2 )  as  avg_performance,
    tuner_name,
    MAX
(ts)  as  last_tuning_time
FROM
 px4_simulation.parameter_tuning
WHERE
 ts  >=  NOW()  -  INTERVAL  '24 hours'
GROUP
 BY  simulation_id, parameter_name, tuner_name
ORDER
 BY  tuning_count  DESC
LIMIT  100 ;
 


在 KaiwuDB 开发者中心中执行上述命令,结果如下,从执行日志中可以看出,每条查询语句都在毫秒级,查询任务总用时不超过 2 秒,相比于传统的关系数据库性能显著提升。





3.3 数据库监控


KaiwuDB  集成 Prometheus 和 Grafana 开源组件监控数据库状态。


3.3.1 部署 Prometheus


Prometheus 是一款开源的系统监控和告警平台,用于采集和存储  KaiwuDB  集群的监控和性能指标信息。Grafana 是一款开源的数据可视化工具,可以从多种数据源获取数据,并在数据面板中展示所有数据。Grafana 读取  KaiwuDB  集群的指标数据,以可视化方式展示数据库的集群节点状态、监控指标。

①  载:Prometheus下载链接  https://prometheus.io/download/

以下示例解压缩 Prometheus v3.5.1 安装包。

tar -zxvf prometheus-3.5.1.linux-amd64.tar.gz

在 Prometheus-3.5.1.linux-amd64 目录下创建 rules 子目录。

Rules 文件下载链接: https://gitee.com/kwdb/kwdb/tree/master/kwbase/monitoring/rules

②  规则文件配置:

下载 Prometheus 告警规则和聚合规则配置文件并将其放置在 rules 子目录。

KaiwuDB 在 monitoring/rules 目录下提供 alerts.rules.yml 和 aggregation.rules.yml 文件。有关告警规则配置项和聚合规则配置项的详细信息,参见 Prometheus 告警规则和 Prometheus 聚合规则。

  alerts.rules.yml:告警规则配置文件。

  aggregation.rules.yml:聚合规则配置文件



cd prometheus-2.53.0.linux-amd64 &&


sudo gedit prometheus.yml

以下是 3.5.1 配置文件示例。用户可以根据版本及实际部署情况,调整配置参数及取值。


global:


  scrape_interval:  10s
  evaluation_interval:  10s

rule_files:
  -
 "rules/alerts.rules.yml"
  -
 "rules/aggregation.rules.yml"

scrape_configs:
  -
 job_name:  'kaiwudb'
    metrics_path:  '/_status/vars'
    
    # 根据实际情况选择http或https

    scheme:  'http'   # 如果KaiwuDB开启了TLS则改为https
    
    # 如果是https,需要配置TLS(可选)

    tls_config:
      insecure_skip_verify:  true   # 自签名证书时设为true
    
    # 可添加认证信息(如果KaiwuDB需要认证)

    # basic_auth:

    #   username: 'prometheus'

    #   password: 'your-password'

    
    static_configs:
      -
 targets:  
          -
 '10.0.1.100:8080'   # KaiwuDB节点1
          -
 '10.0.1.101:8080'   # KaiwuDB节点2
          -
 '10.0.1.102:8080'   # KaiwuDB节点3
        labels:
          cluster:  'production-kaiwudb-cluster'
          environment:  'production'
          region:  'us-east-1'
    
    # 可以添加重试和超时设置

    scrape_timeout:  5s
    honor_labels:  true

③ 启动 Prometheus 服务。

./prometheus --config.file=prometheus.yml

默认情况下,Prometheus 的启动端口是 9090。用户可以按需修改 Prometheus 的启动端口。

④ 登录 Prometheus。

默认情况下,Prometheus 的登录地址是  http://localhost:9090。启动 Prometheus 服务后,用户即可通过该地址访问 Prometheus。


3.3.2 部署 Grafana


① 下载 Grafana 安装包 并解压缩到本地目录。

以下示例下载 Grafana v11.1.0 安装包。


wget https://dl.grafana.com/enterprise/release/grafana-enterprise-11.1.0.linux-amd64.tar.gz


tar -zxvf grafana-enterprise-11.1.0.linux-amd64.tar.gz

② 启动 Grafana 服务。


cd grafana-v11.1.0/bin


./grafana-server



3.3.3 配置 Grafana


添加 Prometheus 数据源。

① 登 录 Grafan a。

默认情况下,Grafana 的登录地址是  http://localhost:3000。用户可以使用默认的用户名和密码(均为 admin)登录 Grafana。

•  在 Grafana 左侧边栏,单击   Connections  >  Data sources

  在  Data sources  窗口,单击  Add data source ,然后选择  Prometheus


undefined


•  配置 Prometheus 的相关信息。

  • Name :数据源的名称。

  • URL :Prometheus Server 的 IP 地址。

  • 按需配置其它字段。

•  单击  Save & test ,保存 Prometheus 数据源。

② 导入 Grafana 面板

默认情况下, KaiwuDB  在 monitoring/grafana-dashboards 目录下提供以下指标面板模板。用户将指标面板模板(.json 格式)导入 Grafana 后,即可监控  KaiwuDB  集群。

•  概览:展示集群和节点的关键指标。

•  硬件:展示硬件相关的监控指标。

•  运行时:展示运行时相关的监控指标。

•  SQL:展示 SQL 相关的监控指标。

•  存储:展示存储相关的监控指标。

•  副本:展示副本相关的监控指标。

•  分布式:展示分布式相关的监控指标。

•  队列:展示队列相关的监控指标。

•  慢查询:展示慢查询相关的监控指标。


如需导入  KaiwuDB  指标面板,遵循以下步骤。

•  在 Grafana 左侧边栏,单击  Dashboards

•  在  Dashboard  窗口,单击  New ,然后从下列菜单中选择  Import

•  上传目标面板文件,然 后单击  Load


undefined

说明

默认情况下, KaiwuDB  在 monitoring/grafana-dashboards 目录下提供以下指标模板。 KaiwuDB  各指标面板对应的文件名如下所示:

•  概览:1.KaiwuDB_Console_Overview.json

•  硬件:2.KaiwuDB_Console_Hardware.json

•  运行时:3.KaiwuDB_Console_Runtime.json

•  SQL:4.KaiwuDB_Console_SQL.json

•  存储:5.KaiwuDB_Console_Storage.json

•  副本:6.KaiwuDB_Console_Replication.json

•  分布式:7.KaiwuDB_Console_Distribution.json

•  队列:8.KaiwuDB_Console_Queue.json

•  慢查询:9.KaiwuDB_Console_Slow_Query.json

(可选)在 Grafana 左侧边栏,单击 Dashboards,然后选择任一指标模板,即可查看监控指标数据。

③ 使用 Grafana 查看指标数据

Grafana 支持查看 KaiwuDB 集群及各个节点的监控指标,包括指标概览、硬件指标、运行指标、SQL 指标、存储指标、副本指标、分布式指标、队列指标和慢查询指标。

undefined

undefined

undefined

undefined

undefined

undefined

undefined

undefined

undefined

undefined


总结

基于上述在 PX4-ROS2 无人机仿真场景中的实践,可以清晰地看到,面对仿真产生的海量、高并发、强时序数据流,传统关系型数据库在写入性能、查询效率、存储成本和数据模型适配性上均存在显著瓶颈,已成为制约研发效率与仿真规模的关键因素。

而分布式多模数据库  KaiwuDB  则以其专为时序和 AIoT 场景设计的架构,提供了一整套精准、高效的解决方案,其核心优势与应用价值体现在:

卓越的性能表现,保障仿真实时性 :凭借其时序引擎, KaiwuDB  轻松实现 每秒百万级数据点的高性能写入与毫秒级查询响应。这确保了在多机、高频仿真中,数据能够被实时、不间断地持久化,同时支持工程师对任意历史片段进行即时回溯与分析,彻底告别了因数据堆积而导致的查询等待,极大提升了调试与验证效率。

极高的存储效率,降低长期运维成本 :通过列式存储与高效压缩算法, KaiwuDB  为仿真时序数据提供了高达  5-30 倍的压缩比。这意味着在存储相同规模历史数据时,可 节省超过 90% 的存储空间,显著降低了数据的长期归档与管理成本,使得保存全生命周期仿真数据以供回归测试和趋势分析变得经济可行。

多模融合能力,支撑复杂业务分析 KaiwuDB  超越了单一时序数据库的范畴。其多模架构允许在同一数据库内无缝管理时序数据(如传感器流)、关系型数据(如飞控参数表)和事件数据(如模式切换日志)。通过跨模计算,可以轻松实现如“将特定异常震动与当时飞控指令关联分析”的复杂查询,为系统级问题定位和性能优化提供了强大支持。

强大的生态兼容与云边端协同 :兼容 PostgreSQL 协议使得现有基于 SQL 的工具链和开发经验可以平滑迁移, 降低了学习与集成门槛。同时,其云边端一体化部署能力,为构建从仿真边缘节点(如运行 ROS2 的工控机)到中心云端的统一数据管道奠定了基础,支持数据的集中管理、分布式分析与协同处理。

面向未来的数据智能底座 KaiwuDB  的定位不仅是高性能存储,更是 “面向 AIoT 场景”。它为仿真数据平台沉淀的高质量、结构化数据提供了理想的承载与分析环境。基于此,可以更便捷地集成机器学习框架,进行飞控算法异常检测、自主飞行策略优化或数字孪生模型训练,从而推动无人机仿真从“测试验证”走向“数据驱动研发”与“智能化分析”的新阶段。

总结而言,在 PX4-ROS2 无人机仿真体系中引入  KaiwuDB ,并非简单的数据库替换,而是对仿真数据基础设施的一次全面升级。 它精准地解决了海量时序数据带来的核心痛点,并通过多模融合与高性能分析能力,将仿真数据从存档文件转变为可实时洞察、可深 度挖掘、可 驱动决策的核心资产,为无人机系统的快速迭代、算法优化与智能化演进构建了坚实、高效的数据底座。



请使用浏览器的分享功能分享到微信等