Conversation
Greptile SummaryThis PR replaces LCM-based viewer communication with a WebSocket protocol for remote
Confidence Score: 4/5Safe to merge once the MovementManager subscription-cleanup bug is fixed; all other findings are P2 or previously addressed. One P1 bug in the new MovementManager module: subscription handles are discarded in start(), preventing cleanup on stop() and risking stale publishes to stopped streams. All other prior P1/P0 concerns from previous review threads are addressed or acknowledged. dimos/navigation/smart_nav/modules/movement_manager/movement_manager.py Important Files Changed
Sequence DiagramsequenceDiagram
participant V as dimos-viewer
participant WS as RerunWebSocketServer
participant MM as MovementManager
participant RB as RerunBridgeModule
participant P as ReplanningAStarPlanner
participant E as WavefrontFrontierExplorer
V->>WS: WS click {x,y,z}
WS->>MM: clicked_point (PointStamped)
MM->>P: goal (PointStamped)
V->>WS: WS twist {linear,angular}
WS->>MM: tele_cmd_vel (Twist)
MM->>P: stop_movement (Bool)
MM->>E: stop_movement (Bool)
MM->>MM: cmd_vel (scaled Twist)
V->>WS: WS stop
WS->>MM: tele_cmd_vel (Twist.zero())
P->>MM: nav_cmd_vel (Twist)
Note over MM: suppressed if teleop active
MM->>MM: cmd_vel (nav Twist, after cooldown)
V-->>RB: rerun+http gRPC (visualization data)
Reviews (6): Last reviewed commit: "update docs" | Re-trigger Greptile |
| RERUN_OPEN_DEFAULT: RerunOpenOption = "native" | ||
| RERUN_ENABLE_WEB = True | ||
| RERUN_GRPC_PORT = 9876 | ||
| RERUN_WEB_PORT = 9090 |
There was a problem hiding this comment.
don't bind to 9090, this is an extremely common port (our china VPN already uses for example, TOR is on 9090)
There was a problem hiding this comment.
- pre-existing (I just moved the variable)
- this doesn't set the port (its just for docker to know about the existing Rerun default port)
I think changing the code to set the port to a non-default port (and then testing everything again) is outside the scope of this PR, but I agree we should do it
There was a problem hiding this comment.
There was a problem hiding this comment.
I realized whats happening, this would probably be a problem if you try to use the rerun web on dev. The web server was started in the background when native wasn't explicitly set - which I'm not going to debate right now so I just changed that to not start it.
Also the port should be properly configurable now.
| ViewerBackend: TypeAlias = Literal["rerun", "foxglove", "none"] | ||
| RerunOpenOption: TypeAlias = Literal["none", "web", "native", "both"] | ||
|
|
||
| RERUN_OPEN_DEFAULT: RerunOpenOption = "native" |
There was a problem hiding this comment.
shouldn't rerun defaults belong to visualization/rerun in a standard config dict?
There was a problem hiding this comment.
No because they need to be imported by global_config and we don't want to import rerun just to run dimos --help
There was a problem hiding this comment.
rerun bridge.py actually doesn't import rerun until start() is called so this can be imported freely
(at least it isn't supposed to, I see Sam added two imports at the top but those can be guarded by a if TYPE_CHECKING since they are just for typing)
generally if extracting (which is not needed here) I'd rather extract the config into an external file rerun/config.py then start creating constants.py files with dilluted ownership
There was a problem hiding this comment.
If you're saying move class RerunConfig() to config.py it makes a circular import:
global_config.py → rerun/config.py → core/module.py (ModuleConfig) → global_config.py
There was a problem hiding this comment.
I improved the imports, made RERUN_WEB_PORT, but I think I'm gonna leave this this as-is since this was more or less pre-existing and this PR is really starting to expand.
We already need to clean up the terrible rerun_config later so we can clean it up with that.
|
Sorry I forgot to port the project.toml change from rosnav8 back to this branch. Ready now though |
Add entries for all remaining review comments: - leshy comments on constants.py (3114946798, 3114953830) - greptile automated comments (3074737748, 3074737821, 3074737877, 3074737977) - Update entries for newly fixed comments (mod->module, inline import, __init__/__new__) - Remove duplicate entry for comment 3120880870
Delete dimos/visualization/constants.py and consolidate all rerun defaults/types into rerun/config.py per review feedback (no diluted ownership). Also wire web_port through to rr.serve_web_viewer() so it actually sets the port, and guard Blueprint import behind TYPE_CHECKING.
adf4627 to
073d0a7
Compare
| # point DYLD_LIBRARY_PATH at the real libpython directory. | ||
| executable = sys.executable if sys.platform != "darwin" else "mjpython" | ||
| env = os.environ.copy() | ||
| if sys.platform == "darwin": |
There was a problem hiding this comment.
problem specific to newer mac's. (this got in the way of me testing this branch)
# Conflicts: # dimos/robot/unitree/keyboard_teleop.py
| def start(self) -> None: | ||
| super().start() | ||
| self.clicked_point.subscribe(self._on_click) | ||
| self.nav_cmd_vel.subscribe(self._on_nav) | ||
| self.tele_cmd_vel.subscribe(self._on_teleop) |
There was a problem hiding this comment.
Subscriptions never unregistered on
stop()
The three subscribe() calls in start() each return an unsubscribe callable, but all three return values are discarded. The rest of the codebase wraps these in Disposable and passes them to register_disposable (e.g. ReplanningAStarPlanner and WavefrontFrontierExplorer in this same PR) so super().stop() can clean them up.
Without registration, _on_click, _on_nav, and _on_teleop will continue to fire after stop() is called. Because stop() calls super().stop() which tears down the output streams, any late-arriving message will try to publish() on a stopped cmd_vel / goal / stop_movement stream — and may raise or silently produce stale commands.
# start() should be:
@rpc
def start(self) -> None:
super().start()
self.register_disposable(Disposable(self.clicked_point.subscribe(self._on_click)))
self.register_disposable(Disposable(self.nav_cmd_vel.subscribe(self._on_nav)))
self.register_disposable(Disposable(self.tele_cmd_vel.subscribe(self._on_teleop)))
NOTE: this will become ready-for-review once this dimos-viewer PR is merged
Problem(s)
--connectdoesn't work for remote connections.cmd_velwhich ends up making stream-renaming a pain since everything else must be renamed to know if the cmd_vel is coming from the viewer or from a planner/module.Solution
Use websockets instead of LCM for the viewer.
vis_moduleto de-dup the visualization logicBreaking Changes
None
How to Test
You'll need the
jeff/fix/connectbranch ofdimos-viewercompiled and python installed into dimos:Alternatively
Click in the 3D viewport and use WASD keys — should see
[CLICK]and[TWIST]in terminal 1.Contributor License Agreement