Skip to content

Conversation

@ruthwikdasyam
Copy link
Contributor

@ruthwikdasyam ruthwikdasyam commented Jan 8, 2026

[Check latest comment for updated info]

Quest3 Teleop Module Implementation

Features Included

  • WebSocket Support: WebSocket server that supports VR headset and reads tracking data with passthrough view
  • Quest3TeleopModule: Based on BaseTeleopModule, publishes: (Max - 90Hz)
    • 2x PoseStamped (left and right controller poses)
    • 2x Float32 (gripper trigger values)
  • Calibrated Poses: Quest3TeleopModule sends calibrated poses (delta position from initial position)
  • Button Controls: Button press functionality to start and stop teleop
  • Visualization: Visualization of controller movement and gripper topics on Rerun
  • TeleopRobotController: Template module that:
    • Reads from Quest3TeleopModule
    • Publishes 2x Pose + 2x Bool as required by robot modules
    • Reads robot current position and sends absolute position for the robot to move
    • Module designed to support further add-ons such as IK, constraints, and safety features

Topics viz

Screenshot from 2026-01-07 17-47-46

@ruthwikdasyam ruthwikdasyam requested review from a team, leshy and spomichter January 8, 2026 03:08
@greptile-apps
Copy link

greptile-apps bot commented Jan 8, 2026

Greptile Summary

Implements Quest3 VR teleoperation with dual-arm control through WebSocket/WebXR. The architecture follows a clean separation: BaseTeleopModule provides calibration and delta computation, Quest3TeleopModule handles VR-specific WebSocket communication, and TeleopRobotController applies delta poses to robot commands.

Key Changes

  • Added base teleoperation framework with calibration, delta pose computation, and Rerun visualization
  • Implemented Quest3-specific module with FastAPI WebSocket server and HTTPS/SSL certificate generation
  • Created coordinate transformation pipeline from VR space to robot space
  • Added Float32 message type for gripper trigger values (0.0-1.0)
  • Built declarative blueprints for system composition with LCM transports
  • Included WebXR client HTML with controller tracking and X button calibration trigger

Issues Found

  • Syntax error in fastapi_server.py:403 - stop_async() calls disconnect() without required websocket parameter

Confidence Score: 4/5

  • Safe to merge after fixing the syntax error in stop_async() method
  • Well-structured implementation with clean architecture and comprehensive documentation. One critical syntax error prevents server shutdown from working correctly, but the core functionality is sound.
  • Fix dimos/teleop/quest3/control/fastapi_server.py - the stop_async() method has a syntax error that will cause runtime failure

Important Files Changed

Filename Overview
dimos/teleop/quest3/control/fastapi_server.py Added FastAPI WebSocket server with HTTPS support, SSL cert generation, and connection management. Contains syntax error in stop_async() method.
dimos/teleop/base/base_teleop_module.py Base module providing calibration, delta pose computation, and LCM publishing for all teleop devices.
dimos/teleop/quest3/quest3_teleop_module.py Quest3-specific implementation extending base module with WebSocket server integration and X button calibration.
dimos/teleop/quest3/control/tracking_processor.py Processes VR controller tracking data with coordinate frame transformations from VR space to robot space.
dimos/teleop/teleop_robot_controller.py Robot controller that auto-calibrates and applies delta poses to robot, converting VR movements to cartesian commands.

Sequence Diagram

sequenceDiagram
    participant Quest3 as Quest3 Browser
    participant FastAPI as FastAPI Server
    participant Q3Module as Quest3TeleopModule
    participant Controller as TeleopRobotController
    participant Driver as Robot Driver
    
    Quest3->>FastAPI: Open https://ip:8443 (WebXR)
    FastAPI->>Quest3: Serve index.html
    Quest3->>FastAPI: WebSocket handshake (role: teleop)
    FastAPI->>Quest3: handshake_ack
    
    Note over Quest3: User presses X button
    Quest3->>FastAPI: {type: "start_teleop"}
    FastAPI->>Q3Module: _handle_x_button("start_teleop")
    Q3Module->>Q3Module: calibrate_vr() - capture initial poses
    Q3Module->>FastAPI: {type: "teleop_started"}
    FastAPI->>Quest3: Success response
    
    loop Tracking Loop (60 FPS)
        Quest3->>FastAPI: Controller tracking data
        FastAPI->>Q3Module: _on_tracking_data(poses, grippers)
        Q3Module->>Q3Module: update_controller_poses()
        Q3Module->>Q3Module: _compute_and_publish_deltas()
        Q3Module->>Controller: Publish delta poses (LCM)
        
        Note over Controller: First delta triggers auto-calibration
        Controller->>Driver: get_state() RPC
        Driver->>Controller: Robot initial pose
        
        Controller->>Controller: Apply delta: target = initial + delta
        Controller->>Driver: Publish cartesian command
        Driver->>Driver: Execute robot motion
    end
    
    Note over Quest3: User presses X again
    Quest3->>FastAPI: {type: "stop_teleop"}
    FastAPI->>Q3Module: _handle_x_button("stop_teleop")
    Q3Module->>Q3Module: reset_calibration()
    Q3Module->>FastAPI: {type: "teleop_stopped"}
    FastAPI->>Quest3: Success response
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

16 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 403 to 410
# close all connections
await self.manager.disconnect()

"""Stop the FastAPI server asynchronously."""
if self.server:
logger.info("Stopping FastAPI server...")
self.server.should_exit = True
await asyncio.sleep(0.1) # Give time for graceful shutdown
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: await self.manager.disconnect() on line 404 is called without arguments, but ConnectionManager.disconnect() method requires a websocket parameter

Suggested change
# close all connections
await self.manager.disconnect()
"""Stop the FastAPI server asynchronously."""
if self.server:
logger.info("Stopping FastAPI server...")
self.server.should_exit = True
await asyncio.sleep(0.1) # Give time for graceful shutdown
async def stop_async(self) -> None:
"""Stop the FastAPI server asynchronously."""
if self.server:
logger.info("Stopping FastAPI server...")
self.server.should_exit = True
await asyncio.sleep(0.1) # Give time for graceful shutdown

@ruthwikdasyam
Copy link
Contributor Author

ruthwikdasyam commented Jan 8, 2026

Feedback required:

  • Added Float32.py at dimos/msgs/std_msgs as I need to publish a float over LCM. Fine? Or do we have any existing alternative msg type?

Adding Implementation status notes here - #892

  • Mentioning Implemented features and Next Steps

@spomichter spomichter changed the base branch from main to dev January 8, 2026 05:40
config: BaseTeleopConfig

# LCM Output topics
left_controller_delta: Out[PoseStamped] = None # type: ignore[assignment]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just output a transform and then the left and right PoseStamped objects, such that much of your operations / transformations on pose can be done via a type rather core implementation

Copy link
Contributor Author

@ruthwikdasyam ruthwikdasyam Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Planning to do something similar in the next PR. Having head pos along with left and right PostStamped.

Although, if I have the transforms, I won't have the VR_world to robot_base transform. I need to depend on relative motion of the controllers; thus, had it compute this way to keep it generalizable.
If go2, we can infer the same output as the magnitudes of velocities and move the robot. Without any frame dependency (for now)

# =========================================================================

@rpc
def calibrate_vr(self) -> dict[str, Any]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should definitely not be here. base teleop needs to work with any teleop, even an xbox controller or an iphone imu

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, its in the right place, typo with the naming, changing it.

return {"success": True, "message": "Calibration reset - recalibrate to resume"}

@rpc
def is_vr_calibrated(self) -> bool:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing mentioning VR should be in the generic teleop module

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar issue, renaming methods

Dictionary with status information
"""
return {
"is_calibrated": self._is_calibrated,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be an Enum

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

current_time = time.time()

# Left controller delta
if self.config.enable_left_arm and self._left_controller_initial is not None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

@spomichter spomichter force-pushed the quest_teleop_on_dev branch from 4568283 to 6e2d4e4 Compare January 8, 2026 13:59
@greptile-apps
Copy link

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@spomichter spomichter changed the base branch from dev to dev-legacy January 8, 2026 15:00
@spomichter spomichter changed the base branch from dev-legacy to dev January 8, 2026 15:01
@spomichter spomichter changed the base branch from dev to dev-legacy January 8, 2026 22:04
@spomichter spomichter force-pushed the quest_teleop_on_dev branch from 6e2d4e4 to e300084 Compare January 8, 2026 22:59
@spomichter spomichter force-pushed the quest_teleop_on_dev branch from e300084 to 350721e Compare January 8, 2026 23:18
ruthwikdasyam and others added 13 commits January 9, 2026 17:06
Former-commit-id: d713c7d
Former-commit-id: 1529848
Former-commit-id: f1097f8
Former-commit-id: f146f11
Former-commit-id: c347a33
Former-commit-id: 189e969
Former-commit-id: 4203caa
Former-commit-id: c6fb945
Former-commit-id: fed1dfd
Former-commit-id: 5171a03
Former-commit-id: b1ffc5e
Former-commit-id: ef0c1a9
Former-commit-id: cf57252
Former-commit-id: 577b386
Former-commit-id: e4e96ee
Former-commit-id: b973af9
logger.info(f"Captured controller {self._get_label(idx)} initial: {pose_obj}")
else:
return {
"success": False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs type no json shit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed json type returns

control_loop_hz: float = 50.0


class VRTeleopModule(BaseTeleopModule):
Copy link
Contributor

@spomichter spomichter Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be VRTeleopModule(BaseTeleopModule[VRTeleopModuleConfig]) or whatever the syntax is i forget

super().__init__(*args, **kwargs)

self._lcm_lock = threading.Lock()
self._lcm_controller_poses: dict[int, NDArray[np.float64] | None] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a type for ControllerPose cant just have a dict of random floats here bc need cleanoperations on this tyoe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then you can do stuff like vector3 type conversions there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ControllerPose msg type, shifted all math

Comment on lines 95 to 118
if self.vr_left_transform and self.vr_left_transform.transport:
self.vr_left_transform.subscribe(
lambda msg, idx=left_index: self._on_lcm_transform(idx, msg) # type: ignore[misc]
)

if self.vr_right_transform and self.vr_right_transform.transport:
self.vr_right_transform.subscribe(
lambda msg, idx=right_index: self._on_lcm_transform(idx, msg) # type: ignore[misc]
)

if self.vr_trigger_0 and self.vr_trigger_0.transport:
self.vr_trigger_0.subscribe(
lambda msg, idx=left_index: self._on_lcm_trigger(idx, msg) # type: ignore[misc]
)

if self.vr_trigger_1 and self.vr_trigger_1.transport:
self.vr_trigger_1.subscribe(
lambda msg, idx=right_index: self._on_lcm_trigger(idx, msg) # type: ignore[misc]
)

if self.teleop_enable and self.teleop_enable.transport:
self.teleop_enable.subscribe(self._on_lcm_teleop_enable)

logger.info("VR Teleoperation Module started")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean up can use match here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly pattern matching over a value, but can use loop

)


def _to_twist(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot be here needs to be in the type for the thing i said earlier we need which is ControllerPoseType which will wrap Vector3 and handle all conversion to vector3 very cleanly


return Pose(new_position, new_orientation)

def __sub__(self, other: Pose | PoseConvertable) -> Pose:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@leshy I assume there are issues with this due to other Pose operations. add for example has some checks

Copy link
Contributor

@leshy leshy Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be ok if it passes tests.. but this PoseConvertible is a bit goofy code I wrote very very early, probably we should be strict and only add and sub between Pose and not try and do fancy auto type conversions.

idk if he can easily remove PoseConvertable and pass tests from both add and sub if yes, great. if not, make sub only support Pose so that my wrong approach doesn't spread

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made sub only support Pose and it passes tests.

Comment on lines 89 to 96
controller_delta_0: Out[PoseStamped] = None # type: ignore
trigger_value_0: Out[Bool] = None # type: ignore
controller_delta_1: Out[PoseStamped] = None # type: ignore
trigger_value_1: Out[Bool] = None # type: ignore
controller_delta_2: Out[Twist] = None # type: ignore
trigger_value_2: Out[Bool] = None # type: ignore
controller_delta_3: Out[Twist] = None # type: ignore
trigger_value_3: Out[Bool] = None # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we are teleoping without controllers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no controllers mean no subscribers to read data from vr. Checks to make sure at least one output_type is specified

Comment on lines 33 to 36
("vr_left_transform", LCMTransform): LCMTransport("/vr_left_transform", LCMTransform),
("vr_right_transform", LCMTransform): LCMTransport("/vr_right_transform", LCMTransform),
("vr_trigger_0", Float32): LCMTransport("/vr_trigger_0", Float32),
("vr_trigger_1", Float32): LCMTransport("/vr_trigger_1", Float32),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the defaults, so you can delete these lines.

Also, if you rename teleop_enable to vr_teleop_enable in the Module, you don't need to change the topic here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually yeah. renamed and deleted mentions

Comment on lines 61 to 65
vr_left_transform: In[LCMTransform] = None # type: ignore[assignment]
vr_right_transform: In[LCMTransform] = None # type: ignore[assignment]
vr_trigger_0: In[Float32] = None # type: ignore[assignment]
vr_trigger_1: In[Float32] = None # type: ignore[assignment]
teleop_enable: In[Bool] = None # type: ignore[assignment] # X button calibration toggle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
vr_left_transform: In[LCMTransform] = None # type: ignore[assignment]
vr_right_transform: In[LCMTransform] = None # type: ignore[assignment]
vr_trigger_0: In[Float32] = None # type: ignore[assignment]
vr_trigger_1: In[Float32] = None # type: ignore[assignment]
teleop_enable: In[Bool] = None # type: ignore[assignment] # X button calibration toggle
vr_left_transform: In[LCMTransform]
vr_right_transform: In[LCMTransform]
vr_trigger_0: In[Float32]
vr_trigger_1: In[Float32]
teleop_enable: In[Bool] # X button calibration toggle

= None isn't needed anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, updating all declarations!

Comment on lines 84 to 91
controller_delta_0: Out[PoseStamped] = None # type: ignore
trigger_value_0: Out[Bool] = None # type: ignore
controller_delta_1: Out[PoseStamped] = None # type: ignore
trigger_value_1: Out[Bool] = None # type: ignore
controller_delta_2: Out[Twist] = None # type: ignore
trigger_value_2: Out[Bool] = None # type: ignore
controller_delta_3: Out[Twist] = None # type: ignore
trigger_value_3: Out[Bool] = None # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
controller_delta_0: Out[PoseStamped] = None # type: ignore
trigger_value_0: Out[Bool] = None # type: ignore
controller_delta_1: Out[PoseStamped] = None # type: ignore
trigger_value_1: Out[Bool] = None # type: ignore
controller_delta_2: Out[Twist] = None # type: ignore
trigger_value_2: Out[Bool] = None # type: ignore
controller_delta_3: Out[Twist] = None # type: ignore
trigger_value_3: Out[Bool] = None # type: ignore
controller_delta_0: Out[PoseStamped]
trigger_value_0: Out[Bool]
controller_delta_1: Out[PoseStamped]
trigger_value_1: Out[Bool]
controller_delta_2: Out[Twist]
trigger_value_2: Out[Bool]
controller_delta_3: Out[Twist]
trigger_value_3: Out[Bool]

Comment on lines 51 to 72
def compute_active_indices(output_types: list[type]) -> list[int]:
"""Compute active indices from output types.
Example:
[PoseStamped, Twist] → [0, 2]
[Twist, PoseStamped] → [2, 0]
[PoseStamped, PoseStamped] → [0, 1]
[Twist, Twist] → [2, 3]
"""
indices: list[int] = []
used_indices: set[int] = set()

for output_type in output_types:
available = OUTPUT_TYPE_INDICES.get(output_type, [])
for idx in available:
if idx not in used_indices:
indices.append(idx)
used_indices.add(idx)
break
else:
raise ValueError(f"No available index for output type {output_type.__name__}")

return indices
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring is quite puzzling.

My understanding now is that it maps to the first available output in controller_delta_0, ..., _3 in BaseTeleopModule. Is this correct?

If so, it should be a method on that class as it's specific to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as we can't declare them at run time - initiating all potential streams we need, which are mapped later using this method - it can be 2xPoseStamped, 2xTwist, or one each.

mm... Implementation didn't feel too traditional to put it inside the class.
But, yes, this is super specific to class, I will move it

]
for stream, handler in subscriptions:
if stream and stream.transport:
stream.subscribe(handler) # type: ignore[misc, arg-type]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
stream.subscribe(handler) # type: ignore[misc, arg-type]
self._disposables.add(Disposable(stream.subscribe(handler))) # type: ignore[misc, arg-type]

You also have to import Disposable

"""

@classmethod
def from_pose(cls, pose: Pose) -> ControllerPose:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'm not a fan of this.

If you need ways to convert Pose to PoseStamped or Twist, you can just write standalone functions for that. There's no need to introduce a new type but with no new fields.

Copy link
Contributor

@leshy leshy Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, also shouldn't use Pose at all but generate PoseStamped straight from your hardware, we always want the pose with the frame_id and timestamp.

I also don't understand exactly why we are converting pose to twist? We should probably be generating twist in some intelligent way when holding a button or something, otherwise scratching your butt would make a robot go insane?

Copy link
Contributor Author

@ruthwikdasyam ruthwikdasyam Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I can get timestamp and frame_id from the controller.

Reg Twist: I have start/stop (X button), so hoping this should be enough to control it well. Planning further to have spherical volume of say 5cm radius, around caliberated point - which would not send any twist pos (zeros), and moving controller further would start velocities.. something safe.

Copy link
Contributor Author

@ruthwikdasyam ruthwikdasyam Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, reg ControllerPose type...
As an alternative, I can have PoseStamped in place of ControllerPoseStamped (Now that we need to carry timestamps... It shall be ControllerPoseStamped) and use the 'to_twist' methods in utils. What do you suggest? @spomichter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted!
Replaced ControllerPose with Pose, Added standalone functions in utils/teleop_transform.py.
frame_id and timestamps, added as received from hardware.

Copy link
Contributor

@leshy leshy Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I still see ControllerPose file, this file shouldn't exist, geometry_msgs matches ros msgs, and ControllerPose isn't one

Copy link
Contributor Author

@ruthwikdasyam ruthwikdasyam Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did remove the file. I don't find it anywhere. Can you lmk where you see it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha it's gone, was some github stale diff issue


return Twist(linear=linear, angular=angular)

def __sub__(self, other: Pose | PoseConvertable) -> ControllerPose: # type: ignore[override]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you need this, but generally # type: ignore[override] is bad because it means you're not respecting the contract.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without -> ControllerPose the method returns a Pose. ignore is added as this overrides parents __sub__ with different return type.

Anyways, I have removed entire ControllerPose msg type now

from dimos_lcm.std_msgs import Float32 as LCMFloat32

try:
from std_msgs.msg import Float32 as ROSFloat32 # type: ignore[attr-defined]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have ros stuff in this? don't just delete, pls explain, I want to understand why I keep seeing this in PRs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned below, took reference from other message type classes. If we don't need this, should we remove it from all those msg types?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes no ros needed

self.data = data

@classmethod
def from_ros_msg(cls, ros_msg: ROSFloat32) -> "Float32":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you write this conversion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    @classmethod
    def from_ros_msg(cls, ros_msg: ROSBool) -> "Bool":
        """Create a Bool from a ROS std_msgs/Bool message.
    @classmethod
    def from_ros_msg(cls, ros_msg: ROSInt8) -> "Int8":
        """Create a Bool from a ROS std_msgs/Bool message.

Don't we want it? Int8, Bool types from std_msgs have this method. I assumed its a convention we follow

Copy link
Contributor

@leshy leshy Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why it seems so :) this is part of an older ros integration we are obsoleting

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file seems teleop specific? pls put it in your teleop dir

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are. Maybe I can add them at dimos/teleop/utils/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also seems like something that belongs in teleop dir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants