【AprilTag】视觉定位实战 | 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别

写在前面:
🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝
个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。

🔍 本文系 清流君 原创之作,荣幸在CSDN首发🐒
若您觉得内容有价值,还请评论告知一声,以便更多人受益。
转载请注明出处,尊重原创,从我做起。

👍 点赞、评论、收藏,三连走一波,让我们一起养成好习惯😜
在这里,您将收获的不只是技术干货,还有思维的火花

📚 系列专栏:【机器视觉】系列,带您深入浅出,探索机器视觉技术。🖊
愿我的分享能为您带来启迪,如有不足,敬请指正,让我们共同学习,交流进步!

🎭 人生如戏,我们并非能选择舞台和剧本,但我们可以选择如何演绎 🌟
感谢您的支持与关注,让我们一起在知识的海洋中砥砺前行~~~


文章目录

  • 引言
  • 一、准备工作
    • 1.1 安装 usb_cam 驱动
    • 1.2 安装相机标定功能包
    • 1.3 准备标定板和 USB 摄像头
  • 二、相机标定
    • 2.1 启动摄像头驱动节点
    • 2.2 确定相机编号
    • 2.3 查看启动的设备是否正确
    • 2.4 运行相机标定节点
    • 2.5 移动标定板或摄像头
    • 2.6 得到标定结果
    • 2.7 保存保定数据
  • 三、对焦问题
    • 3.1 启动摄像头存在的警告
    • 3.2 对焦问题的可能原因
  • 四、运行Apriltag_ros
    • 4.1 安装 Apriltag_ros 功能包
    • 4.2 修改配置文件
    • 4.3 运行Apriltag_ros
      • (1) 启动 USB 相机驱动
      • (2) 运行 AprilTag_ros 算法
      • (3) RViz 可视化界面
      • (4) 输出定位数据
  • 五、总结
  • 参考资料


引言

  上一篇博客介绍了虚拟机 Ubuntu18.04 安装 USB 摄像头 ROS 驱动 usb_cam 的最新方法,本篇博客讲解如何使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别。


一、准备工作

1.1 安装 usb_cam 驱动

  系统环境:Ubuntu18.04

  本教程是基于 usb_cam 包读取图像,因此需要提前安装 usb_cam 驱动,参见:

  【Ubuntu】虚拟机安装USB摄像头ROS驱动 usb_cam(最新方法)

1.2 安装相机标定功能包

  安装 camera_calibration 功能包:

sudo apt-get install ros-melodic-camera-calibration

1.3 准备标定板和 USB 摄像头

  准备一个已知尺寸的标定板,本实验使用的是 6 × 9 6\times9 6×9(列X行),边长为 1.8 c m 1.8cm 1.8cm 的棋盘标定板。

  一个通过 ROS 发布图像的单目 USB 摄像头。


二、相机标定

2.1 启动摄像头驱动节点

rosrun usb_cam usb_cam_node

2.2 确定相机编号

  确定使用的video_id,使用如下命令查看:

ls /dev/video*

  一般笔记本电脑自带的摄像头 id 0 0 0,外接的摄像头 id 1 1 1。然后根据需要修改usb_cam/src/usb_cam/launch/usb_cam-test.launch里面的<param name="video_device" value="/dev/video1" />

  尝试启动摄像头。

roslaunch usb_cam usb_cam-test.launch

  但是博主这样写会报错:

… logging to /home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/roslaunch-qingliu-4538.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://localhost:44077/
SUMMARY
========
PARAMETERS

  • /image_view/autosize: True
  • /rosdistro: melodic
  • /rosversion: 1.14.13
  • /usb_cam/camera_frame_id: usb_cam
  • /usb_cam/color_format: yuv422p
  • /usb_cam/image_height: 480
  • /usb_cam/image_width: 640
  • /usb_cam/io_method: mmap
  • /usb_cam/pixel_format: yuyv
  • /usb_cam/video_device: /dev/video1

NODES
/image_view (image_view/image_view)
usb_cam (usb_cam/usb_cam_node)
ROS_MASTER_URI=http://localhost:11311
process[usb_cam-1]: started with pid [4558]
process[image_view-2]: started with pid [4559]
[ INFO] [1726639123.930729617]: Initializing nodelet with 4 worker threads.
[ INFO] [1726639124.024001715]: Using transport “raw”
[ INFO] [1726639124.046743699]: using default calibration URL
[ INFO] [1726639124.047399791]: camera calibration URL: file:///home/qingliu/.ros/camera_info/head_camera.yaml
[ INFO] [1726639124.047502595]: Unable to open camera calibration file [/home/qingliu/.ros/camera_info/head_camera.yaml]
[ WARN] [1726639124.047555944]: Camera calibration file /home/qingliu/.ros/camera_info/head_camera.yaml not found.
[ INFO] [1726639124.047608139]: Starting ‘head_camera’ (/dev/video1) at 640x480 via mmap (yuyv) at 30 FPS
[ERROR] [1726639124.047678525]: VIDIOC_G_FMT error 22, Invalid argument
[usb_cam-1] process has died [pid 4558, exit code 1, cmd /home/qingliu/catkin_ws/devel/lib/usb_cam/usb_cam_node __name:=usb_cam __log:=/home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/usb_cam-1.log].
log file: /home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/usb_cam-1*.log

解决方法

  修改文件~/catkin_ws/src/usb_cam/launch/usb_cam-test.launch

<param name="video_device" value="/dev/video0" />

  修改为 /dev/video0

2.3 查看启动的设备是否正确

查看启动的设备是否正确,若正确则关掉再打开驱动:

rosrun usb_cam usb_cam_node

查看图像是否发布, 列出 topic 确保相机正在通过ROS发布图像:

rostopic list 

这会显示所有已发布的 topic,检查是否有 image_raw topic。以下是本实验的相机topic:

/image_view/output
/image_view/parameter_descriptions
/image_view/parameter_updates
/usb_cam/camera_info
/usb_cam/image_raw
/usb_cam/image_raw/compressed
/usb_cam/image_raw/compressed/parameter_descriptions
/usb_cam/image_raw/compressed/parameter_updates
/usb_cam/image_raw/compressedDepth
/usb_cam/image_raw/compressedDepth/parameter_descriptions
/usb_cam/image_raw/compressedDepth/parameter_updates
/usb_cam/image_raw/theora
/usb_cam/image_raw/theora/parameter_descriptions
/usb_cam/image_raw/theora/parameter_updates

2.4 运行相机标定节点

运行 camera_calibration 标定节点:

rosrun camera_calibration cameracalibrator.py --size 5x8 --square 0.018 image:=/usb_cam/image_raw camera:=/usb_cam  --no-service-check

此命令运行标定结点的python脚本,其中 :

  • --size 5x8 为棋盘内部角点的个数,方格几列几行(需要减 1 1 1),比如我的标定板方格是 6 × 9 6\times 9 6×9,则 size 5 × 8 5\times 8 5×8
  • --square 0.018 为每个棋盘格的边长,单位默认为米( m m m)

  注意 7 × 9 7\times 9 7×9 中间不能用“ ∗ * ”,是字母“ x x x”。

  • image:=/usb_cam/image_raw 为当前订阅的图像来自名为/usb_cam/image_raw的 topic
  • camera:=/usb_cam 为摄像机名
  • 加上--no-service-check是因为一开始运行后出现下面的错误,参考官网加上此参数后就可正常显示。

(‘Waiting for service’, ‘/camera/set_camera_info’, ‘…’)
Service not found

  此操作将打开标定窗口,如下图所示:

在这里插入图片描述

2.5 移动标定板或摄像头

为了达到良好的标定效果,需要在摄像机周围移动标定板,并完成以下基本需求:

  • 移动标定板到画面的最左、右,最上、下方
  • 移动标定板到视野的最近和最远处
  • 移动标定板使其充满整个画面
  • 保持标定板倾斜状态并使其移动到画面的最左、右,最上、下方

右侧四个参数的含义:

  • 当标定板移动到画面的最左、右方时,此时,窗口的X会达到最小或满值
  • 同理,Y指示标定板的在画面的上下位置
  • Size表示标定板在视野中的距离,也可以理解为标定板离摄像头的远近
  • Skew为标定板在视野中的倾斜位置

  每次移动之后,保持标定板不动直到窗口出现高亮提示。

  直到条形变为绿色。当 CRLIBRATE 按钮亮起时,代表已经有足够的数据进行摄像头的标定,此时按下 CRLIBRATE 并等待一分钟左右,标定界面变成灰色,无法进行操作,属于正常情况。
在这里插入图片描述

2.6 得到标定结果

*** Added sample 1, p_x = 0.612, p_y = 0.460, p_size = 0.340, skew = 0.152
*** Added sample 2, p_x = 0.556, p_y = 0.498, p_size = 0.319, skew = 0.277
*** Added sample 3, p_x = 0.373, p_y = 0.579, p_size = 0.321, skew = 0.245
*** Added sample 4, p_x = 0.363, p_y = 0.353, p_size = 0.319, skew = 0.201
*** Added sample 5, p_x = 0.471, p_y = 0.309, p_size = 0.294, skew = 0.162
*** Added sample 6, p_x = 0.603, p_y = 0.319, p_size = 0.282, skew = 0.110
*** Added sample 7, p_x = 0.663, p_y = 0.296, p_size = 0.358, skew = 0.164
*** Added sample 8, p_x = 0.671, p_y = 0.199, p_size = 0.434, skew = 0.139
*** Added sample 9, p_x = 0.674, p_y = 0.144, p_size = 0.524, skew = 0.194
*** Added sample 10, p_x = 0.683, p_y = 0.026, p_size = 0.572, skew = 0.131
*** Added sample 11, p_x = 0.623, p_y = 0.086, p_size = 0.652, skew = 0.143
*** Added sample 12, p_x = 0.586, p_y = 0.262, p_size = 0.635, skew = 0.183
*** Added sample 13, p_x = 0.531, p_y = 0.403, p_size = 0.635, skew = 0.250
*** Added sample 14, p_x = 0.485, p_y = 0.223, p_size = 0.663, skew = 0.244
*** Added sample 15, p_x = 0.560, p_y = 0.329, p_size = 0.516, skew = 0.194
*** Added sample 16, p_x = 0.570, p_y = 0.489, p_size = 0.470, skew = 0.177
*** Added sample 17, p_x = 0.515, p_y = 0.515, p_size = 0.399, skew = 0.122
*** Added sample 18, p_x = 0.494, p_y = 0.618, p_size = 0.334, skew = 0.089
*** Added sample 19, p_x = 0.491, p_y = 0.516, p_size = 0.265, skew = 0.061
*** Added sample 20, p_x = 0.459, p_y = 0.414, p_size = 0.207, skew = 0.069
**** Calibrating ****
mono pinhole calibration…
*** Added sample 63, p_x = 0.568, p_y = 0.398, p_size = 0.252, skew = 0.181
*** Added sample 64, p_x = 0.449, p_y = 0.598, p_size = 0.242, skew = 0.006
*** Added sample 65, p_x = 0.382, p_y = 0.635, p_size = 0.218, skew = 0.080
D = [0.03868745150785007, -0.029877004108823855, -0.0007851867081518497, -0.0008866834766470662, 0.0]
K = [433.18386473568006, 0.0, 341.5023734989315, 0.0, 433.4953796121861, 244.3823670617905, 0.0, 0.0, 1.0]
R = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
P = [438.92010498046875, 0.0, 340.88175832247, 0.0, 0.0, 439.3984375, 243.95816827518865, 0.0, 0.0, 0.0, 1.0, 0.0]
None
# oST version 5.0 parameters

[image]

width 640

height 480

[narrow_stereo]

camera matrix
433.183865 0.000000 341.502373
0.000000 433.495380 244.382367
0.000000 0.000000 1.000000

distortion
0.038687 -0.029877 -0.000785 -0.000887 0.000000

rectification
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000

projection
438.920105 0.000000 340.881758 0.000000
0.000000 439.398438 243.958168 0.000000
0.000000 0.000000 1.000000 0.000000

其中,K为相机内参矩阵

  • distortion:畸变系数矩阵
  • camera matrix:摄像头的内部参数矩阵
  • distortion:畸变系数矩阵
  • rectification:矫正矩阵,一般为单位阵
  • projection:外部世界坐标到像平面的投影矩阵

2.7 保存保定数据

  点击 SAVE 按钮。

在这里插入图片描述
  点击 COMMIT 按钮将结果保存到默认文件夹,终端输出如下信息,说明标定结果已经保存在相应文件夹下。下次启动 usb_cam 节点时,会自动调用。

(‘Wrote calibration data to’, ‘/tmp/calibrationdata.tar.gz’)

在这里插入图片描述
  其中,ost.yaml 文件即为相机内参的标定文件。

  至此,相机标定完成!


三、对焦问题

3.1 启动摄像头存在的警告

  启动摄像头存在如下警告:

[ WARN] [1726642015.933315970]: unknown control ‘focus_auto’

3.2 对焦问题的可能原因

出现这个警告可能是有以下两种原因:

  • 因为参数设置不匹配,默认像素的宽和高跟摄像头不匹配。

  • 还有可能只是所使用的相机根本没有自动对焦功能。

因此不用管这个问题。


四、运行Apriltag_ros

4.1 安装 Apriltag_ros 功能包

  Apriltag_ros 的安装非常简单,将源码放到工作空间路径下,如catkin_ws/src,然后编译即可。

cd catkin_ws/src
git clone https://github.com/AprilRobotics/apriltag_ros.git
cd ..
catkin_make

4.2 修改配置文件

  首先修改 ~/catkin_ws/src/apriltag_ros/apriltag_ros/launch/continuous_detection.launch 文件。

  apriltag_ros 需要订阅相机图像数据与相机信息,比如对于USB摄像头,在开启相机时会发布两个相关的 topic:

  • /usb_cam/camera_info
  • /usb_cam/image_raw

  因此需将 camera_namecamera_frame 的内容修改为订阅的 topic。

launch 文件内容修改如下:

<!-- 修改 --><arg name="camera_name" default="/usb_cam" /><arg name="image_topic" default="image_raw" />
<!-- 添加 --><arg name="camera_frame" default="/camera" />

完整launch文件内容如下:

<launch><!-- set to value="gdbserver localhost:10000" for remote debugging --><arg name="launch_prefix" default="" /><!-- configure camera input --><arg name="camera_name" default="/usb_cam" /><arg name="image_topic" default="image_raw" /><arg name="camera_frame" default="/camera" /><arg name="queue_size" default="1" /> <!-- apriltag_ros continuous detection node --><node pkg="apriltag_ros" type="apriltag_ros_continuous_node" name="apriltag_ros_continuous_node" clear_params="true" output="screen" launch-prefix="$(arg launch_prefix)"><!-- Remap topics from those used in code to those on the ROS network --><remap from="image_rect" to="$(arg camera_name)/$(arg image_topic)" /><remap from="camera_info" to="$(arg camera_name)/camera_info" /><param name="publish_tag_detections_image" type="bool" value="true" /><!-- default: false --><param name="queue_size" type="int" value="$(arg queue_size)" /><!-- load parameters (incl. tag family, tags, etc.) --><rosparam command="load" file="$(find apriltag_ros)/config/settings.yaml"/><rosparam command="load" file="$(find apriltag_ros)/config/tags.yaml"/></node>
</launch>

  修改 ~/catkin_ws/src/apriltag_rosapriltag_ros/config/tags.yaml 文件,添加需要检测的二维码id与自己测量得到的二维码尺寸大小size(单位:米)。

standalone_tags:[{id: 1, size: 0.0515},{id: 2, size: 0.0515},{id: 3, size: 0.0515},{id: 4, size: 0.0515},{id: 5, size: 0.0515},{id: 6, size: 0.0515}    ]

注意
1、同一 ID 的 Apriltag 码不能在该配置文件中以不同的大小出现两次,也不能出现在一张图片的两个地方。这些都将在检测中产生歧义。

2、确保打印的 AprilTag 码至少包含 1 1 1 位宽的白色边框,AprilTag 算法会对周围的白色边框进行采样。

4.3 运行Apriltag_ros

  分别打开四个终端,运行如下命令行:

(1) 启动 USB 相机驱动

roslaunch usb_cam usb_cam-test.launch

(2) 运行 AprilTag_ros 算法

roslaunch apriltag_ros continuous_detection.launch

(3) RViz 可视化界面

rosrun rviz rviz

(4) 输出定位数据

rostopic echo /tag_detections

  正确运行识别到 AprilTag 的界面如下图所示:

在这里插入图片描述

  输出的定位数据如下:

在这里插入图片描述


五、总结

  本教程介绍了如何使用 ROS 进行相机标定和 Apriltag 识别。

  首先,安装了 usb_cam 驱动和 camera_calibration 功能包,并准备了一个 6 × 9 6\times9 6×9 的棋盘格标定板和一个单目 USB 摄像头。

  然后,启动了摄像头驱动节点,并调整了摄像头视频设备 id,以正确地接收摄像头图像。

  接下来,运行了相机标定节点,通过在摄像机周围移动标定板,完成了标定过程,并得到了相机的内参矩阵和畸变系数矩阵。

  最后,安装了 Apriltag_ros 功能包,并修改了配置文件以匹配摄像头和 Apriltag 尺寸。运行了 Apriltag 识别节点,并在 RViz 中可视化了检测结果。

  通过本教程,读者可掌握如何使用 ROS 进行相机标定和 Apriltag 识别,这对于机器人视觉系统至关重要。


参考资料

  1、【Ubuntu】虚拟机安装USB摄像头ROS驱动 usb_cam(最新方法)

  2、使用Apriltags实现定位、评估定位精度的全流程记录

  3、ROS下采用camera_calibration进行单目相机标定


后记:

🌟 感谢您耐心阅读这篇关于 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别 的技术博客。 📚

🎯 如果您觉得这篇博客对您有所帮助,请不要吝啬您的点赞和评论 📢

🌟您的支持是我继续创作的动力。同时,别忘了收藏本篇博客,以便日后随时查阅。🚀

🚗 让我们一起期待更多的技术分享,共同探索移动机器人的无限可能!💡

🎭感谢您的支持与关注,让我们一起在知识的海洋中砥砺前行 🚀

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Mapsui:一个 .NET 开源的地图组件库

前言 今天大姚给大家分享一个.NET开源&#xff08;MIT License&#xff09;、免费、同时支持多平台框架&#xff08;MAUI、WPF、Avalonia、Uno、Blazor、WinUI、Eto、.NET Android 和 .NET iOS&#xff09;地图组件库&#xff1a;Mapsui。 项目源代码 支持的UI框架的NuGet包 创…

文章排名优化@大众点评代发灰色词是什么软件

文章排名优化大众点评代发灰色词是什么软件 如何优化灰色词百度排名推广&#xff08;灰色词推广代发/代做&#xff09;#百度推广#关键词排名#灰色词排名 欢迎来到百收网SEO搜索群&#xff0c;我是狂潮老师&#xff0c;这一节我们来讲一下 on page SEO是什么&#xff1f;大众点…

【JAVA入门】Day46 - Commons-io

【JAVA入门】Day46 - Commons-io 文章目录 【JAVA入门】Day46 - Commons-io一、Commons-io 的常见方法 Commons-io 其实是一个工具包&#xff0c;它里面包含一系列有关IO操作的方法。它的作用就是来提高IO流的开发效率。 Commons 工具包中包含了很多很多有用的工具类&a…

【专题】2024中国生物医药出海现状与趋势蓝皮书报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37719 出海已成为中国医药产业实现提速扩容的重要途径。目前&#xff0c;中国医药产业发展态势良好&#xff0c;创新能力不断增强&#xff0c;然而也面临着医保政策改革和带量集采带来的压力。政府积极出台多项政策支持医药企业出海…

【新手上路】衡石分析平台使用手册-租户管理

租户管理​ 衡石系统支持服务一个平台方和多个企业客户的租户模式&#xff0c;平台方管理租户&#xff0c;为租户提供数据&#xff0c;租户在系统内进行数据分析。 衡石系统增加工作空间的设计&#xff0c;在平台方和租户之间提供单向的传递通道&#xff0c;平台厂商可以轻松…

nature communications |多层次蛋白质组分析揭示弥漫型和肠型胃癌之间的分子多样性

文章信息 发表期刊&#xff1a;nature communications 发表日期&#xff1a;2023年2月14日 影响因子&#xff1a;14.7 研究背景 胃癌是世界上主要的癌症类型之一。弥漫型胃癌(DGC)和肠型胃癌(IGC)是胃癌(GC)的主要组织学类型&#xff0c;DGC呈分散的细胞组织&#xff0c;黏…

Vue3使用shapefile读取矢量数据,以数组形式返回坐标点

npm安装: npm install shapefile --save-dev 源码: <script setup> import { ElMessage } from element-plus; import { ref } from vue; // 引入 ref import * as shapefile from "shapefile";// 使用 ref 创建一个引用 const uploadRef ref(null);// 解析…

怎么能让电脑屏幕显示多个监控画面?电脑监控如何多画面显示?

想象一下&#xff0c;你的电脑屏幕变成了一个“指挥中心”&#xff0c;上面同时显示多个监控画面&#xff0c;每个角落都有重要的信息。无论是监控员工的工作情况、实时查看服务器状态&#xff0c;还是观看监控视频&#xff0c;一切尽在掌握中。这不是科幻电影里的场景&#xf…

使用IDA Pro动态调试Android APP

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 关于 android_server android_server 是 IDA Pro 在 Android 设备上运行的一个调试服务器。 通过在 Android 设备上运行android_server&#xff0c;IDA Pro …

最新简洁大方的自动发卡网站源码/鲸发卡v11.61系统源码/修复版

源码简介&#xff1a; 最新简洁大方的自动发卡网站源码&#xff0c;它就是鲸发卡v11.61系统源码&#xff0c;它是修复版。 说到鲸发卡系统&#xff0c;鲸发卡系统在发卡圈很多人都知道的&#xff0c;它是市面最好发卡系统之一&#xff0c;操作起来简单得很&#xff0c;界面也…

Django 5 学习笔记 2024版

1. 官方中文文档 Django 文档 | Django 文档 | Django (djangoproject.com) 2. 第一个应用 博客 总目录 <1>依赖安装: pip install django <2> 创建 工程 myapp django-admin startproject myapp cd myapp <3>创建 应用 app > python manage.py s…

【protobuf】ProtoBuf的学习与使用⸺C++

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 前言&#xff1a;之前我们学习了Linux与windows的protobuf安装&#xff0c;知道protobuf是做序列化操作的应用&#xff0c;今天我们来学习一下protobuf。 目录 ⼀、初识ProtoBuf 步骤1&#xff1a;创建.proto文件 步…

使用 HFD 加快 Hugging Face 模型和数据集的下载

Hugging Face 提供了丰富的预训练模型和数据集&#xff0c;而且使用 Hugging Face 提供的 from_pretrained() 方法可以轻松加载它们&#xff0c;但是&#xff0c;模型和数据集文件通常体积庞大&#xff0c;用默认方法下载起来非常花时间。 本文将指导你如何使用 HFD&#xff08…

安卓手机改ip地址改到其他市

在数字化时代&#xff0c;IP地址作为设备在网络上的唯一标识&#xff0c;其重要性不言而喻。有时&#xff0c;出于测试、学习或特定服务访问的需求&#xff0c;用户可能希望将安卓手机的IP地址修改为其他城市的地址。本文旨在探讨如何在安卓手机上修改IP地址至其他城市&#xf…

分布式事务学习笔记(五)微服务实现Seata TCC模式、TC服务器高可用异地容灾

文章目录 前言6 Seata TCC 模式6.1 实现原理6.2 优缺点6.3 空回滚和业务悬挂6.3.1 空回滚6.3.2 业务悬挂 6.4 微服务实现TCC模式6.4.1 思路分析6.4.2 声明TCC接口6.4.3 编写实现类6.4.4 Controller类调用TCC接口6.4.5 修改配置文件application.yml6.4.6 重启微服务并测试 7 TC服…

​​使用ENVI之大气校正(下)

再根据遥感影像的拍摄时间将Flight ate与Flight Time GMT (H:M:SS)填写&#xff0c;如要查询按如下方法 这里按照表中的内容修改 根据影像范围的经纬度与拍摄时间更改Atmospheric Model&#xff0c;更改完成后点击Multispectral Settings...在跳出的界面中选择GUI再点击Default…

轨迹规划——估计规划轨迹曲率代码实现

已经知道轨迹&#xff08;x&#xff0c;y&#xff0c;theta&#xff09;一系列点集合&#xff0c;根据之前一篇文章&#xff1a; Estimating the Trajectory Curvature Using Three Trajectory Points Output From Motion Planning 代码如下&#xff1a; #include<iostre…

「iOS」——单例模式

iOS学习 前言单例模式的概念单例模式的优缺点单例模式的两种模式懒汉模式饿汉模式单例模式的写法 总结 前言 在一开始学习OC的时候&#xff0c;我们初步接触过单例模式。在学习定时器与视图移动的控件中&#xff0c;我们初步意识到单例模式的重要性。对于我们需要保持的控件&a…

【StringUtils工具类】isEmpty 和 isBlank 的区别

isEmpty 和 isBlank 的区别 前言isEmpty系列StringUtils.isEmpty&#xff08;&#xff09;StringUtils.isNotEmpty&#xff08;&#xff09;StringUtils.isAnyEmpty&#xff08;&#xff09;StringUtils.isNoneEmpty&#xff08;&#xff09;如何插入一段漂亮的代码片 isBank系…

FastDFS架构和原理

FastDFS 项目地址&#xff1a;https://github.com/happyfish100FastDFS 主要功能包括&#xff1a;文件存储&#xff0c;同步和访问&#xff0c;基于高可用的负载均衡。FastDFS 非常适合基于文件服务的站点。FastDFS 有跟踪服务器&#xff08;Tracker Server&#xff09;、存储服…