Data Types

All data classes inherit from Data, which provides a frame_id attribute. Time-ordered data extends SequentialData, adding timestamps and hertz analysis. Spatial pose data extends PathData, adding positions, orientations, and a coordinate frame.

Enumerations

class robotdataprocess.CoordinateFrame(value)

Enum for different coordinate frames used in robotics.

FLU

X forward, Y left, Z up := RHS

NED

X forward (north), Y right (east), Z down := RHS

ENU

X right (east), Y forward (north), Z up := RHS

NONE

No defined coordinate frame.

class robotdataprocess.ROSMsgLibType(value)

Enum for different ROS message library types.

ROSBAGS

Use ROS messages from the rosbags library (Pure Python library).

RCLPY

Use ROS messages from the rclpy library (ROS2 Python client library).

ROSPY

Use ROS messages from the rospy library (ROS1 Python client library).

NONE

No ROS message library (for testing purposes only).

SequentialData

class robotdataprocess.SequentialData(frame_id: str, timestamps: ndarray | list)

Bases: Data

Data class for sequential (time-ordered) data. Provides timestamps, hertz analysis, and methods that should be overwritten by children.

compute_hertz_stats(trim_outliers: bool = True) tuple[List, List, int]

Compute hertz statistics from timestamps.

Parameters:

trim_outliers – If True and there are more than 5 samples, remove first and last 5 values.

Returns:

  • hertz_diffs: List of time differences between consecutive timestamps

  • hertz_values: List of hertz values (1/diff) for non-zero differences

  • num_zero_diffs: Number of consecutive timestamp pairs with zero difference

Return type:

Tuple of (hertz_diffs, hertz_values, num_zero_diffs) where

Raises:

ValueError – If there are fewer than 2 data samples.

crop_data(start: Decimal, end: Decimal)

Will crop the data so only values within [start, end] inclusive are kept.

Parameters:
  • start – The earliest timestamp to keep.

  • end – The latest timestamp to keep.

Raises:

NotImplementedError – Always; must be overridden by subclasses.

get_ros_msg(libtype: ROSMsgLibType, i: int)

Will create and return a ROS message object.

Parameters:
  • libtype – Which ROS message library to use.

  • i – Index of the data sample to convert.

Returns:

A ROS message populated with the data at index i.

Raises:

NotImplementedError – Always; must be overridden by subclasses.

static get_ros_msg_type(libtype: ROSMsgLibType)

Will return the msgtype for the ROS message for this Data object.

Parameters:

libtype – Which ROS message library to use.

Returns:

The ROS message type class.

Raises:

NotImplementedError – Always; must be overridden by subclasses.

hertz_analysis(show_plots: bool = True) tuple[List, List]

Plot histograms with the sequential data hertz rates and time differences.

Parameters:

show_plots – If True, display matplotlib plots. Set to False for testing.

Returns:

Tuple of (hertz_diffs, hertz_values) for testing purposes.

len() int

Returns the number of items in this data class.

Returns:

The number of timestamped entries.

Return type:

int

round_timestamps(decimals: int)

Rounds all timestamps to the specified number of decimal places.

Parameters:

decimals – Number of decimal places to round to.

PathData

class robotdataprocess.PathData(frame_id: str, timestamps: ndarray | List, positions: ndarray | List, orientations: ndarray | List, frame: CoordinateFrame)

Bases: SequentialData

Trajectory data with timestamped 3D positions and orientations.

Extends SequentialData with spatial pose information. Serves as the base class for OdometryData and provides methods for frame conversion, trajectory alignment, error evaluation (APE/RPE via evo), and 2D/3D visualization.

positions

(N, 3) array of x, y, z positions in meters.

Type:

numpy.ndarray

orientations

(N, 4) array of quaternions in (x, y, z, w) order.

Type:

numpy.ndarray

frame

The coordinate frame convention of this data.

Type:

robotdataprocess.data_types.Data.CoordinateFrame

static align_and_calculate_traj_errors(gt_path: PathData, est_path: PathData, max_diff: float, visualize: bool = False, axes_length: float | list[float] = 10.0, axes_interval: int | list[int] = 1000) Tuple[dict, PathData, PathData]

Utilizing the evo library, calculates a variety of trajectory error metrics and returns them in a dictionary. Also returns aligned PathData objects.

Parameters:
  • max_diff – maximum absolute time difference allowed between associated timestamps

  • visualize – If true, will show a 3D plot of the aligned trajectories.

  • axes_length – Same as in visualize() method.

  • axes_interval – Same as in visualize() method.

apply_transformation_left_side(H: ndarray)

Applies a rigid-body transformation to the entire path. In terms of transformation matrices, this multiplies this path on the left side.

Parameters:

H – The 4x4 transformation matrix

apply_transformation_right_side(H: ndarray)

Applies a rigid-body transformation to the entire path. In terms of transformation matrices, this multiplies this path on the right side (row-vector convention).

Parameters:

H – The 4x4 transformation matrix

static concatenate_PathData(path_data_objs: list[PathData]) PathData

Combines multiple PathData objects into a single PathData object. In doing so, will shift the timestamps of each subsequent PathData so that their data starts one second after the previous PathData ends. Also assumes the frame_id and frame of the first PathData object for final PathData object.

Mimics the behavior found in ROMAN’s (https://github.com/lunarlab-gatech/roman) evaluation scripts.

Parameters:

path_data_objs – List of PathData objects to concatenate.

Returns:

A single PathData with all trajectories joined end-to-end.

Return type:

PathData

Raises:

ValueError – If the list is empty or has only one element.

crop_data(start: Decimal, end: Decimal | None = None)

Will crop the data so only values within [start, end] inclusive are kept.

Parameters:
  • start – The earliest timestamp to keep.

  • end – The latest timestamp to keep. If None, keeps all data from start onward.

classmethod from_csv(csv_path: Path | str, frame_id: str, frame: CoordinateFrame, header_included: bool, column_to_data: List[int] | None = None, separator: str | None = None, filter: Tuple[str, str] | None = None, ts_in_ns: bool = False, reorder_data: bool = False)

Creates a class structure from a csv file.

Parameters:
  • csv_path (Path | str) – Path to the CSV file.

  • frame_id (str) – The frame that this path is relative to.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

  • header_included (bool) – If this csv file has a header, so we can remove it.

  • column_to_data (list[int]) – Tells the algorithms which columns in the csv contain which of the following data: [‘timestamp’, ‘x’, ‘y’, ‘z’, ‘qw’, ‘qx’, ‘qy’, ‘qz’]. Thus, index 0 of column_to_data should be the column that timestamp data is found in the csv file. Set to None to use [0,1,2,3,4,5,6,7].

  • separator (str | None) – The separator used in the csv file. If None, will use a comma by default.

  • filter – A tuple of (column_name, value), where only rows with column_name == value will be kept. If csv file has no headers, then column_name should be the index of the column as a string.

  • ts_in_ns (bool) – If True, assumes timestamps are in nanoseconds and converts to seconds. Otherwise, assumes timestamps are already in seconds.

  • reorder_data (bool) – If True, reorders the data to be in order of timestamps. If False, assumes data is already ordered by timestamp.

Returns:

Instance of this class.

Return type:

PathData

classmethod from_evo(pose_trajectory_3d: PoseTrajectory3D, frame_id: str, frame: CoordinateFrame) PathData

Creates a PathData object from an evo PoseTrajectory3D object.

Parameters:
  • pose_trajectory_3d – An evo PoseTrajectory3D with positions, orientations, and timestamps.

  • frame_id – The frame ID to assign.

  • frame – The coordinate frame of this data.

Returns:

Instance of this class.

Return type:

PathData

classmethod from_ros2_bag(bag_path: Path | str, odom_topic: str, frame: CoordinateFrame) PathData

Creates a class structure from a ROS2 bag file with a Path topic.

Parameters:
  • bag_path (Union[Path, str]) – Path to the ROS2 bag file.

  • odom_topic (str) – Topic of the Path messages.

  • frame – The coordinate frame of this data.

Returns:

Instance of this class.

Return type:

PathData

classmethod from_tum(file_path: Path | str, frame_id: str, frame: CoordinateFrame) PathData

Creates a PathData class from a TUM RGB-D dataset trajectory format text file.

Each row must contain 8 space-separated values:

timestamp x y z q_x q_y q_z q_w

where timestamp is in seconds and the orientation quaternion is in (x, y, z, w) order.

Parameters:
  • file_path (Path | str) – Path to the TUM trajectory file.

  • frame_id (str) – The frame where this path is relative to.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

Returns:

Instance of this class.

Return type:

PathData

classmethod from_txt(file_path: Path | str, frame_id: str, frame: CoordinateFrame, header_included: bool, column_to_data: List[int] | None = None)

Creates a PathData class from a text file.

Parameters:
  • file_path (Path | str) – Path to the file containing the path data.

  • frame_id (str) – The frame where this path is relative to.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

  • header_included (bool) – If this text file has a header, so we can remove it.

  • column_to_data (list[int]) – Tells the algorithms which columns in the text file contain which of the following data: [‘timestamp’, ‘x’, ‘y’, ‘z’, ‘qw’, ‘qx’, ‘qy’, ‘qz’]. Thus, index 0 of column_to_data should be the column that timestamp data is found in the text file. Set to None to use [0,1,2,3,4,5,6,7].

Returns:

Instance of this class.

Return type:

PathData

interpolate_to_hz(target_hz: float)

Linearly interpolates position and SLERPs orientation so that path data is output at the desired frequency.

Parameters:

target_hz (float) – Desired output frequency in Hertz (e.g. 6.0)

static make_start_and_end_times_match(est: list[PathData], gt: list[PathData]) Tuple[list[PathData], list[PathData]]

For pairs of lists of PathData objects, extract each pair by index and ensure that the first and last timestamps match by extending the data as necessary at the start and end with duplicate values. Used for evaluation purposes.

Mimics the behavior found in ROMAN’s (https://github.com/lunarlab-gatech/roman) evaluation scripts.

Parameters:
  • est – List of PathData objects that represent estimated paths.

  • gt – List of PathData objects that represent ground truth paths.

static seperate_PathData(original_PathDatas: list[PathData], merged_PathData: PathData) list[PathData]

Inverse of concatenate_PathData(); needs the original objects to know the timestamps that each trajectory is found on.

Parameters:
  • original_PathDatas – The original PathData objects used during concatenation, needed to determine timestamp boundaries.

  • merged_PathData – The single merged PathData to split apart.

Returns:

One PathData per original trajectory, cropped from the merged data.

Return type:

list[PathData]

shift_position(x_shift: float, y_shift: float, z_shift: float)

Shifts the positions of the path.

Parameters:
  • x_shift (float) – Shift in x-axis.

  • y_shift (float) – Shift in y_axis.

  • z_shift (float) – Shift in z_axis.

shift_to_start_at_identity()

Alter the positions and orientations based so that the first pose starts at Identity.

to_OdometryData(new_frame_id: str, new_child_frame_id: str)

Returns an OdometryData object for this class.

Parameters:
  • new_frame_id – The new frame ID to assign to the OdometryData object.

  • new_child_frame_id – The new child frame ID to assign to the OdometryData object.

to_coordinate_frame(target_frame: CoordinateFrame, transform_type: TransformType = TransformType.CHANGE_OF_BASIS)

Converts positions and orientations into the target coordinate frame.

Parameters:
  • target_frame – The desired coordinate frame.

  • transform_type – How to apply the frame change. CHANGE_OF_BASIS applies a similarity transform to orientations (R * q * R^-1) and rotates positions (default, original behaviour). ROTATION left-multiplies the frame change rotation onto both positions and orientations without the inverse on orientations.

to_csv(csv_path: Path | str, write_header: bool = True)

Writes the path data to a .csv file. Note that data will be saved in the following order: timestamp, pos.x, pos.y, pos.z, ori.w, ori.x, ori.y, ori.z. Timestamp is in seconds.

Parameters:
  • csv_path (Path | str) – Path to the output csv file.

  • write_header (bool) – If false, skip the header row.

Raises:

ValueError – If the output file already exists.

to_evo() PoseTrajectory3D

Returns an evo PoseTrajectory3D object for this class.

Returns:

Trajectory with positions, orientations (wxyz), and timestamps.

Return type:

PoseTrajectory3D

to_tum(file_path: Path | str)

Writes the path data to a TUM RGB-D dataset trajectory format text file.

Each row contains 8 space-separated values:

timestamp x y z q_x q_y q_z q_w

where timestamp is in seconds and the orientation quaternion is in (x, y, z, w) order.

Parameters:

file_path (Path | str) – Path to the output text file.

Raises:

ValueError – If the output file already exists.

to_txt_file(file_path: Path | str, data_to_column: List[int] | None = None)

Writes the path data to a space-separated text file. This is the inverse of from_txt().

data_to_column specifies the output column index for each of the 8 data fields (in this fixed order): timestamp, x, y, z, qw, qx, qy, qz. For example, the default [0, 1, 2, 3, 4, 5, 6, 7] produces:

timestamp x y z qw qx qy qz

Set to None to use the default [0, 1, 2, 3, 4, 5, 6, 7].

Parameters:
  • file_path (Path | str) – Path to the output text file.

  • data_to_column (list[int] | None) – Maps each data field to its output column index. Must be a permutation of [0, 1, 2, 3, 4, 5, 6, 7].

Raises:

ValueError – If the output file already exists.

static visualize_2D(dataList: List[PathData], isGTList: List[bool], colorList: List[str], nameList: List[str], save_path: str | None = None, no_background: bool = False, line_width: float = 1.0, show_grid: bool = False, legend: bool = True, no_border: bool = False, disable_x_label: bool = False, disable_y_label: bool = False, google_maps_scale_bar: bool = False, google_maps_scale_bar_loc: str = 'bottom-right', gt_color_lightness_range_val: int = 3, background_image_path: str | None = None, background_image_x_edge: float | None = None, ax: Axes | None = None, background_image_extent_offsets: Tuple[float, float] | None = None)

Plot all PathData objects on a 2D XY plane.

Parameters:
  • dataList – All PathData objects to plot.

  • isGTList – Whether or not each PathData object is GT.

  • colorList – Colors to assign to each PathData object (as hex strings starting with #).

  • nameList – Robot names corresponding to each PathData object.

  • save_path – If provided, figure will be saved to the location. Otherwise, show the figure. This does nothing if ax is not None.

  • no_background – If true, plot with a transparent background.

  • line_width – Width of trajectory lines in the plot.

  • show_grid – Whether to draw a grid on the plot.

  • legend – If true, include a legend.

  • no_border – If true, remove the x & y axes.

  • disable_x_label – Remove the x label.

  • disable_y_label – Remove the y label.

  • google_maps_scale_bar – Whether to add a Google Maps-like scale bar onto the plot.

  • google_maps_scale_bar_loc – Location for the scale bar.

  • background_image_path – Path to an image to plot in the background; It is assumed that the center of the image corresponds to x=0 & y=0 in the PataData frames.

  • background_image_x_edge – The distance in meters from center of image to the x edge.

  • background_image_extent_offets – XY locations where the image center should be located.

  • ax – If passed, plot is drawn onto these axes instead of on a new figure.

visualize_3D(otherList: List[PathData], titles: List[str], axes_length: float | List[float] = 10.0, axes_interval: int | List[int] = 1000)

Visualizes this PathData (and all others included in otherList) on a single plot.

Parameters:
  • otherList (List[PathData]) – All other PathData objects whose path should also be visualized on this plot.

  • titles (List[str]) – Titles for each PathData object, starting with self.

OdometryData

class robotdataprocess.OdometryData(frame_id: str, child_frame_id: str, timestamps: ndarray | list, positions: ndarray | list, orientations: ndarray | list, frame: CoordinateFrame)

Bases: PathData

Odometry data extending PathData with a child frame ID and ROS message caching.

Supports loading from ROS2 bags, CSV files, and TXT files, and exporting to CSV or ROS messages (Odometry, Path, and maplab OdometryWithImuBiases).

child_frame_id

The frame whose pose is described by this odometry (e.g. "base_link").

Type:

str

poses

Cached rosbags PoseStamped messages (rebuilt after any mutation).

Type:

list

poses_rclpy

Cached rclpy/rospy PoseStamped messages (rebuilt after any mutation).

Type:

list

classmethod from_csv(csv_path: Path | str, frame_id: str, child_frame_id: str, frame: CoordinateFrame, header_included: bool, column_to_data: List[int] | None = None, separator: str | None = None, filter: Tuple[str, str] | None = None, ts_in_ns: bool = False, reorder_data: bool = False)

Creates a class structure from a csv file.

Parameters:
  • csv_path (Path | str) – Path to the CSV file.

  • frame_id (str) – The frame that this odometry is relative to.

  • child_frame_id (str) – The frame whose pose is represented by this odometry.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

  • header_included (bool) – If this csv file has a header, so we can remove it.

  • column_to_data (list[int]) – Tells the algorithms which columns in the csv contain which of the following data: [‘timestamp’, ‘x’, ‘y’, ‘z’, ‘qw’, ‘qx’, ‘qy’, ‘qz’]. Thus, index 0 of column_to_data should be the column that timestamp data is found in the csv file. Set to None to use [0,1,2,3,4,5,6,7].

  • separator (str | None) – The separator used in the csv file. If None, will use a comma by default.

  • filter – A tuple of (column_name, value), where only rows with column_name == value will be kept. If csv file has no headers, then column_name should be the index of the column as a string.

  • ts_in_ns (bool) – If True, assumes timestamps are in nanoseconds and converts to seconds. Otherwise, assumes timestamps are already in seconds.

  • reorder_data (bool) – If True, reorders the data to be in order of timestamps. If False, assumes data is already ordered by timestamp.

Returns:

Instance of this class.

Return type:

OdometryData

classmethod from_ros2_bag(bag_path: Path | str, odom_topic: str, frame: CoordinateFrame)

Creates a class structure from a ROS2 bag file with an Odometry topic.

Parameters:
  • bag_path (Path | str) – Path to the ROS2 bag file.

  • odom_topic (str) – Topic of the Odometry messages.

Returns:

Instance of this class.

Return type:

OdometryData

classmethod from_tum(file_path: Path | str, frame_id: str, child_frame_id: str, frame: CoordinateFrame)

Creates an OdometryData class from a TUM RGB-D dataset trajectory format text file.

Each row must contain 8 space-separated values:

timestamp x y z q_x q_y q_z q_w

where timestamp is in seconds and the orientation quaternion is in (x, y, z, w) order.

Parameters:
  • file_path (Path | str) – Path to the TUM trajectory file.

  • frame_id (str) – The frame where this odometry is relative to.

  • child_frame_id (str) – The frame whose pose is represented by this odometry.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

Returns:

Instance of this class.

Return type:

OdometryData

classmethod from_txt(file_path: Path | str, frame_id: str, child_frame_id: str, frame: CoordinateFrame, header_included: bool, column_to_data: List[int] | None = None)

Creates an OdometryData class from a text file.

Parameters:
  • file_path (Path | str) – Path to the file containing the odometry data.

  • frame_id (str) – The frame where this odometry is relative to.

  • child_frame_id (str) – The frame whose pose is represented by this odometry.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

  • header_included (bool) – If this text file has a header, so we can remove it.

  • column_to_data (list[int]) – Tells the algorithms which columns in the text file contain which of the following data: [‘timestamp’, ‘x’, ‘y’, ‘z’, ‘qw’, ‘qx’, ‘qy’, ‘qz’]. Thus, index 0 of column_to_data should be the column that timestamp data is found in the text file. Set to None to use [0,1,2,3,4,5,6,7].

Returns:

Instance of this class.

Return type:

OdometryData

get_ros_msg(lib_type: ROSMsgLibType, i: int, msg_type: str = 'Odometry')

Gets an Odometry ROS message corresponding to the data at index i.

Parameters:
  • lib_type – Which ROS message library to use.

  • i – The index of the odometry data to convert.

  • msg_type – The message type name ("Odometry", "Path", "TFMessage", or "maplab_msg/OdometryWithImuBiases").

Raises:
  • IndexError – If i is outside the data bounds.

  • ValueError – If msg_type is not supported for the given lib_type.

static get_ros_msg_type(lib_type: ROSMsgLibType, msg_type: str = 'Odometry') Any

Return the ROS message type class for odometry-related messages.

Parameters:
  • lib_type – Which ROS message library to use.

  • msg_type – The message type name. Supported values are "Odometry", "Path", "TFMessage", and "maplab_msg/OdometryWithImuBiases" (ROSPY only).

Returns:

The ROS message type class.

Raises:
  • ValueError – If msg_type is not supported for the given lib_type.

  • NotImplementedError – If lib_type is not supported.

ImuData

class robotdataprocess.ImuData(frame_id: str, frame: CoordinateFrame, timestamps: ndarray | list, lin_acc: ndarray | list, ang_vel: ndarray | list, orientations: ndarray[Any, dtype[ScalarType]] | None)

Bases: SequentialData

IMU sensor data with linear acceleration, angular velocity, and optional orientation.

Supports loading from ROS2 bags and TXT files (TartanAir format). Can be integrated via Euler’s method to produce a PathData trajectory, or published as sensor_msgs/Imu ROS messages.

lin_acc

(N, 3) array of linear accelerations in m/s^2.

Type:

numpy.ndarray[Any, numpy.dtype[numpy._typing._generic_alias.ScalarType]]

ang_vel

(N, 3) array of angular velocities in rad/s.

Type:

numpy.ndarray[Any, numpy.dtype[numpy._typing._generic_alias.ScalarType]]

orientations

(N, 4) array of quaternions (x, y, z, w), or None if unavailable.

Type:

numpy.ndarray[Any, numpy.dtype[numpy._typing._generic_alias.ScalarType]] | None

frame

The coordinate frame convention of this data.

Type:

robotdataprocess.data_types.Data.CoordinateFrame

crop_data(start: Decimal, end: Decimal | None = None)

Will crop the data so only values within [start, end] inclusive are kept.

Parameters:
  • start – The earliest timestamp to keep.

  • end – The latest timestamp to keep. If None, keeps all data from start onward.

classmethod from_ros2_bag(bag_path: Path | str, imu_topic: str, frame_id: str)

Creates a class structure from a ROS2 bag file with an Imu topic.

Parameters:
  • bag_path (Path | str) – Path to the ROS2 bag file.

  • imu_topic (str) – Topic of the Imu messages.

  • frame_id (str) – The frame where this IMU data was collected.

Returns:

Instance of this class.

Return type:

ImuData

classmethod from_txt(file_path: Path | str, frame_id: str, frame: CoordinateFrame, nine_axis: bool = False)

Creates a class structure from the TartanAir dataset format, which includes various .txt files with IMU data. It expects (in order) the timestamp, the linear acceleration, and the angular velocity seperated by spaces. Will also expect orientation (xyzw) at the end if nine_axis is set to True.

Parameters:
  • file_path (Path | str) – Path to the file containing the IMU data.

  • frame_id (str) – The frame where this IMU data was collected.

  • frame (CoordinateFrame) – The coordinate system convention of this data.

  • nine_axis (bool) – If true, will also load orientations from txt file.

Returns:

Instance of this class.

Return type:

ImuData

get_ros_msg(lib_type: ROSMsgLibType, i: int)

Gets an Imu ROS message corresponding to the data at index i.

Parameters:
  • lib_type – Which ROS message library to use.

  • i – The index of the IMU data to convert.

Raises:
  • ValueError – If i is outside the data bounds.

  • NotImplementedError – If lib_type is not supported.

static get_ros_msg_type(lib_type: ROSMsgLibType) Any

Return the ROS message type class for an Imu message.

Parameters:

lib_type – Which ROS message library to use.

Returns:

The ROS message type class for sensor_msgs/Imu.

Raises:

NotImplementedError – If lib_type is not supported.

to_PathData(initial_pos: ndarray[Any, dtype[ScalarType]], initial_vel: ndarray[Any, dtype[ScalarType]], initial_ori: ndarray[Any, dtype[ScalarType]], use_ang_vel: bool) PathData

Converts this IMUData class into OdometeryData by integrating the IMU data using Euler’s method.

Parameters:
  • initial_pos – The initial position as a numpy array.

  • initial_vel – The initial velocity as a numpy array.

  • initial_ori – The initial orientation as a numpy array (quaternion x, y, z, w), only used if use_ang_vel is True.

  • use_ang_vel – If True, will use angular velocity data to calculate orientation. If False, will use orientation data directly from the IMUData class.

Returns:

The resulting PathData class.

Return type:

PathData

visualize(ts_start: float, ts_end: float)

Plot the linear acceleration, angular velocity, and orientation data.

Parameters:
  • ts_start – Start timestamp of the window to plot.

  • ts_end – End timestamp of the window to plot.

LiDARData

class robotdataprocess.data_types.LiDARData.LiDARData(frame_id: str, timestamps: ndarray | list, point_clouds: List[ndarray], channels: List[ndarray] | None, frame: CoordinateFrame)

Bases: SequentialData

LiDAR Data class that contains LiDAR-specific attributes and methods. Inherits from the generic Data class.

NOTE: Assumes points at [0,0,0] are invalid and will set them to NaNs when necessary. Thus, all other points are assumed to be valid.

calculate_point_channels(num_channels: int, v_min_angle: float, v_max_angle: float) None

Calculate channel numbers for each point.

NOTE: This assumes that lasers are evenly spaced within the angular range and that the first laser fires at v_min_angle and the last laser fires at v_max_angle. NOTE: Invalid points (NaNs) get a channel of 65535.

Parameters:
  • num_channels – Number of laser channels (e.g. 16 for VLP-16).

  • v_min_angle – Minimum vertical angle in degrees.

  • v_max_angle – Maximum vertical angle in degrees.

crop_data(start: Decimal, end: Decimal | None = None)

Will crop the data so only values within [start, end] inclusive are kept.

Parameters:
  • start – The earliest timestamp to keep.

  • end – The latest timestamp to keep. If None, keeps all data from start onward.

estimate_FOV(n_frames: int = 10) Tuple[float, float]

Estimate the vertical field of view of the LiDAR sensor from the point cloud data.

Samples up to n_frames evenly-spaced frames, computes the elevation angle of every valid point in each frame, and returns the observed vertical FOV as a (v_min_deg, v_max_deg) tuple. Elevation is measured from the horizontal plane: positive angles are above horizontal, negative angles are below. The data must be in the FLU coordinate frame; call to_FLU_frame() first if needed.

The 1st and 99th percentiles are used rather than strict min/max to guard against stray points near the sensor or at extreme ranges.

Parameters:

n_frames – Maximum number of frames to sample. Frames are drawn evenly across the full dataset. Defaults to 10.

Returns:

(v_min_deg, v_max_deg) — the estimated vertical FOV in degrees, consistent with the lidar_v_fov convention used elsewhere in this library.

Raises:
  • RuntimeError – If the data is not in the FLU coordinate frame.

  • RuntimeError – If no valid points are found across the sampled frames.

classmethod from_npy_files(npy_folder_path: Path | str, frame_id: str, frame: CoordinateFrame) LiDARData

Load LiDAR data from a series of .npy files in a specified folder, where file names correspond to timestamps. Each point is expected to contain either [x, y, z] or [x, y, z, channel].

Parameters:
  • npy_folder_path – Path to the folder.

  • frame_id – The frame ID for the LiDAR data.

  • frame – The coordinate frame of the LiDAR data.

Returns:

An instance of LiDARData populated with the loaded data.

Return type:

LiDARData

classmethod from_ros2_bag(bag_path: Path | str, lidar_topic: str, frame: CoordinateFrame)

Creates a class structure from a ROS2 bag file with a PointCloud2 topic. The frame_id is loaded directly from the message header in the bag.

Parameters:
  • bag_path (Path | str) – Path to the ROS2 bag file.

  • lidar_topic (str) – Topic of the PointCloud2 messages.

  • frame – The coordinate frame of the LiDAR data.

Returns:

Instance of this class.

Return type:

LiDARData

get_point_cloud_at_index(index: int)

Gets the point cloud at index T and ensures all necessary transformations are applied. This is a safe copy of the memmapped array, meaning it can be transformed and changed.

Parameters:

index – The index of the point cloud to retrieve (0-based within the possibly-cropped dataset).

Returns:

Tuple of (points, channels) where points is an (N, 3) float32 array and channels is an (N,) uint16 array or None.

get_ros_msg(lib_type: ROSMsgLibType, i: int)

Gets a PointCloud2 message corresponding to the point cloud at index i.

Parameters:
  • lib_type (ROSMsgLibType) – The type of ROS message to return (e.g., ROSBAGS, RCLPY).

  • i (int) – The index of the point cloud to convert.

Raises:

ValueError – If i is outside the data bounds.

NOTE: Currently publishes an unordered point cloud. NOTE: Assumes all points are collected at same time (likely false in the real-world). NOTE: Assumes channels data is provided. NOTE: Assumes intensity of 255 for all points.

static get_ros_msg_type(lib_type: ROSMsgLibType) Any

Return the ROS message type class for a PointCloud2 message.

Parameters:

lib_type – Which ROS message library to use.

Returns:

The ROS message type class for sensor_msgs/PointCloud2.

Raises:

NotImplementedError – If lib_type is not supported.

make_dense()

Removes invalid points (infinity and NaNs) to make the point cloud dense.

to_FLU_frame()

Adds a transformation so that point clouds returned by get_point_cloud_at_index are rotated into the FLU coordinate frame.

to_npy_files(npy_folder_path: Path | str) None

Save LiDAR data to a series of .npy files in a specified folder, where file names correspond to timestamps. Each file contains an (N, 3) array if channels are None, or (N, 4) array if channels exist (4th column is the channel).

Parameters:

npy_folder_path – Path to the output folder. Created if it doesn’t exist.

visualize(interval_ms: int = 100, plot_lims: Tuple[float, float] = (-50.0, 50.0), testing: bool = False)

Visualizes the raw LiDAR data over time using Matplotlib FuncAnimation.

Parameters:
  • interval_ms – The time between plotted frames.

  • plot_lims – The axes limits of the 3D plot.

  • testing – Only used for test cases, disables blocking in plt.show()

LoopClosureData

class robotdataprocess.LoopClosureData(timestamps_a: ndarray | list, timestamps_b: ndarray | list, names: List[Tuple[str, str]], translations: ndarray | list, orientations: ndarray | list, detected_inliers: ndarray | list | None = None)

Bases: Data

Data class for inter-robot loop closure measurements. Each loop closure represents a relative pose between two robots at specific timestamps.

calculate_errors(name_to_path: dict) dict

Calculate translation and rotation errors for each loop closure by comparing the estimated relative transform against ground truth computed from PathData trajectories.

The estimated loop closure provides the pose of the second robot (names[1]) with respect to the first robot (names[0]), or H_A->B. The GT relative transform is computed as (T_W->A)^{-1} * T_W->B, where A is names[0] and B is names[1].

Parameters:

name_to_path – Dict mapping robot names to their ground truth PathData.

Returns:

“translation_errors”: (N,) float64 array of translation magnitude errors in meters. “rotation_errors”: (N,) float64 array of rotation angle errors in degrees.

Return type:

Dict with

classmethod from_g2o(g2o_path: Path | str, time_path: Path | str, names_override: dict | None = None) LoopClosureData

Creates a LoopClosureData instance from a g2o file containing EDGE_SE3:QUAT entries, using a timestamp file to map keyframe indices to real timestamps.

GTSAM symbol keys are decoded as (character << 56 | index). The character is converted to a robot id (‘a’ -> 0, ‘b’ -> 1, etc.) and used together with the index to look up the timestamp from the time file.

The g2o quaternion order is (qx, qy, qz, qw), which matches the xyzw convention used by this class.

Parameters:
  • g2o_path – Path to the .g2o file.

  • time_path – Path to the timestamp file. Each line has: robot_id keyframe_id timestamp_ns [ignored…]

  • names_override – Optional dict mapping decoded character keys to desired robot names (e.g. {"a": "aerial-07", "b": "ground-03"}). Keys not present in the dict are kept as their decoded character.

Returns:

LoopClosureData instance.

classmethod from_json(json_path: Path | str, names_override: dict | None = None) LoopClosureData

Creates a LoopClosureData instance from a JSON file containing loop closure alignment data.

Parameters:
  • json_path – Path to the JSON file.

  • names_override – Optional dict mapping names found in the JSON to desired replacement names (e.g. {"0": "aerial-07", "1": "ground-03"}). Names not present in the dict are kept as-is.

Returns:

LoopClosureData instance.

label_inliers_via_other_LoopClosureData(other: LoopClosureData) None

Label loop closures as inliers if they are also detected in another LoopClosureData instance. The other object is assumed to be a subset of self — every loop closure in other must have a matching entry in self. A ValueError is raised if any loop closure in other cannot be matched.

This modifies the detected_inliers attribute in place.

Matches are checked by name pairs, timestamps, translations, and orientations. Quaternion sign ambiguity is handled: q and -q are treated as equivalent.

Note: Swapped name pairs ((A,B) vs (B,A)) are NOT matched. Both LoopClosureData instances must use the same robot1-to-robot2 convention for loop closures to be identified as inliers.

Parameters:

other – Another LoopClosureData instance that is a subset of self; unaffected by this method.

Raises:

ValueError – If any loop closure in other is not found in self, violating the subset assumption.

round_timestamps(decimals: int)

Rounds all timestamps to the specified number of decimal places.

Parameters:

decimals – Number of decimal places to round to.

static visualize_error_scatter(errors: List[dict], labels: List[str], inlier_masks: List[ndarray] | None = None, show_plots: bool = True, save_path: str | None = None, max_translation_frac: float = 1.0, max_rotation_frac: float = 1.0, trans_err_in_target: float = 1.0, rot_err_in_target: float = 5.0, title: str | None = None)

Scatter plot of loop closure errors (log-log scale): each point is one loop closure. Inliers and outliers are shown with different markers.

Parameters:
  • errors – List of error dicts, each containing "translation_errors" and "rotation_errors" arrays.

  • labels – Display name for each error dict.

  • inlier_masks – Optional list of boolean arrays marking inlier loop closures. If None, all points are treated as outliers.

  • show_plots – If True, display the plot interactively.

  • save_path – If provided, save the figure to this path instead of showing.

  • max_translation_frac – Fraction of max translation error for axis limit.

  • max_rotation_frac – Fraction of max rotation error for axis limit.

  • trans_err_in_target – Translation error threshold for the highlighted region.

  • rot_err_in_target – Rotation error threshold for the highlighted region.

  • title – Optional plot title.

Returns:

matplotlib Figure object.

Raises:
  • ValueError – If list lengths do not match or fraction values are out of range.

  • RuntimeError – If both show_plots and save_path are set.

static visualize_success_rate(errors: List[dict], labels: List[str], num_thresholds: int = 100, show_plots: bool = True, max_translation_frac: float = 1.0, max_rotation_frac: float = 1.0)

Plot loop closure success as a function of error threshold. Produces six plots: translation success rate, rotation success rate, translation count, rotation count, combined success rate, and combined count.

Parameters:
  • errors – List of error dicts, each containing "translation_errors" and "rotation_errors" arrays.

  • labels – Display name for each error dict.

  • num_thresholds – Number of evenly-spaced threshold values to evaluate.

  • show_plots – If True, display the plots interactively.

  • max_translation_frac – Fraction of the maximum translation error to use as the upper threshold bound.

  • max_rotation_frac – Fraction of the maximum rotation error to use as the upper threshold bound.

Returns:

Tuple of six matplotlib Figure objects (translation %, rotation %, translation count, rotation count, combined %, combined count).

Raises:

ValueError – If list lengths do not match or fraction values are out of range.

ImageData

class robotdataprocess.data_types.ImageData.ImageData.ImageData(frame_id: str, timestamps: ndarray | list, height: int, width: int, encoding: ImageEncoding, images: ndarray | Any)

Bases: SequentialData

Generic ImageData class that should be overwritten by children

class ImageEncoding(value)

Bases: Enum

An enumeration.

crop_data(start: Decimal, end: Decimal | None = None)

Will crop the data so only values within [start, end] inclusive are kept.

Parameters:
  • start – The earliest timestamp to keep.

  • end – The latest timestamp to keep. If None, keeps all data from start onward.

classmethod from_image_files(image_folder_path: Path | str, frame_id: str) ImageData

Creates a class structure from a folder with .png files.

Parameters:
  • image_folder_path – Path to the folder containing image files.

  • frame_id – The frame ID to assign.

Returns:

Instance of this class.

Return type:

ImageData

get_ros_msg(lib_type: ROSMsgLibType, i: int)

Gets an Image ROS2 Humble message corresponding to the image represented by index i.

Parameters:
  • lib_type (ROSMsgLibType) – The type of ROS message to return (e.g., ROSBAGS, RCLPY).

  • i (int) – The index of the image message to convert.

Raises:

ValueError – If i is outside the data bounds.

static get_ros_msg_type(lib_type: ROSMsgLibType) Any

Return the __msgtype__ for an Image msg.

Parameters:

lib_type – The ROS message library to use.

Returns:

The Image message type for the specified library.

Raises:

NotImplementedError – If lib_type is not supported.

to_image_files(output_folder_path: Path | str)

Saves each image in this ImageData instance to the specified folder, using the timestamps as filenames in .png format (lossless compression).

Parameters:

output_folder_path (Path | str) – The folder to save images into.

to_npy(output_folder_path: Path | str)

Saves each image in this ImageData into three files:

  • imgs.npy (with image data)

  • times.npy (with timestamps)

  • attributes.txt

Parameters:

output_folder_path (Path | str) – The folder to save the .npy file at.

ImageDataInMemory

class robotdataprocess.ImageDataInMemory(frame_id: str, timestamps: ndarray | list, height: int, width: int, encoding: ImageEncoding, images: ndarray)

Bases: ImageData

Image data stored entirely in RAM (or as a memory-mapped numpy array).

Supports loading from ROS2 bags, .npy files, and .png folders. Provides in-memory downscaling and export to PNG or .npy format.

downscale_by_factor(scale: int)

Scales down all images by the provided factor.

Parameters:

scale (int) – The downscaling factor. Must evenly divide both height and width.

classmethod from_image_files(image_folder_path: Path | str, frame_id: str)

Creates a class structure from a folder with .png files, using the file names as the timestamps. This is the format that the HERCULES v1.4 dataset provides for image data.

Parameters:
  • image_folder_path (Path | str) – Path to the folder with the images.

  • frame_id (str) – The frame where this image data was collected.

Returns:

Instance of this class.

Return type:

ImageData

classmethod from_npy(folder_path: Path | str)

Creates a class structure from .npy and .txt files (the ones written by from_ros2_bag()).

Parameters:

folder_path (Path | str) – Path to the folder with: - imgs.npy - times.npy - attributes.txt

Returns:

Instance of this class.

Return type:

ImageData

classmethod from_npy_files(npy_folder_path: Path | str, frame_id: str)

Creates a class structure from .npy files, where each individual image is stored in an .npy file with the timestamp as the name

Parameters:
  • npy_folder_path (Path | str) – Path to the folder with the npy images.

  • frame_id (str) – The frame where this image data was collected.

Returns:

Instance of this class.

Return type:

ImageData

classmethod from_ros2_bag(bag_path: Path | str, img_topic: str, save_folder: Path | str)

Creates a class structure from a ROS2 bag file with an Image topic. Will Also save all the data into .npy and .txt files as this is required if image data doesn’t fit into the RAM.

Parameters:
  • bag_path (Path | str) – Path to the ROS2 bag file.

  • img_topic (str) – Topic of the Image messages.

  • save_folder (Path | str) – Path to save class data into.

Returns:

Instance of this class.

Return type:

ImageData

ImageDataOnDisk

class robotdataprocess.ImageDataOnDisk(frame_id: str, timestamps: ndarray | list, height: int, width: int, encoding: ImageEncoding, image_paths: List[Path], transformations: List[Callable] | None = None)

Bases: ImageData

Image data loaded lazily from disk, reading each image only when accessed. Uses a LazyImageArray that loads PNG or .npy files on demand, keeping memory usage low for large image sequences. Supports loading from .png and .npy folders where filenames encode timestamps.

crop_images_to_LiDAR_FOV(lidar_v_fov: Tuple[float, float], camera_data: Any) None

Crop the top and bottom of every image so that the camera’s vertical FOV matches the given LiDAR vertical FOV.

The LiDAR vertical FOV is specified in degrees, measured from the horizontal plane: positive angles are above horizontal, negative angles are below. The crop is applied lazily via the transformation pipeline, so no images are read from disk until accessed.

The crop row boundaries are computed from the camera intrinsic matrix K (specifically fy and cy). For a pixel row v in the original image, the elevation angle is theta = -arctan((v - cy) / fy), so the row that maps to a given angle is v = cy - fy * tan(theta).

Parameters:
  • lidar_v_fov(min_deg, max_deg) tuple giving the LiDAR’s vertical angular range in degrees. Positive is above horizontal, negative is below. min_deg < max_deg is required.

  • camera_data – A CameraData instance whose intrinsics are used to compute the crop boundaries. Its height, K, and P fields are updated to reflect the new image dimensions.

Raises:
  • ValueError – If min_deg >= max_deg.

  • ValueError – If the LiDAR FOV does not intersect the image’s vertical extent, or if the computed crop has zero height.

classmethod from_image_files(image_folder_path: Path | str, frame_id: str) ImageDataOnDisk

Creates a class structure from a folder with .png files, using the file names as the timestamps.

Parameters:
  • image_folder_path (Path | str) – Path to the folder with the images.

  • frame_id (str) – The frame where this image data was collected.

Returns:

Instance of this class.

Return type:

ImageDataOnDisk

classmethod from_npy_files(npy_folder_path: Path | str, frame_id: str)

Creates a class structure from .npy files, where each individual image is stored in an .npy file with the timestamp as the name

Parameters:
  • npy_folder_path (Path | str) – Path to the folder with the npy images.

  • frame_id (str) – The frame where this image data was collected.

Returns:

Instance of this class.

Return type:

ImageData

to_encoding(encoding: ImageEncoding)

Swap the encoding of the image data. Currently only supports RGB8 -> BGR8.

Parameters:

encoding – The target encoding to convert to.

Raises:

NotImplementedError – If the conversion between the current and target encoding is not supported.