百度Apollo规划算法——OBB障碍物检测代码解析

2024-02-26 20:30

本文主要是介绍百度Apollo规划算法——OBB障碍物检测代码解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

百度Apollo规划算法——Box障碍物检测代码解析

  • 前言
  • 代码
  • 代码分析
    • f1
    • f2
    • f3
    • f4
    • f5
    • f6
  • 参考

前言

本文主要分析Apollo代码中函数bool Box::HasOverlap(const Box2d &box) const {}的数学原理。

在阅读此部分代码时,第一遍没看懂return的一堆什么意思,百度之后说是采用OBB原理,所以就去了解下OBB原理,回来看还是没太明白,直到看到了博客[1],通过博主的图解才有了进一步的了解,但对照代码还是没能完全理解,后来结合向量的相关知识,才算彻底明白了HasOverlap()实现的具体数学原理。
下面,作者仅对代码进行数学解读。

代码

直接上代码,代码路径/self_driving/Optimization/Apollo-DL-IAPS/util/box2d.cc,作者在这里将代码划分为几个部分分别解读。Apollo对Box2d的碰撞检测分为两步进行,第一步使用AABB进行粗检测(f1部分)快速剔除非碰撞的box,第二部分使用OBB进行细检测(f2~f6部分),对f1检测到有碰撞的box进一步进行检测。

bool Box2d::HasOverlap(const Box2d &box) const {// f1if (box.max_x() < min_x() || box.min_x() > max_x() || box.max_y() < min_y() ||box.min_y() > max_y()) {return false;}//f2const double shift_x = box.center_x() - center_.x();const double shift_y = box.center_y() - center_.y();const double dx1 = cos_heading_ * half_length_;const double dy1 = sin_heading_ * half_length_;const double dx2 = sin_heading_ * half_width_;const double dy2 = -cos_heading_ * half_width_;const double dx3 = box.cos_heading() * box.half_length();const double dy3 = box.sin_heading() * box.half_length();const double dx4 = box.sin_heading() * box.half_width();const double dy4 = -box.cos_heading() * box.half_width();//f3return std::abs(shift_x * cos_heading_ + shift_y * sin_heading_) <=std::abs(dx3 * cos_heading_ + dy3 * sin_heading_) +std::abs(dx4 * cos_heading_ + dy4 * sin_heading_) +half_length_ &&//f4std::abs(shift_x * sin_heading_ - shift_y * cos_heading_) <=std::abs(dx3 * sin_heading_ - dy3 * cos_heading_) +std::abs(dx4 * sin_heading_ - dy4 * cos_heading_) +half_width_ &&//f5std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading()) <=std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading()) +std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading()) +box.half_length() &&//f6std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading()) <=std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading()) +std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading()) +box.half_width();
}

代码分析

f1

AABB检测用于粗检测,根据自车和障碍物的box角点构建两个长宽分别平行于坐标轴的box,查看这两个box(两个虚线box表示)是否有交集,可以直接根据新构建的box的角点的坐标值来判断。如下图所示,通过这种方式可以粗略检测到A、B有碰撞,但是是否真的有碰撞还需要通过OBB进一步检测。
AABB

f2

根据OBB检测原理,构建向量如下图所示:
分离轴投影
假设有两个Box类型的对象A和B,计算A.HasOverlap(B)的结果。
以下两行代码计算的时A的中心到B的中心的向量

  const double shift_x = box.center_x() - center_.x();const double shift_y = box.center_y() - center_.y();

转换为数学计算为:
a b ⃗ = ( x s h i f t , y s h i f t ) = ( B . x c e n t e r − A . x c e n t e r , B . y c e n t e r − A . y c e n t e r ) (1) \vec{ab}=(x_{shift},y_{shift})=(B.x_{center}-A.x_{center},B.y_{center}-A.y_{center})\tag{1} ab =(xshift,yshift)=(B.xcenterA.xcenter,B.ycenterA.ycenter)(1)
以下四行代码是分别计算A的纵向方向(指box的朝向)和横向方向的两个向量,其中纵向方向的向量模为 l e n g t h h a l f length_{half} lengthhalf,横向方向的向量模为 w i d t h h a l f width_{half} widthhalf

  const double dx1 = cos_heading_ * half_length_;const double dy1 = sin_heading_ * half_length_;const double dx2 = sin_heading_ * half_width_;const double dy2 = -cos_heading_ * half_width_;

纵向向量:
v 1 ⃗ = ( d x 1 , d y 1 ) = A . l e n g t h h a l f ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) (2) \vec{v_1}=(dx1,dy1)=A.length_{half}\cdot(\cos(heading_A),\sin(heading_A))\tag{2} v1 =(dx1,dy1)=A.lengthhalf(cos(headingA),sin(headingA))(2)
横向向量:
v 2 ⃗ = ( d x 2 , d y 2 ) = A . w i d t h h a l f ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) (3) \vec{v_2}=(dx2,dy2)=A.width_{half}\cdot(\sin(heading_A),-\cos(heading_A))\tag{3} v2 =(dx2,dy2)=A.widthhalf(sin(headingA),cos(headingA))(3)
其中, h e a d i n g A heading_A headingA为A的方向角,则 ( cos ⁡ ( h e a d i n g A ) , s i n ( h e a d i n g A ) ) (\cos(heading_A),\ sin(heading_A)) (cos(headingA), sin(headingA))为A的单位方向向量, ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) (\sin(heading_A),-\cos(heading_A) (sin(headingA),cos(headingA)为A的单位法向量(为啥单位法向量这样表示?可参考线性代数相关知识)。

同理,以下四行代码分别计算的是B的纵向方向和横向方向的两个向量,纵向方向向量和横向方向向量的模分别是B的半长 l e n g t h h a l f length_{half} lengthhalf,半宽 w i d t h h a l f width_{half} widthhalf

  const double dx3 = box.cos_heading() * box.half_length();const double dy3 = box.sin_heading() * box.half_length();const double dx4 = box.sin_heading() * box.half_width();const double dy4 = -box.cos_heading() * box.half_width();

纵向向量:
v 3 ⃗ = ( d x 3 , d y 3 ) = B . l e n g t h h a l f ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) (4) \vec{v_3}=(dx3,dy3)=B.length_{half}\cdot(\cos(heading_B),\sin(heading_B))\tag{4} v3 =(dx3,dy3)=B.lengthhalf(cos(headingB),sin(headingB))(4)
横向向量:
v 4 ⃗ = ( d x 4 , d y 4 ) = B . w i d t h h a l f ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) (5) \vec{v_4}=(dx4,dy4)=B.width_{half}\cdot(\sin(heading_B),-\cos(heading_B))\tag{5} v4 =(dx4,dy4)=B.widthhalf(sin(headingB),cos(headingB))(5)
其中, h e a d i n g B heading_B headingB为B的方向角,则 ( cos ⁡ ( h e a d i n g B ) , s i n ( h e a d i n g B ) ) (\cos(heading_B),\ sin(heading_B)) (cos(headingB), sin(headingB))为B的单位方向向量, ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) (\sin(heading_B),-\cos(heading_B) (sin(headingB),cos(headingB)为A的单位法向量。

f3

f 3 f3 f3表示的是计算往A纵轴上的投影

std::abs(shift_x * cos_heading_ + shift_y * sin_heading_) <=std::abs(dx3 * cos_heading_ + dy3 * sin_heading_) +std::abs(dx4 * cos_heading_ + dy4 * sin_heading_) +half_length_

如下图所示
往A纵轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * cos_heading_ + shift_y * sin_heading_)所表示的是向量 a b ⃗ \vec{ab} ab 在A的纵轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ x s h i f t ⋅ cos ⁡ ( h e a d i n g A ) + y s h i f t ⋅ sin ⁡ ( h e a d i n g A ) ∣ c=|\vec{ab}\cdot(\cos(heading_A),\sin(heading_A))|=|x_{shift}\cdot\cos(heading_A)+y_{shift}\cdot\sin(heading_A)| c=ab (cos(headingA),sin(headingA))=xshiftcos(headingA)+yshiftsin(headingA)
(2)代码中std::abs(dx3 * cos_heading_ + dy3 * sin_heading_)所表示的是向量 v 3 ⃗ \vec{v_3} v3 在A的纵轴上投影的模 b 1 b1 b1,结合公式(4)可知:
b 1 = ∣ v 3 ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 3 ⋅ cos ⁡ ( h e a d i n g A ) + d y 3 ⋅ sin ⁡ ( h e a d i n g A ) ∣ b1=|\vec{v_3}\cdot(\cos(heading_A),\sin(heading_A))|=|dx3\cdot\cos(heading_A)+dy3\cdot\sin(heading_A)| b1=v3 (cos(headingA),sin(headingA))=dx3cos(headingA)+dy3sin(headingA)
代码中std::abs(dx4 * cos_heading_ + dy4 * sin_heading_)所表示的是向量 v 4 ⃗ \vec{v_4} v4 在A的纵轴上投影的模 b 2 b2 b2,结合公式(5)可知:
b 2 = ∣ v 4 ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 4 ⋅ cos ⁡ ( h e a d i n g A ) + d y 4 ⋅ sin ⁡ ( h e a d i n g A ) ∣ b2=|\vec{v_4}\cdot(\cos(heading_A),\sin(heading_A))|=|dx4\cdot\cos(heading_A)+dy4\cdot\sin(heading_A)| b2=v4 (cos(headingA),sin(headingA))=dx4cos(headingA)+dy4sin(headingA)
由上图可知:
b = b 1 + b 2 b=b1+b2 b=b1+b2
(3)代码中half_length_是向量 v 1 ⃗ \vec{v_1} v1 在其纵轴上的投影的模,另外,向量 v 2 ⃗ \vec{v_2} v2 此时在其纵轴上投影的模为0。
c 1 = b + l e n g t h h a l f c1=b+length_{half} c1=b+lengthhalf

f4

f 4 f4 f4表示的是计算往A横轴上的投影

 std::abs(shift_x * sin_heading_ - shift_y * cos_heading_) <=std::abs(dx3 * sin_heading_ - dy3 * cos_heading_) +std::abs(dx4 * sin_heading_ - dy4 * cos_heading_) +half_width_

如下图所示
往A横轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * sin_heading_ - shift_y * cos_heading_)所表示的是向量 a b ⃗ \vec{ab} ab 在A的横轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ x s h i f t ⋅ sin ⁡ ( h e a d i n g A ) − y s h i f t ⋅ cos ⁡ ( h e a d i n g A ) ∣ c=|\vec{ab}\cdot(\sin(heading_A),-\cos(heading_A))|=|x_{shift}\cdot\sin(heading_A)-y_{shift}\cdot\cos(heading_A)| c=ab (sin(headingA),cos(headingA))=xshiftsin(headingA)yshiftcos(headingA)
(2)代码中std::abs(dx3 * sin_heading_ - dy3 * cos_heading_)所表示的是向量 v 3 ⃗ \vec{v_3} v3 在A的横轴上投影的模 b 1 b1 b1,结合公式(4)可知:
b 1 = ∣ v 3 ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 3 ⋅ sin ⁡ ( h e a d i n g A ) − d y 3 ⋅ cos ⁡ ( h e a d i n g A ) ∣ b1=|\vec{v_3}\cdot(\sin(heading_A),-\cos(heading_A))|=|dx3\cdot\sin(heading_A)-dy3\cdot\cos(heading_A)| b1=v3 (sin(headingA),cos(headingA))=dx3sin(headingA)dy3cos(headingA)
代码中std::abs(dx4 * sin_heading_ - dy4 * cos_heading_)所表示的是向量 v 4 ⃗ \vec{v_4} v4 在A的横轴上投影的模 b 2 b2 b2,结合公式(5)可知:
b 2 = ∣ v 4 ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 4 ⋅ sin ⁡ ( h e a d i n g A ) − d y 4 ⋅ cos ⁡ ( h e a d i n g A ) ∣ b2=|\vec{v_4}\cdot(\sin(heading_A),-\cos(heading_A))|=|dx4\cdot\sin(heading_A)-dy4\cdot\cos(heading_A)| b2=v4 (sin(headingA),cos(headingA))=dx4sin(headingA)dy4cos(headingA)
由上图可知:
b = b 1 + b 2 b=b1+b2 b=b1+b2
(3)代码中half_width_是向量 v 2 ⃗ \vec{v_2} v2 在其横轴上的投影的模,另外,向量 v 1 ⃗ \vec{v_1} v1 此时在其横轴上投影的模为0。
c 1 = b + w i d t h h a l f c1=b+width_{half} c1=b+widthhalf

f5

f 5 f5 f5表示的是计算往B纵轴上的投影

std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading()) <=std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading()) +std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading()) +box.half_length()

如下图所示:
往B纵轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading())所表示的是向量 a b ⃗ \vec{ab} ab 在B的纵轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ x s h i f t ⋅ cos ⁡ ( h e a d i n g B ) + y s h i f t ⋅ sin ⁡ ( h e a d i n g B ) ∣ c=|\vec{ab}\cdot(\cos(heading_B),\sin(heading_B))|=|x_{shift}\cdot\cos(heading_B)+y_{shift}\cdot\sin(heading_B)| c=ab (cos(headingB),sin(headingB))=xshiftcos(headingB)+yshiftsin(headingB)
(2)代码中std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading())所表示的是向量 v 1 ⃗ \vec{v_1} v1 在B的纵轴上投影的模 a 1 a1 a1,结合公式(2)可知:
a 1 = ∣ v 1 ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 1 ⋅ cos ⁡ ( h e a d i n g B ) + d y 1 ⋅ sin ⁡ ( h e a d i n g B ) ∣ a1=|\vec{v_1}\cdot(\cos(heading_B),\sin(heading_B))|=|dx1\cdot\cos(heading_B)+dy1\cdot\sin(heading_B)| a1=v1 (cos(headingB),sin(headingB))=dx1cos(headingB)+dy1sin(headingB)
代码中std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading())所表示的是向量 v 2 ⃗ \vec{v_2} v2 在B的纵轴上投影的模 a 2 a2 a2,结合公式(3)可知:
a 2 = ∣ v 2 ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 2 ⋅ cos ⁡ ( h e a d i n g B ) + d y 2 ⋅ sin ⁡ ( h e a d i n g B ) ∣ a2=|\vec{v_2}\cdot(\cos(heading_B),\sin(heading_B))|=|dx2\cdot\cos(heading_B)+dy2\cdot\sin(heading_B)| a2=v2 (cos(headingB),sin(headingB))=dx2cos(headingB)+dy2sin(headingB)
由上图可知:
a = a 1 + a 2 a=a1+a2 a=a1+a2
(3)代码中half_length是向量 v 3 ⃗ \vec{v_3} v3 在其纵轴上的投影的模,另外,向量 v 4 ⃗ \vec{v_4} v4 此时在其纵轴上投影的模为0。
c 1 = a + l e n g t h h a l f c1=a+length_{half} c1=a+lengthhalf

f6

f 6 f6 f6表示的是计算往B横轴上的投影

std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading()) <=std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading()) +std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading()) +box.half_width()

如下图所示:
往B横轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading())所表示的是向量 a b ⃗ \vec{ab} ab 在B的横轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ x s h i f t ⋅ sin ⁡ ( h e a d i n g B ) − y s h i f t ⋅ cos ⁡ ( h e a d i n g B ) ∣ c=|\vec{ab}\cdot(\sin(heading_B),-\cos(heading_B))|=|x_{shift}\cdot\sin(heading_B)-y_{shift}\cdot\cos(heading_B)| c=ab (sin(headingB),cos(headingB))=xshiftsin(headingB)yshiftcos(headingB)
(2)代码中std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading())所表示的是向量 v 1 ⃗ \vec{v_1} v1 在B的横轴上投影的模 a 1 a1 a1,结合公式(2)可知:
a 1 = ∣ v 1 ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 1 ⋅ sin ⁡ ( h e a d i n g B ) − d y 1 ⋅ cos ⁡ ( h e a d i n g B ) ∣ a1=|\vec{v_1}\cdot(\sin(heading_B),-\cos(heading_B))|=|dx1\cdot\sin(heading_B)-dy1\cdot\cos(heading_B)| a1=v1 (sin(headingB),cos(headingB))=dx1sin(headingB)dy1cos(headingB)
代码中std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading())所表示的是向量 v 2 ⃗ \vec{v_2} v2 在B的横轴上投影的模 a 2 a2 a2,结合公式(3)可知:
a 2 = ∣ v 2 ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 2 ⋅ sin ⁡ ( h e a d i n g B ) − d y 2 ⋅ cos ⁡ ( h e a d i n g B ) ∣ a2=|\vec{v_2}\cdot(\sin(heading_B),-\cos(heading_B))|=|dx2\cdot\sin(heading_B)-dy2\cdot\cos(heading_B)| a2=v2 (sin(headingB),cos(headingB))=dx2sin(headingB)dy2cos(headingB)
由上图可知:
a = a 1 + a 2 a=a1+a2 a=a1+a2
(3)代码中half_width是向量 v 4 ⃗ \vec{v_4} v4 在其横轴上的投影的模,另外,向量 v 3 ⃗ \vec{v_3} v3 此时在其横轴上投影的模为0。
c 1 = a + w i d t h h a l f c1=a+width_{half} c1=a+widthhalf

若步骤f3~f6均满足 c < = c 1 c<=c1 c<=c1,则可判定两个Box存在碰撞(具体原理可参考OBB原理)。

参考

[1] Apollo中Lattice轨迹碰撞检测
[2]自动驾驶运动规划中的碰撞检测

这篇关于百度Apollo规划算法——OBB障碍物检测代码解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/750067

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

python多进程实现数据共享的示例代码

《python多进程实现数据共享的示例代码》本文介绍了Python中多进程实现数据共享的方法,包括使用multiprocessing模块和manager模块这两种方法,具有一定的参考价值,感兴趣的可以... 目录背景进程、进程创建进程间通信 进程间共享数据共享list实践背景 安卓ui自动化框架,使用的是

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R