diff --git a/dimos/robot/all_blueprints.py b/dimos/robot/all_blueprints.py index 6fbf0138bb..0f9ce19dd7 100644 --- a/dimos/robot/all_blueprints.py +++ b/dimos/robot/all_blueprints.py @@ -73,6 +73,7 @@ "openarm-planner-coordinator": "dimos.robot.manipulators.openarm.blueprints:openarm_planner_coordinator", "teleop-phone": "dimos.teleop.phone.blueprints:teleop_phone", "teleop-phone-go2": "dimos.teleop.phone.blueprints:teleop_phone_go2", + "teleop-phone-go2-agentic": "dimos.robot.unitree.go2.blueprints.agentic.unitree_go2_agentic_phone:teleop_phone_go2_agentic", "teleop-phone-go2-fleet": "dimos.teleop.phone.blueprints:teleop_phone_go2_fleet", "teleop-quest-dual": "dimos.teleop.quest.blueprints:teleop_quest_dual", "teleop-quest-piper": "dimos.teleop.quest.blueprints:teleop_quest_piper", diff --git a/dimos/robot/unitree/go2/blueprints/agentic/unitree_go2_agentic_phone.py b/dimos/robot/unitree/go2/blueprints/agentic/unitree_go2_agentic_phone.py new file mode 100644 index 0000000000..1605707a0b --- /dev/null +++ b/dimos/robot/unitree/go2/blueprints/agentic/unitree_go2_agentic_phone.py @@ -0,0 +1,29 @@ +#!/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. + +from dimos.core.coordination.blueprints import autoconnect +from dimos.robot.unitree.go2.blueprints.agentic.unitree_go2_agentic import unitree_go2_agentic +from dimos.teleop.phone.phone_extensions import SimplePhoneTeleop + +teleop_phone_go2_agentic = autoconnect( + SimplePhoneTeleop.blueprint(), + unitree_go2_agentic, +).remappings( + [ + (SimplePhoneTeleop, "cmd_vel", "tele_cmd_vel"), + ] +) + +__all__ = ["teleop_phone_go2_agentic"] diff --git a/dimos/teleop/phone/README.md b/dimos/teleop/phone/README.md index da84bfd124..aacd8a4eff 100644 --- a/dimos/teleop/phone/README.md +++ b/dimos/teleop/phone/README.md @@ -13,11 +13,21 @@ Phone Browser ──WebSocket──→ Embedded HTTPS Server ──→ Phone ```bash dimos run teleop-phone-go2 # Go2 +dimos run teleop-phone-go2-agentic # Go2 agentic stack with phone override dimos run teleop-phone # Generic ground robot ``` Open `https://:8444/teleop` on phone. Accept cert, allow sensors, connect, hold to drive. +## Agentic Go2 Override + +`teleop-phone-go2-agentic` adds the phone controller to the full agentic Go2 +stack. Phone commands are remapped into `MovementManager.tele_cmd_vel`, so +holding the phone teleop button cancels active navigation goals and temporarily +takes over velocity control. Release the button to stop sending manual commands +and allow autonomous navigation commands to resume after the movement manager's +teleop cooldown. + ## Subclassing | Method | Purpose | diff --git a/pyproject.toml b/pyproject.toml index 39db0c1b7c..92616928e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -212,6 +212,7 @@ agents = [ web = [ "fastapi>=0.115.6", + "python-multipart>=0.0.27", "sse-starlette>=2.2.1", "uvicorn>=0.34.0", "jinja2>=3.1.6", diff --git a/uv.lock b/uv.lock index b4da9cadaf..f6d30cfc75 100644 --- a/uv.lock +++ b/uv.lock @@ -40,7 +40,7 @@ resolution-markers = [ ] [options] -exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. +exclude-newer = "2026-05-21T12:08:30.150078Z" exclude-newer-span = "P7D" [options.exclude-newer-package] @@ -2028,6 +2028,7 @@ base = [ { name = "omegaconf" }, { name = "openai" }, { name = "pillow" }, + { name = "python-multipart" }, { name = "rerun-sdk" }, { name = "sounddevice" }, { name = "soundfile" }, @@ -2159,6 +2160,7 @@ unitree = [ { name = "omegaconf" }, { name = "openai" }, { name = "pillow" }, + { name = "python-multipart" }, { name = "rerun-sdk" }, { name = "sounddevice" }, { name = "soundfile" }, @@ -2192,6 +2194,7 @@ unitree-dds = [ { name = "omegaconf" }, { name = "openai" }, { name = "pillow" }, + { name = "python-multipart" }, { name = "rerun-sdk" }, { name = "sounddevice" }, { name = "soundfile" }, @@ -2210,6 +2213,7 @@ web = [ { name = "fastapi" }, { name = "ffmpeg-python" }, { name = "jinja2" }, + { name = "python-multipart" }, { name = "soundfile" }, { name = "sse-starlette" }, { name = "uvicorn" }, @@ -2457,6 +2461,7 @@ requires-dist = [ { name = "pyrealsense2", marker = "sys_platform != 'darwin' and extra == 'manipulation'" }, { name = "python-dotenv" }, { name = "python-multipart", marker = "extra == 'misc'", specifier = ">=0.0.27" }, + { name = "python-multipart", marker = "extra == 'web'", specifier = ">=0.0.27" }, { name = "pyturbojpeg", specifier = "==1.8.2" }, { name = "pyturbojpeg", marker = "extra == 'docker'" }, { name = "pyyaml", marker = "extra == 'manipulation'", specifier = ">=6.0" },