Skip to content

Support Multi-Log - #1083

Draft
m3d wants to merge 11 commits into
masterfrom
feature/multilog
Draft

Support Multi-Log#1083
m3d wants to merge 11 commits into
masterfrom
feature/multilog

Conversation

@m3d

@m3d m3d commented Aug 4, 2026

Copy link
Copy Markdown
Member

Multi-Log Feature Design

This document details the design and implementation strategy for the Multi-Log feature in OSGAR.
The goal of this feature is to allow users to process and replay multiple independent, temporally overlapping log files under a unified interface, as if they were reading from a single "virtual" log file.


1. Use Cases

In real-world operations, data often comes from multiple independent sources:

  1. Multi-Robot Operations: Coordinating or analyzing the behavior of multiple autonomous robots (e.g., pat and m03).
  2. Robot with External Sensors: A robot logging its internal states (pose, lidar) while an external stationary camera or motion capture system logs ground-truth data in a separate file.
  3. Algorithmic Reprocessing: An old recording of raw sensor data replayed/reprocessed into a new log with updated pose estimations. We want to read the raw streams from the old log and the processed streams from the new log simultaneously.

To analyze these systems holistically, we need a unified time domain where streams from different logs can be accessed synchronously.


2. Configuration Schema

A Multi-Log session is defined via a JSON configuration. Each nickname maps to an object specifying the file path and an optional time offset (in seconds) to align log timelines.

If offset_sec is omitted, it defaults to 0.0, which is ideal for systems that are already temporally synchronized (e.g., when multiple sensors or robots record on the same machine/network using synchronized clocks).

{
  "m03": {
    "file": "m03-matty-on-pat-redroad-260801_105050.log",
    "offset_sec": -1.23
  },
  "pat": {
    "file": "pat-dh26-260801_105022.log"
  }
}

Elena Ai added 7 commits August 4, 2026 20:18
1. Helper Functions Extended (osgar/logger.py):
      - lookup_stream_names(filename): Dynamically detects dictionary or .json path inputs, parses sub-logs, and consolidates prefixed stream
        names (e.g., "nickname.original_name").
      - lookup_config(filename): Recursively retrieves and aggregates local configurations mapped to their corresponding nicknames.
      - lookup_stream_id(filename, stream_name): Transparently returns Virtual Stream IDs (1-based index) based on prefixed stream names.

   2. Created Low-Level MultiLogReader (osgar/logger.py):
      - Manages dictionary / JSON configurations, loading and instantiating individual LogReaders for each sub-log.
      - Implements Timeline Reference synchronization: Computes the global reference start time T_{ref} = min(startₜimeᵢ + offsetₛecᵢ) and
        aligns all packet timestamps in global time.
      - Performs Chronological Stream Merging using heapq.merge over sub-generators.
      - Optimized Stream Filtering (only_stream_id): Maps requested Virtual IDs back to local stream IDs to configure sub-LogReaders with
        minimal file-parsing overhead.
      - System Stream (Stream 0) Filtering: Explicitly filters out and skips all local metadata/system packets from sub-logs during merging to
        prevent stream pollution.

   3. Extended LogReaderEx (osgar/logger.py):
      - Transparently handles single-log and multi-log paths.
      - In multi-log mode, delegates parsing to MultiLogReader while performing automatic deserialization and friendly stream-name mapping.
@m3d
m3d requested review from MartinLocker and tajgr August 4, 2026 19:24
@m3d

m3d commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

Note, that this implementation is very fresh and I did not review it yet, but I see this feature as very valuable for further development, and coordination of multiple robots, reprocessing or recording multiple independent units.

@m3d

m3d commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

it is kind of fun:

0:00:29.580205 m03.gps.nmea_data {'identifier': '$GNGGA', 'lon': 14.349618833333333, 'lon_dir': 'E', 'lat': 48.883964666666664, 'lat_dir': 'N', 'utc_time': '105051.00', 'quality': 1, 'sats': 12, 'hdop': 0.72, 'alt': 534.4, 'a_units': 'M', 'undulation': 44.1, 'u_units': 'M', 'age': None, 'stn_id': None}
0:00:30.331310 pat.gps.nmea_data {'identifier': '$GPGGA', 'lon': 14.349608333333334, 'lon_dir': 'E', 'lat': 48.88400166666667, 'lat_dir': 'N', 'utc_time': '105051.000', 'quality': 1, 'sats': 9, 'hdop': 0.9, 'alt': 531.5, 'a_units': 'M', 'undulation': 45.5, 'u_units': 'M', 'age': None, 'stn_id': '0000'}

@m3d
m3d marked this pull request as draft August 6, 2026 15:02
@m3d

m3d commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

switching to draft as I am playing with it further more, but still comments are welcome :)

@m3d

m3d commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

another motivation example

python -m osgar.tools.lidarview multi-log.json --camera m03.oak.color --pose2d pat.platform.pose2d --lidar pat.vanjee.scan10 --lidar2 pat.vanjee.scan5
Screenshot from 2026-08-06 17-37-13

@tajgr

tajgr commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

It looks good and I might use it soon.
I would like the option of multilog without json. E.g.:
python -m osgar.logger m03-matty-on-pat-redroad-260801_105050.log --add-log pat-dh26-260801_105022.log
or something similar. Just avoid to creating extra json config. What do you think?

@tajgr

tajgr commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Or just a script for creation the json configuration..

@m3d

m3d commented Aug 14, 2026

Copy link
Copy Markdown
Member Author

@tajgr thanks for comments. I am afraid that there will be need for the offsets?? Also the input should be for other tools like "lidarview" - do you have some use cases? Did you try it? Yes, AI suggested "auto-generated JSON", but I did not want it in the first round - in particular I would like to align timing of GPS for example.

@tajgr

tajgr commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

With Spider, I’m now running the driver and the application separately. That might come in handy. In future, part of the code will run on the APU and part on a second high-performance computer.
There is my output:

$ python -m osgar.logger logs/260814_czu/multi.json 
 k                                   name     bytes | count | freq Hz
---------------------------------------------------------------------
 0                                    sys         0 |     0 |   0.0Hz
 1                         can.spider.can     98028 | 10892 |  39.0Hz
 2                      can.spider.status     44948 |  5446 |  19.5Hz
 3                    can.spider.encoders     22467 |  7489 |  26.8Hz
 4                      can.spider.pose2d     47847 |  5402 |  19.3Hz
 5                     can.spider.bumpers       837 |   279 |   1.0Hz
 6                            can.can.can    435489 | 31710 | 113.5Hz
 7                            can.can.raw     65396 | 10899 |  39.0Hz
 8                         can.serial.raw    292847 |  7943 |  28.4Hz
 9          can.receiver.desired_steering     34469 |  5030 |  18.0Hz
10                     can.receiver.reset         0 |     0 |   0.0Hz
11             can.receiver.desired_speed         0 |     0 |   0.0Hz
12          invasive.app.desired_steering     34472 |  5031 |  18.0Hz
13           invasive.localization.pose3d    232164 |  3522 |  12.6Hz
14                   invasive.lsqr.pose3d    341748 |  5178 |  18.5Hz
15                   invasive.reset.reset         1 |     1 |   0.0Hz
16               invasive.receiver.status     29424 |  3522 |  12.6Hz
17             invasive.receiver.encoders     15621 |  5207 |  18.6Hz
18               invasive.receiver.pose2d     34991 |  3522 |  12.6Hz
19              invasive.receiver.bumpers       528 |   176 |   0.6Hz
20                invasive.lidar.metadata      2396 |     1 |   0.0Hz
21                  invasive.lidar.scan3d 230528942 |  1757 |   6.3Hz
22            invasive.lidar.reflectivity  57805300 |  1757 |   6.3Hz
23               invasive.imu.orientation    262663 |  7099 |  25.4Hz
24                  invasive.imu.rotation     63747 |  7099 |  25.4Hz
25                      invasive.imu.data    802187 |  7099 |  25.4Hz
26                   invasive.imu_tcp.raw    883126 |  8351 |  29.9Hz
27                   invasive.gps_tcp.raw    335809 |  3947 |  14.1Hz
28                  invasive.gps.position     39090 |  3590 |  12.9Hz
29              invasive.gps.rel_position         0 |     0 |   0.0Hz
30                 invasive.gps.nmea_data    683290 |  3590 |  12.9Hz
31           invasive.rtk_filter.filtered     15510 |   165 |   0.6Hz
32                 invasive.rtk_modem.raw         0 |     0 |   0.0Hz
33            invasive.camera_front.depth         0 |     0 |   0.0Hz
34            invasive.camera_front.color 349350827 |  1662 |   5.9Hz
35 invasive.camera_front.orientation_list         0 |     0 |   0.0Hz
36       invasive.camera_front.detections         0 |     0 |   0.0Hz
37          invasive.camera_front.left_im         0 |     0 |   0.0Hz
38         invasive.camera_front.right_im         0 |     0 |   0.0Hz
39        invasive.camera_front.depth_seq         0 |     0 |   0.0Hz
40        invasive.camera_front.color_seq     14574 |  1662 |   5.9Hz
41   invasive.camera_front.detections_seq         0 |     0 |   0.0Hz
42      invasive.camera_front.left_im_seq         0 |     0 |   0.0Hz
43     invasive.camera_front.right_im_seq         0 |     0 |   0.0Hz
44          invasive.camera_front.nn_mask         0 |     0 |   0.0Hz
45           invasive.camera_front.pose3d         0 |     0 |   0.0Hz
46          invasive.camera_front.gridmap         0 |     0 |   0.0Hz
47          invasive.camera_front.redroad         0 |     0 |   0.0Hz
48      invasive.camera_front.robotourist         0 |     0 |   0.0Hz
49              invasive.rtk_gps.position     38786 |  3526 |  12.6Hz
50          invasive.rtk_gps.rel_position         0 |     0 |   0.0Hz
51             invasive.rtk_gps.nmea_data    673466 |  3526 |  12.6Hz
52            invasive.rtk_gps_serial.raw    763304 |  3632 |  13.0Hz

Total time 0:04:39.345845

It looks working for now.

@m3d

m3d commented Aug 15, 2026

Copy link
Copy Markdown
Member Author

OK, thanks - so two computers. Do you have them somehow synchronized or what do you use for synchronization of two logfiles?

@tajgr

tajgr commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

For now, everything is on the APU. But as the navigation improves and sensors are added, I’ll have to move the main app to the other computer. I’ll definitely be synchronising the data, but I’m not sure how just yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants