Imu_heading使用

本文介绍了如何进行IMU的航向角标定。通过执行GitHub上的SensorsCalibration项目,利用imu_heading模块进行编译并运行。在完成编译后,使用特定方法_id对数据进行处理,例如方法_id=1对应直行驾驶,方法_id=2对应自由行驶。最终,程序输出了标定结果,包括最佳得分、真值、GNSS值、偏移量以及校正后的数据组件等,帮助评估和调整IMU的航向角精度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

imu的航向角标定。

首先获取imu_heading,打开终端输入:


git clone SensorsCalibration/imu_heading at master · PJLab-ADG/SensorsCalibration · GitHub
​

在imu_heading目录下打开终端,依次输入:

mkdir build
cd build 
cmake ..
make

小技巧:根据自己电脑的线程可选择编译的速度 ,make时可选择

make make -j4 make -j12

会在bin目录下生成可执行程序
运行程序时的方式:

./bin/run_imu_heading method_id <data_dir>

#其中:Note: [method_id=1]drives in straight
#     Note: [method_id=2]free drive

实际运行时的命令:

./bin/run_imu_heading 1 ./data

得到的结果:


    Yaw Calib:
    best score: 0.883891
    GT value(degree): 134.623
    GNSS value(degree): 134.318
    Offset(degree): 0.304195

    Check result:
    origin_v_componet: 0.0236951
      max: 0.153196
      min: 1.17621e-05
    calibrated_v_componet: 0.00649881
      max: 0.154361
      min: 2.7096e-06
    Euler2RotationMatrix result is:
    R =
    0.00530918  -0.999986          0
      0.999986 0.00530918          0
         0          0          1


imu的航向角标定。

guo@guo-Dell-G15-5520:~/8.4$ python odom_tra.py Exception in Tkinter callback Traceback (most recent call last): File "/usr/lib/python3.8/tkinter/__init__.py", line 1892, in __call__ return self.func(*args) File "odom_tra.py", line 264, in on_save_button_click extracted_data = extract_data(log_file, start_line, end_line) File "odom_tra.py", line 22, in extract_data with open(log_file, 'r') as f: FileNotFoundError: [Errno 2] No such file or directory: '/home/guo/tool/python脚本/imu_integration.log' 源代码为:import re import csv from datetime import datetime, timedelta from tkinter import Tk, Label, Entry, Button, StringVar, messagebox, filedialog import matplotlib.pyplot as plt def parse_timestamp(timestamp_str): formats = ['%Y-%m-%d %H:%M:%S,%f', '%Y-%m-%d %H:%M:%S'] for fmt in formats: try: return datetime.strptime(timestamp_str, fmt) except ValueError: continue raise ValueError(f"Time data '{timestamp_str}' does not match any known format.") def extract_data(log_file, start_line, end_line): odom_data = [] map_data = [] robot_freq_dict = {} imu_freq_dict = {} with open(log_file, 'r') as f: for i, line in enumerate(f, 1): if start_line <= i <= end_line: parts = line.split(',') if len(parts) < 2: continue timestamp_part = parts[0].strip() timestamp_parts = timestamp_part.split() if len(timestamp_parts) < 2: continue timestamp_str = timestamp_parts[0] + ' ' + timestamp_parts[1] try: timestamp = parse_timestamp(timestamp_str) except ValueError: print(f"Failed to parse timestamp: {timestamp_str}") continue # Extract odom data odom_match = re.search(r'odom = ([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+),([-+\d.eE+-]+)', line) if odom_match: try: odom_values = list(map(float, odom_match.groups())) odom_data.append([timestamp] + odom_values) except ValueError: print(f"Failed to convert odom values: {odom_match.groups()}") continue # Extract map data map_match = re.search(r'map = ([-+\d.eE+-]+),([-+\d.eE+-]+)(?:,\d+)?', line) if map_match: try: x, y = map(float, map_match.groups()) map_data.append((x, y)) except ValueError: print(f"Failed to convert map values: {map_match.groups()}") continue # Extract robot data frequency robot_freq_match = re.search(r'@@@robot data frequency = (\d+\.\d+)Hz', line) if robot_freq_match: try: freq = float(robot_freq_match.group(1)) robot_freq_dict[timestamp] = freq except ValueError: print(f"Failed to convert robot frequency: {robot_freq_match.group(1)}") continue # Extract IMU data frequency imu_freq_match = re.search(r'@@@ IMU data frequency = (\d+\.\d+) Hz', line) if imu_freq_match: try: freq = float(imu_freq_match.group(1)) imu_freq_dict[timestamp] = freq except ValueError: print(f"Failed to convert IMU frequency: {imu_freq_match.group(1)}") continue elif i > end_line: break robot_timestamps = sorted(robot_freq_dict.keys()) robot_freqs = [robot_freq_dict[t] for t in robot_timestamps] imu_timestamps = sorted(imu_freq_dict.keys()) imu_freqs = [imu_freq_dict[t] for t in imu_timestamps] if robot_timestamps and imu_timestamps: base_time = min(robot_timestamps[0], imu_timestamps[0]) elif robot_timestamps: base_time = robot_timestamps[0] elif imu_timestamps: base_time = imu_timestamps[0] else: base_time = None if base_time is not None: relative_odom_timestamps = [(t - base_time).total_seconds() for t in [data[0] for data in odom_data]] relative_robot_timestamps = [(t - base_time).total_seconds() for t in robot_timestamps] relative_imu_timestamps = [(t - base_time).total_seconds() for t in imu_timestamps] else: relative_odom_timestamps = [] relative_robot_timestamps = [] relative_imu_timestamps = [] return odom_data, map_data, relative_odom_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps, relative_robot_timestamps, relative_imu_timestamps def save_to_csv(odom_data, map_data, relative_robot_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps): # Save Odom Data to CSV with open('odom_data.csv', mode='w', newline='') as file: writer = csv.writer(file) writer.writerow(['Timestamp', 'X', 'Y', 'X_Velocity', 'Y_Velocity', 'Odometry_Heading_Angle', 'IMU_Heading_Angle', 'Slope_Magnitude', 'Slope_Heading_Angle']) writer.writerows(odom_data) # Save Map Data to CSV with open('map_data.csv', mode='w', newline='') as file: writer = csv.writer(file) writer.writerow(['X', 'Y']) writer.writerows(map_data) # Save Robot Frequency Data to CSV with open('robot_frequency_data.csv', mode='w', newline='') as file: writer = csv.writer(file) writer.writerow(['Relative Time (s)', 'Frequency (Hz)', 'Timestamp']) for rt, freq, ts in zip(relative_robot_timestamps, robot_freqs, robot_timestamps): writer.writerow([rt, freq, ts.isoformat()]) # Save IMU Frequency Data to CSV with open('imu_frequency_data.csv', mode='w', newline='') as file: writer = csv.writer(file) writer.writerow(['Relative Time (s)', 'Frequency (Hz)', 'Timestamp']) for rt, freq, ts in zip(relative_imu_timestamps, imu_freqs, imu_timestamps): writer.writerow([rt, freq, ts.isoformat()]) def plot_data(odom_data, map_data, relative_odom_timestamps, relative_robot_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, additional_points=None): # Clear previous plots plt.close('all') # Plot Odom Data plt.figure(figsize=(16, 18)) plt.subplot(3, 3, 1) odom_x, odom_y = zip(*[(data[1], data[2]) for data in odom_data]) plt.plot(odom_x, odom_y, marker='o') plt.title('Odom Data (X vs Y)') plt.xlabel('X') plt.ylabel('Y') plt.axis('equal') # Plot Map Data plt.subplot(3, 3, 2) map_x, map_y = zip(*map_data) plt.plot(map_x, map_y, marker='o', color='green', label='Map') if additional_points: for point in additional_points: plt.scatter(point[0], point[1], color='red', zorder=5, label='Additional Point' if additional_points.index(point) == 0 else "") plt.title('Map Data (X vs Y)') plt.xlabel('X') plt.ylabel('Y') plt.legend() plt.axis('equal') # Add zoom button for Map Data def zoom_map_plot(): plt.figure(figsize=(12, 8)) plt.plot(map_x, map_y, marker='o', color='green', label='Map') if additional_points: for point in additional_points: plt.scatter(point[0], point[1], color='red', zorder=5, label='Additional Point' if additional_points.index(point) == 0 else "") plt.title('Zoomed Map Data (X vs Y)') plt.xlabel('X') plt.ylabel('Y') plt.legend() plt.grid(True) plt.axis('equal') # Ensure equal scaling on both axes plt.show() map_zoom_button = Button(root, text="Zoom Map", command=zoom_map_plot) map_zoom_button.grid(row=14, columnspan=2, pady=5) # Plot Odom and Map Comparison plt.subplot(3, 3, 3) plt.plot(odom_x, odom_y, marker='o', label='Odom') plt.plot(map_x, map_y, marker='x', color='green', label='Map') if additional_points: for point in additional_points: plt.scatter(point[0], point[1], color='red', zorder=5, label='Additional Point' if additional_points.index(point) == 0 else "") plt.title('Odom vs Map Comparison') plt.xlabel('X') plt.ylabel('Y') plt.legend() plt.axis('equal') # Define a function to zoom into a specific plot def zoom_plot(title, y_label, y_values): plt.figure(figsize=(12, 8)) plt.plot(relative_odom_timestamps, y_values, marker='o', color='blue') plt.title(title) plt.xlabel('Relative Time (s)') plt.ylabel(y_label) plt.grid(True) plt.show() # Create buttons for each plot buttons = [ ("X Axis Velocity", "X Velocity", [data[3] for data in odom_data]), ("Y Axis Velocity", "Y Velocity", [data[4] for data in odom_data]), ("Odometry Heading Angle", "Odometry Heading Angle", [data[5] for data in odom_data]), ("IMU Heading Angle", "IMU Heading Angle", [data[6] for data in odom_data]), ("Slope Magnitude", "Slope Magnitude", [data[7] for data in odom_data]), ("Slope Heading Angle", "Slope Heading Angle", [data[8] for data in odom_data]) ] for idx, (label, y_label, y_values) in enumerate(buttons): button = Button(root, text=f"Zoom {label}", command=lambda l=label, yl=y_label, v=y_values: zoom_plot(l, yl, v)) button.grid(row=idx+7, columnspan=2, pady=5) # Add button for plotting IMU vs Odometry Heading Angle def plot_heading_angle_comparison(): plt.figure(figsize=(12, 8)) plt.plot(relative_odom_timestamps, [data[5] for data in odom_data], marker='o', label='Odometry Heading Angle') plt.plot(relative_odom_timestamps, [data[6] for data in odom_data], marker='x', color='orange', label='IMU Heading Angle') plt.title('IMU vs Odometry Heading Angle') plt.xlabel('Relative Time (s)') plt.ylabel('Heading Angle (rad)') plt.legend() plt.grid(True) plt.show() heading_angle_compare_button = Button(root, text="Compare IMU & Odometry Heading Angles", command=plot_heading_angle_comparison) heading_angle_compare_button.grid(row=15, columnspan=2, pady=5) # Plot Robot Frequency Data plt.subplot(3, 3, 4) plt.plot(relative_robot_timestamps, robot_freqs, marker='o', color='purple') plt.title('Robot Frequency Data') plt.xlabel('Relative Time (s)') plt.ylabel('Frequency (Hz)') plt.grid(True) # Plot IMU Frequency Data plt.subplot(3, 3, 5) plt.plot(relative_imu_timestamps, imu_freqs, marker='o', color='brown') plt.title('IMU Frequency Data') plt.xlabel('Relative Time (s)') plt.ylabel('Frequency (Hz)') plt.grid(True) plt.tight_layout() plt.show() def on_save_button_click(): try: start_line = int(start_line_var.get().strip()) end_line = int(end_line_var.get().strip()) if start_line >= end_line: raise ValueError("Start line must be less than end line.") log_file = '/home/guo/tool/python脚本/imu_integration.log' # 提取数据 extracted_data = extract_data(log_file, start_line, end_line) # 解包数据 global odom_data, map_data, relative_odom_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps, relative_robot_timestamps, relative_imu_timestamps odom_data, map_data, relative_odom_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps, relative_robot_timestamps, relative_imu_timestamps = extracted_data # 打印调试信息 print(f"Extracted ODOM Data: {len(odom_data)} entries") print(f"Extracted MAP Data: {len(map_data)} entries") print(f"Relative ODOM Timestamps: {len(relative_odom_timestamps)} entries") print(f"Robot Frequencies: {len(robot_freqs)} entries") print(f"Relative IMU Timestamps: {len(relative_imu_timestamps)} entries") print(f"IMU Frequencies: {len(imu_freqs)} entries") print(f"Robot Timestamps: {len(robot_timestamps)} entries") print(f"IMU Timestamps: {len(imu_timestamps)} entries") if not odom_data or not map_data: messagebox.showwarning("No Data", "No valid data found within the specified range.") return save_to_csv(odom_data, map_data, relative_robot_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps) messagebox.showinfo("Success", "Data saved successfully.") # 绘制图表 plot_data(odom_data, map_data, relative_odom_timestamps, relative_robot_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, additional_points=additional_points) except ValueError as ve: messagebox.showerror("Invalid Input", str(ve)) def on_add_point_button_click(): try: point_x = float(point_x_var.get().strip()) point_y = float(point_y_var.get().strip()) # 将新点添加到地图数据中 global additional_points additional_points.append((point_x, point_y)) # 重新绘制图表 plot_data(odom_data, map_data, relative_odom_timestamps, relative_robot_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, additional_points=additional_points) except ValueError as ve: messagebox.showerror("Invalid Input", "Please enter valid numeric values for X and Y coordinates.") # 创建主窗口 root = Tk() root.title("Comprehensive Log Data Extraction") # 创建标签和输入框 Label(root, text="Start Line:").grid(row=0, column=0, padx=10, pady=5) start_line_var = StringVar() Entry(root, textvariable=start_line_var).grid(row=0, column=1, padx=10, pady=5) Label(root, text="End Line:").grid(row=1, column=0, padx=10, pady=5) end_line_var = StringVar() Entry(root, textvariable=end_line_var).grid(row=1, column=1, padx=10, pady=5) # 创建按钮 Button(root, text="Save Data to CSV", command=on_save_button_click).grid(row=2, columnspan=2, pady=10) # 创建额外点输入框和按钮 Label(root, text="Point X:").grid(row=3, column=0, padx=10, pady=5) point_x_var = StringVar() Entry(root, textvariable=point_x_var).grid(row=3, column=1, padx=10, pady=5) Label(root, text="Point Y:").grid(row=4, column=0, padx=10, pady=5) point_y_var = StringVar() Entry(root, textvariable=point_y_var).grid(row=4, column=1, padx=10, pady=5) Button(root, text="Add Point to Map", command=on_add_point_button_click).grid(row=5, columnspan=2, pady=10) # 初始化全局变量 global additional_points, odom_data, map_data, relative_odom_timestamps, robot_freqs, relative_imu_timestamps, imu_freqs, robot_timestamps, imu_timestamps, relative_robot_timestamps, relative_imu_timestamps additional_points = [] odom_data = [] map_data = [] relative_odom_timestamps = [] robot_freqs = [] relative_imu_timestamps = [] imu_freqs = [] robot_timestamps = [] imu_timestamps = [] relative_robot_timestamps = [] relative_imu_timestamps = [] # 运行主循环 root.mainloop()
最新发布
08-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值