嵌入式数据库SQLite 3配置使用详细笔记教程

0、惨痛教训

        随着管理开发的项目体积越来越庞大,产品系统涉及的数据量也越来越多,并且伴随着项目不久就要交付给甲方了。如果项目的数据信息没有被妥善管理,后期设备的运行状态、操作状况等数据流信息不能被溯源,当出现了一些特殊意外时,就会导致对于故障信息不能迅速准确的追踪,甚至会被甩锅、推卸责任,白白当了冤大头。因此对于嵌入式项目中,其产品运行时的数据库建立非常有必要,且是迫在眉睫!!!

        目前常用的数据库系统有:MySQL、PostgreSQL、Oracle Database、Microsoft SQL Server、SQLite等。在嵌入式项目中,前面几个数据库显然是不合适的,而SQLite是一个轻量级的数据库管理系统,它包含在一个C库中,提供了零配置、无服务器、事务性的SQL数据库引擎。所以SQLite的特点使其非常适合嵌入式系统、移动设备、小型项目或者作为应用程序的本地数据库使用。本文选用了嵌入式数据库SQLite3进行配置和讲解。

1、Sqlite3环境配置

(1)、下载安装SQLite库

根据目标系统平台,下载sqlite源码,或下载官方提供的已经编译好的库。本文目标平台是Windows11 64位平台,进入SQLite Download Page的主页,选择需要的库版本(Windows)。

下载的压缩包一共有如下所示的三个:

sqlite-dll-win-x64-3450300.zip

sqlite-dll-win-x86-3450300.zip

sqlite-tools-win-x64-3450300.zip

(2)、解压下载的文件

        本文中将对应的Sqlite库文件解压到了,C:\Program Files\sqlite路径下。

(3)、添加库路径到环境变量

        根据下图所示的步骤,进入系统属性-->环境变量-->系统变量-->编辑环境变量,将路径加入到环境变量中。

(4)、检查数据库安装状态

        打开Windows的命令行,输入sqlite3,有类似如下的数据信息说明库安装成功,后续只需在程序代码中,将库加入到工程代码中即可。

(5)、SQLiteStudio工具

        如果有可视化分析数据需求、推荐使用下载:SQLiteStudioicon-default.png?t=N7T8https://sqlitestudio.pl/

2、SQLite3基础

        SQL(Structured Query Language)是一种结构化查询语言,SQL 是一种专门用来与数据库通信的语言。

        不同的数据库管理系统在其实践过程中都对 SOL 规范作了某些改编和扩充。故不同数据库管理系统之间的 SOL语言不能完全相互通用。

        以下是SQLite的一些关键特点:

  • 零配置: SQLite不需要安装或者管理服务器进程。启动一个使用SQLite的应用程序时,数据库文件会自动创建(如果尚不存在),并且直接通过程序访问。
  • 轻量级: SQLite的代码量小,资源消耗少,对硬件要求很低。这使得它非常适合资源有限的环境,如手机、平板电脑或微型设备。
  • 跨平台: SQLite兼容几乎所有主流的操作系统,包括Windows、Linux、Unix、Android、iOS等。
  • 服务器less: 由于SQLite是嵌入式的,没有单独运行的数据库服务器进程,数据直接存储在文件中。这简化了部署和维护过程。
  • 事务处理: SQLite支持ACID(原子性、一致性、隔离性、持久性)事务,确保数据的完整性。
  • SQL标准兼容: 虽然SQLite有自己的SQL方言,但它大体上遵循ANSI SQL标准,支持大多数标准SQL语句。
  • 单一文件存储: SQLite数据库完全存储在一个磁盘文件中,这使得备份和迁移数据库变得非常简单,只需复制该文件即可。
  • 动态类型: SQLite具有弱类型特性,允许更灵活的数据存储,但也可能需要开发者更加注意数据类型的处理。
  • 广泛使用: SQLite被许多应用程序和操作系统采用,包括浏览器(如Firefox)、操作系统组件、手机应用等,是世界上最广泛部署的数据库引擎之一。

        有个重要的点值得注意,SQLite 是不区分大小写的,但也有一些命令是大小写敏感的,比如 GLOB 和 glob 在 SQLite 的语句中有不同的含义。一般数据采用固定的静态数据类型,而 SOLite 采用的是动态数据类型,会根据存入值自动判断。

SQLite 存储类:SOLite 具有以下五种基本数据类型

(1)integer:带符号的整型(最多64位)。

(2)real:8字节表示的浮点类型。

(3)text:字符类型,支持多种编码(如 UTF-8、UTF-16),大小无限制。

(4)blob:任意类型的数据,大小无限制。 BLOB(binary large obiect)二进制大对象,使用二进制保存数据。

(5)null:表示空值

SQLite 亲和类型(Affinity)及类型名称

下表列出了当创建 SQLite3 表时可使用的各种数据类型名称,同时也显示了相应的亲和类型

数据类型

亲和类型

  • INT
  • INTEGER
  • TINYINT
  • SMALLINT
  • MEDIUMINT
  • BIGINT
  • UNSIGNED BIG INT
  • INT2
  • INT8

INTEGER

  • CHARACTER(20)
  • VARCHAR(255)
  • VARYING CHARACTER(255)
  • NCHAR(55)
  • NATIVE CHARACTER(70)
  • NVARCHAR(100)
  • TEXT
  • CLOB

TEXT

  • BLOB
  • 未指定类型

BLOB

  • REAL
  • DOUBLE
  • DOUBLE PRECISION
  • FLOAT

REAL

  • NUMERIC
  • DECIMAL(10,5)
  • BOOLEAN
  • DATE
  • DATETIME

NUMERIC

SQLite 语句:所有的 SQLite 语句可以以任何关键字开始,如 SELECT、INSERT、UPDATE、DELETE、ALTER、DROP 等,所有的语句以分号 ; 结束。

3、SQLite3基本语法

(1)、创建数据库

//打开数据库,如不存在则会创建数据库
int ret = sqlite3_open("project_data.db", &db);
if( ret )
{
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    exit(-1);
}
fprintf(stderr, "Opened database successfully\n");

(2)、创建表

//CREATE TABLE 告诉数据库系统创建一个新表的关键字。CREATE TABLE 语句后跟着表的唯一的名称或标识。
CREATE TABLE database_name.table_name(
   column1 datatype  PRIMARY KEY(one or more columns),
   column2 datatype,
   column3 datatype,
   .....
   columnN datatype,
);

char table_name[200] = {0};
char *err_msg = NULL;
snprintf(table_name, sizeof(table_name), "create table if not exists camera(time_stamp integer primary key, action text, x integer, y integer, z integer, vx integer, vy integer, vz integer, time integer);");
int ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
if(ret){
    fprintf(stderr, "create table err:%s\n", err_msg);
    return -1;
}
fprintf(stderr, "create table successfully\n");

(3)、删除表

//SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据、索引、触发器、约束和该表的权限规范。
//DROP TABLE 语句的基本语法如下。
DROP TABLE database_name.table_name;

char table_name[200] = {0};
char *err_msg = NULL;
snprintf(table_name, sizeof(table_name), "DROP TABLE database_name.table_name;");
int ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
if(ret){
    fprintf(stderr, "delete table err:%s\n", err_msg);
    return -1;
}
fprintf(stderr, "delete table successfully\n");

(4)、插入数据

INSERT INTO 语句有两种基本语法,如下所示:
INSERT INTO TABLE_NAME [(column1, column2, column3,...columnN)]  VALUES (value1, value2, value3,...valueN);//在这里,column1, column2,...columnN 是要插入数据的表中的列的名称
或
INSERT INTO TABLE_NAME VALUES (value1,value2,value3,...valueN);
//确保值的顺序与列在表中的顺序一致。

char table_value[200] = {0};
int ret = 0;
char *err_msg = NULL;
snprintf(table_value, sizeof(table_value),"insert into camera values(%lld, '%c', %d, %d, %d, %d, %d, %d, %d);", get_current_timestamp_ms(), action, x, y, z, vx, vy, vz, time);
ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);
if(ret)
{
    fprintf(stderr, "insert value to table err:%s\n", err_msg);
    return -1;
}
fprintf(stderr, "insert value to table successfully\n");

(5)、查询数据

//SQLite 的 SELECT 语句用于从 SQLite 数据库表中获取数据,以结果表的形式返回数据。这些结果表也被称为结果集。
//SQLite 的 SELECT 语句的基本语法如下:
SELECT column1, column2, columnN FROM table_name;//在这里,column1, column2...是表的字段,他们的值即是您要获取的。
SELECT * FROM table_name;    //获取所有可用的字段

char *err_msg = NULL;
sprintf(sql, "select * from table_value;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{
    fprintf(stderr, "Can't select sqlite value: %s\n", sqlite3_errmsg(db));
    return -1;
}

(6)、删除数据

//SQLite 的 DELETE 查询用于删除表中已有的记录。可以使用带有 WHERE 子句的 DELETE 查询来删除选定行,否则所有的记录都会被删除。
//带有 WHERE 子句的 DELETE 查询的基本语法如下:
DELETE FROM table_name
WHERE [condition];
//可以使用 AND 或 OR 运算符来结合 N 个数量的条件。

char *err_msg = NULL;
sprintf(sql, "DELETE FROM camera WHERE time_stamp = 123456789;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{
    fprintf(stderr, "Can't DELETE sqlite data: %s\n", sqlite3_errmsg(db));
    return -1;
}

(7)、修改数据

//SQLite 的 UPDATE 查询用于修改表中已有的记录。可以使用带有 WHERE 子句的 UPDATE 查询来更新选定行,否则所有的行都会被更新。
//带有 WHERE 子句的 UPDATE 查询的基本语法如下:
UPDATE table_name
SET column1 = value1, column2 = value2...., columnN = valueN
WHERE [condition];

char *err_msg = NULL;
sprintf(sql, "UPDATE camera SET action = 't' WHERE time_stamp = 123456789;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{
    fprintf(stderr, "Can't DELETE sqlite data: %s\n", sqlite3_errmsg(db));
    return -1;
}

4、SQLite3代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sqlite3.h>

int database_init();
int write_motor_info_to_database(sqlite3 *db, int motor_id, double target_pos, double real_pos, double real_speed, double real_current);
int write_camera_info_to_database(sqlite3 *db, char action, int x, int y, int z, int vx, int vy, int vz, int time);
long long get_current_timestamp_ms(void); 

int main(void)
{
    printf("sqlite3 database test!\n");    
    database_init();
    return 0;
}

/**
  * @brief  数据库初始化
  * @param  NONE
  * @retval 成功返回0, 失败返回-1
  */
int database_init(void)  
{
    int ret = -1;
    sqlite3 *db;
    char *err_msg = NULL;
    char database_name[128] = {0};
    //获取当前时间
    struct tm t; 
    time_t now;

    time(&now);
    localtime_s(&t, &now);
    snprintf(database_name, sizeof(database_name),"%02d%02d%02d.db", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
    printf("date:%s\n", database_name);

   //打开数据库
    ret = sqlite3_open(database_name, &db);
    if( ret )
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    fprintf(stderr, "Opened database successfully\n");

    char table_name[200] = {0};
    //时间戳 目标位置 实际位置 实际速度 实际电流
    //create table if not exists motor0 (time_stamp integer primary key, target_pos real, real_pos real, real_speed real, real_current, real);
    for(int motor_id = 0; motor_id < 6; motor_id++)
    {
        snprintf(table_name, sizeof(table_name),"create table if not exists motor%d (time_stamp integer primary key, target_pos real, real_pos real, real_speed real, real_current real);", motor_id);
        ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
        if(ret)
        {
            fprintf(stderr, "create table err:%s\n", err_msg);
            return -1;
        }
        fprintf(stderr, "create table successfully\n");
    }
    memset(table_name, 0, sizeof(table_name));
    snprintf(table_name, sizeof(table_name), "create table if not exists camera(time_stamp integer primary key, action text, x integer, y integer, z integer, vx integer, vy integer, vz integer, time integer);");
    ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
    if(ret)
    {
        fprintf(stderr, "create table err:%s\n", err_msg);
        return -1;
    }
    fprintf(stderr, "create table successfully\n");

    write_motor_info_to_database(db, 0, 90.0, 87.2, 5.0, 0.85);
    write_motor_info_to_database(db, 1, 90.0, 87.2, 5.0, 0.85);
    write_motor_info_to_database(db, 2, 90.0, 87.2, 5.0, 0.85);
    write_motor_info_to_database(db, 3, 90.0, 87.2, 5.0, 0.85);
    write_motor_info_to_database(db, 4, 90.0, 87.2, 5.0, 0.85);
    write_motor_info_to_database(db, 5, 90.0, 87.2, 5.0, 0.85);
    write_camera_info_to_database(db, 't', 100,200,150,160,130,110,1000);
    
    return 0;
}

/**
  * @brief  写入电机数据到数据库中
  * @param  db:数据库文件描述符
  * @param  target_pos:目标位置
  * @param  real_pos:实际位置
  * @param  real_speed:实际速度
  * @param  real_current:实际电流
  * @retval 写入成功返回0,失败-1
  */
int write_motor_info_to_database(sqlite3 *db, int motor_id, double target_pos, double real_pos, double real_speed, double real_current)
{
    char table_value[200] = {0};
    int ret = 0;
    char *err_msg = NULL;
    //insert into motor0 values(1798345, 90.0, 88.66, 45.1, 0.97);
    snprintf(table_value, sizeof(table_value),"insert into motor%d values(%lld, %.2f, %.2f, %.2f, %.2f);", motor_id, get_current_timestamp_ms(), target_pos, real_pos, real_speed, real_current);
    ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);
    if(ret)
    {
        fprintf(stderr, "insert value to table err:%s\n", err_msg);
        return -1;
    }
    fprintf(stderr, "insert value to table successfully\n");

    return 0;
}

/**
  * @brief  写入相机数据到数据库中
  * @param  db:数据库文件描述符
  * @param  action:动作
  * @param  x:
  * @param  y:
  * @param  z:
  * @param  vx:
  * @param  vy:
  * @param  vz:
  * @retval 写入成功返回0,失败-1
  */
int write_camera_info_to_database(sqlite3 *db, char action, int x, int y, int z, int vx, int vy, int vz, int time)
{
    char table_value[200] = {0};
    int ret = 0;
    char *err_msg = NULL;
    //insert into motor0 values(1798345, 90.0, 88.66, 45.1, 0.97);
    snprintf(table_value, sizeof(table_value),"insert into camera values(%lld, '%c', %d, %d, %d, %d, %d, %d, %d);", get_current_timestamp_ms(), action, x, y, z, vx, vy, vz, time);
    ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);
    if(ret)
    {
        fprintf(stderr, "insert value to table err:%s\n", err_msg);
        return -1;
    }
    fprintf(stderr, "insert value to table successfully\n");

    return 0;
}

/**
  * @brief  获取毫秒级时间戳
  * @param  NONE
  * @retval 成功返回时间戳值,失败返回-1
  */
long long get_current_timestamp_ms(void)
{
#if defined(_WIN32) || defined(_WIN64)
    struct _timeb timebuffer;
    _ftime64_s(&timebuffer);
    return (long long)timebuffer.time * 1000 + timebuffer.millitm;
#elif defined(__unix__) || defined(__unix) || defined(unix)
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}

参考代码运行结果

使用可视化工具SQLiteStudio,对SQLite3数据库进行查看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/605319.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【35分钟掌握金融风控策略16】贷前风控策略详解-1

目录 贷前风控策略详解 贷前风控目标 精准审核申请贷款客户资质 对申请贷款客户进行合理定额 对申请贷款客户进行合理定价 推动实现利润最大化 贷前风控数据源 客户贷款时提供的数据 贷前风控策略详解 俗话说&#xff0c;良好的开端是成功的一半&#xff0c;而贷前是风…

C++新手村指南:入门基础

目录 C概念 C发展史 C关键字&#xff08;C98&#xff09; 命名空间 命名空间的定义 命名空间的使用 C中的输入&&输出 缺省参数 缺省参数的概念 缺省参数的分类 函数重载 函数重载概念 函数重载实现 引用 引用的概念 引用的特性 常引用 引用的使用场景…

基于单片机的小型自动浇灌系统设计

摘 要:以单片机为主控芯片,结合传感器和计算机,搭建了一套智能化的浇灌系统;利用LabVIEW 设计并编写了基于状态机程序架构的上位机软件,实现了友好的用户交互界面,实时测量、显示与记录等功能,并由主控芯片进行浇灌。经测试,本系统具有结构简单,研制成本低,运…

详细介绍一下PointPillars算法的网络结构

PointPillars是一种用于3D目标检测的算法&#xff0c;它主要使用了点云数据和深度学习模型。 PointPillars算法的网络结构主要可以分为三个主要阶段&#xff1a; Pillar Feature Net&#xff08;点云特征处理网络&#xff09;&#xff1a;此阶段的主要任务是将输入的点云数据转…

回答篇:测试开发高频面试题目

引用之前文章&#xff1a;《测试开发高频面试题目》 https://blog.csdn.net/qq_41214208/article/details/138193469?spm1001.2014.3001.5502 本篇文章是回答篇&#xff08;持续更新中&#xff09; 1. 什么是测试开发以及其在软件开发流程中的作用。 a. 测试开发是指测试人员或…

Java:Servlet详解

目录 一、什么是Servlet 二、Servlet原理 Servlet的生命周期 三、 Servlet注释 WebServlet 一、什么是Servlet Servlet是JavaWeb开发的一种技术&#xff0c;Servlet程序需要部署在Servlet容器&#xff08;服务端&#xff09;中才能运行&#xff0c;常见的Servlet容器有Tom…

【C++】环境搭建CentOS Clion报错Unsupported git Version 1.8.3.1

【C】环境搭建Clion-Unsupported git Version 1.8.3.1 Git升级步骤1.卸载旧版本2.安装依赖3.下载git最新版本包4.解压git文件包5.编译文件5.将git加入环境变量6.验证git版本 如上图所示&#xff0c;报错Unsupported git Version 1.8.3.1 At least 2.17.0 is required 报错意思…

windows驱动开发-inf文件(一)

驱动总是和inf文件相关&#xff0c;在WinDDK的时候&#xff0c;许多inf文件都需要开发工程师手动编写&#xff0c;不过&#xff0c;现在已经可以使用inx文件来生成inf文件了&#xff0c;它经常用于驱动的安装和卸载&#xff1b;不过&#xff0c;并不是所有的驱动都需要使用inf文…

小白修复msvcp140.dll丢失的解决方法,一键修复丢失的dll文件

在我们使用电脑时&#xff0c;常常会碰到各种烦人的状况。比方说&#xff0c;当我们期待畅玩游戏时&#xff0c;可能会突然遭遇一则令人沮丧的提示&#xff1a;“打开游戏缺少msvcp140.dll文件”。这个问题会给我们带来困扰和不愉快&#xff0c;但庆幸的是&#xff0c;有多种解…

UE4_Water插件_Buoyancy组件使用

water插件提供了一个浮力Actor蓝图类。 需要注意的几个问题&#xff1a; 1、StaticMesh需要替换根组件。 2、需要模拟物理设置质量。 3、需要添加浮力组件&#xff0c;设置浮力点&#xff0c;应用水中牵引力。 4、最重要的是需要激活——自动启用。 5、调水波长的地方 双击图片…

【JavaScript】内置对象 - Date 日期对象 ④ ( 制作倒计时页面 )

文章目录 一、倒计时页面实现1、需求分析2、计算秒数3、计算倒计时时间的 天 / 时 / 分 / 秒4、页面中显示倒计时时间 二、完整代码示例1、完整代码2、执行结果 Date 日期对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Da…

北京大学肖臻老师《区块链技术与应用》P16(状态树)和P17(交易树和收据树)

1️⃣ 参考 北京大学肖臻老师《区块链技术与应用》 P16 - ETH状态树篇P17 - ETH交易树和收据树篇 部分文字和图片 北京大学肖臻老师《区块链技术与应用》公开课笔记18——ETH数据结构篇2(状态树2)北京大学肖臻老师《区块链技术与应用》公开课笔记19——ETH数据结构篇3(交易树和…

入门视频剪辑:视频合并不再难,批量嵌套合并的简单步骤

在数字媒体时代&#xff0c;视频剪辑已成为一项基本技能。无论是制作家庭电影、公司宣传片还是在线教育内容&#xff0c;视频剪辑都扮演着重要角色。对于初学者来说&#xff0c;视频剪辑可能看起来有些复杂&#xff0c;但掌握了正确的步骤和技巧后&#xff0c;你会发现它其实并…

Angular中的路由

Angular中的路由 文章目录 Angular中的路由前言一、创建路由二、创建多个组件路由三、创建子路由四、创建多个组件子路由 前言 在Angular中&#xff0c;路由是用于在不同的视图和组件之间导航的机制。Angular提供了一种强大的路由机制来管理单页应用&#xff08;SPA&#xff0…

十九、分布式数据库MyCat

目录 一、概述 1、MyCat是什么&#xff1f; 2、原理&#xff1a; 3、能干什么 1、读写分离 2、数据分片 3、多数据源整合 4、Mycat监控 4、安装部署 1、环境准备 2、安装 3、Mycat配置详解 1、server.xml user 标签 2、schema.xml schema标签&#xff1a; table标签&…

实践遥感卫星场景海洋船只检测,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建卫星遥感场景下海洋海面船只检测识别系统

遥感相关的实践在我们前面的系列博文中也有相关的一些实践&#xff0c;胡药师基于MASTAR数据集开发构建对应的目标检测系统在前文也有一些介绍&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《基于YOLOv7开发构建MSTAR雷达影像目标检测系统》 《基于yolov5n的轻量…

多角度解析动态住宅IP的多元化应用

动态住宅IP指的是在住宅网络中使用的、能够随时间或用户需求配置的IP地址&#xff0c;能够根据网络状况自动调整&#xff0c;为用户提供更加灵活、高效的上网体验。这种IP地址不是固定不变的&#xff0c;而是会定期自动更换&#xff0c;这种IP地址也让使用者的安全得以保障。 作…

【牛客】【模板】前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 前缀和模板题。 前缀和中数组下标为1~n。 前缀和&#xff1a;pre[i]pre[i-1]a[i]; 某段区间 [l,r]的和&#xff1a;pre[r]-pre[l-1] 3.…

247 基于matlab的梁的振型仿真

基于matlab的梁的振型仿真。利用有限元理论&#xff0c;求二维梁的固有频率和振型。短边固定&#xff0c;给定长度、横截面积&#xff0c;弹性模量及材料密度已知。并对比理论计算结果进行分析。各参数自己设定。程序已调通&#xff0c;可直接运行。 247 梁的振型仿真 固有频率…

顶级SCI优化!24年新算法冠豪猪算法CPO优化无人机集群三维路径规划!先用先发!

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 结果展示 原理讲解 一、路径长度成本 F1 …