Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
e61ef74
Prototype code for ROS2 Publishing, and new ImageDataOnDisk class
DanielChaseButterfield Dec 12, 2025
70830f4
Fix bug with typehint for LazyImageArray
DanielChaseButterfield Dec 12, 2025
37a6541
Publisher runs at desired Hz with workers
DanielChaseButterfield Dec 12, 2025
1470f5b
RosPublisher prototype changes to support ROS1 & ROS2 (test pending)
DanielChaseButterfield Dec 15, 2025
ec1cee5
Updated HERCULES experiment files
DanielChaseButterfield Dec 16, 2025
03989db
Bug fixes and file for publishing for Maplab
DanielChaseButterfield Dec 16, 2025
50a883d
Support for RosPublisher.py to publish Data objects over multiple ROS…
DanielChaseButterfield Dec 17, 2025
bd1272e
SlideSLAM data export changes
DanielChaseButterfield Dec 17, 2025
3311197
Merge branch 'develop' of github.com:lunarlab-gatech/rosbag_manipulat…
DanielChaseButterfield Dec 17, 2025
468a0d1
Reorder data parameter for OdometryData.from_csv
DanielChaseButterfield Jan 1, 2026
4531795
Tweaks to HERCULES dataset management scripts
DanielChaseButterfield Jan 3, 2026
a4508a4
Merge ROS2 and ROS1 publishers into single and rehaul unit tests to h…
DanielChaseButterfield Jan 7, 2026
92d9119
Add debugging statement to test
DanielChaseButterfield Jan 7, 2026
aadf7c2
Fix coverage uploading
DanielChaseButterfield Jan 7, 2026
1acc370
Extend wait for ROS2 Test
DanielChaseButterfield Jan 7, 2026
7ed74d0
Source ROS in ROS2 test
DanielChaseButterfield Jan 7, 2026
5a3e900
Switch shell to bash for ROS2 Tests
DanielChaseButterfield Jan 7, 2026
cd587c6
Fix bug with Coverage report merging
DanielChaseButterfield Jan 7, 2026
c94db77
Add coveragerc to merge coverage files from different environments
DanielChaseButterfield Jan 7, 2026
16812af
Fix bug in coverage merging
DanielChaseButterfield Jan 7, 2026
86a4367
Fix errornous source specified for converage
DanielChaseButterfield Jan 7, 2026
b76d3fc
Add a debugging line
DanielChaseButterfield Jan 7, 2026
5d267b1
Potential fix to coverage file upload
DanielChaseButterfield Jan 7, 2026
308d8ee
Another potential fix to not uploading coverage files
DanielChaseButterfield Jan 7, 2026
65ac54b
Add debug line to github actions
DanielChaseButterfield Jan 8, 2026
9ca6018
Tweak the debug statement
DanielChaseButterfield Jan 8, 2026
2a1aff2
Add missing paths to coverage
DanielChaseButterfield Jan 8, 2026
a4001a2
Another attempt to solve github actions
DanielChaseButterfield Jan 8, 2026
3c66dbc
Hopefully final fix to github action
DanielChaseButterfield Jan 8, 2026
8749f5f
Add publish script for OpenVINS
DanielChaseButterfield Jan 8, 2026
1b35ff5
Add test case for Python 3.10
DanielChaseButterfield Jan 8, 2026
ce6115a
Path message type for RCLPY and OdometryData
DanielChaseButterfield Jan 8, 2026
17ab253
Odometery Path publish bug fixes and clean output for multiprocessing…
DanielChaseButterfield Jan 8, 2026
bbc5f3f
Remove Python 3.10 unit tests as not all test cases pass yet
DanielChaseButterfield Jan 8, 2026
b9710b2
RosPublisher will now skip messages if it is behind to catch up quick…
DanielChaseButterfield Jan 8, 2026
0f1f0b7
Merge branch 'develop' of github.com:lunarlab-gatech/robotdataprocess…
DanielChaseButterfield Jan 8, 2026
6e6bbed
Can choose # of workers in function call for ros publish multiprocess
DanielChaseButterfield Jan 8, 2026
75f9bf3
Results file for OpenVINS
DanielChaseButterfield Jan 8, 2026
6a862e2
LiDAR data visualization, coverage works for multiprocessing
DanielChaseButterfield Jan 9, 2026
cfa07fa
Increase timeout so test has chance at success in github actions
DanielChaseButterfield Jan 9, 2026
15ad45e
Configure test cases to only run on push
DanielChaseButterfield Jan 9, 2026
26bf603
Test cases for LiDARData class
DanielChaseButterfield Jan 9, 2026
78f626b
Remove tutrle import
DanielChaseButterfield Jan 9, 2026
708bacf
Remove pycache files from tracking
DanielChaseButterfield Jan 12, 2026
17a6cf5
Remove hardcoded user paths and replace with getuser()
DanielChaseButterfield Jan 12, 2026
8acdf19
Attempt to make RosPublishers exit cleanly with KeyboardInterrupts
DanielChaseButterfield Jan 12, 2026
387ba70
Swap ROS1 while loop for publishing with rospy.Timer for real-time im…
DanielChaseButterfield Jan 12, 2026
68b4945
Module Importer for cached imports for speed
DanielChaseButterfield Jan 13, 2026
9586737
ImageData & ImuData utilize new ModuleImporter
DanielChaseButterfield Jan 13, 2026
0f6241e
Use SharedMemory to publish Images real-time
DanielChaseButterfield Jan 13, 2026
a139215
Slightly optimize main publishing thread for ROs publisher
DanielChaseButterfield Jan 13, 2026
846087c
Replace resource tracker with DummyTracker for RosPublisher
DanielChaseButterfield Jan 13, 2026
6bffb71
Swap Manager with Queue to enable real-time publishing of IMU message…
DanielChaseButterfield Jan 13, 2026
9667bda
9-axis IMU support in ImuData class
DanielChaseButterfield Jan 13, 2026
cc610e3
WIP LiDAR ROS2 Publishing
DanielChaseButterfield Jan 14, 2026
6f5aca3
Calculate point channels for LiDARData
DanielChaseButterfield Jan 14, 2026
3160c5b
LiDAR data successfully publishing
DanielChaseButterfield Jan 14, 2026
a8ee5a4
Better frames for publish_data_LIO-SAM and included intensity field f…
DanielChaseButterfield Jan 15, 2026
57ffdf8
Keep LiDAR data in NED for easier debugging
DanielChaseButterfield Jan 15, 2026
4ec7a29
Fix broken LiDAR unit tests
DanielChaseButterfield Jan 15, 2026
6117772
Final .coverage file uploaded as artifact in github actions test
DanielChaseButterfield Jan 16, 2026
02e22dd
Include hiddne files so we don't miss .coverage in github actions
DanielChaseButterfield Jan 16, 2026
e651c2d
LiDAR improved channel calculation and test cases
DanielChaseButterfield Jan 16, 2026
8631b27
Refactor RosPublisher test to seperate ROS2 testing utils and ImageDa…
DanielChaseButterfield Jan 16, 2026
cde46f7
Replace function with Callable for typehints
DanielChaseButterfield Jan 16, 2026
39db7b9
Fix bug in TestRosPublisher
DanielChaseButterfield Jan 16, 2026
2f4a2a5
Remove try except wrapper for msg_to_dict_fn for test_RosPublisher.py
DanielChaseButterfield Jan 16, 2026
9c8267c
Remove CvBridge from util_ROS2_test
DanielChaseButterfield Jan 16, 2026
d1baa95
Test LiDARData ROS2 publishing
DanielChaseButterfield Jan 16, 2026
974ecd6
LiDARData ROS2 Pub test with custom implementation to unpack data fro…
DanielChaseButterfield Jan 16, 2026
3d334a1
Add missing call to calculate_point_channels()
DanielChaseButterfield Jan 16, 2026
32e3ff6
GitHub Actions updated timeouts due to use of multiprocessing
DanielChaseButterfield Jan 16, 2026
aeb58ad
Passing test cases for LiDAR Messages
DanielChaseButterfield Jan 16, 2026
8254c45
Make one image later for test_RosPublisher ImageData test
DanielChaseButterfield Jan 16, 2026
606aef4
Test that verbose option doesn't crash ROS2 Publisher
DanielChaseButterfield Jan 16, 2026
79810eb
Test case for ImageDataOnDisk
DanielChaseButterfield Jan 16, 2026
96041f5
Remove unused stereo recify method
DanielChaseButterfield Jan 16, 2026
bfc3844
Change timer freq for RosPublisher and memmap loading of LiDAR data
DanielChaseButterfield Jan 16, 2026
1adf6d5
Bug fixes for LiDARData
DanielChaseButterfield Jan 16, 2026
0cf173f
Using 500Hz IMU for LIO-SAM
DanielChaseButterfield Jan 16, 2026
04fd58f
Bug fixes to visualization LiDARData
DanielChaseButterfield Jan 16, 2026
a54cd25
Merge branch 'develop' of github.com:lunarlab-gatech/rosbag_manipulat…
DanielChaseButterfield Jan 16, 2026
16dc929
ImuData RosPublisher test
DanielChaseButterfield Jan 16, 2026
fc48d81
Add test for Python3.10 to github actions
DanielChaseButterfield Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[run]
branch = False
source = robotdataprocess
concurrency = multiprocessing
disable_warnings =
module-not-measured
no-data-collected

[paths]
source =
src/robotdataprocess
*/site-packages/robotdataprocess
*/robotdataprocess/src/robotdataprocess
*/src/robotdataprocess
/usr/local/lib/python3.10/dist-packages/robotdataprocess
40 changes: 0 additions & 40 deletions .github/workflows/python_test.yml

This file was deleted.

143 changes: 143 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Unit Tests

on:
push:
branches: [ "**" ]

permissions:
contents: read

jobs:
python3_8-tests:
name: "Build & Test Python3.8"
runs-on: ubuntu-latest
timeout-minutes: 10
env:
SKIP_ROS2_TESTS: "True"

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install the package
run: |
python -m pip install -e .
- name: Import external message types
uses: snickerbockers/submodules-init@v4
- name: Test with unittest
run: |
coverage run --source robotdataprocess -m unittest discover tests/ -v
- name: Save coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-${{ github.job }}
path: .coverage.*
include-hidden-files: true

python3_10-tests:
name: "Build & Test Python3.10"
runs-on: ubuntu-latest
timeout-minutes: 10
env:
SKIP_ROS2_TESTS: "True"

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install the package
run: |
python3 -m pip install -e . "numpy<1.25"
pip install --upgrade pydantic typeguard
- name: Import external message types
uses: snickerbockers/submodules-init@v4
- name: Test with unittest
run: |
coverage run --source robotdataprocess -m unittest discover tests/ -v
- name: Save coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-${{ github.job }}
path: .coverage.*
include-hidden-files: true

ros2-tests:
name: "Build & Test ROS2 Python Code"
runs-on: ubuntu-latest
timeout-minutes: 5
container:
image: dlittleman/robotdataprocess_ros2_humble:0.2
options: --user root # optional, helps avoid permission issues
env:
SKIP_PURE_PYTHON_TESTS: "True"

steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install the package
run: |
python3 -m pip install -e . "numpy<1.25"
pip install --upgrade pydantic typeguard
- name: Import external message types
uses: snickerbockers/submodules-init@v4
- name: Test with unittest & evaluate test coverage
shell: bash
run: |
export PATH="$HOME/.local/bin:$PATH"
source /opt/ros/humble/setup.bash
coverage run --source robotdataprocess -m unittest discover tests/ -v
- name: Save coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-${{ github.job }}
path: .coverage.*
include-hidden-files: true

coverage:
name: "Merge & Upload Coverage Reports"
needs: [python3_8-tests, python3_10-tests, ros2-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
with:
path: coverage-files
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install the package
run: |
python3 -m pip install -e .
- name: Merge coverage
run: |
pip install coverage
ls -al
pwd
coverage combine coverage-files/coverage-python3_8-tests/.coverage.* coverage-files/coverage-python3_10-tests/.coverage.* coverage-files/coverage-ros2-tests/.coverage.*
coverage xml
- name: Coveralls GitHub Action (Upload Coverage Report)
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Merged Coverage File
uses: actions/upload-artifact@v4
with:
name: coverage-final
path: .coverage
include-hidden-files: true
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ htmlcov/
profile.out

#ignore pyenv
venv/
venv/

# Ignore Python cache files
*/__pycache__/
__pycache__/
53 changes: 53 additions & 0 deletions docker/ROS2_Humble/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Base image: official ROS2 Humble
FROM ros:humble

# Avoid interactive prompts
ENV DEBIAN_FRONTEND=noninteractive

# Install python3-pip and basic tools
RUN apt-get update && apt-get install -y \
python3-pip \
python3-venv \
build-essential \
git \
curl \
&& rm -rf /var/lib/apt/lists/*

# Upgrade pip
RUN python3 -m pip install --upgrade pip

# Install ROS2 packages
RUN apt-get update && apt-get install -y \
ros-humble-cv-bridge \
ros-humble-image-transport \
&& rm -rf /var/lib/apt/lists/*

# Set default workdir inside container
WORKDIR /workspace

# Source ROS setup automatically in bash
SHELL ["/bin/bash", "-c"]
RUN echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc

# Default command
CMD ["bash"]

# Set user arguments (being username, echo $UID, and id -g)
# NOTE: These should be overwritten when running docker build!
ARG USERNAME=user
ARG USER_UID=1000
ARG USER_GID=1000

# Create a non-root user with matching UID/GID
RUN groupadd --gid ${USER_GID} ${USERNAME} && \
useradd --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME} && \
usermod -aG sudo ${USERNAME} && \
echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Add a custom .bashrc with warm colors and fixed hostname
RUN echo 'export PS1="\\[\\e[1;31m\\]\\u@robotdataprocess_container\\[\\e[0m\\]:\\[\\e[1;33m\\]\\w\\[\\e[0m\\]\\$ "' > /home/${USERNAME}/.bashrc && \
chown ${USERNAME}:${USERNAME} /home/${USERNAME}/.bashrc

# Set default user
USER ${USERNAME}
WORKDIR /home/${USERNAME}
5 changes: 5 additions & 0 deletions docker/ROS2_Humble/build_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
docker build \
--build-arg USERNAME=$(id -un) \
--build-arg USER_UID=$(id -u) \
--build-arg USER_GID=$(id -g) \
-t robotdataprocess_ros2_humble .
4 changes: 4 additions & 0 deletions docker/ROS2_Humble/run_container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
docker run -it --rm \
-v $(pwd):/workspace \
-w /workspace \
robotdataprocess_ros2_humble
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
Configure the paths in the main() function below.
"""

import getpass
from pathlib import Path
import shutil
from robotdataprocess import ImageData, ImuData, CoordinateFrame
from robotdataprocess.rosbag.Ros2BagWrapper import Ros2BagWrapper
from robotdataprocess import ImageDataInMemory, ImuData, CoordinateFrame
from robotdataprocess.ros.Ros2BagWrapper import Ros2BagWrapper


def extract_to_bag(input_dir: str, output_bag: str, robot_name: str):
Expand Down Expand Up @@ -46,28 +47,28 @@ def extract_to_bag(input_dir: str, output_bag: str, robot_name: str):
print(f" Loaded {imu_data.len()} IMU measurements")

# Load images from folder
print("\n2. Loading images...")
image_data = ImageData.from_image_files(
input_path / 'rgb',
print("\n2. Loading left images...")
left_image_data = ImageDataInMemory.from_image_files(
input_path / 'rgb_stereo_left',
f'{robot_name}/cam0'
)
print(f" Loaded {image_data.len()} images")
print(f" Loaded {left_image_data.len()} images")

# Set IMU frame to FLU (ROS standard) without transforming the data
# Note: The IMU data remains in NED frame, but we label it as FLU
# to allow writing to ROS bag without errors. Many applications
# like VINS-Mono handle the coordinate frame conversion internally.
# FIXME: this is not implemented yet!
# imu_data.to_FLU_frame()
imu_data.frame = CoordinateFrame.FLU
# Loading right images
print("\n2.b Loading right images...")
right_image_data = ImageDataInMemory.from_image_files(
input_path / 'rgb_stereo_right',
f'{robot_name}/cam1'
)
print(f" Loaded {right_image_data.len()} images")

print("\n3. Writing to temporary ROS2 bag...")
# Write data to temporary ROS2 bag (required intermediate step)
Ros2BagWrapper.write_data_to_rosbag(
temp_ros2_bag,
[imu_data, image_data], # Data to write
['/imu0', '/cam0/image_raw'], # Topic names
[None, None], # Use default message types
[imu_data, left_image_data, right_image_data], # Data to write
['/imu0', '/cam0/image_raw', '/cam1/image_raw'], # Topic names
[None, None, None], # Use default message types
None # No external message definitions
)

Expand All @@ -87,21 +88,22 @@ def extract_to_bag(input_dir: str, output_bag: str, robot_name: str):

print(f"\n✓ Successfully created ROS1 bag at: {output_path}")
print(f" - IMU topic: /imu0 ({imu_data.len()} messages)")
print(f" - Image topic: /cam0/image_raw ({image_data.len()} messages)")

print(f" - Image topic: /cam0/image_raw ({left_image_data.len()} messages)")
print(f" - Image topic: /cam1/image_raw ({right_image_data.len()} messages)")

def main():
# ========== CONFIGURE THESE PATHS ==========

# Robot name (used for frame IDs in the bag)
robot_name = 'Drone1'
dataset_num = "V1.5"
robot_name = 'Husky1'
dataset_num = "V2.1.0"

# Input directory containing your data
input_dir = '/media/dbutterfield3/T731/Hercules_datasets/' + dataset_num + '/data/' + robot_name
user = getpass.getuser()
input_dir = '/media/' + user + '/T73/Hercules_datasets/' + dataset_num + '/data/' + robot_name

# Output bag path
output_bag = '/media/dbutterfield3/T731/Hercules_datasets/' + dataset_num + '/extract/bags_for_maplab/' + robot_name + '.bag'
output_bag = '/media/' + user + '/T73/Hercules_datasets/' + dataset_num + '/extract/bags_for_maplab/' + robot_name + '.bag'

# ==========================================

Expand Down
Loading
Loading