Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion dimos/control/tasks/teleop_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class TeleopIKTaskConfig:
ee_joint_id: int
priority: int = 10
timeout: float = 0.5
max_joint_delta_deg: float = 5.0 # ~500°/s at 100Hz
max_joint_delta_deg: float = 50.0 # ~500°/s at 100Hz
hand: Literal["left", "right"] | None = None
gripper_joint: str | None = None
gripper_open_pos: float = 0.0
Expand Down
11 changes: 8 additions & 3 deletions dimos/memory2/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from dimos.memory2.transform import QualityWindow
from dimos.memory2.type.observation import EmbeddedObservation, Observation
from dimos.models.embedding.base import EmbeddingModel
from dimos.models.embedding.clip import CLIPModel
from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped
from dimos.msgs.sensor_msgs.Image import Image
from dimos.utils.logging_config import setup_logger
Expand Down Expand Up @@ -198,7 +197,7 @@ def store(self) -> SqliteStore:


class SemanticSearchConfig(MemoryModuleConfig):
embedding_model: type[EmbeddingModel] = CLIPModel
embedding_model: type[EmbeddingModel] | None = None


class SemanticSearch(MemoryModule):
Expand All @@ -210,7 +209,13 @@ class SemanticSearch(MemoryModule):
def start(self) -> None:
super().start()

self.model = self.register_disposable(self.config.embedding_model())
embedding_cls = self.config.embedding_model
if embedding_cls is None:
from dimos.models.embedding.clip import CLIPModel

embedding_cls = CLIPModel

self.model = self.register_disposable(embedding_cls())
self.model.start()

self.embeddings = self.store.stream("color_image_embedded", Image)
Expand Down
7 changes: 7 additions & 0 deletions dimos/robot/all_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
"mid360-fastlio-voxels-native": "dimos.hardware.sensors.lidar.fastlio2.fastlio_blueprints:mid360_fastlio_voxels_native",
"openarm-mock-planner-coordinator": "dimos.robot.manipulators.openarm.blueprints:openarm_mock_planner_coordinator",
"openarm-planner-coordinator": "dimos.robot.manipulators.openarm.blueprints:openarm_planner_coordinator",
"teleop-hosted-go2": "dimos.teleop.quest_hosted.blueprints:teleop_hosted_go2",
"teleop-hosted-xarm7-sim": "dimos.teleop.quest_hosted.blueprints:teleop_hosted_xarm7_sim",
"teleop-phone": "dimos.teleop.phone.blueprints:teleop_phone",
"teleop-phone-go2": "dimos.teleop.phone.blueprints:teleop_phone_go2",
"teleop-phone-go2-fleet": "dimos.teleop.phone.blueprints:teleop_phone_go2_fleet",
Expand Down Expand Up @@ -149,6 +151,10 @@
"grasp-gen-module": "dimos.manipulation.grasping.graspgen_module.GraspGenModule",
"grasping-module": "dimos.manipulation.grasping.grasping.GraspingModule",
"gstreamer-camera-module": "dimos.hardware.sensors.camera.gstreamer.gstreamer_camera.GstreamerCameraModule",
"hosted-arm-teleop-module": "dimos.teleop.quest_hosted.hosted_extensions.HostedArmTeleopModule",
"hosted-teleop-module": "dimos.teleop.quest_hosted.hosted_teleop_module.HostedTeleopModule",
"hosted-teleop-recorder": "dimos.teleop.quest_hosted.blueprints.HostedTeleopRecorder",
"hosted-twist-teleop-module": "dimos.teleop.quest_hosted.hosted_extensions.HostedTwistTeleopModule",
"joint-trajectory-controller": "dimos.manipulation.control.trajectory_controller.joint_trajectory_controller.JointTrajectoryController",
"joystick-module": "dimos.robot.unitree.b1.joystick_module.JoystickModule",
"keyboard-teleop": "dimos.robot.unitree.keyboard_teleop.KeyboardTeleop",
Expand Down Expand Up @@ -190,6 +196,7 @@
"spatial-memory": "dimos.perception.spatial_perception.SpatialMemory",
"speak-skill": "dimos.agents.skills.speak_skill.SpeakSkill",
"temporal-memory": "dimos.perception.experimental.temporal_memory.temporal_memory.TemporalMemory",
"teleop-recorder": "dimos.teleop.quest.blueprints.TeleopRecorder",
"twist-teleop-module": "dimos.teleop.quest.quest_extensions.TwistTeleopModule",
"unitree-g1-skill-container": "dimos.robot.unitree.g1.skill_container.UnitreeG1SkillContainer",
"unitree-skill-container": "dimos.robot.unitree.unitree_skill_container.UnitreeSkillContainer",
Expand Down
2 changes: 1 addition & 1 deletion dimos/robot/unitree/type/lidar.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _repair(item: T) -> T:
if prev_good[0] is not None and item.ts <= prev_good[0]:
old = item.ts
item.ts = prev_good[0] + default_period
logger.warning("repair_stale_ts: stale stamp %.6f → %.6f", old, item.ts)
logger.debug("repair_stale_ts: stale stamp %.6f → %.6f", old, item.ts)
prev_good[0] = item.ts
return item

Expand Down
21 changes: 21 additions & 0 deletions dimos/teleop/quest/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

"""Teleop blueprints for testing and deployment."""

from pathlib import Path

from dimos.control.blueprints.teleop import (
coordinator_teleop_dual,
coordinator_teleop_piper,
Expand All @@ -25,7 +27,9 @@
coordinator_teleop_xarm7,
)
from dimos.core.coordination.blueprints import autoconnect
from dimos.core.stream import In
from dimos.core.transport import LCMTransport
from dimos.memory2.module import Recorder, RecorderConfig
from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped
from dimos.teleop.quest.quest_extensions import ArmTeleopModule
from dimos.teleop.quest.quest_types import Buttons
Expand Down Expand Up @@ -72,6 +76,21 @@
)


class TeleopRecorderConfig(RecorderConfig):
db_path: str | Path = "recording_teleop.db"


class TeleopRecorder(Recorder):
"""Records right-controller pose and button state from any quest teleop blueprint.

Compose at the CLI: ``dimos run teleop-quest-xarm7-sim teleop-recorder``.
"""

right_controller_output: In[PoseStamped]
buttons: In[Buttons]
config: TeleopRecorderConfig


# Single Piper teleop: left controller -> piper arm
teleop_quest_piper = autoconnect(
ArmTeleopModule.blueprint(task_names={"left": "teleop_piper"}),
Expand Down Expand Up @@ -146,6 +165,8 @@


__all__ = [
"TeleopRecorder",
"TeleopRecorderConfig",
"teleop_quest_dual",
"teleop_quest_piper",
"teleop_quest_piper_sim",
Expand Down
84 changes: 84 additions & 0 deletions dimos/teleop/quest_hosted/blueprints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
# Copyright 2025-2026 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.

"""Hosted teleop blueprints (WebRTC transport)."""

from pathlib import Path

from dimos.control.blueprints.teleop import coordinator_teleop_sim_xarm7
from dimos.core.coordination.blueprints import autoconnect
from dimos.core.stream import In
from dimos.core.transport import LCMTransport
from dimos.memory2.module import Recorder, RecorderConfig
from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped
from dimos.msgs.geometry_msgs.TwistStamped import TwistStamped
from dimos.robot.unitree.go2.blueprints.basic.unitree_go2_basic import unitree_go2_basic
from dimos.teleop.quest.quest_types import Buttons
from dimos.teleop.quest_hosted.hosted_extensions import (
HostedArmTeleopModule,
HostedTwistTeleopModule,
)

# Single XArm7 teleop in MuJoCo sim, using the hosted (WebRTC) client.
teleop_hosted_xarm7_sim = autoconnect(
HostedArmTeleopModule.blueprint(task_names={"right": "teleop_xarm"}),
coordinator_teleop_sim_xarm7,
).transports(
{
("right_controller_output", PoseStamped): LCMTransport(
"/coordinator/cartesian_command", PoseStamped
),
("buttons", Buttons): LCMTransport("/teleop/buttons", Buttons),
}
)

# Unitree Go2 keyboard teleop. Operator types WASD in browser → TwistStamped
# over WebRTC → HostedTwistTeleopModule scales by linear/angular_speed and
# publishes Twist on cmd_vel → GO2Connection.cmd_vel (via unitree_go2_basic,
# which also brings in vis + clock sync; no coordinator in path).
teleop_hosted_go2 = autoconnect(
HostedTwistTeleopModule.blueprint(),
unitree_go2_basic,
)


class HostedTeleopRecorderConfig(RecorderConfig):
db_path: str | Path = "recording_hosted_3.db"


class HostedTeleopRecorder(Recorder):
"""Records hosted teleop streams. Captures whatever the connected blueprint
produces — VR controller poses + buttons (xarm7 sim), or cmd_vel_stamped
(go2). Unconnected ports stay empty in the DB.

Compose at the CLI::

dimos run teleop-hosted-xarm7-sim hosted-teleop-recorder
dimos run teleop-hosted-go2 hosted-teleop-recorder
"""

right_controller_output: In[PoseStamped]
left_controller_output: In[PoseStamped]
buttons: In[Buttons]
cmd_vel_stamped: In[TwistStamped]
config: HostedTeleopRecorderConfig


__all__ = [
"HostedTeleopRecorder",
"HostedTeleopRecorderConfig",
"teleop_hosted_xarm7_sim",
"teleop_hosted_go2",
]
Loading