uzh-rpg / rpg_esim

ESIM: an Open Event Camera Simulator
MIT License
591 stars 125 forks source link

Rotations generated in UnrealCV don't match when loaded from csv in esim #87

Open Huizerd opened 3 years ago

Huizerd commented 3 years ago

I use the following code to save a trajectory to csv when running UnrealCV:

import argparse
import atexit
import time

import numpy as np
import pandas as pd
from unrealcv import client

trajectory = []
_TORAD = np.pi / 180

def unreal_euler2quat(roll, pitch, yaw):
    """
    Convert Unreal Euler angles to a quaternion.
    Based on FRotator::Quaternion in
    Engine/Source/Runtime/Core/Private/Math/UnrealMath.cpp ln 373
    :param roll: Roll angle
    :param pitch: Pitch angle
    :param yaw: Yaw angle
    :return: A tuple quaternion in unreal space, w first
    """
    angles = np.array([roll, pitch, yaw])
    angles = angles * _TORAD / 2
    sr, sp, sy = np.sin(angles)
    cr, cp, cy = np.cos(angles)

    x =  cr * sp * sy - sr * cp * cy
    y = -cr * sp * cy - sr * cp * sy
    z =  cr * cp * sy - sr * sp * cy
    w =  cr * cp * cy + sr * sp * sy
    return w, x, y, z

def callback(ts):
    x, y, z, pitch, yaw, roll = [float(v) for v in client.request("vget /camera/0/pose").split(" ")]
    qw, qx, qy, qz = unreal_euler2quat(roll, pitch, yaw)
    entry = {"ts": ts, "x": x / 100, "y": y / 100, "z": z / 100, "qx": qx, "qy": qy, "qz": qz, "qw": qw}
    trajectory.append(entry)

def save_to_file(filename):
    if len(trajectory) != 0:
        df = pd.DataFrame(trajectory)
        df["ts"] -= df["ts"][0]
        df["ts"] *= 1e9
        df["ts"] = df["ts"].astype(int)
        with open(filename, "w") as f:
            f.write("# timestamp, x, y, z, qx, qy, qz, qw\n")
        df.to_csv(filename, index=False, header=False, mode="a")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--filename", default="camera-trajectory.csv")
    args = parser.parse_args()

    atexit.register(save_to_file, args.filename)
    client.connect()

    try:
        if not client.isconnected():
            print("Please connect")
        else:
            last_time = time.time()
            while True:
                current_time = time.time()
                if current_time - last_time >= 0.1:
                    callback(current_time)
                    last_time = current_time

    except KeyboardInterrupt:
        print("\nDone")

I want to have the same trajectory when running esim in combination with UnrealCV, and so I convert the Euler angles I get from UnrealCV to quaternions using unreal_euler2quat(). I save these in a csv which is then loaded in esim with the following .conf:

--data_source=0
--vmodule=unrealcv_renderer=0
--path_to_output_bag=/data/jesse/esim/test_unreal.bag
--random_seed=1

--contrast_threshold_pos=0.6
--contrast_threshold_neg=0.6
--contrast_threshold_sigma_pos=0
--contrast_threshold_sigma_neg=0

--exposure_time_ms=5.0
--use_log_image=1
--log_eps=0.001

--calib_filename=/data/jesse/esim/src/rpg_esim/event_camera_simulator/esim_ros/cfg/calib/pinhole_mono_nodistort_forward.yaml

--renderer_type=3

--trajectory_type=1
--trajectory_spline_order=5
--trajectory_num_spline_segments=100
--trajectory_lambda=0
--trajectory_csv_file=/data/jesse/esim/src/rpg_esim/event_camera_simulator/esim_ros/cfg/traj/test.csv

--x_offset=0.0
--y_offset=0.0
--z_offset=0.0

--simulation_minimum_framerate=5.0
--simulation_imu_rate=1000.0
--simulation_adaptive_sampling_method=1
--simulation_adaptive_sampling_lambda=2.0

--ros_publisher_frame_rate=300
--ros_publisher_depth_rate=300
--ros_publisher_optic_flow_rate=50
--ros_publisher_pointcloud_rate=50
--ros_publisher_camera_info_rate=10

However, the resulting trajectory seems to

  1. have pitch and roll angles swapped
  2. have a yaw offset of 90 degrees

Any idea what could be the cause of this? I saw the other issues regarding trajectories, but these seemed to be largely about --trajectory_lambda=0. I saw something here about a rotation to the right, but that code seems commented out.