For those who only need a traditional discrete-time ground truth for benchmarking SLAM methods, you can use the pose_inW.csv associated with each sequence. This data is sampled from the continuous time ground truth at 0.1s interval. The content looks like the following:
num t x y z qx qy qz qw
11 1644823132.49211 49.2606317111444 107.371797989247 7.63580957239259 0.936118452267473 -0.351663294301812 0.003894594980225 -5.3806028052E-05
12 1644823132.59122 49.2617548510814 107.371820422962 7.63634221875222 0.936400655699795 -0.350853723839147 0.001952716665257 -0.007187723619002
13 1644823132.69085 49.2627442641658 107.370734597833 7.63708972884333 0.937130644015062 -0.348934531427190 0.005541781558079 -0.000370786684933
14 1644823132.79213 49.2634361009274 107.369692804349 7.63756375797164 0.935347736233029 -0.353687216878511 0.004396339541646 -0.003261462726211
15 1644823132.89130 49.2637252742628 107.368872120271 7.63750418262036 0.936261362661676 -0.351231145451445 0.005677919353789 -0.004370867600258
...
Here, num is the index of the lidar pointcloud in the bag file, t is the time stamp, and (x, y, z, qx, qy, qz, qw) is the pose of the body frame wrt to the world frame.
For more advance users that would like to study the motion distortion on lidar, you can use the spline.csv file provided in the same folder (if you are not familar with B-spline, we recommend the following paper and our technical note for the detail description of B-spline based continuous-time trajectory representation ). The control points of the spline are listed in this file. The content resembles the following:
Dt: 0.025, Order: 6, Knots: 24045, MinTime: 1644823132.49097, MaxTime: 1644823733.59097
0,1644823132.4909698963165283,49.2601663093799687,107.3714204060612047,7.6355324272268943,0.9350584912955798,-0.3544839325422865,-0.0006156075556602,0.0025259558046850
1,1644823132.5159699916839600,49.2604201766309515,107.3716637079355962,7.6356371447402402,0.9379846150800922,-0.3462143713078067,0.0005065405451423,-0.0178945351900358
2,1644823132.5409698486328125,49.2606213815611795,107.3717670418042047,7.6358132610019718,0.9354176646728326,-0.3532940094282990,0.0080878815549711,0.0105698482512218
3,1644823132.5659699440002441,49.2608259618997621,107.3719814523942944,7.6359423034838736,0.9358444686488053,-0.3522668912610597,-0.0027447487380264,-0.0097792727269988
4,1644823132.5909698009490967,49.2610915208195834,107.3720644627877050,7.6360616461728057,0.9361526518581488,-0.3515835046668936,0.0011728044948194,-0.0024240863675093
5,1644823132.6159698963165283,49.2614226852895811,107.3720311712474995,7.6362061007328341,0.9359967890920514,-0.3519082642918072,-0.0015771747359690,-0.0082520816979596
...
The first line lists the parameters of the spline: the knot length Dt, the spline Order, the number of Knots, the starting time MinTime and the ending time MaxTime of the trajectory. Subsequently, the index, time stamp and the value of each control pose (x,y,z,qx,qy,qz,qw) is listed line by line.
The best way to read and query the spline information is by using the package ceva that is a python wrapper for the basalt library. For example one can create a spline from the log file as follows:
import numpy as np
from ceva import Ceva
spline_log = '../example/spline.csv'
def load_spline(x):
# Read the spline
log = open(x, 'r')
# Extract some settings in the header
log_header = log.readline()
log.close()
# Read the dt from header
dt = float(log_header.split(sep=',')[0].replace('Dt: ', ''))
# Read the order
order = int(log_header.split(sep=',')[1].replace('Order: ', ''))
# Read the knots
knots = int(log_header.split(sep=',')[2].replace('Knots: ', ''))
# Read the start time in header
start_time = float(log_header.split(sep=',')[3].replace('MinTime: ', ''))
# Calculate the end time
final_time = start_time + dt*(knots - order + 1)
# Create the spline from text
knots = np.loadtxt(x, delimiter=',', skiprows=1)
spline = Ceva(order, dt, start_time, x)
return spline
# Load the spline
gt_traj = load_spline(spline_log)
# Sample the pose at 100s after the start
pose_stamped = gt_traj.getPose(gt_traj.minTime() + 100) # Returns t, x, y, z, qx, qy, qz, qw
print(pose_stamped)
# You can also pass a vector of times and get an array
pose_stamped = gt_traj.getPose(gt_traj.minTime() + np.arange(0, 100, 0.1)) # Returns t, x, y, z, qx, qy, qz, qw
print(pose_stamped)
Check out the list of demos for more examples of ceva's functions.