SLAM定位与地图构建
SLAM介绍
SLAM全称Simultaneous Localization And Mapping,中文名称同时定位与地图构建。旨在让移动设备在未知环境中同时完成以下两个任务(定位需要地图,而建图又依赖定位信息,两者互为依赖):
-
定位(Localization):确定自身在环境中的位置和姿态(如坐标、朝向)。
-
建图(Mapping):构建环境的地图(如2D栅格地图、3D点云地图)。
SLAM基本流程:
-
传感器数据获取
-
使用激光雷达(LiDAR)、摄像头(视觉SLAM)、IMU(惯性测量单元)、超声波等传感器采集环境数据。
-
例如:激光雷达获取点云,摄像头提取特征点。
-
-
前端处理(Frontend)
-
特征提取与匹配:从传感器数据中提取关键特征(如角点、线段、ORB特征点)。
-
运动估计:通过相邻帧数据(如两帧图像或激光扫描)估计机器人的运动(如ICP、视觉里程计VO)。
-
初步定位:计算当前位姿(位置+姿态)的变化。
-
-
后端优化(Backend)
-
位姿图优化(Pose Graph Optimization):利用图优化(如g2o、GTSAM)或滤波(如EKF、粒子滤波)消除累积误差。
-
全局一致性:确保地图和轨迹的长期准确性。
-
-
建图(Mapping)
-
根据优化后的位姿和传感器数据,构建环境的地图:
-
2D地图(如栅格地图,用于扫地机器人)。
-
3D地图(如点云地图或TSDF地图,用于自动驾驶)。
-
-
-
回环检测(Loop Closure)
-
识别机器人是否回到之前访问过的地点,以修正累积误差。
-
例如:通过视觉词袋(BoW)或激光特征匹配判断是否闭环。
-
SLAM的按传感器类型分类
-
激光SLAM(如HectorSLAM、Cartographer):使用LiDAR数据,适合结构化环境(如室内)。
-
视觉SLAM(VSLAM)(如ORB-SLAM、LSD-SLAM):使用摄像头,适合纹理丰富的场景。
-
多传感器融合SLAM(如VINS-Fusion):结合视觉+IMU+LiDAR,提升鲁棒性。
这里着重介绍激光雷达SLAM 2D地图:
机器人搭载的激光雷达通过它的驱动节点发布一个雷达数据话题/scan,激光雷达的测距数值以数据包的形式发布到/scan话题,SLAM节点只需要订阅/scan话题就能获得激光雷达的测距数值了。SLAM节点需要发布一个地图数据话题/map,将SLAM生成的地图消息发送到/map话题中,就可以使用rviz来显示地图的形状了
ROS的2D建图使用栅格地图。SLAM建图的初始状态就是就是一堆未知的栅格,颜色为灰色,栅格值为-1代表格子的障碍物状况未知。接下来使用激光雷达作为传感器获取数据,被激光雷达穿透的栅格将会被标记为白色,数值为0表示这个栅格内无障碍物,而激光被阻挡的栅格将会被标记为黑色,数值为100表示这个栅格里存在障碍物,其他没有被扫描的栅格依然为灰色。
如下图1表示机器人在初始状态激光雷达扫描一周所建图,下图2表示机器人行走一段时间后激光雷达扫描一周所建图,根据转角特征,可以将两张图进行拼合。在激光雷达SLAM中,可以合并的参照物特征是障碍物栅格的排布形状。实际上机器人移动一小段距离雷达可以扫描上百次,所以根据栅格特征合并地图比较精准。机器人不断移动,地图不断拼接,最终就会得到一个比较完整的全局地图
注意,激光雷达SLAM的建图过程并非简单地“每扫描一圈生成一个独立地图再拼接”,而是通过增量式融合和全局优化逐步构建全局地图。 基本过程如下
(1)单次扫描的数据处理
激光雷达每扫描一圈(如10Hz频率)会获取一帧点云数据(Point Cloud),但这一帧数据本身只是环境的“一片切片”,不能直接称为“地图”。
-
预处理:去除噪声、运动畸变校正(因机器人运动导致的点云扭曲)。
-
特征提取(可选):提取直线、角点等特征(如LOAM算法)。
(2)帧间匹配(Scan Matching)
将当前帧点云与上一帧(或局部地图)对齐,估计机器人的位姿变化(位移+旋转)。常用方法:
-
ICP(Iterative Closest Point):通过迭代最小化点云距离匹配两帧数据。
-
NDT(Normal Distributions Transform):将点云转换为概率分布进行匹配。
-
特征匹配(如基于线/面特征的匹配)。
(3)局部地图(Submap)构建
-
连续多帧点云会融合成一个局部地图(Submap),而非独立保存每一帧。
-
例如:Cartographer将几十次扫描的点云叠加为一个Submap,降低计算量。
(4)全局地图(Global Map)拼接
局部地图通过位姿图优化(Pose Graph Optimization)拼接为全局地图,而非简单叠加。关键步骤:
-
回环检测(Loop Closure)
-
当机器人回到之前访问的区域时,系统检测当前扫描与历史Submap的相似性(如匹配点云或特征)。
-
方法:Scan-to-Submap匹配、分支定界法(Branch-and-Bound)等。
-
-
位姿图优化
-
将回环约束、里程计约束、IMU数据等构建成图(节点=位姿,边=约束)。
-
使用优化库(如g2o、Ceres Solver)最小化全局误差,修正所有Submap的位姿。
-
-
地图融合
-
优化后的Submap位姿用于将局部地图对齐到全局坐标系中,最终拼接成一致的全局地图。
-
SLAM建图算法
1.Hector_Mapping
安装:sudo apt install ros-noetic-hector-mapping
要求激光雷达扫描频率高(如 40Hz 以上)且数据质量好
输入和输出数据
Hector_Mapping输入为/scan话题和/syscommand话题,syscommand主要用来接收reset这类重新建图的指令
Hector_Mapping输出如下
第一个map_metadata是地图数据,其消息数据类型如下,主要包括地图加载时间、地图分辨率 、地图宽和高和地图的原点坐标。显然这些都是地图的描述信息
发布的第二个话题/map就是栅格地图数据。后面两个话题slam_out_pose和poseupdate分别是原始和校正后的的机器人定位数据
关于Hector_Mapping的具体参数,可以进入ROS wiki找hector_mapping的参数
2.Gmapping
Hector_Mapping不依赖轮式里程计,仅依靠激光雷达(LIDAR)数据和高频率的扫描匹配(scan matching)实现位姿估计和建图。通过匹配当前激光扫描与已有地图的几何特征,直接优化机器人位姿。所以建图的重点就是找地图的几何特征。
但是gmapping融合激光雷达数据和轮式里程计信息,通过粒子滤波估计机器人轨迹和地图,需要里程计作为运动模型的初始估计,粒子滤波在此基础上优化位姿。也就是说建图的重点不仅在于找地图的几何特征,还有里程计信息来记录机器人走了多远。这样的好处是,如果机器人运行在一个长直走廊,由于两侧都是墙壁并且激光雷达检测到墙壁的距离是不变的,对于没有里程计信息的Hector_Mapping,ROS就会认为小车没有移动而停在原地,但是Gmapping通过里程计就可以得知机器人仍在运动,并继续建图过程。Gmapping可兼容低频率激光雷达(如 10Hz)且对里程计噪声有一定容错能力。
里程计
里程计是机器人通过自身运动传感器(如编码器、IMU、视觉等)估计相对位姿变化的技术,通常输出机器人的位移和转角(即 Δx, Δy, Δθ
)。它不依赖外部环境信息,属于递推定位(Dead Reckoning),会随着时间累积误差。
常见里程计类型
-
轮式里程计(Wheel Odometry):通过电机编码器测量轮子转动圈数,结合轮径和底盘模型计算机器人位移。
-
视觉里程计(VO, Visual Odometry):通过摄像头连续帧间的特征匹配或光流估计运动。
-
惯性里程计(IMU Odometry):使用加速度计和陀螺仪积分得到运动轨迹。
里程计(Odometry)既依赖硬件传感器获取原始数据,又需要软件算法计算位姿变化,这个算法会运行在机器人的驱动节点中,根据电机的转动数据计算机器人位移信息,这个位移信息会以tf消息包的形式发布到/tf话题中。激光雷达SLAM要输出的是map到base_footprint(小车底盘)的tf坐标变换信息,里程计要输出的是map到odom的tf坐标变换信息,实际上是在tf树中是map->odom->base_footprint的父子关系,也就说要发布map到base_footprint的tf坐标变换信息,需要获取map到odom的坐标变换信息和odom到base_footprint的坐标信息,拼接后即为map到base_footprint的tf坐标变换信息。odom更新频率很高(100+Hz)可进行短期运动预测,提供机器人短期运动平滑估计,而map(数据来源于SLAM算法(激光匹配)更新频率较低)可进行全局较准,无累积误差,提供全局一致的地图和定位,SLAM算法(如gmapping
)通过激光匹配计算出一个更准确的位姿,并计算odom
→map
的变换(tf
),这个变换会逐步修正 odom
的漂移,保证长期定位准确。
里程计计算的只是一个机器人位移的理论值,必然会和实际情况存在一些偏差,而且机器人走的越远,这个误差还会累积,这时就需要用到激光雷达检测障碍物特征用的障碍物点云配准的定位算法(也就是Hector_Mapping用的建图方法)进行误差纠正。
如下图,根据里程计信息机器人走的路线如红线所示,但是机器人的实际位置根据激光雷达点云信息(蓝线)是在如图所示的位置。这就是里程计累计产生的误差
这时将机器人位置拉到正确的位置,只需要在里程计估算的位置上加上一段位移(绿线)即可。
但这里有个问题,里程计输出的是odom到base_footprint的TF,而SLAM节点要输出的是map到base_footprint的TF,但这时base_footprint已经被里程计占用了,SLAM就会把绿线这段TF挪到跟端的odom之前和odom到base_footprint这段TF连接起来,就实现了map到base_footprint的TF(开始时map和odom重合,odom
坐标系相对于 map
的偏离(即 map → odom
的变换)直接反映了SLAM算法对里程计误差的修正)。如果直接让base_footprint跳到“真实位置”,控制器会认为机器人“瞬间移动了”,导致电机速度突变(可能急停或加速)导航规划失效(如路径跟踪出现震荡)等等。SLAM 的修正作用在 map → odom
上,相当于“悄悄调整里程计的坐标系”,让base_footprint在全局(map
系)下逐渐对齐到正确位置,而不会引起跳变。
可以参考以下过程理解:
假设:机器人实际向前移动了 4.8 米(真实值)。但里程计因轮子打滑,认为移动了 5.0 米(误差 +0.2m)。SLAM 通过激光匹配发现误差,需要修正。
-
当前
odom → base_link
=(5.0, 0, 0)
(仍然由里程计提供,保持平滑)。 -
SLAM 计算
map → odom
=(-0.2, 0, 0)
(表示里程计多算了0.2米)。 -
全局位姿
map → base_link
=map → odom
+odom → base_link
=4.8m
(正确值)。 -
结果:
base_link
在odom
系下仍然是连续运动的,但全局位置已修正。
像这样,先使用里程计推算机器人的位移,然后通过雷达点云贴合障碍物轮廓修正里程计误差的方法就是Gmapping的核心算法
Gmapping核心原理
Gmapping 基于粒子滤波(Rao-Blackwellized Particle Filter, RBPF) 实现,其核心思想是通过融合激光数据和里程计信息,估计机器人的轨迹并构建环境地图。
Gmapping 的核心是 Rao-Blackwellized 粒子滤波,它将 SLAM 问题分解为:机器人位姿估计(用粒子滤波实现)和地图构建(基于已知位姿的激光数据拼接)。
RBPF 的核心思想:
-
每个粒子(Particle)代表一个可能的机器人轨迹假设。
-
每个粒子独立维护一张地图(即“如果机器人按这个轨迹走,地图应该长这样”)。
-
通过激光匹配和重采样(Resampling)筛选出最可信的粒子,最终用最优粒子的地图作为输出。
Gmapping 的流程可分为以下步骤:
(1) 初始化
-
生成
N
个粒子(默认N=30
),每个粒子的初始位姿相同(通常设为(0,0,0)
)。 -
每个粒子初始化一张空白地图(栅格地图,分辨率通常
0.05m
)。
(2) 运动更新(Prediction)
-
当收到里程计数据时,根据 运动模型 预测每个粒子的新位姿:
- 比如说里程计测量移动
0.1m
,并不是所有粒子都移动了0.1m,而是每个粒子的实际移动量会加入随机噪声(用来模拟里程计误差),例如,某些粒子可能移动0.09m
,另一些0.11m
(取决于噪声参数alpha1~alpha4
)
(3) 观测更新(Correction)
当收到激光扫描数据 z_t
时,对每个粒子执行:
-
扫描匹配(Scan Matching):用当前激光数据和粒子维护的地图匹配,计算最优位姿修正 Δx。不是简单比较激光数据与地图的“相似度”,而是计算似然概率:即“当前激光数据在粒子位姿和地图下的概率”。
- 权重计算:根据匹配结果更新粒子权重:即“当前激光数据与粒子地图的吻合程度”。所有粒子权重会归一化
(4) 重采样(Resampling)
重采样目的:随着时间推移,少数高权重粒子会占据主导,其他粒子权重趋近于0,导致粒子多样性丧失,这可能会导致所有粒子收敛到同一错误位姿,SLAM彻底失效。
重采样作用:通过复制高权重粒子、淘汰低权重粒子,重新分配资源给更可能的位姿假设。重采样本质是按权重概率随机选择粒子并进行复制,高权重粒子被选中的概率更高,可能被多次复制;低权重粒子可能被淘汰。
Gmapping采用自适应重采样,这是因为使用固定频率重采样可能导致过早收敛(如粒子全部集中在错误位姿)。自适应重采样在仅当有效粒子数(Effective Sample Size, Neff)低于阈值时触发。注意在Gmapping的重采样过程中,粒子数量(N)始终不变,所谓的“粒子减少”是指有效粒子数(NeffNeff)的下降,而非物理上的粒子数量减少。
假设有4个粒子,权重分别为 [0.7, 0.2, 0.05, 0.05],
有四个粒子,但是计算Neff,即计算有效粒子数如下,这意味着只有约2个粒子对结果有实质贡献(其他粒子权重可忽略)
当少数粒子权重远高于其他粒子时(例如某个粒子权重接近1),Neff会趋近于1。这种现象称为粒子退化(Particle Deprivation),表明系统过度依赖少数粒子,可能丢失真实位姿。
重采样不是对高权重粒子的简单复制,而是会注入噪声 。Gmapping在复制高权重粒子后,会对其位姿添加微小高斯噪声(如位置噪声 ~N(0, 0.01m)
,角度噪声 ~N(0, 0.02rad)
),形成新粒子。
假设粒子A权重高,位姿为 (5.0, 3.0, 0.1rad)
,复制时可能生成:
-
新粒子1:
(5.01, 2.99, 0.09rad)
-
新粒子2:
(4.99, 3.02, 0.11rad)
(5) 地图更新
-
最终地图是由最高权重粒子(或最后一次重采样后的存活粒子)维护的地图直接输出。
-
地图更新是增量式的:每次激光数据插入到当前最优粒子的地图中(栅格占用概率更新)。
输入和输出数据
订阅的话题有/tf,即需要一些tf坐标变换关系,具体需要的是雷达坐标系到地盘坐标系base_link的TF和base_link到odom的TF。还需要订阅/scan话题
发布的话题一共有三个。第一个map_metadata是地图信息,第二个map是栅格地图数据,第三个~entropy是机器人定位的置信度,这个值越大表示机器人定位错误的可能性就越大。除此之外,Gmapping还会输出地图map到里程计odom的TF关系
参数
Gmapping的参数可大体分为三类,第一类是接口参数,主要就是三个TF坐标系的名称
第二类参数是性能参数,在计算资源有限的平台上使用一组适当的性能参数,可以让Gmapping在略微损失一些精度的情况下流畅运行。如下图,其主要分为四组类型:第一组是地图尺寸相关的参数,包含地图边界尺寸和栅格地图分辨率,地图尺寸越大占用内存也就越大,栅格地图分辨率也就是每个栅格的边长;第二组是激光雷达相关的参数,其中maxUrange指的是长度超过这个范围的射线的有效范围会被限制到以maxUrange为半径的圆形区域里,超出部分会被裁剪。maxRange指的是所有超过这个数值的射线会被直接抛弃,不参与建图运算。lskip跳线,如果一个激光雷达扫描一周为360条射线,lskip=1则每隔一个射线选取一次,即选择第1 3 5 7 9序号的射线。throttle_scans的用法和lskip相似,如果thorottle_scans=3,则对于连续的三帧数据只处理最后一帧,即每隔两帧处理一帧,如果thorottle_scans=1则会处理每一帧数据;第三组是地图更新相关的数据,但是需要注意map_update_interval的地图更新优先级最高,也就是说小车在5s内移动了2米也只会更新一次,linerUpdate和angularUpdate优先级相同;第四组是定位相关的参数
具体参数如下:
<launch><arg name="scan_topic" default="scan" /><!--建图参数调节--><!--最重要的几个参数介绍如下:包括srr,srt,str,stt,--><!--srr/srt/str/stt:描述 机器人运动模型噪声 的关键参数,用于建模里程计(Odometry)的误差分布--><!--srr:平移运动引起的平移噪声。当机器人直线移动一定距离dx时,实际位置与里程计报告的位移之间的误差标准差。设 srr=0.05,机器人命令移动 dx=1m,实际位移可能是 1 ± 0.05m(高斯分布)。--><!--srt:旋转运动引起的平移噪声。当机器人 旋转一定角度 dθ 时,对平移造成的额外误差标准差。设 srt=0.02,机器人旋转 dθ=1rad,可能导致平移误差 ±0.02m。--><!--str:平移运动引起的旋转噪声。当机器人 直线移动 dx 时,对朝向角度的附加误差标准差。设 str=0.01,移动 dx=1m 可能导致角度误差 ±0.01rad。--><!--stt:旋转运动引起的旋转噪声。当机器人 旋转 dθ 时,实际角度与里程计报告角度的误差标准差。设 stt=0.03,旋转 dθ=1rad,实际角度可能是 1 ± 0.03rad。--><!--gmapping 使用 粒子滤波(Particle Filter) 融合激光数据和里程计数据。每个粒子代表一个可能的机器人位姿假设,其运动根据里程计预测,并通过激光匹配修正。当 srr/srt/str/stt 较小时,gmapping 过度信任里程计,若里程计本身有偏差(如持续向左漂移),粒子会继承这一偏差,导致地图偏移。当噪声参数较大时,gmapping 会 放宽对里程计的信任,更多依赖激光匹配纠正位姿,从而抑制漂移。--><!--如果机器人平移时地图偏转增大 str。如果机器人旋转时地图偏转,增大 stt。平常遇到的主要是旋转噪声导致的地图偏转所以一般调这两个参数--><!--linearUpdate:linearUpdate 是 gmapping 中控制 地图更新条件 的关键参数,它决定了机器人 在直线运动过程中,每隔多少距离才触发一次地图更新(即激光数据与地图的匹配和优化)当机器人从上次地图更新位置开始,直线移动的距离超过 linearUpdate 值时,gmapping 会执行一次新的扫描匹配(Scan Matching)和地图更新。如果机器人移动距离未达到该值,则 暂不更新地图,仅依赖里程计预测位姿。linearUpdate较小则地图更新频率高,激光匹配修正更频繁,能 更快纠正里程计漂移。linearUpdate 较大则激光匹配机会减少,过度依赖里程计--><!--angularUpdate:控制机器人旋转角度达到多少弧度时触发地图更新当机器人从上次地图更新后的 累计旋转角度 超过 angularUpdate 时,执行扫描匹配和地图更新。angularUpdate较小则更频繁的旋转修正,适合快速转向或里程计旋转误差大的场景angularUpdate较大则旋转漂移可能累积。--><!--temporalUpdate:强制按 固定时间间隔(秒)更新地图,优先级高于 linearUpdate 和 angularUpdate。默认值:-1.0(表示禁用,完全依赖运动阈值更新)。无论机器人是否移动,每隔 temporalUpdate 秒必更新一次地图。--><!--sigma:激光扫描匹配的似然场方差,表示激光测距的置信度。控制激光点与地图匹配时的容忍度,即允许激光点与地图障碍物的最大偏差。越小 → 匹配越严格;越大 → 匹配越宽松。通俗易懂的来说,当你蒙着眼睛用手摸墙找门,sigma=0.02表示你的手指必须几乎贴到墙才能确认位置(稍有偏差就认为“不匹配”)。sigma=0.1即使手指离墙有10厘米,你也认为“差不多是这里”。对于建图来说,更小的sigma让地图细节更清晰(适合高精度激光雷达),但是抗干扰弱,如果机器人轻微晃动或有人走过,地图容易错乱。而较大的sigma,抗干扰强,人在旁边走动也不影响地图,但是地图上的墙会变“厚”,精度下降。--><!--ogain:地图的 增益因子,控制激光数据融入地图的强度。决定激光雷达观测到障碍物时,地图栅格概率的更新速度.越大 → 地图更新越快,障碍物越清晰;越小 → 地图更新越保守。通俗易懂的来说,当你用粉笔画地图,ogain=5.0看到障碍物就画一笔浓墨重彩,立刻标到地图上。地图快速成型,但如果有人路过,会留下“鬼影”。ogain=1.0看到障碍物先轻轻画一笔,反复确认后再加深。地图更新慢,但动态物体(如人)不会留痕迹。--><!--lstep:平移搜索步长(单位:米),表示在 优化机器人位置(x, y) 时,每次尝试调整的最小距离。扫描匹配过程中,算法会尝试不同的平移位置(x, y),寻找最优匹配。lstep 决定了 每次调整位置的步长,步长越小,搜索越精细,但计算量越大。扫描匹配流程:机器人获取一帧激光数据,并尝试与现有地图匹配。算法在当前位置附近 微调机器人的 x 和 y 坐标,计算匹配得分(激光点与地图的吻合程度)。例如,lstep=0.05 表示每次尝试移动 ±0.05m,看看匹配是否更好。lstep较小则位姿优化更精细,能更准确找到最佳匹配位置。lstep较大可能错过最优匹配点,导致位姿误差累积。--><!--astep:旋转搜索步长(单位:弧度),表示在 优化机器人朝向(θ) 时,每次尝试调整的最小角度astep较小则角度优化更精细,能更准确找到最佳朝向。astep较大则 可能错过最优角度,导致旋转漂移。--><node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen" clear_params="true"><param name="odom_frame" value="odom"/><param name="mapp_update_interval" value="3.0"/><!-- Set maxUrange < actual maximum range of the Laser --><param name="maxRange" value="4.2"/><param name="maxUrange" value="4.0"/><param name="sigma" value="0.05"/><param name="kernelSize" value="1"/><param name="minimumScore" value="400"/><param name="lstep" value="0.05"/><param name="astep" value="0.05"/><param name="iterations" value="5"/><param name="lsigma" value="0.075"/><param name="ogain" value="3.0"/><param name="lskip" value="0"/><param name="srr" value="0.01"/><param name="srt" value="0.02"/><param name="str" value="0.01"/><param name="stt" value="0.02"/><param name="linearUpdate" value="0.1"/><param name="angularUpdate" value="0.1"/><param name="temporalUpdate" value="-1.0"/><param name="resampleThreshold" value="0.5"/><param name="particles" value="30"/><param name="xmin" value="-1.0"/><param name="ymin" value="-1.0"/><param name="xmax" value="1.0"/><param name="ymax" value="1.0"/><param name="delta" value="0.01"/><param name="llsamplerange" value="0.01"/><param name="llsamplestep" value="0.01"/><param name="lasamplerange" value="0.005"/><param name="lasamplestep" value="0.005"/><remap from="scan" to="$(arg scan_topic)"/></node>
</launch>
相关文章:
SLAM定位与地图构建
SLAM介绍 SLAM全称Simultaneous Localization And Mapping,中文名称同时定位与地图构建。旨在让移动设备在未知环境中同时完成以下两个任务(定位需要地图,而建图又依赖定位信息,两者互为依赖): 定位&#…...
REST架构风格介绍
一.REST(表述性状态转移) 1.定义 REST(Representational State Transfer)是由 Roy Fielding 在 2000 年提出的一种软件架构风格,用于设计网络应用的通信模式。它基于 HTTP 协议,强调通过统一的接口&#…...
前端流行框架Vue3教程:16. 组件事件配合`v-model`使用
组件事件配合v-model使用 如果是用户输入,我们希望在获取数据的同时发送数据配合v-model 来使用,帮助理解组件间的通信和数据绑定。 🧩 第一步:创建子组件(SearchComponent.vue) 这个组件用于处理用户的搜…...
5月15日day26打卡
函数专题1 知识点回顾: 函数的定义变量作用域:局部变量和全局变量函数的参数类型:位置参数、默认参数、不定参数传递参数的手段:关键词参数传递参数的顺序:同时出现三种参数类型时 作业: 题目1:…...
Java中的深拷贝与浅拷贝
什么是拷贝 在Java中,拷贝是指创建一个对象的副本。拷贝主要分为两种类型:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。理解这两种拷贝的区别对于编写正确的Java程序非常重要,特别是在处理对象引用时。 浅拷贝(Shallow Copy) 浅拷贝是指创建…...
springboot AOP中,通过解析SpEL 表达式动态获取参数值
切面注解 import com.bn.document.constants.FmDeptCatalogueConstants;import java.lang.annotation.*;Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface FmDeptCatalogueAopAnnotation {/*** 权限类型*/FmDeptCatalogueConstants value();/…...
【论信息系统项目的合同管理】
论信息系统项目的合同管理 论文要求写作要点正文前言一、合同的签订管理二、合同履行管理三、合同变更管理四、合同档案管理五、合同违约索赔管理结语 论文要求 项目合同管理通过对项目合同的全生命周期进行管理,来回避和减轻可识别的项目风险。 请以“论信息系统项…...
redis持久化方式
一、RDB redis database:快照,某一时刻将内存中的数据,写入磁盘中生成1个dump.rdb文件RDB的触发方式: 手动触发:save(阻塞主进程,阻塞其它指令,保证数据一致性)、bgsave…...
free void* 指令
https://stackoverflow.com/questions/2182103/is-it-ok-to-free-void free(ptr) 仅释放指针指向的内存,不会修改指针变量本身的值。调用后,ptr 仍然指向原来的地址(称为 "悬空指针"),但该地址对应的内存已…...
ADS1220高精度ADC(TI)——应用 源码
文章目录 德州仪器ADS1220概述资料引脚&封装布线寄存器配置寄存器0(00h)配置寄存器1(01h)配置寄存器2(02h)配置寄存器3(03h) 连续转换流程驱动源码ads1220.cads1220.h 德州仪器A…...
mysql-Java手写分布式事物提交流程
准备 innodb存储引擎开启支持分布式事务 set global innodb_support_axon分布式的流程 详细流程: XA START ‘a’; 作用:开始一个新的XA事务,并分配一个唯一的事务ID ‘a’。 说明:在这个命令之后,所有后续的SQL操…...
红黑树:数据世界的平衡守护者
在 C 算法的神秘森林里,红黑树是一棵充满智慧的 “魔法树”。它既不像普通二叉搜索树那样容易失衡,也不像 AVL 树对平衡要求那么苛刻。作为 C 算法小白,今天就和大家一起深入探索红黑树的奥秘,看看它是如何成为数据世界的平衡守护…...
哈夫曼树完全解析:从原理到应用
目录 一、核心概念 二、构造全流程解析 三、编码生成机制 四、C语言实现关键代码 五、核心特性深度解读 六、现代应用场景 七、压缩实战演示 一、核心概念 哈夫曼树(最优二叉树)是带权路径长度(WPL)最短的树形结构&#x…...
如何在 Windows 命令提示符中创建多个文件夹和多个文件
如何在 Windows 命令提示符中创建多个文件夹和多个文件 虽然大多数用户习惯使用 Windows 图形界面来创建文件夹,但如果你需要一次性创建多个文件夹或文件,如同在类Unix系统中可以使用mkdir和touch命令一样,windows下也有创建目录和文件的对应…...
【Java】Spring的声明事务在多线程场景中失效问题。
大家都知道Spring的声明式事务在多线程当中会失效,来看一下如下案例。 按照如下方式,b()方法抛出异常,由于父子线程导致事务失效,a()会成功插入,但是b()不会。 因此成功插入一条数据,事务失效。 Component public class UserServ…...
多平台图标设计与管理的终极解决方案
IconWorkshop Pro 是一款由Axialis团队开发的专业图标设计与制作软件,专注于为设计师、开发者及企业用户提供高效且灵活的图标创作解决方案。该软件凭借其强大的功能与跨平台适配性,成为Windows、macOS、iOS、Android等多系统图标设计的首选工具之一。 …...
【搭建Node-RED + MQTT Broker实现AI大模型交互】
搭建Node-RED MQTT Broker实现AI大模型交互 搭建Node-RED MQTT Broker实现AI大模型交互一、系统架构二、环境准备与安装1. 安装Node.js2. 安装Mosquitto MQTT Broker3. 配置Mosquitto4. 安装Node-RED5. 配置Node-RED监听所有网络接口6. 启动Node-RED 三、Node-RED流程配置1. …...
小结: js 在浏览器执行原理
浏览器多进程与多线程 现代浏览器的标签环境隔离主要通过多进程架构和多线程机制实现,以确保安全、性能和稳定性。以下是浏览器实现标签环境隔离的多进程和多线程交互架构的详细解析: ------------------- ------------------- -----------…...
C++核心编程--2 引用
引用就是给变量起别名,操作引用就等于操作原始变量。 2.1 引用基本用法 int var 10; int & r_var var; 2.2 注意事项 声明时必须初始化不允许更改引用指向的原始变量 2.3 引用作为函数参数传递 简化指针修饰函数参数 2.4 引用作为函数返回值 不要返回…...
音频/AI/BLE/WIFI/玩具/商业等方向的论坛网站总结
我爱音频网 我爱音频网 - 我们只谈音频,丰富的TWS真无线蓝牙耳机拆解报告 (52audio.com) 中国人工智能学会 中国人工智能学会 (caai.cn) AIIA人工智能网 https://www.aiiaw.com/ 世界人工智能论坛 世界人工智能论坛 - (amtbbs.org) 36氪 36氪_让一部分人先…...
告别碎片化!MCP 带来 AI Agent 开发生态的革命性突破
引言: 在当今的智能客服系统开发中,开发者常常面临一个棘手的挑战:需要整合用户的 CRM 数据、知识库和实时聊天记录。然而,由于缺乏统一的标准,每个团队都不得不手动实现这些集成。这不仅延长了开发周期,还…...
centos7部署mysql5.7
1.下载mysql的官方yum源 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm2.安装yum源 yum -y install mysql57-community-release-el7-11.noarch.rpm3.安装秘钥文件 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-20224.安装mysql5.7…...
linux dbus
Linux D-Bus(Desktop Bus)是一种进程间通信(IPC)机制,主要用于Linux桌面环境和系统服务之间的消息传递。它允许不同的应用程序或系统组件以高效、安全的方式相互通信,是现代Linux桌面(如GNOME、KDE)的核心基础设施之一。 1. D-Bus 的核心概念 消息总线(Message Bus):…...
计量——异方差的检验及其修正
目录 1.异方差的检验 1 BP检验 2white检验 2.异方差的修正 1.异方差的检验 1 BP检验 选择检验方法:BP BP检验的实际步骤(非机器): 1.y对所有x进行回归,得到残差u。计算残差的平方u^2 2.u^2对所有x进行回归&#…...
操作系统学习笔记第3章 内存管理(灰灰题库)
1. 单选题 某页式存储管理系统中,主存为 128KB,分成 32 块,块号为 0、1、2、3、…、31。某作业有 5 块,其页号为 0、1、2、3、4,被分别装入主存的 3、8、4、6、9 块中。有一逻辑地址为 [3, 70](其中方括号中…...
vue3项目中使用CanvasEditor开箱即用(组件的形式,组件封装好了)
canvas-editor-vue 这是canvas-editor项目的vue版本,我封装成组建了,当然了这是个已经把canvas-editor封装好的的Vue项目 项目地址GitHub地址:GitHub - aini-aini/canvas-editor-vue: this is a project than can be used in vue project as Componentthis is a project than…...
人体肢体工作识别-一步几个脚印从头设计数字生命——仙盟创梦IDE
人体肢体识别是借助计算机视觉、传感器等技术,对人体各肢体的位置、动作、姿态等进行检测与分析的技术。其在医疗健康、智能交互、运动训练、安全监控等多个领域具有重要价值, 示例代码 import cv2 import mediapipe as mp import numpy as np import c…...
【重磅】配电网智能软开关和储能联合规划
目录 1 主要内容 目标函数 数据说明 节点系统图 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现《具有源荷不平衡特性的配电网智能软开关和储能联合规划》部分模型,未考虑聚类分析和分布鲁棒部分,就智能软开关和储能联合规划部分进行了…...
实验6 电子邮件
实验6 电子邮件 1、实验目的 理解电子邮件系统基本结构 理解客户端和服务器端,以及服务器之间的通信 分析理解SMTP,POP3协议 2、实验环境 硬件要求:阿里云云主机ECS 一台。 软件要求:Linux/ Windows 操作系统 3、实验内容…...
NHANES指标推荐:OBS
文章题目:Association between oxidative balance score and all-cause and cancer-specific mortality among cancer survivors DOI:10.3389/fimmu.2025.1541675 中文标题:癌症幸存者氧化平衡评分与全因死亡率和癌症特异性死亡率之间的关联 …...
python-修改图片背景色
在Python中,可以使用图像处理库(如OpenCV或Pillow)来修改图片的背景色。通常,修改背景色的流程包括以下步骤: 1、对图片进行分割,识别前景和背景。 2、对背景区域进行颜色替换。 下面是两种实现方法&#x…...
数据结构与算法--顺序表--单链表
一 顺序表 需要指向存储位置的基地址分配一段连续的内存用length记录实际的元素的个数,也即顺序表的长度,因为顺序表是允许删除和插入元素的不需要定义数组 1.1 普通结构体数组实现版本,实现白色的点以一定的步长移除画面,大量fo…...
MATLAB安装全攻略:常见问题与解决方案
MATLAB安装常见问题与解决方案 一、系统兼容性验证 安装前需确认操作系统满足MATLAB版本要求: Windows 10版本1903及以上(64位)macOS Monterey 12.6及以上Ubuntu 22.04 LTS及以上 验证命令示例: # Linux系统验证 lsb_release…...
constexpr 关键字的意义(入门)
author: hjjdebug date: 2025年 05月 15日 星期四 16:03:33 CST description: constexpr 关键字的意义(入门) constexpr 是c11 引入的一个关键字, 代表了一种属性. 文章目录 1. constexpr 修饰的变量, 在编译期间就可以得到其数值.2. constexpr 修饰的函数, 可以在编译期间被调…...
aptitude 深度教程:从基础到生产实践
目录 一、aptitude 基础:核心概念与环境准备 1.1 aptitude 是什么? 1.2 安装与环境配置 二、aptitude 核心操作:从命令行到交互式界面 2.1 命令行基础操作 2.2 交互式界面(TUI)入门 三、高级功能:依赖管理与版本控制 3.1 依赖冲突解决实战 3.2 版本锁定与降级 3…...
嵌入式开发学习日志(数据结构--双链表)Day21
一、双链表 1.定义 双向链表是在单链表的每个结点中,再设置一个指向其钱去节点的指针域。 2、声明文件 3、创建表头 4、头插 5、 遍历 6、尾插、 7、指定插 8、查找 9、修改 10.、删除 11、逆序 12、销毁链表 13、main.c 三、扩展:工程管理工具&#…...
抢购Python代码示例与技术解析
引言:抢购系统的技术挑战 在当今电子商务高度发达的时代,抢购活动已成为各大电商平台吸引用户的重要手段。然而,高并发、低延迟的抢购场景对系统设计提出了严峻挑战。本文将提供一个完整的Python抢购代码示例,并深入分析其技术实…...
undefined reference to CPUAllocatorSingleton::instance
它发生的原因是你声明了 CPUAllocatorSingleton 类中的 instance 变量,但没有提供它的定义。 这个错误是链接器无法找到 CPUAllocatorSingleton::instance 的定义。它发生的原因是你声明了 CPUAllocatorSingleton 类中的 instance 变量,但没有提供它的定…...
【c语言】动态内存分配
文章标题 一、为什么要进行动态内存管理二、malloc和free2.1. malloc2.2. free2.3. 举例 三、calloc和realloc3.1. calloc3.2. realloc 四、常见的动态内存错误4.1. 对NULL指针的解引用操作4.2. 对动态开辟空间的越界访问4.3. 对非动态开辟内存使用free释放4.4. 使用free释放⼀…...
深入理解JavaScript中的闭包:原理、应用与常见问题
引言 闭包(Closure)是JavaScript中一个既强大又容易让人困惑的概念。理解闭包对于成为一名优秀的JavaScript开发者至关重要。本文将深入探讨闭包的工作原理、实际应用场景以及常见问题,帮助你彻底掌握这一重要概念。 什么是闭包? 闭包是指那些能够访问…...
IPLOOK | 2025 MVNOs 世界大会:从Wi-Fi通话到卫星覆盖
2025 MVNOs 世界大会于5月12日至14日在奥地利维也纳举行,汇聚了来自50多个国家的550余位行业领袖,共同探讨移动虚拟网络运营商(MVNO)领域的变革趋势。本届大会聚焦数字化转型、技术创新与战略合作,其中IPLOOK凭借其创新…...
为什么elasticsearch配置文件JVM配置31G最佳
Elasticsearch的JVM堆内存配置为32GB被视为最佳实践,主要基于以下综合技术原理和性能优化考量: 1. JVM指针压缩机制优化内存效率 当堆内存≤32GB时,JVM启用对象指针压缩(Compressed Ordinary Object Pointers, COOP&#…...
单片机开发软件
目录 纯编码 vscode Ardunio Keil 1. 集成化开发环境(IDE) 2. 多架构芯片支持 3. 高效的代码生成与优化 4. 强大的调试与仿真功能 5. 丰富的库函数与生态系统 6. 教育与企业级适用性 典型应用场景 半编码半图形化 STM32CUBEIED 1. 图形化配置…...
Java随机生成邀请码 (包含字母大小写+数字)
前言: 目前我们生成的是6位包含数字和大小写字母的随机邀请码, 并且代码中已经有了处理冲突的机制确保了邀请码的唯一性如(①生成随机邀请码后会检查数据库中是否已存在②如果存在冲突,会尝试最多10次重新生成③如果多次尝试仍失败,会使用"U"用户ID派生的…...
mybatis-plus配置逻辑删除
在实体类中标记软删除字段使用注解 TableLogic 标记该字段为软删除字段 import com.baomidou.mybatisplus.annotation.*;public class YourEntity {// ...其他字段TableLogicprivate Integer isDeleted;// getter/setter }yml配置 # 逻辑已删除值 logicDeleteValue: 2 # 逻辑…...
第二十五天打卡
常见报错类型 try-except-else-finally 语句 首先执行try语句,若正确直接执行else语句 若try语句发生错误,则判断错误类型,执行错误类型对应的except语句,不执行else语句 finally语句无条件执行,多用于资源保存&…...
JESD204 ip核使用与例程分析(一)
JESD204 ip核使用与例程分析(一) JESD204理解JESD204 与JESD204 PHY成对使用原因JESD204B IP核JESD204B IP核特点JESD204B IP核配置第一页第二页第三页第四页JESD204 PHY IP核配置第一页第二页JESD204理解 JESD204B是一种针对ADC、DAC设计的传输接口协议。此协议包含四层, …...
Synchronized详解及高频面试问答
目录 JVM简述 Synchronized详解及面试高频问答 而synchronized是什么,可以解决什么问题? synchronized怎么使用? 锁升级升级了什么? 为什么要这样做锁升级? 锁升级的过程是怎样的?为什么会有偏向锁&…...
【LLIE专题】基于码本先验与生成式归一化流的低光照图像增强新方法
GLARE: Low Light Image Enhancement via Generative Latent Feature based Codebook Retrieval(2024,ECCV) 专题介绍一、研究背景二、GLARE方法阶段一:正常光照代码本学习(Normal-Light Codebook Learning)…...
26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述
26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述 文章目录 26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述1.1 计算机的发展1.2 计算机硬件和软件1.2.1 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机软件1.2.4 计算机系统的层次结构1.2.5 计算机系统…...