轨迹规划 | 图解最优控制LQR算法(附ROS C++/Python/Matlab仿真)
目录
- 0 专栏介绍
- 1 最优控制理论
- 2 线性二次型问题
- 3 LQR的价值迭代推导
- 4 基于差速模型的LQR控制
- 5 仿真实现
- 5.1 ROS C++实现
- 5.2 Python实现
- 5.3 Matlab实现
0 专栏介绍
🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。
🚀详情:图解自动驾驶中的运动规划(Motion Planning),附几十种规划算法
1 最优控制理论
最优控制理论是一种数学和工程领域的理论,旨在寻找如何使系统在给定约束条件下达到最佳性能的方法。它的基本思想是通过选择合适的控制输入,以最小化或最大化某个性能指标来优化系统的行为。其中,系统的动态行为通常用状态方程描述,状态表示系统在某一时刻的内部状态。状态空间表示将系统的状态和控制输入表示为向量,通常用微分方程或差分方程来描述系统的演化。在最优控制理论中,会设置代价函数或者目标函数,用来衡量系统行为的好坏的函数。性能指标可以是各种形式,如最小化路径长度、最小化能量消耗、最大化系统稳定性等。最优控制理论在许多领域都有广泛的应用,包括航空航天、机器人学、经济学、生态学等。
2 线性二次型问题
若系统动力学特性可以用一组线性微分方程表示,且性能指标为状态变量和控制变量的二次型函数,则此类最优控制问题称为线性二次型问题。线性二次调节器(Linear Quadratic Regulator, LQR)是求解线性二次型问题常用的求解方法之一,其假设系统零输入且期望状态为零。

如图所示的全状态反馈控制系统。设控制误差 x k = z k − z k ∗ \boldsymbol{x}_k=\boldsymbol{z}_k-\boldsymbol{z}_{k}^{*} xk=zk−zk∗,其中 z k \boldsymbol{z}_k zk、 z k ∗ \boldsymbol{z}_{k}^{*} zk∗分别是第 k k k个控制时间步的实际状态和期望状态,则全反馈控制律由误差驱动
v k = v k ∗ − K x k ⇔ u = v − v ∗ u k = − K x k \boldsymbol{v}_k=\boldsymbol{v}_{k}^{*}-\boldsymbol{Kx}_k\xLeftrightarrow{\boldsymbol{u}=\boldsymbol{v}-\boldsymbol{v}^*}\boldsymbol{u}_k=-\boldsymbol{Kx}_k vk=vk∗−Kxku=v−v∗ uk=−Kxk
上式表明可以通过选取状态变量和输入变量,使系统等效为零输入(跟踪期望输入)且期望状态为零(消除状态误差),满足应用LQR进行最优控制的条件。定义代价函数
J = ∑ k = 0 N ( x k T Q x k + u k T R u k ) J=\sum_{k=0}^N{\left( \boldsymbol{x}_{k}^{T}\boldsymbol{Qx}_k+\boldsymbol{u}_{k}^{T}\boldsymbol{Ru}_k \right)} J=k=0∑N(xkTQxk+ukTRuk)
其中 Q \boldsymbol{Q} Q与 R \boldsymbol{R} R是用户设定的半正定矩阵,前者衡量了系统状态向期望轨迹的收敛速度,后者衡量了系统能量消耗的相对大小,二者互相制约——希望系统快速收敛往往需要加强控制力度,导致能量耗散。因此, 与 需要结合具体场景进行调节。
3 LQR的价值迭代推导
针对 J J J进行优化,引入价值迭代策略,价值迭代的理论基础请看Pytorch深度强化学习1-4:策略改进定理与贝尔曼最优方程详细推导
J k ( x k , u k ) = min u k [ x k T Q x k + u k T R u k + J k + 1 ( x k + 1 ) ] J_k\left( \boldsymbol{x}_k,\boldsymbol{u}_k \right) =\underset{\boldsymbol{u}_k}{\min}\left[ \boldsymbol{x}_{k}^{T}\boldsymbol{Qx}_k+\boldsymbol{u}_{k}^{T}\boldsymbol{Ru}_k+J_{k+1}\left( \boldsymbol{x}_{k+1} \right) \right] Jk(xk,uk)=ukmin[xkTQxk+ukTRuk+Jk+1(xk+1)]
即第 k k k步到终端的代价等于当前步的代价与第 k + 1 k+1 k+1步到终端的代价之和。根据 J J J的定义,其一定能表示成二次型 J k = x k T P k x k J_k=\boldsymbol{x}_{k}^{T}\boldsymbol{P}_k\boldsymbol{x}_k Jk=xkTPkxk,对于优化问题 u k = a r g min u k J k ( x k , u k ) \boldsymbol{u}_k=\mathrm{arg}\min _{\boldsymbol{u}_k}J_k\left( \boldsymbol{x}_k,\boldsymbol{u}_k \right) uk=argminukJk(xk,uk),令
∂ J k ( x k , u k ) ∂ u k = ∂ ∂ u k ( x k T P k x k + u k T R u k + J k + 1 ( A x k + B u k ) ) = ∂ ∂ u k ( u k T R u k + ( A x k + B u k ) T P k + 1 ( A x k + B u k ) ) = 2 ( R + B T P k + 1 B ) u k + 2 B T P k + 1 A x k = 0 \begin{aligned}\frac{\partial J_k\left( \boldsymbol{x}_k,\boldsymbol{u}_k \right)}{\partial \boldsymbol{u}_k}&=\frac{\partial}{\partial \boldsymbol{u}_k}\left( \boldsymbol{x}_{k}^{T}\boldsymbol{P}_k\boldsymbol{x}_k+\boldsymbol{u}_{k}^{T}\boldsymbol{Ru}_k+J_{k+1}\left( \boldsymbol{Ax}_k+\boldsymbol{Bu}_k \right) \right) \\&=\frac{\partial}{\partial \boldsymbol{u}_k}\left( \boldsymbol{u}_{k}^{T}\boldsymbol{Ru}_k+\left( \boldsymbol{Ax}_k+\boldsymbol{Bu}_k \right) ^T\boldsymbol{P}_{k+1}\left( \boldsymbol{Ax}_k+\boldsymbol{Bu}_k \right) \right) \\&=2\left( \boldsymbol{R}+\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{B} \right) \boldsymbol{u}_k+2\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{Ax}_k\\&=0\end{aligned} ∂uk∂Jk(xk,uk)=∂uk∂(xkTPkxk+ukTRuk+Jk+1(Axk+Buk))=∂uk∂(ukTRuk+(Axk+Buk)TPk+1(Axk+Buk))=2(R+BTPk+1B)uk+2BTPk+1Axk=0
则 u k ∗ = − ( R + B T P k + 1 B ) − 1 B T P k + 1 A x k \boldsymbol{u}_{k}^{*}=-\left( \boldsymbol{R}+\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{B} \right) ^{-1}\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{Ax}_k uk∗=−(R+BTPk+1B)−1BTPk+1Axk,对比 u k = − K x k \boldsymbol{u}_k=-\boldsymbol{Kx}_k uk=−Kxk可得
K k = ( R + B T P k + 1 B ) − 1 B T P k + 1 A \boldsymbol{K}_k=\left( \boldsymbol{R}+\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{B} \right) ^{-1}\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{A} Kk=(R+BTPk+1B)−1BTPk+1A
将 u k = − K x k \boldsymbol{u}_k=-\boldsymbol{Kx}_k uk=−Kxk代入 J k J_k Jk可得
J k = x k T P k x k = x k T ( Q + K k T R K k + ( A − B K k ) P k + 1 ( A − B K k ) ) x k J_k=\boldsymbol{x}_{k}^{T}\boldsymbol{P}_k\boldsymbol{x}_k=\boldsymbol{x}_{k}^{T}\left( \boldsymbol{Q}+\boldsymbol{K}_{k}^{T}\boldsymbol{RK}_k+\left( \boldsymbol{A}-\boldsymbol{BK}_k \right) \boldsymbol{P}_{k+1}\left( \boldsymbol{A}-\boldsymbol{BK}_k \right) \right) \boldsymbol{x}_k Jk=xkTPkxk=xkT(Q+KkTRKk+(A−BKk)Pk+1(A−BKk))xk
从而
P k = Q + A T P k + 1 A − A T P k + 1 B ( R + B T P k + 1 B ) − 1 B T P k + 1 A \boldsymbol{P}_k=\boldsymbol{Q}+\boldsymbol{A}^T\boldsymbol{P}_{k+1}\boldsymbol{A}-\boldsymbol{A}^T\boldsymbol{P}_{k+1}\boldsymbol{B}\left( \boldsymbol{R}+\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{B} \right) ^{-1}\boldsymbol{B}^T\boldsymbol{P}_{k+1}\boldsymbol{A} Pk=Q+ATPk+1A−ATPk+1B(R+BTPk+1B)−1BTPk+1A
称为离散迭代黎卡提方程。根据贝尔曼最优原理,在迭代过程中 P k \boldsymbol{P}_k Pk会逐步收敛。
4 基于差速模型的LQR控制
根据差分机器人运动学模型
p ˙ = [ x ˙ y ˙ θ ˙ ] = [ v cos θ v sin θ ω ] = [ f 1 f 2 f 3 ] \boldsymbol{\dot{p}}=\left[ \begin{array}{c} \dot{x}\\ \dot{y}\\ \dot{\theta}\\\end{array} \right] =\left[ \begin{array}{c} v\cos \theta\\ v\sin \theta\\ \omega\\\end{array} \right] =\left[ \begin{array}{c} f_1\\ f_2\\ f_3\\\end{array} \right] p˙= x˙y˙θ˙ = vcosθvsinθω = f1f2f3
选择状态量 p = [ x y θ ] T \boldsymbol{p}=\left[ \begin{matrix} x& y& \theta\\\end{matrix} \right] ^T p=[xyθ]T和状态误差量 x = [ x − x r y − y r θ − θ r ] T \boldsymbol{x}=\left[ \begin{matrix} x-x_r& y-y_r& \theta -\theta _r\\\end{matrix} \right] ^T x=[x−xry−yrθ−θr]T,控制量 s = [ v ω ] T \boldsymbol{s}=\left[ \begin{matrix} v& \omega\\\end{matrix} \right] ^T s=[vω]T和控制误差量 u = [ v − v r ω − ω r ] T \boldsymbol{u}=\left[ \begin{matrix} v-v_r& \omega -\omega _r\\\end{matrix} \right] ^T u=[v−vrω−ωr]T,可得
x ( k + 1 ) = ( T A + I ) x ( k ) + T B u ( k ) \boldsymbol{x}\left( k+1 \right) =\left( T\boldsymbol{A}+\boldsymbol{I} \right) \boldsymbol{x}\left( k \right) +T\boldsymbol{Bu}\left( k \right) x(k+1)=(TA+I)x(k)+TBu(k)
其中
A = [ 0 0 − v r sin θ r 0 0 v r cos θ r 0 0 0 ] , B = [ cos θ r 0 sin θ r 0 0 1 ] \boldsymbol{A}=\left[ \begin{matrix} 0& 0& -v_r\sin \theta _r\\ 0& 0& v_r\cos \theta _r\\ 0& 0& 0\\\end{matrix} \right] , \boldsymbol{B}=\left[ \begin{matrix} \cos \theta _r& 0\\ \sin \theta _r& 0\\ 0& 1\\\end{matrix} \right] A= 000000−vrsinθrvrcosθr0 ,B= cosθrsinθr0001
接着按照LQR算法求解即可。
5 仿真实现
5.1 ROS C++实现
核心代码如下所示
Eigen::Vector2d LQRPlanner::_lqrControl(Eigen::Vector3d s, Eigen::Vector3d s_d, Eigen::Vector2d u_r)
{Eigen::Vector2d u;Eigen::Vector3d e(s - s_d);e[2] = regularizeAngle(e[2]);// state equation on errorEigen::Matrix3d A = Eigen::Matrix3d::Identity();A(0, 2) = -u_r[0] * sin(s_d[2]) * d_t_;A(1, 2) = u_r[0] * cos(s_d[2]) * d_t_;Eigen::MatrixXd B = Eigen::MatrixXd::Zero(3, 2);B(0, 0) = cos(s_d[2]) * d_t_;B(1, 0) = sin(s_d[2]) * d_t_;B(2, 1) = d_t_;// discrete iteration Ricatti equationEigen::Matrix3d P, P_;P = Q_;for (int i = 0; i < max_iter_; ++i){Eigen::Matrix2d temp = R_ + B.transpose() * P * B;P_ = Q_ + A.transpose() * P * A - A.transpose() * P * B * temp.inverse() * B.transpose() * P * A;if ((P - P_).array().abs().maxCoeff() < eps_iter_)break;P = P_;}// feedbackEigen::MatrixXd K = -(R_ + B.transpose() * P_ * B).inverse() * B.transpose() * P_ * A;u = u_r + K * e;return u;
}

5.2 Python实现
核心代码如下所示
def lqrControl(self, s: tuple, s_d: tuple, u_r: tuple) -> np.ndarray:dt = self.params["TIME_STEP"]# state equation on errorA = np.identity(3)A[0, 2] = -u_r[0] * np.sin(s_d[2]) * dtA[1, 2] = u_r[0] * np.cos(s_d[2]) * dtB = np.zeros((3, 2))B[0, 0] = np.cos(s_d[2]) * dtB[1, 0] = np.sin(s_d[2]) * dtB[2, 1] = dt# discrete iteration Ricatti equationP, P_ = np.zeros((3, 3)), np.zeros((3, 3))P = self.Q# iterationfor _ in range(self.lqr_iteration):P_ = self.Q + A.T @ P @ A - A.T @ P @ B @ np.linalg.inv(self.R + B.T @ P @ B) @ B.T @ P @ Aif np.max(P - P_) < self.eps_iter:breakP = P_# feedbackK = -np.linalg.inv(self.R + B.T @ P_ @ B) @ B.T @ P_ @ Ae = np.array([[s[0] - s_d[0]], [s[1] - s_d[1]], [self.regularizeAngle(s[2] - s_d[2])]])u = np.array([[u_r[0]], [u_r[1]]]) + K @ ereturn np.array([[self.linearRegularization(float(u[0]))], [self.angularRegularization(float(u[1]))]])

5.3 Matlab实现
核心代码如下所示
function u = lqrControl(s, s_d, u_r, robot, param)dt = param.dt;% state equation on errorA = eye(3);A(1, 3) = -u_r(1) * sin(s_d(3)) * dt;A(2, 3) = u_r(1) * cos(s_d(3)) * dt;B = zeros(3, 2);B(1, 1) = cos(s_d(3)) * dt;B(2, 1) = sin(s_d(3)) * dt;B(3, 2) = dt;% discrete iteration Ricatti equationP = param.Q;% iterationfor i=1:param.lqr_iterationP_ = param.Q + A' * P * A - A' * P * B / (param.R + B' * P * B) * B' * P * A;if max(P - P_) < param.eps_iterbreak;endP = P_;end% feedbackK = -inv(param.R + B' * P_ * B) * B' * P_ * A;e = [s(1) - s_d(1); s(2) - s_d(2); regularizeAngle(s(3) - s_d(3))];u = [u_r(1); u_r(2)] + K * e;u = [linearRegularization(robot, u(1), param), angularRegularization(robot, u(2), param)];
end

完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏:
- 《ROS从入门到精通》
- 《Pytorch深度学习实战》
- 《机器学习强基计划》
- 《运动规划实战精讲》
- …
相关文章:
轨迹规划 | 图解最优控制LQR算法(附ROS C++/Python/Matlab仿真)
目录 0 专栏介绍1 最优控制理论2 线性二次型问题3 LQR的价值迭代推导4 基于差速模型的LQR控制5 仿真实现5.1 ROS C实现5.2 Python实现5.3 Matlab实现 0 专栏介绍 🔥附C/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全…...
工业视觉检测
目录 我对工业视觉检测的了解 一、关键组成部分 二、应用场景 三、技术挑战 我对工业视觉检测的了解 工业视觉检测是利用机器视觉技术对产品质量进行自动化检查的过程,它在制造业中扮演着至关重要的角色,用于确保产品质量、提高生产效率、减少人工成…...
wheeltec轮趣ROS教育机器人的网络连接
一、术语解析 宿主机:宿主机是指物理主机,比如用于开发测试的笔记本电脑和台式机电脑。 虚拟机:虚拟机是指安装在宿主机的VMware,推荐在宿主机上安装虚拟机,官方提供虚拟机的镜像以及配套的开发环境。 ROS主机&…...
【Linux ARM 裸机】开发环境搭建
1、Ubuntu 和 Windows 文件互传 使用过程中,要频繁进行 Ubuntu 和 Windows 的文件互传,需要使用 FTP 服务; 1.1、开启 Ubuntu 下的 FTP 服务 //安装 FTP 服务 sudo apt-get install vsftpd //修改配置文件 sudo vi /etc/vsftpd.conf//重启…...
怎么保证缓存与数据库的最终一致性?
目录 零.读数据的标准操作 一.Cache aside Patten--旁路模式 二.Read/Write Through Pattern--读写穿透 三.Write Back Pattern--写回 四.运用canal监听mysql的binlog实现缓存同步 零.读数据的标准操作 这里想说的是不管哪种模式读操作都是一样的,这是一种统一…...
免费SSL通配符证书/SSL泛域名证书获取教程
我们先基本了解什么是SSL证书以及其作用。SSL证书是一种数字证书,它通过为网站提供身份验证和数据加密服务,从而保护网站的用户信息安全。当我们在浏览器的地址栏看到“https”和绿色锁标志时,就表示该网站使用了SSL证书。 那么什么又是通配…...
mysql结构与sql执行流程
Mysql的大体结构 客户端:用于链接mysql的软件 连接池: sql接口: 查询解析器: MySQL连接层 连接层: 应用程序通过接口(如odbc,jdbc)来连接mysql,最先连接处理的是连接层。 连接层…...
vue快速入门(十二)v-key索引标志
注释很详细,直接上代码 新增内容 v-key的使用场景数组筛选器的使用 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-…...
智能网联汽车自动驾驶数据记录系统DSSAD数据配置
目录 第一章 数据配置一般要求 第二章 数据配置文件中的文件描述 第三章 数据配置文件中的数据描述 第四章 数据配置文件中的数据字典 表A.1 数据字典格式定义 第一章 数据配置一般要求 数据配置文件数据内容应为可读的十进制数据。 数据配置文件应以文件的形式存储在自动驾驶…...
linux知识点
绝对路径用什么符号表示?当前目录、上层目录用什么表示?主目录用什么表示? 切换目录用什么命令 绝对路径: 如/etc/init.d当前目录和上层目录: ./ …/主目录: ~/切换目录: cd 怎么查看当前进程?…...
微信小程序实现滚动标签
使用scroll-view标签可实现组件滚动标签 1、list中 list.wxml代码如下: <!--pages/list/list.wxml--> <navigation-bartitle"小程序" back"{{false}}"color"black" background"#FFF"></navigation-bar><scroll-…...
大语言模型上下文窗口初探(下)
由于篇幅原因,本文分为上下两篇,上篇主要讲解上下文窗口的概念、在LLM中的重要性,下篇主要讲解长文本能否成为LLM的护城河、国外大厂对长文本的态度。 3、长文本是护城河吗? 毫无疑问,Kimi从一开始就用“长文本”占领…...
Java整合ElasticSearch8.13
1、引入Jar包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> 2、配置ES连接信息 spring:elasticsearch:# 地址uris: http://xxx:9200# 用户…...
2.网络编程-HTTP和HTTPS
目录 HTTP介绍 HTTP协议主要组成部分 GET 和 POST有什么区别 常见的 HTTP 状态码有哪些 http状态码100 HTTP1.1 和 HTTP1.0 的区别有哪些 HTTPS 和 HTTP 的区别是什么 HTTP2 和 HTTP1.1 的区别是什么 HTTP3 和 HTTP2 的区别是什么 HTTPS的请求过程 对称加密和非对称…...
MTK i500p AIoT解决方案
一、方案概述 i500p是一款强大而高效的AIoT平台,专为便携式、家用或商用物联网应用而设计,这些应用通常需要大量的边缘计算,需要强大的多媒体功能和多任务操作系统。该平台集成了Arm Cortex-A73 和 Cortex-A53 的四核集群,工作频…...
ES入门十四:分词器
我们存储到ES中数据大致分为以下两种: 全文本,例如文章内容、通知内容精确值,如实体Id 在对这两类值进行查询的时候,精确值类型会比较它们的二进制,其结果只有相等或者不想等。而对全文本类型进行等值比较是不太实现…...
汇编——SSE打包整数
SSE也可以进行整数向量的加法,示例如下: ;sse_integer.asm extern printfsection .datadummy db 13 align 16pdivector1 dd 1dd 2dd 3dd 4pdivector2 dd 5dd 6dd 7dd 8fmt1 db "Packed Integer Vector 1: %d, %d, %d, %d",…...
动态规划(2)
动态规划(2) 文章目录 动态规划(2)1、聪明的寻宝人2、基因检测3、药剂稀释4、找相似串 1、聪明的寻宝人 #include <iostream> using namespace std; void MaxValue(int values[], int weights[], int n, int m) {int dp[21…...
JetBrains IDE 2024.1 发布 - 开发者工具
JetBrains IDE 2024.1 (macOS, Linux, Windows) - 开发者工具 CLion, DataGrip, DataSpell, Fleet, GoLand, IntelliJ IDEA, PhpStorm, PyCharm, Rider, RubyMine, WebStorm 请访问原文链接:JetBrains IDE 2024.1 (macOS, Linux, Windows) - 开发者工具࿰…...
C++ 构造函数中的参数顺序
描述: 未初始化的参数必须在初始化参数之前 正确 ✓ 写法: mother(const char* food, const char* lastName"无姓", const char* firstName "无名" ); 错误❌写法: mother(const char* lastName"无姓", …...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
