当前位置: 首页 > news >正文

移动机器人激光SLAM导航(五):Cartographer SLAM 篇

参考

  • Cartographer 官方文档
  • Cartographer 从入门到精通

1. Cartographer 安装

1.1 前置条件

  • 推荐在刚装好的 Ubuntu 16.04 或 Ubuntu 18.04 上进行编译
  • ROS 安装:ROS学习1:ROS概述与环境搭建

1.2 依赖库安装

  • 资源下载完解压并执行以下指令
    • https://pan.baidu.com/s/1LWqZ4SOKn2sZecQUDDXXEw?pwd=j6cf
    $ sudo chmod 777 auto-carto-build.sh
    $ ./auto-carto-build.sh
    

1.3 编译

本文只编译 cartographer_ros,以下为同时开三个终端操作

$ mkdir -p cartographer_ws/src
$ cd ~
$ git clone https://github.com/xiangli0608/cartographer_detailed_comments_ws
$ mv ~/cartographer_detailed_comments_ws/src/cartographer_ros ~/cartographer_ws/src
$ cd ~/cartographer_ws
$ catkin_make

2. Cartographer 运行

2.1 数据集下载

  • 百度网盘链接(rslidar-outdoor-gps.bag、landmarks_demo_uncalibrated.bag)
    • https://pan.baidu.com/s/1leRr4JDGg61jBNCwNlSCJw?pwd=5nkq

2.2 配置文件

  • lx_rs16_2d_outdoor.launch

    <launch><!-- bag 的地址与名称(根据自己情况修改,建议使用绝对路径) --><arg name="bag_filename" default="/home/yue/bag/rslidar-outdoor-gps.bag"/><!-- 使用 bag 的时间戳 --><param name="/use_sim_time" value="true" /><!-- 启动 cartographer --><node name="cartographer_node" pkg="cartographer_ros"type="cartographer_node" args="-configuration_directory $(find cartographer_ros)/configuration_files-configuration_basename lx_rs16_2d_outdoor.lua"output="screen"><remap from="points2" to="rslidar_points" /><remap from="scan" to="front_scan" /><remap from="odom" to="odom_scout" /><remap from="imu" to="imu" /></node><!-- 生成 ros 格式的地图 --><node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"type="cartographer_occupancy_grid_node" args="-resolution 0.05" /><!-- 启动 rviz --><node name="rviz" pkg="rviz" type="rviz" required="true"args="-d $(find cartographer_ros)/configuration_files/lx_2d.rviz" /><!-- 启动 rosbag --><node name="playbag" pkg="rosbag" type="play"args="--clock $(arg bag_filename)" /></launch>
    
  • lx_rs16_2d_outdoor.lua

    include "map_builder.lua"
    include "trajectory_builder.lua"options = {map_builder = MAP_BUILDER,               -- map_builder.lua的配置信息trajectory_builder = TRAJECTORY_BUILDER, -- trajectory_builder.lua的配置信息map_frame = "map"-- 地图坐标系的名字tracking_frame = "imu_link"-- 将所有传感器数据转换到这个坐标系下published_frame = "footprint"-- tf: map -> footprintodom_frame = "odom"-- 里程计的坐标系名字provide_odom_frame = false-- 是否提供odom的tf,如果为true,则tf树为map->odom->footprint-- 如果为false tf树为map->footprintpublish_frame_projected_to_2d = false-- 是否将坐标系投影到平面上--use_pose_extrapolator = false,           -- 发布tf时是使用pose_extrapolator的位姿还是前端计算出来的位姿use_odometry = false-- 是否使用里程计,如果使用要求一定要有odom的tfuse_nav_sat = false-- 是否使用gpsuse_landmarks = false-- 是否使用landmarknum_laser_scans = 0-- 是否使用单线激光数据num_multi_echo_laser_scans = 0-- 是否使用multi_echo_laser_scans数据num_subdivisions_per_laser_scan = 1-- 1帧数据被分成几次处理,一般为1num_point_clouds = 1-- 是否使用点云数据lookup_transform_timeout_sec = 0.2-- 查找tf时的超时时间submap_publish_period_sec = 0.3-- 发布数据的时间间隔pose_publish_period_sec = 5e-3,trajectory_publish_period_sec = 30e-3,rangefinder_sampling_ratio = 1.-- 传感器数据的采样频率odometry_sampling_ratio = 1.,fixed_frame_pose_sampling_ratio = 1.,imu_sampling_ratio = 1.,landmarks_sampling_ratio = 1.,
    }MAP_BUILDER.use_trajectory_builder_2d = trueTRAJECTORY_BUILDER_2D.use_imu_data = true
    TRAJECTORY_BUILDER_2D.min_range = 0.3
    TRAJECTORY_BUILDER_2D.max_range = 100.
    TRAJECTORY_BUILDER_2D.min_z = 0.2
    --TRAJECTORY_BUILDER_2D.max_z = 1.4
    --TRAJECTORY_BUILDER_2D.voxel_filter_size = 0.02--TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.max_length = 0.5
    --TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.min_num_points = 200.
    --TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.max_range = 50.--TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.max_length = 0.9
    --TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.min_num_points = 100
    --TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.max_range = 50.TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = false
    TRAJECTORY_BUILDER_2D.ceres_scan_matcher.occupied_space_weight = 1.
    TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1.
    TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight = 1.
    --TRAJECTORY_BUILDER_2D.ceres_scan_matcher.ceres_solver_options.max_num_iterations = 12--TRAJECTORY_BUILDER_2D.motion_filter.max_distance_meters = 0.1
    --TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = 0.004
    --TRAJECTORY_BUILDER_2D.imu_gravity_time_constant = 1.TRAJECTORY_BUILDER_2D.submaps.num_range_data = 80.
    TRAJECTORY_BUILDER_2D.submaps.grid_options_2d.resolution = 0.1POSE_GRAPH.optimize_every_n_nodes = 160.
    POSE_GRAPH.constraint_builder.sampling_ratio = 0.3
    POSE_GRAPH.constraint_builder.max_constraint_distance = 15.
    POSE_GRAPH.constraint_builder.min_score = 0.48
    POSE_GRAPH.constraint_builder.global_localization_min_score = 0.60return options
    
  • trajectory_builder_2d.lua

    TRAJECTORY_BUILDER_2D = {use_imu_data = true,            -- 是否使用imu数据min_range = 0.,                 -- 雷达数据的最远最近滤波, 保存中间值max_range = 30.,min_z = -0.8,                   -- 雷达数据的最高与最低的过滤, 保存中间值max_z = 2.,missing_data_ray_length = 5.,   -- 超过最大距离范围的数据点用这个距离代替num_accumulated_range_data = 1, -- 几帧有效的点云数据进行一次扫描匹配voxel_filter_size = 0.025,      -- 体素滤波的立方体的边长-- 使用固定的voxel滤波之后, 再使用自适应体素滤波器-- 体素滤波器 用于生成稀疏点云 以进行 扫描匹配adaptive_voxel_filter = {max_length = 0.5,             -- 尝试确定最佳的立方体边长, 边长最大为0.5min_num_points = 200,         -- 如果存在 较多点 并且大于'min_num_points', 则减小体素长度以尝试获得该最小点数max_range = 50.,              -- 距远离原点超过max_range 的点被移除},-- 闭环检测的自适应体素滤波器, 用于生成稀疏点云 以进行 闭环检测loop_closure_adaptive_voxel_filter = {max_length = 0.9,min_num_points = 100,max_range = 50.,},-- 是否使用 real_time_correlative_scan_matcher 为ceres提供先验信息-- 计算复杂度高 , 但是很鲁棒 , 在odom或者imu不准时依然能达到很好的效果use_online_correlative_scan_matching = false,real_time_correlative_scan_matcher = {linear_search_window = 0.1,             -- 线性搜索窗口的大小angular_search_window = math.rad(20.),  -- 角度搜索窗口的大小translation_delta_cost_weight = 1e-1,   -- 用于计算各部分score的权重rotation_delta_cost_weight = 1e-1,},-- ceres匹配的一些配置参数ceres_scan_matcher = {occupied_space_weight = 1.,translation_weight = 10.,rotation_weight = 40.,ceres_solver_options = {use_nonmonotonic_steps = false,max_num_iterations = 20,num_threads = 1,},},-- 为了防止子图里插入太多数据, 在插入子图之前之前对数据进行过滤motion_filter = {max_time_seconds = 5.,max_distance_meters = 0.2,max_angle_radians = math.rad(1.),},-- TODO(schwoere,wohe): Remove this constant. This is only kept for ROS.imu_gravity_time_constant = 10.,-- 位姿预测器pose_extrapolator = {use_imu_based = false,constant_velocity = {imu_gravity_time_constant = 10.,pose_queue_duration = 0.001,},imu_based = {pose_queue_duration = 5.,gravity_constant = 9.806,pose_translation_weight = 1.,pose_rotation_weight = 1.,imu_acceleration_weight = 1.,imu_rotation_weight = 1.,odometry_translation_weight = 1.,odometry_rotation_weight = 1.,solver_options = {use_nonmonotonic_steps = false;max_num_iterations = 10;num_threads = 1;},},},-- 子图相关的一些配置submaps = {num_range_data = 90,          -- 一个子图里插入雷达数据的个数的一半grid_options_2d = {grid_type = "PROBABILITY_GRID", -- 地图的种类, 还可以是tsdf格式resolution = 0.05,},range_data_inserter = {range_data_inserter_type = "PROBABILITY_GRID_INSERTER_2D",-- 概率占用栅格地图的一些配置probability_grid_range_data_inserter = {insert_free_space = true,hit_probability = 0.55,miss_probability = 0.49,},-- tsdf地图的一些配置tsdf_range_data_inserter = {truncation_distance = 0.3,maximum_weight = 10.,update_free_space = false,normal_estimation_options = {num_normal_samples = 4,sample_radius = 0.5,},project_sdf_distance_to_scan_normal = true,update_weight_range_exponent = 0,update_weight_angle_scan_normal_to_ray_kernel_bandwidth = 0.5,update_weight_distance_cell_to_hit_kernel_bandwidth = 0.5,},},},
    }
    
  • pose_graph.lua

    POSE_GRAPH = {-- 每隔多少个节点执行一次后端优化optimize_every_n_nodes = 90,-- 约束构建的相关参数constraint_builder = {sampling_ratio = 0.3,                 -- 对局部子图进行回环检测时的计算频率, 数值越大, 计算次数越多max_constraint_distance = 15.,        -- 对局部子图进行回环检测时能成为约束的最大距离min_score = 0.55,                     -- 对局部子图进行回环检测时的最低分数阈值global_localization_min_score = 0.6,  -- 对整体子图进行回环检测时的最低分数阈值loop_closure_translation_weight = 1.1e4,loop_closure_rotation_weight = 1e5,log_matches = true,                   -- 打印约束计算的log-- 基于分支定界算法的2d粗匹配器fast_correlative_scan_matcher = {linear_search_window = 7.,angular_search_window = math.rad(30.),branch_and_bound_depth = 7,},-- 基于ceres的2d精匹配器ceres_scan_matcher = {occupied_space_weight = 20.,translation_weight = 10.,rotation_weight = 1.,ceres_solver_options = {use_nonmonotonic_steps = true,max_num_iterations = 10,num_threads = 1,},},-- 基于分支定界算法的3d粗匹配器fast_correlative_scan_matcher_3d = {branch_and_bound_depth = 8,full_resolution_depth = 3,min_rotational_score = 0.77,min_low_resolution_score = 0.55,linear_xy_search_window = 5.,linear_z_search_window = 1.,angular_search_window = math.rad(15.),},-- 基于ceres的3d精匹配器ceres_scan_matcher_3d = {occupied_space_weight_0 = 5.,occupied_space_weight_1 = 30.,translation_weight = 10.,rotation_weight = 1.,only_optimize_yaw = false,ceres_solver_options = {use_nonmonotonic_steps = false,max_num_iterations = 10,num_threads = 1,},},},matcher_translation_weight = 5e2,matcher_rotation_weight = 1.6e3,-- 优化残差方程的相关参数optimization_problem = {huber_scale = 1e1,                -- 值越大,(潜在)异常值的影响就越大acceleration_weight = 1.1e2,      -- 3d里imu的线加速度的权重rotation_weight = 1.6e4,          -- 3d里imu的旋转的权重-- 前端结果残差的权重local_slam_pose_translation_weight = 1e5,local_slam_pose_rotation_weight = 1e5,-- 里程计残差的权重odometry_translation_weight = 1e5,odometry_rotation_weight = 1e5,-- gps残差的权重fixed_frame_pose_translation_weight = 1e1,fixed_frame_pose_rotation_weight = 1e2,fixed_frame_pose_use_tolerant_loss = false,fixed_frame_pose_tolerant_loss_param_a = 1,fixed_frame_pose_tolerant_loss_param_b = 1,log_solver_summary = false,use_online_imu_extrinsics_in_3d = true,fix_z_in_3d = false,ceres_solver_options = {use_nonmonotonic_steps = false,max_num_iterations = 50,num_threads = 7,},},max_num_final_iterations = 200,   -- 在建图结束之后执行一次全局优化, 不要求实时性, 迭代次数多global_sampling_ratio = 0.003,    -- 纯定位时候查找回环的频率log_residual_histograms = true,global_constraint_search_after_n_seconds = 10., -- 纯定位时多少秒执行一次全子图的约束计算--  overlapping_submaps_trimmer_2d = {--    fresh_submaps_count = 1,--    min_covered_area = 2,--    min_added_submaps_count = 5,--  },
    }
    

2.3 运行演示

$ source devel/setup.bash
$ roslaunch cartographer_ros lx_rs16_2d_outdoor.launch

在这里插入图片描述

3. Cartographer 调参总结

3.1 降低延迟与减小计算量

  • 前端

    • 减小 max_range 即减小了需要处理的点数,在激光雷达远距离的数据点不准时一定要减小这个值
    • 增大 voxel_filter_size,相当于减小了需要处理的点数
    • 增大 submaps.resolution,相当于减小了匹配时的搜索量
    • 对于自适应体素滤波 减小 min_num_points 与 max_range,增大 max_length,相当于减小了需要处理的点数
  • 后端

    • 减小 optimize_every_n_nodes, 降低优化频率, 减小了计算量
    • 增大 MAP_BUILDER.num_background_threads, 增加计算速度
    • 减小 global_sampling_ratio, 减小计算全局约束的频率
    • 减小 constraint_builder.sampling_ratio, 减少了约束的数量
    • 增大 constraint_builder.min_score, 减少了约束的数量
    • 减小分枝定界搜索窗的大小, 包括linear_xy_search_window,inear_z_search_window, angular_search_window
    • 增大 global_constraint_search_after_n_seconds, 减小计算全局约束的频率
    • 减小 max_num_iterations, 减小迭代次数

3.2 降低内存

  • 增大子图的分辨率 submaps.resolution

3.3 常调的参数

TRAJECTORY_BUILDER_2D.min_range = 0.3
TRAJECTORY_BUILDER_2D.max_range = 100.
TRAJECTORY_BUILDER_2D.min_z = 0.2 -- / -0.8
TRAJECTORY_BUILDER_2D.voxel_filter_size = 0.02
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.occupied_space_weight = 10.
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1.
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight = 1.
TRAJECTORY_BUILDER_2D.submaps.num_range_data = 80.
TRAJECTORY_BUILDER_2D.submaps.grid_options_2d.resolution = 0.1 -- / 0.02
POSE_GRAPH.optimize_every_n_nodes = 160. -- 2倍的num_range_data以上
POSE_GRAPH.constraint_builder.sampling_ratio = 0.3
POSE_GRAPH.constraint_builder.max_constraint_distance = 15.
POSE_GRAPH.constraint_builder.min_score = 0.48
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.60

4. Cartographer 工程化建议

4.1 如何提升建图质量

  • 选择频率高(25 Hz 以上)、精度高的激光雷达
  • 如果只能用频率低的激光雷达
    • 使用高频、高精度 IMU,且让机器人运动慢一点
    • 调 ceres 的匹配权重,将地图权重调大,平移旋转权重调小
    • 将代码中平移和旋转的残差注释掉
  • 里程计
    • Cartographer 中对里程计的使用不太好
    • 可以将 karto 与 GMapping 中使用里程计进行预测的部分拿过来进行使用,改完后就可达到比较好的位姿预测效果
  • 粗匹配
    • 将 karto 的扫描匹配的粗匹配放过来,karto 的扫描匹配的计算量很小,当做粗匹配很不错
  • 地图
    • 在最终生成地图的时候使用后端优化后的节点重新生成一次地图,这样生成的地图效果会比前端地图的叠加要好很多

4.2 降低计算量与内存

  • 体素滤波与自适应体素滤波的计算量(不是很大)
  • 后端进行子图间约束时的计算量很大
  • 分支定界算法的计算量很大
  • 降低内存,内存的占用基本就是多分辨率地图,每个子图的多分辨率地图都进行保存是否有必要

4.3 纯定位的改进建议

  • 将纯定位模式与建图拆分开,改成读取之前轨迹的地图进行匹配.
  • 新的轨迹只进行位姿预测,拿到预测后的位姿与之前轨迹的地图进行匹配,新的轨迹不再进行地图的生成与保存,同时将整个后端的功能去掉.
  • 去掉后端优化会导致没有重定位功能,这时可将 cartographer 的回环检测(子图间约束的计算)部分单独拿出来,做成一个重定位功能,通过服务来调用这个重定位功能,根据当前点云确定机器人在之前地图的位姿

4.4 去 ros 的参考思路

  • 仿照 cartographer_ros 里的操作:获取到传感器数据,将数据转到 tracking_frame 坐标系下并进行格式转换,再传入到 cartographer 里就行

5. 源码注释

  • cartographer_detailed_comments_ws

相关文章:

移动机器人激光SLAM导航(五):Cartographer SLAM 篇

参考 Cartographer 官方文档Cartographer 从入门到精通 1. Cartographer 安装 1.1 前置条件 推荐在刚装好的 Ubuntu 16.04 或 Ubuntu 18.04 上进行编译ROS 安装&#xff1a;ROS学习1&#xff1a;ROS概述与环境搭建 1.2 依赖库安装 资源下载完解压并执行以下指令 https://pa…...

第四篇【传奇开心果微博系列】Python微项目技术点案例示例:美女颜值判官

传奇开心果微博系列 系列微博目录Python微项目技术点案例示例系列 微博目录一、微项目目标二、雏形示例代码三、扩展思路四、添加不同类型的美女示例代码五、增加难度等级示例代码六、添加特殊道具示例代码七、设计关卡系统示例代码八、添加音效和背景音乐示例代码九、多人游戏…...

Python学习之路-初识爬虫:requests

Python学习之路-初识爬虫:requests requests的作用 作用&#xff1a;发送网络请求&#xff0c;返回响应数据 中文文档 &#xff1a; http://docs.python-requests.org/zh_CN/latest/index.html 为什么学requests而不是urllib requests的底层实现就是urllibrequests在pytho…...

Linux 常用的命令

① 基本命令 uname -m 显示机器的处理器架构uname -r 显示正在使用的内核版本dmidecode -q 显示硬件系统部件(SMBIOS / DMI) hdparm -i /dev/hda 罗列一个磁盘的架构特性hdparm -tT /dev/sda 在磁盘上执行测试性读取操作系统信息arch 显示机器的处理器架构uname -m 显示机器的处…...

假期作业 10

1.整理磁盘操作的完整流程&#xff0c;如何接入虚拟机&#xff0c;是否成功识别&#xff0c;对磁盘分区工具的使用&#xff0c;格式化&#xff0c;挂载以及取消挂载 U盘接入虚拟机 在虚拟机--->可移动设备--->找到U盘---->连接 检测U盘是否被虚拟机识别 ls /dev/s…...

【洛谷 P3367】【模板】并查集 题解(并查集+路径压缩)

【模板】并查集 题目描述 如题&#xff0c;现在有一个并查集&#xff0c;你需要完成合并和查询操作。 输入格式 第一行包含两个整数 N , M N,M N,M ,表示共有 N N N 个元素和 M M M 个操作。 接下来 M M M 行&#xff0c;每行包含三个整数 Z i , X i , Y i Z_i,X_i,Y…...

Netty应用(一) 之 NIO概念 基本编程

目录 第一章 概念引入 1.分布式概念引入 第二章 Netty基础 - NIO 1.引言 1.1 什么是Netty&#xff1f; 1.2 为什么要学习Netty&#xff1f; 2.NIO编程 2.1 传统网络通信中开发方式及问题&#xff08;BIO&#xff09; 2.1.1 多线程版网络编程 2.1.2 线程池版的网络编程…...

tkinter-TinUI-xml实战(10)展示画廊

tkinter-TinUI-xml实战&#xff08;10&#xff09;展示画廊 引言声明文件结构核心代码主界面统一展示控件控件展示界面单一展示已有展示多类展示 最终效果在这里插入图片描述 ![](https://img-blog.csdnimg.cn/direct/286fcaa2fa5648a992a0ac79b4efad82.png) ………… 结语 引言…...

LeetCode二叉树的垂序遍历

题目描述 给你二叉树的根结点 root &#xff0c;请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言&#xff0c;其左右子结点分别位于 (row 1, col - 1) 和 (row 1, col 1) 。树的根结点位于 (0, 0) 。 二叉树的 垂序遍历 从最左边的列开始直到…...

[linux c]linux do_div() 函数用法

linux do_div() 函数用法 do_div() 是一个 Linux 内核中的宏&#xff0c;用于执行 64 位整数的除法操作&#xff0c;并将结果存储在给定的变量中&#xff0c;同时将余数存储在另一个变量中。这个宏通常用于内核编程中&#xff0c;特别是在处理大整数和性能敏感的场合。 函数原…...

Python学习之路-爬虫提高:常见的反爬手段和解决思路

Python学习之路-爬虫提高:常见的反爬手段和解决思路 常见的反爬手段和解决思路 明确反反爬的主要思路 反反爬的主要思路就是&#xff1a;尽可能的去模拟浏览器&#xff0c;浏览器在如何操作&#xff0c;代码中就如何去实现。浏览器先请求了地址url1&#xff0c;保留了cookie…...

python_numpy库_ndarray的聚合操作、矩阵操作等

一、ndarray的聚合操作 1、求和np.sum() import numpy as np ​ n np.arange(10) print(n) ​ s np.sum(n) print(s) ​ n np.random.randint(0,10,size(3,5)) print(n) s1 np.sum(n) print(s1) #全部数加起来 s2 np.sum(n,axis0) print(s2) #表示每一列的多行求和 …...

python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui

文章目录 用GUI自动控制键盘和鼠标pyautogui 模块鼠标屏幕位置——移动地图——pyautogui.size鼠标位置——自身定位——pyautogui.position()移动鼠标——pyautogui.moveTo拖动鼠标滚动鼠标 键盘按下键盘释放键盘 开始与结束通过注销关闭所有程序 用GUI自动控制键盘和鼠标 在…...

面试:大数据和深度学习之间的关系是什么?

大数据与深度学习之间存在着紧密的相互关系&#xff0c;它们在当今技术发展中相辅相成。 大数据的定义与特点:大数据指的是规模(数据量)、多样性(数据类型)和速度(数据生成及处理速度)都超出了传统数据处理软件和硬件能力范围的数据集。它具有四个主要特点&#xff0c;通常被称…...

航芯ACM32G103开发板评测 08 ADC Timer外设测试

航芯ACM32G103开发板评测 08 ADC Timer外设测试 1. 软硬件平台 ACM32G103 Board开发板MDK-ARM Keil 2. 定时器Timer 在一般的MCU芯片中&#xff0c;定时器这个外设资源是非常重要的&#xff0c;一般可以分为SysTick定时器&#xff08;系统滴答定时器&#xff09;、常规定时…...

【Linux学习】生产者-消费者模型

目录 22.1 什么是生产者-消费者模型 22.2 为什么要用生产者-消费者模型? 22.3 生产者-消费者模型的特点 22.4 BlockingQueue实现生产者-消费者模型 22.4.1 实现阻塞队列BlockQueue 1) 添加一个容器来存放数据 2)加入判断Blocking Queue情况的成员函数 3)实现push和pop方法 4)完…...

三、案例 - MySQL数据迁移至ClickHouse

MySQL数据迁移至ClickHouse 一、生成测试数据表和数据1.在MySQL创建数据表和数据2.在ClickHouse创建数据表 二、生成模板文件1.模板文件内容2.模板文件参数详解2.1 全局设置2.2 数据读取&#xff08;Reader&#xff09;2.3 数据写入&#xff08;Writer&#xff09;2.4 性能设置…...

[WinForm开源]概率计算器 - Genshin Impact(V1.0)

创作目的&#xff1a;为方便旅行者估算自己拥有的纠缠之缘能否达到自己的目的&#xff0c;作者使用C#开发了一款小型软件供旅行者参考使用。 创作说明&#xff1a;此软件所涉及到的一切概率与规则完全按照游戏《原神》(V4.4.0)内公示的概率与规则&#xff08;包括保底机制&…...

vscode 代码调试from IPython import embed

一、讲解 这种代码调试方法非常的好用。 from IPython import embed上面的代码片段是用于Python中嵌入一个交互式IPython shell的方法。这可以在任何Python脚本或程序中实现&#xff0c;允许在执行到该点时暂停程序&#xff0c;并提供一个交互式环境&#xff0c;以便于检查、…...

双活工作关于nacos注册中心的数据迁移

最近在做一个双活的项目&#xff0c;在纠结一个注册中心是在双活机房都准备一个&#xff0c;那主机房的数据如果传过去呢&#xff0c;查了一些资料&#xff0c;最终在官网查到了一个NacosSync 的组件&#xff0c;主要用来做数据传输的&#xff0c;并且支持在线替换注册中心的&a…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...