使用kaliber与imu_utils进行IMU、相机+IMU联合标定
目录
1 标定工具编译
1.1 IMU标定工具 imu_utils
1.2 相机标定工具 kaliber
2 标定数据录制
3 开始标定
3.1 IMU标定
3.2 相机标定
3.3 相机+IMU联合标定
4 将参数填入ORBSLAM的文件中
1 标定工具编译
1.1 IMU标定工具 imu_utils
标定IMU我们使用imu_utils软件进行标定:
首先我们安装标定软件的依赖项:Eigen、Ceres
通过命令行安装Eigen3.3.4即可
sudo apt-get install libdw-dev sudo apt-get install libeigen3-dev
安装Ceres1.14.0的依赖项:
sudo apt-get install liblapack-dev libblas-dev libeigen3-dev libgflags-dev libgoogle-glog-dev sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3 libgflags-dev libgoogle-glog-dev libgtest-dev
安装Ceres1.14.0
wget -O ~/Downloads/ceres.zip https://github.com/ceres-solver/ceres-solver/archive/1.14.0.zip cd ~/Downloads/ && unzip ceres.zip -d ~/Downloads/ cd ~/Downloads/ceres-solver-1.14.0 mkdir ceres-bin && cd ceres-bin cmake .. sudo make install -j4
这些安装之后,我们开始安装imu_utils。
首先为我们要先在ROS环境下编译code_utils,否则会报错:
cd ..catkin_imu/src git clone https://github.com/gaowenliang/code_utils cd .. catkin_make
运行这个步骤会报错,找不到backward.hpp这个头文件:
解决方案:
把src/code_utils/CMakeList.txt中,添加路径:include_directories(“include/code_utils”)
如下图:
安装imu_utils:
cd ..catkin_imu/src git clone https://github.com/gaowenliang/imu_utils cd .. catkin_make #编译imu_utils
这样就编译成功了:
1.2 相机标定工具 kaliber
标定IMU+相机与相机的标定我们使用kaliber软件进行标定:
先进行依赖安装:
sudo apt install python-setuptools python-rosinstall ipython libeigen3-dev libboost-all-dev doxygen libopencv-dev sudo apt install ros-noetic-vision-opencv ros-noetic-image-transport-plugins ros-noetic-cmake-modules sudo apt install python-software-properties software-properties-common libpoco-dev python-matplotlib python-scipy python-git python-pip ipython sudo apt install libtbb-dev libblas-dev liblapack-dev python-catkin-tools libv4l-dev sudo apt install build-essential python-dev libxml2 libxml2-dev zlib1g-dev bison flex libigraph0-dev texlive-binaries sudo pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-igraph sudo pip install python-igraph --upgrade sudo apt-get install python-setuptools python-rosinstall ipython libeigen3-dev libboost-all-dev doxygen libopencv-dev ros-melodic-vision-opencv ros-melodic-image-transport-plugins ros-melodic-cmake-modules python-software-properties software-properties-common libpoco-dev python-matplotlib python-scipy python-git python-pip ipython libtbb-dev libblas-dev liblapack-dev python-catkin-tools libv4l-dev
编译:
kaliber下载网站https://gitcode.net/mirrors/ethz-asl/kalibr 从上述网址下载Kaliber,正常编译即可。不会出什么问题。
2 标定数据录制
IMU数据:
IMU静置2小时,周围不要有振动,录制完成后利用下面的脚本转化成rosbag的格式。
这里是一个可以使用的转化脚本:将文本的IMU信息转化为了sensor_msgs/Imu的信息
""" Function: convert rawdata into rosbag Author: Yiheng Zhao Date: 2023.10.11 """ import math import os import cv2 import numpy as np from vp_config import ROOT_PATH from utility import ReadQapData, fix_filenameimport rospy import rosbag from sensor_msgs.msg import Imu, Image from cv_bridge import CvBridge import openpyxl import timeif __name__ == "__main__":############################# rosbag config###########################save_path = os.path.join(ROOT_PATH, "imu.bag")bag = rosbag.Bag(save_path, 'w')############################# main function############################# read dataworkbook = openpyxl.load_workbook(r'D:\projectslam\off_data_zhuan_ros\raw_data\20231010_180949.xlsx')sheet = workbook.active## begin frame by frame processi = 0for row in sheet.iter_rows(values_only=True):#create new messageimu_msg = Imu()imu_msg.header.frame_id = "base_link"imu_msg.header.seq = itimestamp = time.time()formatted_timestamp = "{:.9f}".format(timestamp)secs = int(formatted_timestamp.split('.')[0])nsecs = int(formatted_timestamp.split('.')[1])imu_msg.header.stamp.secs = secsimu_msg.header.stamp.nsecs = nsecsimu_msg.linear_acceleration.x = float(row[9])imu_msg.linear_acceleration.y = float(row[10])imu_msg.linear_acceleration.z = float(row[11])print("acceleration x is %f" % imu_msg.linear_acceleration.x)print("acceleration y is %f" % imu_msg.linear_acceleration.y)print("acceleration z is %f" % imu_msg.linear_acceleration.z)imu_msg.angular_velocity.x = ( float(row[6])/ 180.0 * 3.1415926)imu_msg.angular_velocity.y = ( float(row[7])/ 180.0 * 3.1415926)imu_msg.angular_velocity.z = ( float(row[8])/ 180.0 * 3.1415926)print("angular x is %f" % imu_msg.angular_velocity.x)print("angular y is %f" % imu_msg.angular_velocity.y)print("angular z is %f" % imu_msg.angular_velocity.z)bag.write(topic="/imu/data_raw", msg=imu_msg)i += 1time.sleep(0.033)bag.close()
我们得到了一个仅含IMU数据的bag。
相机数据录制:
缓慢移动相机,且相机和IMU之间不要发生相对运动,将相机左右移动、上下移动、旋转移动充分激励IMU,录制三分钟左右即可。
我们得到一个bag,包含IMU和相机数据:
下面这个脚本是合并IMU、相机图像数据的脚本:
""" Function: convert rawdata into rosbag Author: Yiheng Zhao Date: 2023.10.11 """ import math import os import cv2 import numpy as np from vp_config import ROOT_PATH from utility import ReadQapData, fix_filenameimport rospy import rosbag from sensor_msgs.msg import Imu, Image from cv_bridge import CvBridge import openpyxl import timeif __name__ == "__main__":############################# rosbag config###########################save_path = os.path.join(ROOT_PATH, "imu_cam.bag")bag = rosbag.Bag(save_path, 'w')############################# main function############################# read data image# 指定存储图片的目录路径image_directory = r'D:\projectslam\off_data_zhuan_ros\qap_out_data\image'# 初始化一个空列表来存储图片路径image_paths = []# 遍历目录下的所有文件for root, dirs, files in os.walk(image_directory):for file in files:# 检查文件扩展名是否为图片格式(例如,这里假设是以.jpg、.png、.jpeg为扩展名的图片)if file.lower().endswith(('.jpg', '.png', '.jpeg')):# 使用os.path.join()将目录和文件名组合成完整的文件路径image_path = os.path.join(root, file)# 将图片路径添加到列表中image_paths.append(image_path)print(image_paths)## read data imuworkbook = openpyxl.load_workbook(r'D:\projectslam\off_data_zhuan_ros\qap_out_data\imu.xlsx')sheet = workbook.active## begin frame by frame processi = 0for row in sheet.iter_rows(values_only=True):# create new messageimu_msg = Imu()imu_msg.header.frame_id = "base_link"imu_msg.header.seq = itimestamp = time.time()formatted_timestamp = "{:.9f}".format(timestamp)secs = int(formatted_timestamp.split('.')[0])nsecs = int(formatted_timestamp.split('.')[1])imu_msg.header.stamp.secs = secsimu_msg.header.stamp.nsecs = nsecsimu_msg.linear_acceleration.x = float(row[9])imu_msg.linear_acceleration.y = float(row[10])imu_msg.linear_acceleration.z = float(row[11])print("acceleration x is %f" % imu_msg.linear_acceleration.x)print("acceleration y is %f" % imu_msg.linear_acceleration.y)print("acceleration z is %f" % imu_msg.linear_acceleration.z)imu_msg.angular_velocity.x = (float(row[6]) / 180.0 * 3.1415926)imu_msg.angular_velocity.y = (float(row[7]) / 180.0 * 3.1415926)imu_msg.angular_velocity.z = (float(row[8]) / 180.0 * 3.1415926)print("angular x is %f" % imu_msg.angular_velocity.x)print("angular y is %f" % imu_msg.angular_velocity.y)print("angular z is %f" % imu_msg.angular_velocity.z)# 图像 msgimage = cv2.imread(image_paths[i])my_bridge = CvBridge()img_msg = my_bridge.cv2_to_imgmsg(cvim=image)img_msg.header.frame_id = "base_link"img_msg.header.seq = iimg_msg.header.stamp.secs = secsimg_msg.header.stamp.nsecs = nsecsbag.write(topic="/image/data_raw", msg=img_msg)bag.write(topic="/imu/data_raw", msg=imu_msg)i += 1time.sleep(0.033)bag.close()
下面开始标定。
3 开始标定
3.1 IMU标定
对于6轴的IMU,我们修改这个文件:
/bag/catkin_imu/src/imu_utils/launch/tum.launch
修改内容如下:
修改我们IMU的录制时间与IMU话题:
<launch><node pkg="imu_utils" type="imu_an" name="imu_an" output="screen"><param name="imu_topic" type="string" value= "/imu/data_raw"/><param name="imu_name" type="string" value= "custom_imu_nrxdwcs"/><param name="data_save_path" type="string" value= "$(find imu_utils)/imu666/"/><param name="max_time_min" type="int" value= "90"/><param name="max_cluster" type="int" value= "50"/></node></launch>
修改imu_topic为我们包的IMU录制话题:
修改imu_name为我们IMU的名字:这里我随便起得名,和客户名字有关系.....
修改max_time_min为我们IMU录制的时间:我这里是从09:55 - 11:30,我选择取前90分钟的数据。
修改max_cluster为采样频率,由于我录制不够2小时,因此修改采样频率为50HZ(增大了采样频率)。
修改data_save_path为我们标定完成的路径,即标定文件存放的位置。
下面开始标定:
打开标定IMU的ROS节点:
liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:~/Downloads$ cd /bag/catkin_imu/ liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:/bag/catkin_imu$ source devel/setup.bash liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:/bag/catkin_imu$ roslaunch imu_utils tum.launch
打开节点后,我们以200倍速度播包。
rosbag play imu.bag -r 200
播包完毕后,我们IMU标定就完成了。
标定文件存储在我们指定的路径中。
第一个文件就是我们需要的IMU参数。
3.2 相机标定
我们先需要下载标定版,这里我推荐带编码信息的棋盘格标定板:
标定版下载链接https://doc-08-5c-docs.googleusercontent.com/docs/securesc/2nlhb7mn3rh7ilhvic8i1i0lcg6lvbo5/kcic7lcag2vqbkks6cg7sa20rnhoqc5r/1696916775000/08341388560495021951/08634034057607032407/1DqKWgePodCpAKJCd_Bz-hfiEQOSnn_k0?e=download&ax=AA75yW7BQ9IbcKRqN7F30tCa7QeNZmYUtrGfL0rCKL3H-BPWurSVMZ8SlMyN7l7mcABbUuU4t6LKNh1GUv6oaKYdz8fhFhpvrys81_Tr-LK6b6VaHTYZrKdK1Xl-7jalz-zRTbOGJI0B_pxlK-zYjlJ5qptj6eJa12S-A520-9oO-QwEJa2FTA10ED_NooTkPqK2nYqfulra1G-7X7By1KB5iB1aK6goViNqPnnFNBWaSyNKb2GBEDPdMgTphe8yFZ9OSGtrzNW9zdbAdM-Ohm-JP34_llYMgTzRxwqKX9ltC34xf4bCU83vDIOfrjqZHos9XkPmWahZuxtJxZGuRDWIBKhOb1P8y6qOVpvRP-hNZB4z8uPyiQ-Qu8q5xqGH1oT6kuQONiCAm1kDI0c0wp4lBi0DMV_5HHBnOrS7x26nTrsWYFAsqdjcx0awomsAlDtSVMc4zZ8pQJDeoV7Qa19VAC-9BidANzgAca2TyLven2FHj3ogrAz-2nlHDOK6OHT3Rzjdd9I5UNRg3ZQUP5g8SEXUo3qHDM0u1n1PKoaZKoRlFaYTYyZKMTqnhOBiBuyjqNB8LRCIteoBC335dRHdjRSzwlOD79bLwQGjXw_ItlDo_6YUV1ZM8nep9kzzcLNP34d_MUMNp6rSBHyfug5jobqcdtHmcWFgJuf2b0u6H2UWHP-0WRmjbHWfdbDQKK8vEmgRlndGnk6gxL8HqL_PQYO0yJ6ddagbHBztZZCZbXSl_KUPYDVd212u-vsoc6BsgYoj200XU7vQE3AfekgV0RLJNzeL0RCIT7ghfHQIBNXFmfTq8Y4byyh5-wnlqTvHi5WgCsF6x9_2sC6FVdZtvOxmpBlufS_eT9FaWu-cNk30Kor_OnQUv8RMLO9mcJbtzw&uuid=51452ed9-1b64-4adc-88d9-65bedb46fdfc&authuser=0&nonce=5kor9vi5br1lg&user=08634034057607032407&hash=7qn0q7b6strcok04upeb271oq7qcpf6c 我们需要制作参数文档,参数文档的数学信息如下:
原始pdf的格子参数是: 6*6的格子 大格子边长:5.5cm 小格子边长:1.65cm 小格子与大格子边长比例:0.3调整后的格子参数是: 大格子边长:2.2cm 小格子边长:0.66cm 小格子与大格子边长比例:0.3
然后如果你是打印成了A4纸的形式,可以参考我的参数文档:A4.yaml
target_type: 'aprilgrid' #gridtype tagCols: 6 #number of apriltags tagRows: 6 #number of apriltags tagSize: 0.021 #size of apriltag, edge to edge [m] tagSpacing: 0.285714285714 #ratio of space between tags to tagSize codeOffset: 0 #code offset for the first tag in the aprilboard
现在我们进行针孔相机的标定:
rosrun kalibr kalibr_calibrate_cameras --target '/bag/catkin_kaliber/src/Kalibr/a4.yaml' --bag /home/liuhongwei/Desktop/imu_cam.bag --models pinhole-radtan --topics /image/data_raw --bag-from-to 10 100 --show-extraction
然后就开始了标定工作:
解释一下具体的参数:
--target:标定版的参数,就是我们刚才写的那个
--bag:包的路径
--models:针孔相机模型选这个
--topics:图像信息的话题
--bag-from-to:选取10-100s的图像进行标定,这个可以按照自己需求改,一般都是前几秒比较模糊就不要了
--show-extraction:展示图形化界面
标定完成后,会输出几个文件:
这个就是我们相机的内参了。
标定时可能会遇到这个问题,这是因为相机焦距太大了,我们需要设置个初始值:
Initialization of focal length failed. You can enable manual input by setting ‘KALIBR_MANUAL_FOCAL_LENGTH_INIT’.
遇到这种情况,我们先终端中设置变量
KALIBR_MANUAL_FOCAL_LENGTH_INIT = 1
然后程序运行时手动给相机设置初始焦距。
3.3 相机+IMU联合标定
这个我们事先制作几个文件:
1.imu的配置信息,我们取名为imu.yaml,这个就是我们把我们之前标定的IMU信息写入这个文件就行:
rostopic: /imu/data_raw update_rate: 30.0 #Hzaccelerometer_noise_density: 1.7640241083260223e-03 accelerometer_random_walk: 4.6133140085614272e-05 gyroscope_noise_density: 1.2287169549703986e-05 gyroscope_random_walk: 8.1951127134973680e-07
图像的话题还有IMU的频率不要忘记修改。
2.相机的内参标定信息:
这个是3.2节中生成的文件imu_cam-camchain.yaml:
cam0:cam_overlaps: []camera_model: pinholedistortion_coeffs: [-0.34038923175502456, 0.06977055299360228, 0.015293838790916657, -0.010372561499554008]distortion_model: radtanintrinsics: [1685.169877633105, 1656.9322836449144, 997.1304121813936, 474.3184148435317]resolution: [1920, 1080]rostopic: /image/data_raw
3.标定版文件,就是3.2中我们自己写的
target_type: 'aprilgrid' #gridtype tagCols: 6 #number of apriltags tagRows: 6 #number of apriltags tagSize: 0.021 #size of apriltag, edge to edge [m] tagSpacing: 0.285714285714 #ratio of space between tags to tagSize codeOffset: 0 #code offset for the first tag in the aprilboard
执行下面代码进行标定:
rosrun kalibr kalibr_calibrate_imu_camera --bag '/home/liuhongwei/Desktop/imu_cam.bag' --target '/bag/catkin_kaliber/src/Kalibr/a4.yaml' --cam '/bag/catkin_kaliber/src/Kalibr/imu_cam-camchain.yaml' --imu '/bag/catkin_kaliber/src/Kalibr/imu.yaml' --show-extraction
参数列表含义如下:
--bag:数据包路径
--target:标定版文件路径(A4.yaml)
--cam:相机内参文件路径(mu_cam-camchain.yaml)
--imu:IMU标定文件路径(imu.yaml)
--show-extraction:显示标定过程
执行如下:
标定结束:
结束后生成标定文件imu_cam-results-imucam.txt:
标定完毕。
4 将参数填入ORBSLAM的文件中
根据上述我们的标定结果,我们的yaml文件为:
%YAML:1.0#-------------------------------------------------------------------------------------------- # Camera Parameters. Adjust them! #-------------------------------------------------------------------------------------------- File.version: "1.0"Camera.type: "PinHole"# Camera calibration and distortion parameters (OpenCV) Camera1.fx: 1685.16987763 Camera1.fy: 1656.93228364 Camera1.cx: 997.13041218 Camera1.cy: 474.31841484Camera1.k1: -0.34038923175502456 Camera1.k2: 0.06977055299360228 Camera1.p1: 0.015293838790916657 Camera1.p2: -0.010372561499554008# Camera resolution Camera.width: 1920 Camera.height: 1080Camera.newWidth: 600 Camera.newHeight: 350# Camera frames per second Camera.fps: 30# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale) Camera.RGB: 1# Transformation from camera to body-frame (imu) IMU.T_b_c1: !!opencv-matrixrows: 4cols: 4dt: fdata: [0.94880513, 0.12309341, 0.27236458, 0.00027046,0.12309341, 0.98136615, 0.14754149, -0.00012572,-0.29088973, -0.10646184, 0.95081494, 0.00034056,0.0, 0.0, 0.0, 1.0]# IMU noise IMU.NoiseGyro: 1.2287169549703986e-05 #1.6968e-04 IMU.NoiseAcc: 1.7640241083260223e-03 #2.0e-3 IMU.GyroWalk: 8.1951127134973680e-07 IMU.AccWalk: 4.6133140085614272e-05 # 3e-03 IMU.Frequency: 30.0#-------------------------------------------------------------------------------------------- # ORB Parameters #--------------------------------------------------------------------------------------------# ORB Extractor: Number of features per image ORBextractor.nFeatures: 1000 # 1000# ORB Extractor: Scale factor between levels in the scale pyramid ORBextractor.scaleFactor: 1.2# ORB Extractor: Number of levels in the scale pyramid ORBextractor.nLevels: 8# ORB Extractor: Fast threshold # Image is divided in a grid. At each cell FAST are extracted imposing a minimum response. # Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST # You can lower these values if your images have low contrast ORBextractor.iniThFAST: 20 ORBextractor.minThFAST: 7#-------------------------------------------------------------------------------------------- # Viewer Parameters #-------------------------------------------------------------------------------------------- Viewer.KeyFrameSize: 0.05 Viewer.KeyFrameLineWidth: 1.0 Viewer.GraphLineWidth: 0.9 Viewer.PointSize: 2.0 Viewer.CameraSize: 0.08 Viewer.CameraLineWidth: 3.0 Viewer.ViewpointX: 0.0 Viewer.ViewpointY: -0.7 Viewer.ViewpointZ: -3.5 # -1.8 Viewer.ViewpointF: 500.0
5 Euroc单目+IMU数据集制作及跑通
用这个脚本进行拆包:
# -*- coding: utf-8 -*-import rosbag import csv from sensor_msgs.msg import Imu import os import roslib import rospy import cv2 from sensor_msgs.msg import Image from cv_bridge import CvBridge from cv_bridge import CvBridgeError import shutildef CreateDIR():folder_name = 'bag_tum'subfolders = ['left', 'right' , 'rgb' , 'depth']if not os.path.exists(folder_name):os.makedirs(folder_name)# 在主文件夹下创建子文件夹for subfolder in subfolders:subfolder_path = os.path.join(folder_name, subfolder)if not os.path.exists(subfolder_path):os.makedirs(subfolder_path)def CreateIMUCSV(umpackbag):csvfile = open('imudata.csv', 'w')csvwriter = csv.writer(csvfile)csvwriter.writerow(['timestamp [ns]', 'w_RS_S_x [rad s^-1]', 'w_RS_S_y [rad s^-1]', 'w_RS_S_z [rad s^-1]', 'a_RS_S_x [rad m s^-2]', 'a_RS_S_y [rad m s^-2]', 'a_RS_S_z [rad m s^-2]'])for topic, msg, t in umpackbag.read_messages(topics=['/imu/data_raw']):timestamp = msg.header.stamp.to_nsec()ax = msg.linear_acceleration.xay = msg.linear_acceleration.yaz = msg.linear_acceleration.zwx = msg.angular_velocity.xwy = msg.angular_velocity.ywz = msg.angular_velocity.zcsvwriter.writerow([timestamp, wx, wy, wz, ax, ay, az])#umpackbag.close()csvfile.close()def TransIMUdatatotxt():csv_file = './imudata.csv'txt_file = './imudata.txt'with open(csv_file, 'r') as file:reader = csv.reader(file)with open(txt_file, 'w') as output_file:writer = csv.writer(output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)for i, row in enumerate(reader):if i == 0:writer.writerow(['#' + cell for cell in row]) # 添加#号else:writer.writerow(row)# Save RGBD image and Save its timestamp def Savergb(umpackbag):path = './bag_tum/rgb/'bridge = CvBridge()image_names = []txt_file = './rgbtimestamp.txt'with rosbag.Bag(bagname, 'r') as bag:for topic, msg, t in umpackbag.read_messages():if topic == "/image/data_raw":try:cv_image = bridge.imgmsg_to_cv2(msg)except CvBridgeError as e:print(e)continue#timestr = "%.9f" % msg.header.stamp.to_sec()timestr = "%.6f" % msg.header.stamp.to_sec()#timestr = "%.1f" % msg.header.stamp.to_sec()image_name = timestr#image_name = timestr.replace('.', '') # Remove periods from the timestampcv2.imwrite(path + image_name + '.png', cv_image) # Save as PNG formatimage_names.append(image_name) # Add image name to the listwith open(txt_file, 'w') as f:#f.write('\n'.join(["{} rgb/{}.png".format(t, t) for t in image_names]))f.write('\n'.join(image_names))# Script Menu # Make a folder name bag_tum include three sunfolder : left right rgb , in folder their image in it # in python main.py folder , create imudata.scv and imudata.txt ,aim for KITTI or TUM dataset # in python main.py folder , create timestamp.txt for image timestamp # in python main.py folder , create timestamp.txt for image timestamp if __name__ == '__main__':bagname = 'imu_cam.bag'umpackbag = rosbag.Bag(bagname)CreateDIR()CreateIMUCSV(umpackbag)TransIMUdatatotxt()Savergb(umpackbag)
执行脚本后,得到如下文件 + timestamp.txt文件夹:
我们开始制作数据集:建立一个01文件夹
将timestamp.txt文件夹放在这里,再创建一个mav0的文件夹。
在mav0文件夹里面创建cam0和imu0文件夹:
cam0里面创建data文件夹,存放图像数据,这里的图像就是bag_tum/rgb目录下的图像:
imu0里面存放的是data.csv和data.txt存放IMU数据。
至此,我们数据集制作完毕,向程序输入参数:
ORB词典位置、标定参数文件位置、01文件夹位置以及时间戳的位置。
此外,还需要改一个地方:
mono_inertial_euroc.cc文件的86行改为:
string pathImu = pathSeq + "/mav0/imu0/data.txt";
这样就可以跑啦!
相关文章:
使用kaliber与imu_utils进行IMU、相机+IMU联合标定
目录 1 标定工具编译 1.1 IMU标定工具 imu_utils 1.2 相机标定工具 kaliber 2 标定数据录制 3 开始标定 3.1 IMU标定 3.2 相机标定 3.3 相机IMU联合标定 4 将参数填入ORBSLAM的文件中 1 标定工具编译 1.1 IMU标定工具 imu_utils 标定IMU我们使用imu_utils软件进行标定…...
统一观测丨使用 Prometheus 监控 SQL Server 最佳实践
作者:啃唯 SQL Server 简介 SQL Server 是什么? Microsoft SQL Server 是 Microsoft 推出的关系型数据库解决方案,支持企业 IT 环境中的各种事务处理、商业智能和分析应用程序。Microsoft SQL Server 是市场领先的数据库技术之一。 SQL S…...
最短无序连续子数组
题目链接 最短无序连续子数组 题目描述 注意点 找出符合题意的 最短 子数组,并输出它的长度-100000 < nums[i] < 100000 解答思路 本题的数组可以分为三段,左段中段和右段,如下图所示 观察规律可知,左段元素始终比中段…...
更新 | 持续开源迅为RK3568驱动指南第十二篇-GPIO子系统
《iTOP-RK3568开发板驱动开发指南》更新,本次更新内容对应的是驱动(第十二期_GPIO子系统-全新升级)视频,后续资料会不断更新,不断完善,帮助用户快速入门,大大提升研发速度。 文档教程更新至第十…...
centos7安装erlang23.3.4.11及rabbitmq3.9.16版本
rpm包有系统版本要求,el是Red Hat Enterprise Linux(EL)的缩写。 EL7是Red Hat 7.x,Centos 7.x EL8是Red Hat 8.x, Centos 8.x 所以我们在安装erlang及rabbitmq时需要选择与自己的服务器相对应的rpm包 # rabbitmq的rpm安装包 https://github.com/rabbi…...
VMware和Debian下载
文章目录 ⭐️写在前面的话⭐️一、VMware二、Debain三、建立虚拟机🚀 先看后赞,养成习惯!🚀🚀 先看后赞,养成习惯!🚀 ⭐️写在前面的话⭐️ CSDN主页:程序员好冰 目前在…...
mysql面试题48:MySQL中 Innodb的事务与日志的实现方式
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官: Innodb的事务与日志的实现方式 以下是InnoDB事务和日志的实现方式的详细说明: 事务日志(Transaction Log): InnoDB使用事务日志来保证事务的…...
数据结构 优先级队列(堆)
数据结构 优先级队列(堆) 文章目录 数据结构 优先级队列(堆)1. 优先级队列1.1 概念 2. 优先级队列的模拟实现2.1 堆的概念2.2 堆的存储方式2.3 堆的创建2.3.1 堆向下调整2.3.2 堆的创建2.3.3 建堆的时间复杂度 2.4 堆的插入与删除2.4.1 堆的插入2.4.2 堆的删除 2.5 用堆模拟实现…...
如何在edge浏览器中给PDF添加文字批注
我用的edge浏览器是目前最新版的(一般自动更新到最新版) 最近,我喜欢用edge浏览器查看PDF,节省电脑资源,快捷且方便。 但edge对PDF的标注种类较少,主要是划线和涂色,文字批注功能尚未出现在工具…...
集成学习的小九九
集成学习(Ensemble Learning)是一种机器学习的方法,通过结合多个基本模型的预测结果来进行决策或预测。集成学习的目标是通过组合多个模型的优势,并弥补单个模型的不足,从而提高整体性能。 集成学习的主要策略 在集成…...
深入理解Scrapy
Scrapy是什么 An open source and collaborative framework for extracting the data you need from websites. In a fast, simple, yet extensible way. Scrapy是适用于Python的一个快速、简单、功能强大的web爬虫框架,通常用于抓取web站点并从页面中提取结构化的数…...
想做WMS仓库管理系统,找了好久才找到云表
公司内部仓库管理原方式均基于人工电子表格管理方式来实现收发存管理,没有流程化管理,无法保证数据的准确性和及时性,同时现场操作和数据核对会出现不同步的情况,无法提高仓库的运作效率,因此,我们基于云表…...
公司销售个人号如何管理?
微信管理系统可以帮助企业解决哪些问题呢? 一、解决聊天记录监管问题 1.聊天记录的保存,让公司的管理者可以随时查看公司任意销售与客户的聊天记录,不用一个一个员工逐一去看,方便管理; 2.敏感词监控,管理者…...
COLE HERSEE 48408 工业4.0、制造业X和元宇宙
COLE HERSEE 48408 工业4.0、制造业X和元宇宙 需要数据来释放工业4.0的全部潜力——价值链中的所有公司都可以访问大量数据。一个新的互联数据生态系统旨在提供解决方案:制造业x。 在德国联邦经济事务和气候行动部以及BDI、VDMA和ZVEI贸易协会的密切合作下,实施制…...
【Vue基础-数字大屏】加载动漫效果
一、需求描述 当网页正在加载而处于空白页面状态时,可以在该页面上显示加载动画提示。 二、步骤代码 1、全局下载npm install -g json-server npm install -g json-server 2、在src目录下新建文件夹mock,新建文件data.json存放模拟数据 {"one&…...
CSS 样式简写
在CSS中有许多简写的样式,它们被广泛使用。简写最好按照如下顺序进行书写 font font: font-style font-weight font-size/line-height font-familyfont-style italic//斜体 normal//正常字体(默认)font-weight 一般填写数字 400 normal(默认值) 700 bold(默认值)f…...
SQL Server创建数据库
简单创建写法 默认初始大小为5MB,增长速度为2MB create database DBTEST自定义 用户创建的数据库都被存放在sys.database中,每个数据库在表中占一行,name字段存放的数据库的名称,具体字段可以看此博客sys.database系统表详细说明 所以判断…...
树莓派安装.NET 6.0
首先安装.Net Core依赖(未使用) sudo apt install -y libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4 libcurl4-openssl-dev libssl-dev uuid-dev unzip libgdiplus libc6-dev libkrb5-3 需要安装的依赖微软官方文档已经列出…...
小华HC32F448串口使用
目录 1. 串口GPIO配置 2. 串口波特率配置 3. 串口接收超时配置 4. 串口中断注册 5. 串口初始化 6. 串口数据接收处理 7. DMA接收配置和处理 1. 串口GPIO配置 端口号和Pin脚号跟STM32没什么区别。 串口复用功能跟STM32大不一样。 如下图,选自HC32F448 表 2…...
Redis实现简易消息队列的三种方式
Redis实现简易消息队列的三种方式 消息队列简介 消息队列是一种用于在计算机系统中传递和处理数据的重要工具。如果你完全不了解消息队列,不用担心,我将尽力以简单明了的方式来解释它。 首先,想象一下你正在玩一个游戏,而游戏中…...
基于SpringBoot的在线小说阅读平台系统
基于SpringBoot的在线小说阅读平台系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringBootMyBatisVue工具:IDEA/Ecilpse、Navicat、Maven 系统展示 主页 个人中心 登录界面 管理员界面 摘要 基于Spring Boot的在线小说阅读…...
uniapp h5 MD5加密
文章目录 1.当使用 CryptoJS 进行 MD5 加密时,你需要先引入 CryptoJS 库并确保它已经正确安装。下面是一个更详细的示例代码:2.然后,在需要使用 MD5 加密的地方,引入 CryptoJS 代码库:3.接下来,我们定义一个…...
2023_Spark_实验十八:安装FinalShell
下载安装包 链接:https://pan.baidu.com/s/14cOJDcezzuwUYowPsOA-sg?pwd6htc 提取码:6htc 下载文件名称:FinalShell.zip 二、安装 三、启动FinalShell 四、连接远程 linux 服务器 先确保linux系统已经开启,不然连接不上 左边…...
文件服务器管理服务器怎么设置
文件服务器是一种提供文件存储和共享服务的服务器,它可以方便企业内部的员工共享文件,提高工作效率。为了更好地管理和维护文件服务器,需要对其进行合理的设置。下面小编将介绍文件服务器管理服务器的基本设置方法。 一、选择合适的操作系统 …...
LeetCode每日一题——Single Number
文章目录 一、题目二、题解 一、题目 136. Single Number Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra …...
有什么手机软件能分离人声和音乐?
很多人在制作混剪视频,需要二次创作的时候,就经常会把人声分离、背景音乐伴奏提取出来,然后重新加入自己的创意跟想法。下面就一起来看看如何用手机软件分离人声和音乐的吧! 音分轨 一款可以分离人声和背景音乐的手机软件&#x…...
私人服务器可以干嘛
目录 搭建个人网站或博客: 远程桌面: 作为网盘储存: 作为测试和学习环境: 推广产品: 游戏私服(注意,仅限于个人自己单机玩): 个人服务器可以用于多种用途,以下是一些常见的用途:…...
【EI会议征稿】第三届高性能计算与通信工程国际学术会议(HPCCE 2023)
第三届高性能计算与通信工程国际学术会议(HPCCE 2023) 第三届高性能计算与通信工程国际学术会议(HPCCE 2023)将于2023年12月22-24日在长沙召开。HPCCE 2023将围绕“高性能计算与通信工程”的最新研究领域,为来自国内外高等院校、科学研究所、…...
项目管理,如何做到流程标准化?
在PMP管理学习规范化、标准化和流程化的背景下,我们在日常工作中会遇到各种大小不一的工作项目。为了能够确保项目按时高质量地完成,项目管理变得至关重要。项目管理可以简单地解释为,在给定的时间和资源限制下,通过协调有限资源&…...
宝安做棋牌网站建设/广州seo网站推广优化
MD文件在网络上很常见,您可能已经注意到,不同软件的自述文件以及文档通常以Markdown格式创建。在本文中,我们将学习使用C#语言通过编程将Markdown文件转换为PDF,PNG,JPG和其他图像格式。(点击下…...
网站建设优化服务方案/网站优化seo
闲聊 最近一直不在状态,月初就被博客质量的事给弄的情绪低落,之后群里又走了两个朋友,心情是一直在低谷徘徊,博客也是不想写,状态一天不如一天,总之就是一句话,不想工作。所以…… 有没有小(fu)…...
wordpress 目录扫描/自己创建网页
一、环境搭建 1、安装nodejs node - v :查看版本 npm -v :查看npm 的版本 2、安装cnpm 疑问:npm和cnpm 都是什么? npm(node package manager):nodejs的包管理器,用于node插件管理(包括安装、卸载、管…...
如何网站做镜像/网站关键词优化费用
1.设计思想:先从命令行中输入想要相加的数,将输入的字符串全部转化为int类型的数字,之后设定一个int型的result,将转化完的数字全部相加起来,并将结果保存在result内,最后将result输出出来,得到…...
古风网站建设模板/seo入门基础教程
一、什么是序列化 在我们存储数据或者网络传输数据的时候,需要对我们的对象进行处理,把对象处理成方便存储和传输的数据格式。这个过程叫序列化,不同的序列化结果也不同,但目的是一样的,都是为了存储和传输 在Python中…...
云南省城乡住房建设厅网站/市场调研方法
引言 本文主要介绍 Pandas 对 CSV, Excel 格式数据的读写,更多 Python 进阶系列文章,请参考 Python 进阶学习 玩转数据系列 内容提要: XLS, CSV Data I/O Modules in Python Pandas 对 CSV 格式数据的读写 Pandas 对 Excel 格式数据的读写 …...