Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9423ae4
all vis changes
jeff-hykin Apr 13, 2026
6d6151c
fixup
jeff-hykin Apr 13, 2026
ac62445
add a conventions.md to dev docs
jeff-hykin Apr 13, 2026
36492b1
fixup cmd_vel timer edgecase leaks
jeff-hykin Apr 13, 2026
306bd2b
switch cmd_vel_scaling to be on rerun
jeff-hykin Apr 13, 2026
f7277d9
add convention
jeff-hykin Apr 13, 2026
75bf186
fixup
jeff-hykin Apr 13, 2026
29875f8
missed edgecase
jeff-hykin Apr 14, 2026
dd10ae4
fix webvis logic
jeff-hykin Apr 15, 2026
a3c5666
make pydantic happy
jeff-hykin Apr 15, 2026
9683ea6
global config patch
jeff-hykin Apr 15, 2026
247571f
cleanup
jeff-hykin Apr 15, 2026
bffc95d
better helper message
jeff-hykin Apr 17, 2026
43d6f78
Merge branch 'dev' into jeff/fix/rconnect2
jeff-hykin Apr 18, 2026
a009186
-
jeff-hykin Apr 21, 2026
20d455a
Merge branch 'jeff/fix/rconnect2' of github.com:dimensionalOS/dimos i…
jeff-hykin Apr 21, 2026
0b962a3
merge dev
jeff-hykin Apr 21, 2026
a22150d
uv lock was incorrect somehow
jeff-hykin Apr 21, 2026
a8f9653
add conventions
jeff-hykin Apr 23, 2026
769c8b8
switch to rosnav's MovementManager
jeff-hykin Apr 23, 2026
a3a2ab5
refactor: move rerun constants into dimos/visualization/rerun/config.py
jeff-hykin Apr 23, 2026
e7106aa
simplify tests and make them good
jeff-hykin Apr 23, 2026
f6de436
import improve
jeff-hykin Apr 23, 2026
1dce3fe
restore constants.py
jeff-hykin Apr 24, 2026
f41ffc8
refactor(cli): move cast, get_args, RerunOpenOption to top-level imports
jeff-hykin Apr 24, 2026
881fc04
import psutil
jeff-hykin Apr 24, 2026
b35242c
-
jeff-hykin Apr 24, 2026
3b745dc
-
jeff-hykin Apr 24, 2026
009aff9
cleanup test
jeff-hykin Apr 24, 2026
474f10e
clean
jeff-hykin Apr 24, 2026
72500ff
add scaling
jeff-hykin Apr 24, 2026
4e38462
-
jeff-hykin Apr 24, 2026
4591285
add scaling check
jeff-hykin Apr 24, 2026
76d50e4
address main comments
jeff-hykin Apr 24, 2026
073d0a7
refactor(ws-server): add ViewerMsg TypedDict union for typed message …
jeff-hykin Apr 24, 2026
cdd07b5
remove junk comments
jeff-hykin Apr 24, 2026
4d2072b
-
jeff-hykin Apr 24, 2026
39c2769
re-apply the SIGINT fix
jeff-hykin Apr 24, 2026
3d0aa56
Merge remote-tracking branch 'origin/dev' into jeff/fix/rconnect2
jeff-hykin Apr 24, 2026
ef579e8
-
jeff-hykin Apr 24, 2026
83ad060
update docs
jeff-hykin Apr 24, 2026
059564b
fixes
jeff-hykin Apr 24, 2026
293642e
Merge remote-tracking branch 'origin/dev' into jeff/fix/rconnect2
jeff-hykin Apr 24, 2026
38b4e29
test: ignore .ignore.enhance overlay in section-marker scan
jeff-hykin Apr 24, 2026
6165d65
fix: cast pipe() return to satisfy mypy no-any-return check
jeff-hykin Apr 24, 2026
92c02d9
refactor: move websockets imports to top of test files
jeff-hykin Apr 24, 2026
473dc5b
refactor: address remaining review nits
jeff-hykin Apr 25, 2026
c1b845a
fix: correct import sort order for ruff
jeff-hykin Apr 25, 2026
aac49ba
revert .ignore.enhance exclusion, use .hidden instead
jeff-hykin Apr 25, 2026
aab885e
Merge branch 'dev' into jeff/fix/rconnect2
jeff-hykin Apr 26, 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
16 changes: 7 additions & 9 deletions dimos/core/coordination/python_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import multiprocessing
from multiprocessing.connection import Connection
import os
import signal
import sys
import threading
import traceback
Expand Down Expand Up @@ -337,12 +338,15 @@ class _WorkerState:

def _worker_entrypoint(conn: Connection, worker_id: int) -> None:
apply_library_config()
# Ignore SIGINT so the coordinator can orchestrate shutdown via the pipe.
# Without this, workers race with the coordinator: they start tearing down
# modules locally while the coordinator tries to send stop() RPCs, causing
# BrokenPipeErrors.
signal.signal(signal.SIGINT, signal.SIG_IGN)
state = _WorkerState(instances={}, worker_id=worker_id)

try:
_worker_loop(conn, state)
except KeyboardInterrupt:
logger.info("Worker got KeyboardInterrupt.", worker_id=worker_id)
except Exception as e:
logger.error(f"Worker process error: {e}", exc_info=True)
finally:
Expand All @@ -361,12 +365,6 @@ def _worker_entrypoint(conn: Connection, worker_id: int) -> None:
worker_id=worker_id,
module_id=module_id,
)
except KeyboardInterrupt:
logger.warning(
"KeyboardInterrupt during worker stop",
module=type(instance).__name__,
worker_id=worker_id,
)
except Exception:
logger.error("Error during worker shutdown", exc_info=True)

Expand Down Expand Up @@ -433,7 +431,7 @@ def _worker_loop(conn: Connection, state: _WorkerState) -> None:
if not conn.poll(timeout=0.1):
continue
request = conn.recv()
except (EOFError, KeyboardInterrupt):
except EOFError:
break

try:
Expand Down
2 changes: 1 addition & 1 deletion dimos/core/docker_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from dimos.core.rpc_client import ModuleProxyProtocol, RpcCall
from dimos.protocol.rpc.pubsubrpc import LCMRPC
from dimos.utils.logging_config import setup_logger
from dimos.visualization.rerun.bridge import RERUN_GRPC_PORT, RERUN_WEB_PORT
from dimos.visualization.rerun.constants import RERUN_GRPC_PORT, RERUN_WEB_PORT

if TYPE_CHECKING:
from collections.abc import Callable
Expand Down
11 changes: 8 additions & 3 deletions dimos/core/global_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
# limitations under the License.

import re
from typing import Literal, TypeAlias

from pydantic_settings import BaseSettings, SettingsConfigDict

from dimos.models.vl.types import VlModelName

ViewerBackend: TypeAlias = Literal["rerun", "rerun-web", "rerun-connect", "foxglove", "none"]
from dimos.visualization.rerun.constants import (
RERUN_ENABLE_WEB,
RERUN_OPEN_DEFAULT,
RerunOpenOption,
ViewerBackend,
)


def _get_all_numbers(s: str) -> list[float]:
Expand All @@ -37,6 +40,8 @@ class GlobalConfig(BaseSettings):
replay_dir: str = "go2_sf_office"
Comment thread
jeff-hykin marked this conversation as resolved.
Outdated
new_memory: bool = False
viewer: ViewerBackend = "rerun"
rerun_open: RerunOpenOption = RERUN_OPEN_DEFAULT
rerun_web: bool = RERUN_ENABLE_WEB
Comment thread
jeff-hykin marked this conversation as resolved.
n_workers: int = 2
memory_limit: str = "auto"
mujoco_camera_position: str | None = None
Expand Down
5 changes: 3 additions & 2 deletions dimos/hardware/sensors/camera/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from dimos.agents.annotation import skill
from dimos.core.coordination.blueprints import autoconnect
from dimos.core.core import rpc
from dimos.core.global_config import global_config
from dimos.core.module import Module, ModuleConfig
from dimos.core.stream import Out
from dimos.hardware.sensors.camera.spec import CameraHardware
Expand All @@ -31,7 +32,7 @@
from dimos.msgs.sensor_msgs.CameraInfo import CameraInfo
from dimos.msgs.sensor_msgs.Image import Image, sharpness_barrier
from dimos.spec import perception
from dimos.visualization.rerun.bridge import RerunBridgeModule
from dimos.visualization.vis_module import vis_module


def default_transform() -> Transform:
Expand Down Expand Up @@ -120,5 +121,5 @@ def stop(self) -> None:

demo_camera = autoconnect(
CameraModule.blueprint(),
RerunBridgeModule.blueprint(),
vis_module(viewer_backend=global_config.viewer),
)
35 changes: 25 additions & 10 deletions dimos/hardware/sensors/lidar/fastlio2/fastlio_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,45 @@
from dimos.core.coordination.blueprints import autoconnect
from dimos.hardware.sensors.lidar.fastlio2.module import FastLio2
from dimos.mapping.voxels import VoxelGridMapper
from dimos.visualization.rerun.bridge import RerunBridgeModule
from dimos.visualization.vis_module import vis_module

voxel_size = 0.05

mid360_fastlio = autoconnect(
FastLio2.blueprint(voxel_size=voxel_size, map_voxel_size=voxel_size, map_freq=-1),
RerunBridgeModule.blueprint(),
vis_module(
"rerun",
rerun_config={
"visual_override": {
"world/lidar": lambda grid: grid.to_rerun(voxel_size=voxel_size, mode="boxes"),
},
},
),
).global_config(n_workers=2, robot_model="mid360_fastlio2")

mid360_fastlio_voxels = autoconnect(
FastLio2.blueprint(),
VoxelGridMapper.blueprint(voxel_size=voxel_size, carve_columns=False),
RerunBridgeModule.blueprint(
visual_override={
"world/lidar": None,
}
vis_module(
"rerun",
rerun_config={
"visual_override": {
"world/global_map": lambda grid: grid.to_rerun(voxel_size=voxel_size, mode="boxes"),
"world/lidar": None,
},
},
),
).global_config(n_workers=3, robot_model="mid360_fastlio2_voxels")

mid360_fastlio_voxels_native = autoconnect(
FastLio2.blueprint(voxel_size=voxel_size, map_voxel_size=voxel_size, map_freq=3.0),
RerunBridgeModule.blueprint(
visual_override={
"world/lidar": None,
}
vis_module(
"rerun",
rerun_config={
"visual_override": {
"world/lidar": None,
"world/global_map": lambda grid: grid.to_rerun(voxel_size=voxel_size, mode="boxes"),
},
},
),
).global_config(n_workers=2, robot_model="mid360_fastlio2")
4 changes: 2 additions & 2 deletions dimos/hardware/sensors/lidar/livox/livox_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

from dimos.core.coordination.blueprints import autoconnect
from dimos.hardware.sensors.lidar.livox.module import Mid360
from dimos.visualization.rerun.bridge import RerunBridgeModule
from dimos.visualization.vis_module import vis_module

mid360 = autoconnect(
Mid360.blueprint(),
RerunBridgeModule.blueprint(),
vis_module("rerun"),
).global_config(n_workers=2, robot_model="mid360")
10 changes: 5 additions & 5 deletions dimos/manipulation/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from dimos.msgs.sensor_msgs.JointState import JointState
from dimos.perception.object_scene_registration import ObjectSceneRegistrationModule
from dimos.robot.catalog.ufactory import xarm6 as _catalog_xarm6, xarm7 as _catalog_xarm7
from dimos.robot.foxglove_bridge import FoxgloveBridge # TODO: migrate to rerun
from dimos.visualization.vis_module import vis_module

# Single XArm6 planner (standalone, no coordinator)
_xarm6_planner_cfg = _catalog_xarm6(
Expand Down Expand Up @@ -196,14 +196,14 @@
use_aabb=True,
max_obstacle_width=0.06,
),
FoxgloveBridge.blueprint(), # TODO: migrate to rerun
vis_module("foxglove"),
)
.transports(
{
("joint_state", JointState): LCMTransport("/coordinator/joint_state", JointState),
}
)
.global_config(viewer="foxglove", n_workers=4)
.global_config(n_workers=4)
)


Expand Down Expand Up @@ -289,7 +289,7 @@

from dimos.robot.catalog.ufactory import XARM7_SIM_PATH
from dimos.simulation.engines.mujoco_sim_module import MujocoSimModule
from dimos.visualization.rerun.bridge import RerunBridgeModule, _resolve_viewer_mode
from dimos.visualization.rerun.bridge import RerunBridgeModule

_xarm7_sim_cfg = _catalog_xarm7(
name="arm",
Expand Down Expand Up @@ -323,7 +323,7 @@
hardware=[_xarm7_sim_cfg.to_hardware_component()],
tasks=[_xarm7_sim_cfg.to_task_config()],
),
RerunBridgeModule.blueprint(viewer_mode=_resolve_viewer_mode()),
RerunBridgeModule.blueprint(),
).transports(
{
("joint_state", JointState): LCMTransport("/coordinator/joint_state", JointState),
Expand Down
4 changes: 2 additions & 2 deletions dimos/manipulation/grasping/demo_grasping.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from dimos.manipulation.grasping.grasping import GraspingModule
from dimos.perception.detection.detectors.yoloe import YoloePromptMode
from dimos.perception.object_scene_registration import ObjectSceneRegistrationModule
from dimos.robot.foxglove_bridge import FoxgloveBridge
from dimos.visualization.vis_module import vis_module

camera_module = RealSenseCamera.blueprint(enable_pointcloud=False)

Expand All @@ -44,7 +44,7 @@
("/tmp", "/tmp", "rw")
], # Grasp visualization debug standalone: python -m dimos.manipulation.grasping.visualize_grasps
),
FoxgloveBridge.blueprint(),
vis_module("foxglove"),
McpServer.blueprint(),
McpClient.blueprint(),
).global_config(viewer="foxglove")
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class WavefrontFrontierExplorer(Module):
goal_reached: In[Bool]
explore_cmd: In[Bool]
stop_explore_cmd: In[Bool]
stop_movement: In[Bool]

# LCM outputs
goal_request: Out[PoseStamped]
Expand Down Expand Up @@ -171,6 +172,10 @@ def start(self) -> None:
unsub = self.stop_explore_cmd.subscribe(self._on_stop_explore_cmd)
self.register_disposable(Disposable(unsub))

if self.stop_movement.transport is not None:
unsub = self.stop_movement.subscribe(self._on_stop_movement)
self.register_disposable(Disposable(unsub))

@rpc
def stop(self) -> None:
self.stop_exploration()
Expand Down Expand Up @@ -201,6 +206,12 @@ def _on_stop_explore_cmd(self, msg: Bool) -> None:
logger.info("Received exploration stop command via LCM")
self.stop_exploration()

def _on_stop_movement(self, msg: Bool) -> None:
"""Handle stop movement from teleop — cancel active exploration."""
if msg.data and self.exploration_active:
logger.info("WavefrontFrontierExplorer: stop_movement received, stopping exploration")
self.stop_exploration()

def _count_costmap_information(self, costmap: OccupancyGrid) -> int:
"""
Count the amount of information in a costmap (free space + obstacles).
Expand Down
18 changes: 16 additions & 2 deletions dimos/navigation/replanning_a_star/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
from dimos.msgs.nav_msgs.Path import Path
from dimos.navigation.base import NavigationInterface, NavigationState
from dimos.navigation.replanning_a_star.global_planner import GlobalPlanner
from dimos.utils.logging_config import setup_logger

logger = setup_logger()


class ReplanningAStarPlanner(Module, NavigationInterface):
Expand All @@ -36,10 +39,11 @@ class ReplanningAStarPlanner(Module, NavigationInterface):
goal_request: In[PoseStamped]
clicked_point: In[PointStamped]
target: In[PoseStamped]
stop_movement: In[Bool]

goal_reached: Out[Bool]
navigation_state: Out[String] # TODO: set it
cmd_vel: Out[Twist]
nav_cmd_vel: Out[Twist]
path: Out[Path]
navigation_costmap: Out[OccupancyGrid]

Expand Down Expand Up @@ -72,9 +76,14 @@ def start(self) -> None:
)
)

if self.stop_movement.transport is not None:
self.register_disposable(
Disposable(self.stop_movement.subscribe(self._on_stop_movement))
)

self.register_disposable(self._planner.path.subscribe(self.path.publish))

self.register_disposable(self._planner.cmd_vel.subscribe(self.cmd_vel.publish))
self.register_disposable(self._planner.cmd_vel.subscribe(self.nav_cmd_vel.publish))

self.register_disposable(self._planner.goal_reached.subscribe(self.goal_reached.publish))

Expand All @@ -92,6 +101,11 @@ def stop(self) -> None:

super().stop()

def _on_stop_movement(self, msg: Bool) -> None:
if msg.data:
logger.info("ReplanningAStarPlanner: stop_movement received, cancelling goal")
self.cancel_goal()

@rpc
def set_goal(self, goal: PoseStamped) -> bool:
self._planner.handle_goal_request(goal)
Expand Down
Loading