OxIOD IMU Dataset

Dataset

OxIOD Dataset

Oxford Inertial Odometry Dataset [1] is a large set of inertial data for inertial odometry which is recorded by smartphones at 100 Hz in indoor environment. The suite consists of 158 tests and covers a distance of over 42 km, with OMC ground track available for 132 tests. Therefore, it does not include pure rotational movements and pure translational movements, which are helpful for systematically evaluating the model’s performance under different conditions; however, it covers a wide range of everyday movements.

Due to the different focus, some information (for example, the alignment of the coordinate frames) is not accurately described. In addition, the orientation of the ground trace contains frequent irregularities (e.g., jumps in orientation that are not accompanied by similar jumps in the IMU data). The dataset is available at Link.

How to use OxIOD Dataset

The dataset can be download from here. The Dataset Contains:

24 Handheld Sequences

Total 8821 seconds for 7193 meters.

data1time (s)distance (m)
seq1376301
seq2234177
seq3188147
seq4216166
seq5322264
seq6325274
seq7141118
total18021447
data2time (s)dis (m)
seq1326281
seq2312264
seq3301249
total939794
data3timedis
seq1308251
seq2379324
seq3609533
seq4538467
seq5383319
total22171894
data4timedis
seq1317242
seq2322243
seq3606476
seq4438359
seq5350284
total20331604
data5timedis
seq1310237
seq2594466
seq3560445
seq4366306
total18301454

11 Pocket Sequences

Total 5622 seconds for 4231 meters.

data1timedis
seq1330284
seq2456379
seq3506405
seq4491387
seq5240182
total20231637
data2timedis
seq1651492
seq2559414
seq3628429
seq4668494
seq5470371
seq6623494
total35992694

8 Handbag Sequences

Total 4100 seconds for 3431 meters.

data1timedis
seq1575437
seq2570467
seq3580466
seq4445366
total21701736
data2timedis
seq1575487
seq2560499
seq3425381
seq4370328
total19301695

13 Trolley Sequences

Total 4262 seconds for 2685 meters.

data1timedis
seq1447251
seq2309169
seq3359209
seq4599362
seq5612374
seq6586380
seq7274174
total31861919
data2timedis
seq1156106
seq2168118
seq3161113
seq4163113
seq5217158
seq6211158
total1076766

8 Slow Walking Sequences

Total 4150 seconds for 2421 meters.

data1timedis
seq1612382
seq2603353
seq3617341
seq4594323
seq5606352
seq6503331
seq7311172
seq8304167
total41502421

7 Running Sequences

Total 3732 seconds for 4356 meters.

data1timedis
seq1691761
seq2623719
seq3590665
seq4603679
seq5619766
seq6303373
seq7303393
total37324356

26 Multi Devices Sequences

Total 7144 seconds for 5350 meters.

iPhone 5timedis
seq1178150
seq2163133
seq3160126
seq4124100
seq5174139
seq6167136
seq7197150
seq8184141
seq9184142
total15311217
iPhone 6timedis
seq1180165
seq2184171
seq3182168
seq4150140
seq5183162
seq6171155
seq7184139
seq8185148
seq9173133
total15921381
nexus 5timedis
seq1604452
seq2609438
seq3605414
seq4609403
seq5607388
seq6607401
seq7186130
seq8194127
total40212752

35 Multi Users Sequences

Total 8821 seconds for 9465 meters.

user 2timedis
seq1311284
seq2358313
seq3390328
seq4217172
seq5311240
seq6256193
seq7371296
seq8450375
seq9264221
total29282422
user 3timedis
seq1382301
seq2318272
seq3340295
seq4232198
seq5214185
seq6356289
seq7258203
total21001743
user 4timedis
seq1387367
seq2329307
seq3305288
seq4248229
seq5356314
seq6293272
seq7297260
seq8468411
seq9435364
total31182812
user 5timedis
seq1294237
seq2305264
seq3253211
seq4390337
seq5300226
seq6338284
seq7168154
seq8410395
seq9274250
seq10152130
total28842488

26 Large Scale Sequences

Total 4161 seconds for 3465 meters.

floor1timedis
seq1153142
seq2165143
seq3158142
seq4157145
seq5156142
seq6156142
seq7161144
seq8155143
seq9160126
seq10158143
total15791412
floor4timedis
seq1160170
seq2157153
seq3162153
seq4118106
seq5164153
seq6163143
seq7169141
seq8166153
seq9172135
seq10169154
seq11166152
seq12165154
seq13165133
seq14164153
seq15163153
seq16159133
total25822053

In each folder, there is a raw data subfolder and a syn data subfolder, which represent the raw data collection without synchronisation but with high precise timestep, and the synchronised data but without high precise timestep.

The header of files is

vicon (vi.csv)*

  1. Time
  2. Header
  3. translation.x translation.y translation.z
  4. rotation.x rotation.y rotation.z rotation.w

Sensors (imu.csv)*

  1. Time
  2. attitude_roll(radians) attitude_pitch(radians) attitude_yaw(radians)
  3. rotation_rate_x(radians/s) rotation_rate_y(radians/s) rotation_rate_z(radians/s)
  4. gravity_x(G) gravity_y(G) gravity_z(G)
  5. user_acc_x(G) user_acc_y(G) user_acc_z(G)
  6. magnetic_field_x(microteslas) magnetic_field_y(microteslas) magnetic_field_z(microteslas)

Use OxIOD Dataset in Python

First, we need to import libraries

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Create variables to store data

imu_data_OxIOD =[]
gt_data_OxIOD = []
imu = np.zeros((1,9))
gt = np.zeros((1,7))

Load data files

imu_data_OxIOD.append(
    'handheld/data5/syn/imu3.csv')
imu_data_OxIOD.append(
    'handheld/data2/syn/imu1.csv')
imu_data_OxIOD.append(
    'handheld/data2/syn/imu2.csv')
imu_data_OxIOD.append(
    'handheld/data5/syn/imu2.csv')
imu_data_OxIOD.append(
    'handheld/data3/syn/imu4.csv')
imu_data_OxIOD.append(
    'handheld/data4/syn/imu4.csv')
imu_data_OxIOD.append(
    'handheld/data4/syn/imu2.csv')
imu_data_OxIOD.append(
    'handheld/data1/syn/imu7.csv')
imu_data_OxIOD.append(
    'handheld/data5/syn/imu4.csv')
imu_data_OxIOD.append(
    'handheld/data4/syn/imu5.csv')
imu_data_OxIOD.append(
    'handheld/data1/syn/imu3.csv')
imu_data_OxIOD.append(
    'handheld/data3/syn/imu2.csv')
imu_data_OxIOD.append(
    'handheld/data2/syn/imu3.csv')
imu_data_OxIOD.append(
    'handheld/data1/syn/imu1.csv')
imu_data_OxIOD.append(
    'handheld/data3/syn/imu3.csv')
imu_data_OxIOD.append(
    'handheld/data3/syn/imu5.csv')
imu_data_OxIOD.append(
    'handheld/data1/syn/imu4.csv')

gt_data_OxIOD.append(
    'handheld/data5/syn/vi3.csv')
gt_data_OxIOD.append(
    'handheld/data2/syn/vi1.csv')
gt_data_OxIOD.append(
    'handheld/data2/syn/vi2.csv')
gt_data_OxIOD.append(
    'handheld/data5/syn/vi2.csv')
gt_data_OxIOD.append(
    'handheld/data3/syn/vi4.csv')
gt_data_OxIOD.append(
    'handheld/data4/syn/vi4.csv')
gt_data_OxIOD.append(
    'handheld/data4/syn/vi2.csv')
gt_data_OxIOD.append(
    'handheld/data1/syn/vi7.csv')
gt_data_OxIOD.append(
    'handheld/data5/syn/vi4.csv')
gt_data_OxIOD.append(
    'handheld/data4/syn/vi5.csv')
gt_data_OxIOD.append(
    'handheld/data1/syn/vi3.csv')
gt_data_OxIOD.append(
    'handheld/data3/syn/vi2.csv')
gt_data_OxIOD.append(
    'handheld/data2/syn/vi3.csv')
gt_data_OxIOD.append(
    'handheld/data1/syn/vi1.csv')
gt_data_OxIOD.append(
    'handheld/data3/syn/vi3.csv')
gt_data_OxIOD.append(
    'handheld/data3/syn/vi5.csv')
gt_data_OxIOD.append(
    'handheld/data1/syn/vi4.csv')

Import data from file

for i, (imu_data_filename, gt_data_filename) in enumerate(zip(imu_data_OxIOD, gt_data_OxIOD)):
        oxiod_gt    = pd.read_csv(gt_data_filename).values
        oxiod_imu   = pd.read_csv(imu_data_filename).values
        oxiod_imu   = np.hstack([oxiod_imu[:, 10:13], oxiod_imu[:, 4:7], oxiod_imu[:, 7:10]])
        oxiod_gt = np.hstack([np.concatenate([oxiod_gt[:, 8:9], oxiod_gt[:, 5:8]], axis=1), oxiod_gt[:, 2:5]])
        imu = np.vstack([imu, oxiod_imu])
        gt = np.vstack([gt,oxiod_gt])
acc = imu[:,0:3]
gyro =imu[:,3:6]
mag = imu[:,6:9]
ori = gt[:,0:4]
pose = gt[:,4:7]

Store in csv file

df_imu = pd.DataFrame({'Acc x': acc[1:, 0], 'Acc y': acc[1:, 1], 'Acc z': acc[1:, 2], 'Gyro x': gyro[1:, 0],
                      'Gyro y': gyro[1:, 1], 'Gyro z': gyro[1:, 2], 'Mag x': mag[1:, 0], 'Mag y': mag[1:, 1], 'Mag z': mag[1:, 2]})
df_imu.to_csv('OxIOD_IMU_train.csv', index=False)
df_gt = pd.DataFrame({'Ori w': ori[1:, 0], 'Ori x': ori[1:, 1], 'Ori y': ori[1:, 2],
                     'Ori z': ori[1:, 3], 'Pose x': pose[1:, 0], 'Pose y': pose[1:, 1], 'Pose z': pose[1:, 2]})
df_gt.to_csv('OxIOD_GT_train.csv', index=False)

The data could be plot by

import matplotlib.pyplot as plt
fs = 100
dt = 1/fs
t = np.arange(0, acc.shape[0]/fs, dt)

# Plot the IMU readings
## Accelermoter 
# Plotting the three axis of the accelerometer in one figure.
plt.figure(figsize=(15, 10))
plt.subplot(3, 1, 1)
plt.plot(t, acc[:, 0], label='Acc x', color='b')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Acceleration in X-Axis ($m/s^2$)')
plt.subplot(3, 1, 2)
plt.plot(t, acc[:, 1], label='Acc y', color='g')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Acceleration in Y-Axis ($m/s^2$)')
plt.subplot(3, 1, 3)
plt.plot(t, acc[:, 2], label='Acc z', color='r')
plt.xlabel('Time (s)')
plt.ylabel('Acceleration in Z-Axis ($m/s^2$)')
plt.legend(loc="upper right")
plt.suptitle("Accelermoter", fontsize=25)
plt.savefig('RIDI_Acc.png', dpi=300)

## Gyroscope 
# Plotting the three axis of the gyroscope in one figure.
plt.figure(figsize=(15, 10))
plt.subplot(3, 1, 1)
plt.plot(t, gyro[:, 0], label='Gyro x', color='b')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Angular Velocity in X-Axis ($rad/s$)')
plt.subplot(3, 1, 2)
plt.plot(t, gyro[:, 1], label='Gyro y', color='g')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Angular Velocity in Y-Axis ($rad/s$)')
plt.subplot(3, 1, 3)
plt.plot(t, gyro[:, 2], label='Gyro z', color='r')
plt.xlabel('Time (s)')
plt.ylabel('Angular Velocity in Z-Axis ($rad/s$)')
plt.legend(loc="upper right")
plt.suptitle("Gyroscope", fontsize=25)
plt.savefig('RIDI_Gyro.png', dpi=300)

## Magnetometer
# Plotting the three axis of the magnetometer in one figure.
plt.figure(figsize=(15, 10))
plt.subplot(3, 1, 1)
plt.plot(t, mag[:, 0], label='Mag x', color='b')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Magnetic Field in X-Axis ($\mu T$)')
plt.subplot(3, 1, 2)
plt.plot(t, mag[:, 1], label='Mag y', color='g')
plt.legend(loc="upper right")
plt.xlabel('Time (s)')
plt.ylabel('Magnetic Field in Y-Axis ($\mu T$)')
plt.subplot(3, 1, 3)
plt.plot(t, mag[:, 2], label='Mag z', color='r')
plt.xlabel('Time (s)')
plt.ylabel('Magnetic Field in Z-Axis ($\mu T$)')
plt.legend(loc="upper right")
plt.suptitle("Magnetometer", fontsize=25)
plt.savefig('RIDI_Mag.png', dpi=300)
Accelerometer Gyro Magnetometer

The magnetomer 3d scatter plot can be found here

To test the dataset, we can use AHRS [2] library which has multiple sensor fusion algorithm for python. The Madgwick algorithm has been chosen as SFA.

fs = 100
dt = 1/fs
t = np.arange(0, acc.shape[0]/fs, dt)
madgwick = sfa.Madgwick(gyr=gyro, acc=acc, mag=mag, frequency=fs)

roll_ref, pitch_ref, yaw_ref = quat2eul(ori)
roll_est, pitch_est, yaw_est = quat2eul(madgwick.Q)

# Plot the results
# Roll
plt.figure(figsize=(15, 5))
plt.plot(t, roll_ref, label='roll_ref')
plt.plot(t, roll_est, label='roll_est')
plt.title('Roll angle (rad)')
plt.xlabel('Time (s)')
plt.ylabel('Roll angle (rad)')
plt.ylim(-3.5, 3.999)
plt.legend(loc='upper right')
plt.show()
# Pitch
plt.figure(figsize=(15, 5))
plt.plot(t, pitch_ref, label='pitch_ref')
plt.plot(t, pitch_est, label='pitch_est')
plt.title('Pitch angle (rad)')
plt.xlabel('Time (s)')
plt.ylabel('Pitch angle (rad)')
plt.ylim(-3.5, 3.999)
plt.legend(loc='upper right')
plt.show()
# Yaw
plt.figure(figsize=(15, 5))
plt.plot(t, yaw_ref, label='yaw_ref')
plt.plot(t, yaw_est, label='yaw_est')
plt.title('Yaw angle (rad)')
plt.xlabel('Time (s)')
plt.ylabel('Yaw angle (rad)')
plt.ylim(-3.5, 3.999)
plt.legend(loc='upper right')
plt.show()

The result would be as follows Roll Pitch Yaw

Dataset

References

[1] C. Chen, P. Zhao, C. X. Lu, W. Wang, A. Markham, and N. Trigoni, “Oxiod: The dataset for deep inertial odometry,” arXiv preprint arXiv:1809.07491, 2018. Link

[2] ahrs.readthedocs.io/en

Arman Asgharpoor Golroudbari
Arman Asgharpoor Golroudbari
Space-AI Researcher

My research interests revolve around planetary rovers and spacecraft vision-based navigation.