Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
d6467de
g1 switched over to webcam module
alexlin2 Sep 19, 2025
78238de
Merge remote-tracking branch 'origin/spatial-object-localization' int…
alexlin2 Sep 19, 2025
b4a80ee
camera system cleanup, calibration loading
leshy Sep 19, 2025
649e51b
zed calibration file
leshy Sep 19, 2025
9c81189
removed comments / unused imports from zed
leshy Sep 19, 2025
ec0754d
integration wip
alexlin2 Sep 19, 2025
b90c57c
Merge branch 'camerainfo-yaml-loading' into g1-localzed
leshy Sep 19, 2025
4be2c8f
Merge branch 'spatial-object-localization' into g1-localzed
leshy Sep 19, 2025
b74d468
universal camera module
leshy Sep 19, 2025
1afae19
fixed flakey test_reactive test
leshy Sep 19, 2025
7b93442
removed obsolete test
leshy Sep 19, 2025
3e397a6
print cleanup
leshy Sep 19, 2025
91bb2e5
topic change for bridge, small camera module fixes
leshy Sep 20, 2025
cdb8a09
g1 local changes
alexlin2 Sep 20, 2025
7e9c801
Merge branch 'g1-localzed' of github.com:dimensionalOS/dimos into g1-…
alexlin2 Sep 20, 2025
e3e1c75
ros global map
alexlin2 Sep 20, 2025
320f29e
height filter config for module3d
leshy Sep 20, 2025
de440af
splitting types, object db work
leshy Sep 21, 2025
6ffe119
circular imports solved
leshy Sep 21, 2025
c7568a6
foxglove sceneupdate
leshy Sep 21, 2025
9e89f92
pointcloud bounding box intersection, detection3d projection refactor
leshy Sep 21, 2025
a1b96b6
checkpoint
leshy Sep 21, 2025
51dc58d
detection work snapshot
leshy Sep 22, 2025
11ed0b3
testing refactor
leshy Sep 22, 2025
e53dc6e
good replay example
leshy Sep 22, 2025
fa56bc8
bugfixes, improvements, g1 compatibilty
leshy Sep 22, 2025
77be0ee
working on universal recorder
leshy Sep 22, 2025
48d1f17
recorder cli
leshy Sep 22, 2025
f741d1d
onboard g1 changes and recording
alexlin2 Sep 23, 2025
267952f
corrected timestamp alignment
leshy Sep 23, 2025
220445f
temporary nav integration
alexlin2 Sep 23, 2025
8896671
color hash type, timestamp alignment fix
leshy Sep 23, 2025
cf4d29a
new timestamp alignment
leshy Sep 23, 2025
3317373
timed replay refactor
leshy Sep 23, 2025
8a51860
correct detected image broadcast from module2d
leshy Sep 23, 2025
387a75b
better dict repr
leshy Sep 23, 2025
73284e9
g1 replay system
leshy Sep 24, 2025
7af3661
g1 filters
leshy Sep 24, 2025
fc6afbc
g1 local merge
alexlin2 Sep 24, 2025
3f39c00
weaklist
leshy Sep 24, 2025
2a5f4d4
Merge branch 'g1-localzed' of github.com:dimensionalOS/dimos into g1-…
leshy Sep 24, 2025
a0883ef
raycast bugfix
leshy Sep 24, 2025
03af0b8
small bugfixes
leshy Sep 24, 2025
ee37053
agent integration to unitree_go2
leshy Sep 24, 2025
f8c4bf0
TOFIX double pub goal message for reliability
alexlin2 Sep 24, 2025
7c2e8a3
Merge branch 'g1-localzed' of github.com:dimensionalOS/dimos into g1-…
alexlin2 Sep 24, 2025
6765c23
fix
leshy Sep 24, 2025
7b64494
cam fix
alexlin2 Sep 24, 2025
4f3fcad
added joy message type to dimos
alexlin2 Sep 25, 2025
59a1084
added set autonomy mode
alexlin2 Sep 25, 2025
f9f1837
added joy to ros bridge
alexlin2 Sep 25, 2025
cdddc13
working agent/localization
alexlin2 Sep 25, 2025
b7a5b57
Merge branch 'g1-localzed' of github.com:dimensionalOS/dimos into g1-…
alexlin2 Sep 25, 2025
ca3de7e
fixed
alexlin2 Sep 25, 2025
a553d0e
CI code cleanup
alexlin2 Sep 25, 2025
7ab9835
sharpness window generalized to quality_barrier
leshy Sep 26, 2025
d97dfef
tests consolidation, preparing for merge
leshy Sep 27, 2025
e15069c
Merge branch 'dev' into g1-localzed
leshy Sep 27, 2025
e0bd35c
tests fix
leshy Sep 27, 2025
f6234b7
qwen localization
leshy Sep 27, 2025
4a300be
nav to object in view
leshy Sep 27, 2025
742247f
forgot init
leshy Sep 27, 2025
1981c9e
bugfix
leshy Sep 27, 2025
8dde97d
bugfix
leshy Sep 27, 2025
83a30a3
fix for timestamp on g1
leshy Sep 27, 2025
03d4a36
killing time stuff
leshy Sep 27, 2025
8cf46ae
onboard unitree changes
alexlin2 Sep 27, 2025
2b0a179
CI code cleanup
alexlin2 Sep 27, 2025
ab10747
quick fixes
leshy Sep 28, 2025
e5300d2
Merge branch 'g1-localzed' of github.com:dimensionalOS/dimos into g1-…
leshy Sep 28, 2025
7b58306
moduledb hack
leshy Sep 28, 2025
b219f3b
moduledb hack
leshy Sep 28, 2025
9381370
current g1
leshy Sep 28, 2025
7d6e9da
reenabling qwen
leshy Sep 30, 2025
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
4 changes: 0 additions & 4 deletions .envrc

This file was deleted.

1 change: 1 addition & 0 deletions .envrc
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ FastSAM-x.pt
yolo11n.pt

/thread_monitor_report.csv

# symlink one of .envrc.* if you'd like to use
.envrc
3 changes: 3 additions & 0 deletions data/.lfs/replay_g1.tar.gz
Git LFS file not shown
3 changes: 3 additions & 0 deletions data/.lfs/replay_g1_run.tar.gz
Git LFS file not shown
28 changes: 25 additions & 3 deletions dimos/agents2/temp/webcam_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@
from pathlib import Path

from dotenv import load_dotenv
from dimos.hardware.camera import zed
from dimos.msgs.geometry_msgs import Quaternion, Transform, Vector3

from dimos.agents2.cli.human import HumanInput

# Add parent directories to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from dimos.hardware.camera.module import CameraModule
from dimos.hardware.camera.webcam import Webcam

from threading import Thread

Expand All @@ -39,8 +43,9 @@
from dimos.agents2 import Agent, Output, Reducer, Stream, skill
from dimos.agents2.spec import Model, Provider
from dimos.core import LCMTransport, Module, pLCMTransport, start
from dimos.hardware.webcam import ColorCameraModule, Webcam
from dimos.msgs.sensor_msgs import Image

# from dimos.hardware.webcam import ColorCameraModule, Webcam
from dimos.msgs.sensor_msgs import Image, CameraInfo
from dimos.protocol.skill.test_coordinator import SkillContainerTest
from dimos.robot.unitree_webrtc.unitree_go2 import UnitreeGo2
from dimos.robot.unitree_webrtc.unitree_skill_container import UnitreeSkillContainer
Expand Down Expand Up @@ -110,7 +115,24 @@ def main():
)

testcontainer = dimos.deploy(SkillContainerTest)
webcam = dimos.deploy(ColorCameraModule, hardware=lambda: Webcam(camera_index=0))
webcam = dimos.deploy(
CameraModule,
transform=Transform(
translation=Vector3(0.0, 0.0, 0.0),
rotation=Quaternion(0.0, 0.0, 0.0, 1.0),
frame_id="base_link",
child_frame_id="camera_link",
),
hardware=lambda: Webcam(
camera_index=0,
frequency=15,
stereo_slice="left",
camera_info=zed.CameraInfo.SingleWebcam,
),
)

webcam.camera_info.transport = LCMTransport("/camera_info", CameraInfo)

webcam.image.transport = LCMTransport("/image", Image)

webcam.start()
Expand Down
3 changes: 2 additions & 1 deletion dimos/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ def _close_rpc(self):
@property
def tf(self):
if self._tf is None:
self._tf = self.config.tf_transport()
# self._tf = self.config.tf_transport()
self._tf = LCMTF()
return self._tf

@tf.setter
Expand Down
127 changes: 127 additions & 0 deletions dimos/hardware/camera/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Copyright 2025 Dimensional Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import queue
import time
from dataclasses import dataclass, field
from typing import Any, Callable, Generic, Literal, Optional, Protocol, TypeVar

import reactivex as rx
from dimos_lcm.sensor_msgs import CameraInfo
from reactivex import operators as ops
from reactivex.disposable import Disposable
from reactivex.observable import Observable

from dimos.agents2 import Output, Reducer, Stream, skill
from dimos.core import Module, Out, rpc
from dimos.core.module import Module, ModuleConfig
from dimos.hardware.camera.spec import (
CameraHardware,
)
from dimos.hardware.camera.webcam import Webcam, WebcamConfig
from dimos.msgs.geometry_msgs import Quaternion, Transform, Vector3
from dimos.msgs.sensor_msgs import Image
from dimos.msgs.sensor_msgs.Image import Image, sharpness_barrier

default_transform = lambda: Transform(
translation=Vector3(0.0, 0.0, 0.0),
rotation=Quaternion(0.0, 0.0, 0.0, 1.0),
frame_id="base_link",
child_frame_id="camera_link",
)


@dataclass
class CameraModuleConfig(ModuleConfig):
frame_id: str = "camera_link"
transform: Optional[Transform] = field(default_factory=default_transform)
hardware: Callable[[], CameraHardware] | CameraHardware = Webcam


class CameraModule(Module):
image: Out[Image] = None
camera_info: Out[CameraInfo] = None

hardware: CameraHardware = None
_module_subscription: Optional[Disposable] = None
_camera_info_subscription: Optional[Disposable] = None
_skill_stream: Optional[Observable[Image]] = None

default_config = CameraModuleConfig

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

@rpc
def start(self):
if callable(self.config.hardware):
self.hardware = self.config.hardware()
else:
self.hardware = self.config.hardware

if self._module_subscription:
return "already started"

stream = self.hardware.image_stream().pipe(sharpness_barrier(5))

# camera_info_stream = self.camera_info_stream(frequency=5.0)

def publish_info(camera_info: CameraInfo):
self.camera_info.publish(camera_info)

if self.config.transform is None:
return

camera_link = self.config.transform
camera_link.ts = camera_info.ts
camera_optical = Transform(
translation=Vector3(0.0, 0.0, 0.0),
rotation=Quaternion(-0.5, 0.5, -0.5, 0.5),
frame_id="camera_link",
child_frame_id="camera_optical",
ts=camera_link.ts,
)

self.tf.publish(camera_link, camera_optical)

self._camera_info_subscription = self.camera_info_stream().subscribe(publish_info)
self._module_subscription = stream.subscribe(self.image.publish)

@skill(stream=Stream.passive, output=Output.image, reducer=Reducer.latest)
def video_stream(self) -> Image:
"""implicit video stream skill"""
_queue = queue.Queue(maxsize=1)
self.hardware.image_stream().subscribe(_queue.put)

for image in iter(_queue.get, None):
yield image

def camera_info_stream(self, frequency: float = 5.0) -> Observable[CameraInfo]:
def camera_info(_) -> CameraInfo:
self.hardware.camera_info.ts = time.time()
return self.hardware.camera_info

return rx.interval(1.0 / frequency).pipe(ops.map(camera_info))

def stop(self):
if self._module_subscription:
self._module_subscription.dispose()
self._module_subscription = None
if self._camera_info_subscription:
self._camera_info_subscription.dispose()
self._camera_info_subscription = None
# Also stop the hardware if it has a stop method
if self.hardware and hasattr(self.hardware, "stop"):
self.hardware.stop()
super().stop()
55 changes: 55 additions & 0 deletions dimos/hardware/camera/spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2025 Dimensional Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod, abstractproperty
from typing import Generic, Optional, Protocol, TypeVar

from dimos_lcm.sensor_msgs import CameraInfo
from reactivex.observable import Observable

from dimos.msgs.sensor_msgs import Image
from dimos.protocol.service import Configurable


class CameraConfig(Protocol):
frame_id_prefix: Optional[str]


CameraConfigT = TypeVar("CameraConfigT", bound=CameraConfig)


class CameraHardware(ABC, Configurable[CameraConfigT], Generic[CameraConfigT]):
@abstractmethod
def image_stream(self) -> Observable[Image]:
pass

@abstractproperty
def camera_info(self) -> CameraInfo:
pass


# This is an example, feel free to change spec for stereo cameras
# e.g., separate camera_info or streams for left/right, etc.
class StereoCameraHardware(ABC, Configurable[CameraConfigT], Generic[CameraConfigT]):
@abstractmethod
def image_stream(self) -> Observable[Image]:
pass

@abstractmethod
def depth_stream(self) -> Observable[Image]:
pass

@abstractproperty
def camera_info(self) -> CameraInfo:
pass
108 changes: 108 additions & 0 deletions dimos/hardware/camera/test_webcam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright 2025 Dimensional Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import time

import pytest

from dimos import core
from dimos.hardware.camera import zed
from dimos.hardware.camera.module import CameraModule
from dimos.hardware.camera.webcam import Webcam
from dimos.msgs.geometry_msgs import Quaternion, Transform, Vector3
from dimos.msgs.sensor_msgs import CameraInfo, Image


@pytest.mark.tool
def test_streaming_single():
dimos = core.start(1)

camera = dimos.deploy(
CameraModule,
transform=Transform(
translation=Vector3(0.05, 0.0, 0.0),
rotation=Quaternion(0.0, 0.0, 0.0, 1.0),
frame_id="sensor",
child_frame_id="camera_link",
),
hardware=lambda: Webcam(
stereo_slice="left",
camera_index=0,
frequency=15,
camera_info=zed.CameraInfo.SingleWebcam,
),
)

camera.image.transport = core.LCMTransport("/image1", Image)
camera.camera_info.transport = core.LCMTransport("/image1/camera_info", CameraInfo)
camera.start()

try:
while True:
time.sleep(1)
except KeyboardInterrupt:
camera.stop()
dimos.stop()


@pytest.mark.tool
def test_streaming_double():
dimos = core.start(2)

camera1 = dimos.deploy(
CameraModule,
transform=Transform(
translation=Vector3(0.05, 0.0, 0.0),
rotation=Quaternion(0.0, 0.0, 0.0, 1.0),
frame_id="sensor",
child_frame_id="camera_link",
),
hardware=lambda: Webcam(
stereo_slice="left",
camera_index=0,
frequency=15,
camera_info=zed.CameraInfo.SingleWebcam,
),
)

camera2 = dimos.deploy(
CameraModule,
transform=Transform(
translation=Vector3(0.05, 0.0, 0.0),
rotation=Quaternion(0.0, 0.0, 0.0, 1.0),
frame_id="sensor",
child_frame_id="camera_link",
),
hardware=lambda: Webcam(
camera_index=4,
frequency=15,
stereo_slice="left",
camera_info=zed.CameraInfo.SingleWebcam,
),
)

camera1.image.transport = core.LCMTransport("/image1", Image)
camera1.camera_info.transport = core.LCMTransport("/image1/camera_info", CameraInfo)
camera1.start()
camera2.image.transport = core.LCMTransport("/image2", Image)
camera2.camera_info.transport = core.LCMTransport("/image2/camera_info", CameraInfo)
camera2.start()

try:
while True:
time.sleep(1)
except KeyboardInterrupt:
camera1.stop()
camera2.stop()
dimos.stop()
Loading
Loading