-
Notifications
You must be signed in to change notification settings - Fork 611
Nav pt3: Enable PGO topics, Optimize PGO, and add KITTI-360 benchmark scaffolding #2099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jeff-hykin
wants to merge
88
commits into
main
Choose a base branch
from
jeff/feat/better_pgo
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
88 commits
Select commit
Hold shift + click to select a range
a7a9be9
pgo: publish pose graph (nodes + odom/loop edges) over LCM + top-down…
jeff-hykin ba0e17e
pgo: lift pgo_graph_{nodes,edges} via agentic_debug visual override
jeff-hykin 1801759
pgo: drop second rerun pane; revert to single 3D view
jeff-hykin 82d7799
pgo: publish per-keyframe delta on every loop-closure event + slow test
jeff-hykin 3c90a7f
pgo: scan-context-based loop-closure search
jeff-hykin 3e33003
pgo: synthetic drift test — proves Scan Context catches loops positio…
jeff-hykin 5f64131
pgo tests: replace _log() print wrappers with the dimos logger
jeff-hykin 6880ab6
pgo: expand short variable names introduced on this branch
jeff-hykin c7fd631
pgo: KITTI-360 benchmark scaffolding (loader + groundtruth + runner)
jeff-hykin e45b228
merge main into jeff/feat/better_pgo
jeff-hykin 4480966
Merge branch 'main' into jeff/feat/better_pgo
jeff-hykin 5b828e2
fix: mypy errors in pgo benchmark and demo viz
jeff-hykin 59b751c
fix: drop dead positive-yaw wrap in yaw_from_shift
jeff-hykin 4329aac
fix: drop empty pgo benchmark __init__.py
jeff-hykin a88f712
Merge branch 'main' into jeff/feat/better_pgo
jeff-hykin b28cd00
important PGO optimizations
jeff-hykin a0fafbb
fix: annotate pgo smoke_test lcm callback to satisfy mypy
jeff-hykin 4479d8d
fix bug in cmu stack
jeff-hykin 0ffa39a
add additional check
jeff-hykin 6901d71
fix: ignore sklearn import for mypy (no stubs available)
jeff-hykin 1c34ab9
nits + greptile fixes on PGO benchmark + reverse-loop test
jeff-hykin 80adfb6
Merge branch 'main' into jeff/feat/better_pgo
jeff-hykin 4a0de4d
nits: rename msg/msg_cls/msg_type → message/message_class/message_type
jeff-hykin 6de903a
nits: lift scipy import to module top in run_kitti360_benchmark
jeff-hykin fbd00dc
nits: C++ rename mod→native_module, cp→cloud_with_pose, fix tresh typo
jeff-hykin e9f8356
generic-ize PGO output topic names
jeff-hykin 5fe55c8
WIP: move KITTI-360 benchmark out of pgo, refactor into Modules + Blu…
jeff-hykin 44f41f9
fix: annotate runner.get_results local to satisfy mypy
jeff-hykin 3015232
flatten pgo/benchmark/ — drop the dir, files live at pgo/
jeff-hykin c1308e2
fix: regenerate all_blueprints.py for new pose_graph_kitti360 modules
jeff-hykin ff2ccb1
rename
jeff-hykin 8afcf97
nits: expand fid/src/dst/tp/fp/fn/p/r in loop_groundtruth.py
jeff-hykin 91cbdca
benchmark_kitti_smoke_test: rewrite on top of Modules + Blueprint
jeff-hykin b07f9ac
test_pgo_synthetic_drift: rewrite via Modules + Blueprint
jeff-hykin 7f12682
cleaning
jeff-hykin 73669bc
benchmark_place_recognition: humanise top-of-file docstring
jeff-hykin 999a961
-
jeff-hykin caaad9e
fix: drop ASCII section markers from test_pgo_synthetic_drift
jeff-hykin 5bcf724
test_pgo_loop_closure: rewrite via Modules + Blueprint
jeff-hykin 410b7c9
fix: drop ASCII section markers from test_pgo_loop_closure
jeff-hykin 2bdb6e1
test_pgo_rosbag + rosbag_fixtures: drop hardcoded LCM topics, use Mod…
jeff-hykin 0a9b92d
remove empty configs + inline _message_to_dict + pydantic Field
jeff-hykin 74e2c43
fix: cover playback-vs-PGO-startup race + section markers + regen all…
jeff-hykin f4a8e2a
fix: stop the host-side RPC client even when proxy.stop() raises
jeff-hykin bcc422d
test: mark PGO synthetic_drift + loop_closure as self_hosted
jeff-hykin 3eb80b8
test: add skipif_no_nix and apply it to PGO C++-binary tests
jeff-hykin ed64f25
fix: query-level loop scoring + surface playback errors
jeff-hykin 158f3eb
fix: RosbagScanOdomPlaybackModule surfaces playback errors
jeff-hykin 6dccb2d
fix: SyntheticDriftPlaybackModule surfaces playback errors
jeff-hykin c01756d
fix: query-level FP in scoring (TP + FP now dimensionally consistent)
jeff-hykin e376930
Merge remote-tracking branch 'origin/main' into jeff/feat/better_pgo
jeff-hykin eff5254
test: rename benchmark_kitti_smoke_test.py -> demo_benchmark_kitti_sm…
jeff-hykin 9e42096
fix: regenerate all_blueprints.py for TopicCounterModule
jeff-hykin 9af58da
revert
jeff-hykin c7dc341
simplify
jeff-hykin d45adb2
-
jeff-hykin 5d95b34
nav: add LoopClosure spec and use it in run_benchmark
jeff-hykin 026adba
docs
jeff-hykin beba4dd
-
jeff-hykin e0fecd7
pgo: ready handshake — block start() until C++ binary is subscribed
jeff-hykin be7412b
Revert "pgo: ready handshake — block start() until C++ binary is subs…
jeff-hykin 90e062a
make test reliable
jeff-hykin 5e1e225
fixup start
jeff-hykin 1584fe6
-
jeff-hykin a7af8ac
remove flakey test
jeff-hykin 5697835
fixup on macos
jeff-hykin 547205b
fixup LoopClosure spec
jeff-hykin ab133a0
-
jeff-hykin df16d46
fix timeout
jeff-hykin c138f66
Merge remote-tracking branch 'origin/main' into jeff/feat/better_pgo
jeff-hykin 29dfafe
-
jeff-hykin cf6772e
Merge remote-tracking branch 'origin/main' into HEAD
jeff-hykin 5769d48
Merge remote-tracking branch 'origin/main' into HEAD
jeff-hykin 124c4e3
build native modules in the build step
jeff-hykin c152325
feat(msgs): GraphNodes3D Kaitai Struct schema
jeff-hykin 04d73a3
feat(msgs): expose LineSegments3D public attrs + per-segment timestamps
jeff-hykin 3564a77
feat(msgs): C++ LineSegments3D typed publisher header
jeff-hykin 75b4e8d
feat(msgs): Graph3D pose-graph message type
jeff-hykin 9ead549
refactor(far_planner): switch graph_nodes+graph_edges to graph: Out[G…
jeff-hykin 6185f62
refactor(pgo): pose_graph_nodes+edges → pose_graph: Out[Graph3D]; dro…
jeff-hykin f97e1bd
chore(pgo): rename demo_benchmark_kitti_smoke → benchmark_kitti360_smoke
jeff-hykin be9f2ca
remove .ksy
jeff-hykin edb0584
test(pgo): restore filename test_pgo_loop_closure.py
jeff-hykin 7311034
Merge remote-tracking branch 'origin/main' into jeff/feat/better_pgo
jeff-hykin bf3c570
Merge branch 'jeff/feat/better_pgo' of github.com:dimensionalOS/dimos…
jeff-hykin 1c59f23
chore(blueprints): regenerate all_blueprints.py for smoke-test rename
jeff-hykin e4dd71a
feat(msgs): GraphDelta3D + wire PGO's loop_closure_event to it
jeff-hykin 446fa16
clean comments
jeff-hykin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| // Copyright 2026 Dimensional Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| // Typed C++ helper mirroring the Python `dimos.msgs.nav_msgs.Graph3D`. | ||
| // Canonical schema lives in `dimos/msgs/nav_msgs/Graph3D.ksy` — keep | ||
| // encode() in sync with that file (and with Graph3D.py.lcm_decode). | ||
| // | ||
| // Wire format (big-endian): | ||
| // | ||
| // uint64 edge_count | ||
| // uint64 node_count | ||
| // double timestamp // seconds since epoch | ||
| // per node (node_count): | ||
| // pose_stamped: | ||
| // double ts | ||
| // uint32 frame_id_len | ||
| // bytes frame_id (utf-8, no terminator) | ||
| // 7×double pos_x, pos_y, pos_z, quat_x, quat_y, quat_z, quat_w | ||
| // uint64 id | ||
| // uint64 metadata_id | ||
| // per edge (edge_count): | ||
| // uint64 start_id | ||
| // uint64 end_id | ||
| // double timestamp | ||
| // uint64 metadata_id | ||
| // | ||
| // Edges reference nodes by `id`, not by index. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cstdint> | ||
| #include <cstring> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include <lcm/lcm-cpp.hpp> | ||
|
|
||
| namespace dimos { | ||
|
|
||
| namespace graph3d_detail { | ||
|
|
||
| // Host-order → big-endian byte writers. Avoid <endian.h> for portability | ||
| // (macOS uses different names) — write byte-by-byte from the top. | ||
|
|
||
| inline void write_u32_be(std::vector<uint8_t>& out, uint32_t v) { | ||
| out.push_back(static_cast<uint8_t>((v >> 24) & 0xFF)); | ||
| out.push_back(static_cast<uint8_t>((v >> 16) & 0xFF)); | ||
| out.push_back(static_cast<uint8_t>((v >> 8) & 0xFF)); | ||
| out.push_back(static_cast<uint8_t>( v & 0xFF)); | ||
| } | ||
|
|
||
| inline void write_u64_be(std::vector<uint8_t>& out, uint64_t v) { | ||
| for (int shift = 56; shift >= 0; shift -= 8) { | ||
| out.push_back(static_cast<uint8_t>((v >> shift) & 0xFF)); | ||
| } | ||
| } | ||
|
|
||
| inline void write_double_be(std::vector<uint8_t>& out, double v) { | ||
| uint64_t bits; | ||
| std::memcpy(&bits, &v, sizeof(bits)); | ||
| write_u64_be(out, bits); | ||
| } | ||
|
|
||
| inline void write_bytes(std::vector<uint8_t>& out, const std::string& s) { | ||
| out.insert(out.end(), s.begin(), s.end()); | ||
| } | ||
|
|
||
| } // namespace graph3d_detail | ||
|
|
||
| class Graph3D { | ||
| public: | ||
| struct PoseStamped { | ||
| double ts = 0.0; | ||
| std::string frame_id; | ||
| double pos_x = 0.0, pos_y = 0.0, pos_z = 0.0; | ||
| double quat_x = 0.0, quat_y = 0.0, quat_z = 0.0, quat_w = 1.0; | ||
| }; | ||
|
|
||
| struct Node3D { | ||
| PoseStamped pose; | ||
| uint64_t id = 0; | ||
| uint64_t metadata_id = 0; | ||
| }; | ||
|
|
||
| struct Edge { | ||
| uint64_t start_id = 0; | ||
| uint64_t end_id = 0; | ||
| double timestamp = 0.0; | ||
| uint64_t metadata_id = 0; | ||
| }; | ||
|
|
||
| Graph3D(std::string frame_id, double timestamp) | ||
| : frame_id_(std::move(frame_id)), timestamp_(timestamp) {} | ||
|
|
||
| void reserve_nodes(size_t capacity) { nodes_.reserve(capacity); } | ||
| void reserve_edges(size_t capacity) { edges_.reserve(capacity); } | ||
|
|
||
| // Add a node. The pose's frame_id defaults to the graph's frame_id — | ||
| // override per-node only if a node lives in a different frame. | ||
| void add_node(uint64_t id, uint64_t metadata_id, double pose_ts, | ||
| double pos_x, double pos_y, double pos_z, | ||
| double quat_x, double quat_y, double quat_z, double quat_w, | ||
| std::string node_frame_id = "") { | ||
| PoseStamped pose; | ||
| pose.ts = pose_ts; | ||
| pose.frame_id = node_frame_id.empty() ? frame_id_ : std::move(node_frame_id); | ||
| pose.pos_x = pos_x; pose.pos_y = pos_y; pose.pos_z = pos_z; | ||
| pose.quat_x = quat_x; pose.quat_y = quat_y; pose.quat_z = quat_z; pose.quat_w = quat_w; | ||
| nodes_.push_back({pose, id, metadata_id}); | ||
| } | ||
|
|
||
| // Position-only convenience (orientation defaults to identity). | ||
| void add_node_xyz(uint64_t id, uint64_t metadata_id, double pose_ts, | ||
| double pos_x, double pos_y, double pos_z) { | ||
| add_node(id, metadata_id, pose_ts, pos_x, pos_y, pos_z, 0.0, 0.0, 0.0, 1.0); | ||
| } | ||
|
|
||
| void add_edge(uint64_t start_id, uint64_t end_id, double edge_ts, | ||
| uint64_t metadata_id = 0) { | ||
| edges_.push_back({start_id, end_id, edge_ts, metadata_id}); | ||
| } | ||
|
|
||
| size_t node_count() const { return nodes_.size(); } | ||
| size_t edge_count() const { return edges_.size(); } | ||
| const std::string& frame_id() const { return frame_id_; } | ||
|
|
||
| std::vector<uint8_t> encode() const { | ||
| using namespace graph3d_detail; | ||
| std::vector<uint8_t> out; | ||
| // Conservative reservation: header + per-node fixed bytes + per-edge. | ||
| // frame_id strings add variable length on top — that just causes a | ||
| // realloc, not correctness issues. | ||
| out.reserve(24 + nodes_.size() * 84 + edges_.size() * 32); | ||
| write_u64_be(out, static_cast<uint64_t>(edges_.size())); | ||
| write_u64_be(out, static_cast<uint64_t>(nodes_.size())); | ||
| write_double_be(out, timestamp_); | ||
| for (const auto& n : nodes_) { | ||
| // pose_stamped first (per Graph3D.ksy) | ||
| write_double_be(out, n.pose.ts); | ||
| write_u32_be(out, static_cast<uint32_t>(n.pose.frame_id.size())); | ||
| write_bytes(out, n.pose.frame_id); | ||
| write_double_be(out, n.pose.pos_x); | ||
| write_double_be(out, n.pose.pos_y); | ||
| write_double_be(out, n.pose.pos_z); | ||
| write_double_be(out, n.pose.quat_x); | ||
| write_double_be(out, n.pose.quat_y); | ||
| write_double_be(out, n.pose.quat_z); | ||
| write_double_be(out, n.pose.quat_w); | ||
| // then id, metadata_id | ||
| write_u64_be(out, n.id); | ||
| write_u64_be(out, n.metadata_id); | ||
| } | ||
| for (const auto& e : edges_) { | ||
| write_u64_be(out, e.start_id); | ||
| write_u64_be(out, e.end_id); | ||
| write_double_be(out, e.timestamp); | ||
| write_u64_be(out, e.metadata_id); | ||
| } | ||
| return out; | ||
| } | ||
|
|
||
| int publish(lcm::LCM& lcm, const std::string& channel) const { | ||
| std::vector<uint8_t> bytes = encode(); | ||
| return lcm.publish(channel, bytes.data(), static_cast<int>(bytes.size())); | ||
| } | ||
|
|
||
| private: | ||
| std::string frame_id_; | ||
| double timestamp_; | ||
| std::vector<Node3D> nodes_; | ||
| std::vector<Edge> edges_; | ||
| }; | ||
|
|
||
| } // namespace dimos |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.