dexcontrol 0.2.12__py3-none-any.whl → 0.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. dexcontrol/__init__.py +17 -8
  2. dexcontrol/apps/dualsense_teleop_base.py +1 -1
  3. dexcontrol/comm/__init__.py +51 -0
  4. dexcontrol/comm/rtc.py +401 -0
  5. dexcontrol/comm/subscribers.py +329 -0
  6. dexcontrol/config/core/chassis.py +9 -4
  7. dexcontrol/config/core/hand.py +1 -0
  8. dexcontrol/config/sensors/cameras/__init__.py +1 -2
  9. dexcontrol/config/sensors/cameras/zed_camera.py +2 -2
  10. dexcontrol/config/sensors/vega_sensors.py +12 -18
  11. dexcontrol/config/vega.py +4 -1
  12. dexcontrol/core/arm.py +66 -42
  13. dexcontrol/core/chassis.py +142 -120
  14. dexcontrol/core/component.py +107 -58
  15. dexcontrol/core/hand.py +119 -86
  16. dexcontrol/core/head.py +22 -33
  17. dexcontrol/core/misc.py +331 -158
  18. dexcontrol/core/robot_query_interface.py +467 -0
  19. dexcontrol/core/torso.py +5 -9
  20. dexcontrol/robot.py +245 -574
  21. dexcontrol/sensors/__init__.py +1 -2
  22. dexcontrol/sensors/camera/__init__.py +0 -2
  23. dexcontrol/sensors/camera/base_camera.py +150 -0
  24. dexcontrol/sensors/camera/rgb_camera.py +68 -64
  25. dexcontrol/sensors/camera/zed_camera.py +140 -164
  26. dexcontrol/sensors/imu/chassis_imu.py +81 -62
  27. dexcontrol/sensors/imu/zed_imu.py +54 -43
  28. dexcontrol/sensors/lidar/rplidar.py +16 -20
  29. dexcontrol/sensors/manager.py +4 -14
  30. dexcontrol/sensors/ultrasonic.py +15 -28
  31. dexcontrol/utils/__init__.py +0 -11
  32. dexcontrol/utils/comm_helper.py +110 -0
  33. dexcontrol/utils/constants.py +1 -1
  34. dexcontrol/utils/error_code.py +2 -4
  35. dexcontrol/utils/os_utils.py +172 -4
  36. dexcontrol/utils/pb_utils.py +6 -28
  37. {dexcontrol-0.2.12.dist-info → dexcontrol-0.3.4.dist-info}/METADATA +16 -3
  38. dexcontrol-0.3.4.dist-info/RECORD +62 -0
  39. {dexcontrol-0.2.12.dist-info → dexcontrol-0.3.4.dist-info}/WHEEL +1 -1
  40. dexcontrol/config/sensors/cameras/luxonis_camera.py +0 -51
  41. dexcontrol/proto/dexcontrol_msg_pb2.py +0 -73
  42. dexcontrol/proto/dexcontrol_msg_pb2.pyi +0 -220
  43. dexcontrol/proto/dexcontrol_query_pb2.py +0 -77
  44. dexcontrol/proto/dexcontrol_query_pb2.pyi +0 -162
  45. dexcontrol/sensors/camera/luxonis_camera.py +0 -169
  46. dexcontrol/utils/motion_utils.py +0 -199
  47. dexcontrol/utils/rate_limiter.py +0 -172
  48. dexcontrol/utils/rtc_utils.py +0 -144
  49. dexcontrol/utils/subscribers/__init__.py +0 -52
  50. dexcontrol/utils/subscribers/base.py +0 -281
  51. dexcontrol/utils/subscribers/camera.py +0 -332
  52. dexcontrol/utils/subscribers/decoders.py +0 -88
  53. dexcontrol/utils/subscribers/generic.py +0 -110
  54. dexcontrol/utils/subscribers/imu.py +0 -175
  55. dexcontrol/utils/subscribers/lidar.py +0 -172
  56. dexcontrol/utils/subscribers/protobuf.py +0 -111
  57. dexcontrol/utils/subscribers/rtc.py +0 -316
  58. dexcontrol/utils/zenoh_utils.py +0 -122
  59. dexcontrol-0.2.12.dist-info/RECORD +0 -75
  60. {dexcontrol-0.2.12.dist-info → dexcontrol-0.3.4.dist-info}/licenses/LICENSE +0 -0
@@ -8,21 +8,21 @@
8
8
  # 2. Commercial License
9
9
  # For commercial licensing terms, contact: contact@dexmate.ai
10
10
 
11
- """Ultrasonic sensor implementations using Zenoh subscribers.
11
+ """Ultrasonic sensor implementations using DexComm subscribers.
12
12
 
13
- This module provides ultrasonic sensor classes that use the generic
14
- subscriber for distance measurements.
13
+ This module provides ultrasonic sensor classes that use DexComm's
14
+ Raw API for distance measurements.
15
15
  """
16
16
 
17
17
  import numpy as np
18
- import zenoh
18
+ from dexcomm.serialization import deserialize_protobuf
19
+ from dexcomm.serialization.protobuf import control_msg_pb2
19
20
 
20
- from dexcontrol.proto import dexcontrol_msg_pb2
21
- from dexcontrol.utils.subscribers import ProtobufZenohSubscriber
21
+ from dexcontrol.comm import create_subscriber
22
22
 
23
23
 
24
24
  class UltrasonicSensor:
25
- """Ultrasonic sensor using Zenoh subscriber.
25
+ """Ultrasonic sensor using DexComm subscriber.
26
26
 
27
27
  This sensor provides distance measurements from ultrasonic sensors
28
28
  """
@@ -30,24 +30,18 @@ class UltrasonicSensor:
30
30
  def __init__(
31
31
  self,
32
32
  configs,
33
- zenoh_session: zenoh.Session,
34
33
  ) -> None:
35
34
  """Initialize the ultrasonic sensor.
36
35
 
37
36
  Args:
38
37
  configs: Configuration for the ultrasonic sensor.
39
- zenoh_session: Active Zenoh session for communication.
40
38
  """
41
39
  self._name = configs.name
42
40
 
43
- # Create the generic subscriber with JSON decoder
44
- self._subscriber = ProtobufZenohSubscriber(
41
+ # Create the protobuf subscriber using our clean DexComm integration
42
+ self._subscriber = create_subscriber(
45
43
  topic=configs.topic,
46
- zenoh_session=zenoh_session,
47
- message_type=dexcontrol_msg_pb2.UltrasonicState,
48
- name=f"{self._name}_subscriber",
49
- enable_fps_tracking=configs.enable_fps_tracking,
50
- fps_log_interval=configs.fps_log_interval,
44
+ deserializer=lambda data: deserialize_protobuf(data, control_msg_pb2.UltrasonicState),
51
45
  )
52
46
 
53
47
 
@@ -61,7 +55,8 @@ class UltrasonicSensor:
61
55
  Returns:
62
56
  True if receiving data, False otherwise.
63
57
  """
64
- return self._subscriber.is_active()
58
+ data = self._subscriber.get_latest()
59
+ return data is not None
65
60
 
66
61
  def wait_for_active(self, timeout: float = 5.0) -> bool:
67
62
  """Wait for the ultrasonic sensor to start receiving data.
@@ -72,7 +67,8 @@ class UltrasonicSensor:
72
67
  Returns:
73
68
  True if sensor becomes active, False if timeout is reached.
74
69
  """
75
- return self._subscriber.wait_for_active(timeout)
70
+ msg = self._subscriber.wait_for_message(timeout)
71
+ return msg is not None
76
72
 
77
73
  def get_obs(self) -> np.ndarray | None:
78
74
  """Get observation data for the ultrasonic sensor.
@@ -84,7 +80,7 @@ class UltrasonicSensor:
84
80
  Numpy array of distances in meters with shape (4,) in the order:
85
81
  [front_left, front_right, back_left, back_right].
86
82
  """
87
- data = self._subscriber.get_latest_data()
83
+ data = self._subscriber.get_latest()
88
84
  if data is not None:
89
85
  obs = [
90
86
  data.front_left,
@@ -96,15 +92,6 @@ class UltrasonicSensor:
96
92
 
97
93
  return None
98
94
 
99
- @property
100
- def fps(self) -> float:
101
- """Get the current FPS measurement.
102
-
103
- Returns:
104
- Current frames per second measurement.
105
- """
106
- return self._subscriber.fps
107
-
108
95
  @property
109
96
  def name(self) -> str:
110
97
  """Get the sensor name.
@@ -7,14 +7,3 @@
7
7
  #
8
8
  # 2. Commercial License
9
9
  # For commercial licensing terms, contact: contact@dexmate.ai
10
-
11
- from .subscribers import (
12
- BaseZenohSubscriber,
13
- DecoderFunction,
14
- GenericZenohSubscriber,
15
- ProtobufZenohSubscriber,
16
- json_decoder,
17
- protobuf_decoder,
18
- raw_bytes_decoder,
19
- string_decoder,
20
- )
@@ -0,0 +1,110 @@
1
+ # Copyright (C) 2025 Dexmate Inc.
2
+ #
3
+ # This software is dual-licensed:
4
+ #
5
+ # 1. GNU Affero General Public License v3.0 (AGPL-3.0)
6
+ # See LICENSE-AGPL for details
7
+ #
8
+ # 2. Commercial License
9
+ # For commercial licensing terms, contact: contact@dexmate.ai
10
+
11
+ """Communication helper utilities for DexControl using DexComm.
12
+
13
+ This module provides simple helper functions for DexControl's communication
14
+ needs using the DexComm library's Raw API.
15
+ """
16
+
17
+ import json
18
+ import time
19
+ from pathlib import Path
20
+
21
+ from dexcomm import ZenohConfig, call_service
22
+ from dexcomm.serialization import deserialize_json
23
+ from loguru import logger
24
+
25
+ import dexcontrol
26
+ from dexcontrol.utils.os_utils import resolve_key_name
27
+
28
+
29
+ def get_robot_config() -> ZenohConfig:
30
+ """Get DexComm configuration for robot communication.
31
+
32
+ This checks for the robot's Zenoh configuration file and creates
33
+ appropriate DexComm config.
34
+
35
+ Returns:
36
+ ZenohConfig instance configured for the robot.
37
+ """
38
+ config_path = dexcontrol.COMM_CFG_PATH
39
+
40
+ if config_path and config_path != Path("/tmp/no_config") and config_path.exists():
41
+ logger.debug(f"Loading config from: {config_path}")
42
+ return ZenohConfig.from_file(config_path)
43
+ else:
44
+ logger.debug("No config file found, using default peer mode")
45
+ return ZenohConfig.default_peer()
46
+
47
+
48
+ def get_zenoh_config_path() -> Path | None:
49
+ """Get robot config only if not using default SessionManager.
50
+
51
+ DexComm's SessionManager will automatically use the config from
52
+ environment variables if available, so we only need to provide
53
+ config explicitly if we have a specific robot config file.
54
+
55
+ Returns:
56
+ path to the config file
57
+ """
58
+ config_path = dexcontrol.COMM_CFG_PATH
59
+ return config_path
60
+
61
+
62
+ def query_json_service(
63
+ topic: str,
64
+ timeout: float = 2.0,
65
+ max_retries: int = 1,
66
+ retry_delay: float = 0.5,
67
+ ) -> dict | None:
68
+ """Query for JSON information using DexComm with retry logic.
69
+
70
+ Args:
71
+ topic: Topic to query (will be resolved with robot namespace).
72
+ timeout: Maximum time to wait for a response in seconds.
73
+ max_retries: Maximum number of retry attempts.
74
+ retry_delay: Initial delay between retries (doubles each retry).
75
+
76
+ Returns:
77
+ Dictionary containing the parsed JSON response if successful, None otherwise.
78
+ """
79
+ resolved_topic = resolve_key_name(topic)
80
+ logger.debug(f"Querying topic: {resolved_topic}")
81
+
82
+ current_delay = retry_delay
83
+ for attempt in range(max_retries + 1):
84
+ try:
85
+ data = call_service(
86
+ resolved_topic,
87
+ timeout=timeout,
88
+ config=get_zenoh_config_path(),
89
+ request_serializer=None,
90
+ response_deserializer=deserialize_json,
91
+ )
92
+
93
+ if data:
94
+ logger.debug(f"Successfully received JSON data from {resolved_topic}")
95
+ return data
96
+
97
+ except json.JSONDecodeError as e:
98
+ logger.warning(f"Failed to parse JSON response from {resolved_topic}: {e}")
99
+ except Exception as e:
100
+ logger.warning(
101
+ f"Query failed for {resolved_topic} (attempt {attempt + 1}/{max_retries + 1}): {e}"
102
+ )
103
+
104
+ if attempt < max_retries:
105
+ logger.debug(f"Retrying in {current_delay:.1f} seconds...")
106
+ time.sleep(current_delay)
107
+ current_delay *= 2 # Exponential backoff
108
+
109
+ logger.error(f"Failed to query {resolved_topic} after {max_retries + 1} attempts")
110
+ return None
@@ -16,7 +16,7 @@ from typing import Final
16
16
  ROBOT_NAME_ENV_VAR: Final[str] = "ROBOT_NAME"
17
17
 
18
18
  # Environment variable for communication config path
19
- COMM_CFG_PATH_ENV_VAR: Final[str] = "DEXMATE_COMM_CFG_PATH"
19
+ COMM_CFG_PATH_ENV_VAR: Final[str] = "ZENOH_CONFIG"
20
20
 
21
21
  # Environment variable to disable heartbeat monitoring
22
22
  DISABLE_HEARTBEAT_ENV_VAR: Final[str] = "DEXCONTROL_DISABLE_HEARTBEAT"
@@ -10,8 +10,6 @@
10
10
 
11
11
  """Error code interpretation utilities for robot components."""
12
12
 
13
- from typing import Dict
14
-
15
13
 
16
14
  class ErrorCodeInterpreter:
17
15
  """Interprets error codes for different robot components."""
@@ -139,7 +137,7 @@ class ErrorCodeInterpreter:
139
137
 
140
138
  @classmethod
141
139
  def _interpret_bitmask_errors(
142
- cls, error_code: int, error_dict: Dict[int, str]
140
+ cls, error_code: int, error_dict: dict[int, str]
143
141
  ) -> str:
144
142
  """
145
143
  Interpret bitmask-style error codes.
@@ -220,7 +218,7 @@ def get_error_description(component: str, error_code: int) -> str:
220
218
  return ErrorCodeInterpreter.interpret_error(component, error_code)
221
219
 
222
220
 
223
- def get_multiple_errors(components_errors: Dict[str, int]) -> Dict[str, str]:
221
+ def get_multiple_errors(components_errors: dict[str, int]) -> dict[str, str]:
224
222
  """
225
223
  Get error descriptions for multiple components.
226
224
 
@@ -12,8 +12,12 @@
12
12
 
13
13
  import os
14
14
  import re
15
- from typing import Final
15
+ from importlib.metadata import version
16
+ from typing import Any, Final
16
17
 
18
+ from loguru import logger
19
+
20
+ import dexcontrol
17
21
  from dexcontrol.utils.constants import ROBOT_NAME_ENV_VAR
18
22
 
19
23
 
@@ -48,11 +52,175 @@ def get_robot_model() -> str:
48
52
  raise ValueError(
49
53
  f"Robot name is not set, please set the environment variable {ROBOT_NAME_ENV_VAR}"
50
54
  )
51
- if not re.match(r"^dm/[a-zA-Z0-9]{12}-(?:\d+|rc\d+)$", robot_name):
55
+ if not re.match(r"^dm/[a-zA-Z0-9]{12}-(?:\d+p?|rc\d+)$", robot_name):
52
56
  raise ValueError(f"Robot name is not in the correct format: {robot_name}")
53
-
54
57
  robot_model_abb = robot_name.split("/")[-1].split("-")[0][:2]
55
58
  if robot_model_abb not in robot_model_abb_mapping:
56
59
  raise ValueError(f"Unknown robot model: {robot_model_abb}")
57
- model = robot_model_abb_mapping[robot_model_abb] + "-" + robot_name.split("-")[-1]
60
+ model = (
61
+ robot_model_abb_mapping[robot_model_abb] + "-" + robot_name.split("-")[-1][0]
62
+ )
58
63
  return model
64
+
65
+
66
+ def check_version_compatibility(version_info: dict[str, Any]) -> None:
67
+ """Check version compatibility between client and server.
68
+
69
+ This function uses the new JSON-based version interface to:
70
+ 1. Compare client library version with server's minimum required version
71
+ 2. Check server component versions for compatibility
72
+ 3. Provide clear guidance for version mismatches
73
+
74
+ Args:
75
+ version_info: Dictionary containing version information from get_version_info()
76
+ show_warnings: Whether to show warning messages (default: True)
77
+ """
78
+ validate_client_version(version_info)
79
+ validate_server_version(version_info)
80
+
81
+
82
+ def validate_client_version(version_info: dict[str, Any]) -> None:
83
+ """Validate client library version against server requirements.
84
+
85
+ Args:
86
+ version_info: Dictionary containing server and client version information.
87
+ """
88
+
89
+ client_info = version_info.get("client", {})
90
+ min_required_version = client_info.get("minimal_version")
91
+
92
+ if not min_required_version:
93
+ logger.debug("No minimum version requirement from server")
94
+ return
95
+
96
+ # Get current library version using importlib.metadata
97
+ current_version = version("dexcontrol")
98
+
99
+ if current_version == "unknown":
100
+ logger.warning("Could not determine current library version")
101
+ return
102
+
103
+ # Compare versions
104
+ comparison = compare_versions(current_version, min_required_version)
105
+
106
+ if comparison < 0:
107
+ show_version_upgrade_warning(current_version, min_required_version)
108
+
109
+
110
+ def show_version_upgrade_warning(current: str, required: str) -> None:
111
+ """Display version upgrade warning to user.
112
+
113
+ Args:
114
+ current: Current library version
115
+ required: Required minimum version
116
+ """
117
+ logger.error(
118
+ f"🚨 CLIENT VERSION TOO OLD! 🚨\n"
119
+ f"Current library version: {current}\n"
120
+ f"Minimum required version: {required}\n"
121
+ f"\n"
122
+ f"⚠️ Your dexcontrol library is outdated and may not work correctly!\n"
123
+ f"📦 Please update your library using: pip install --upgrade dexcontrol\n"
124
+ )
125
+
126
+
127
+ def validate_server_version(version_info: dict[str, Any]) -> None:
128
+ """Validate server software versions against minimum requirements.
129
+
130
+ Args:
131
+ version_info: Dictionary containing server and client version information.
132
+ """
133
+ server_info = version_info.get("server", {})
134
+
135
+ if not server_info:
136
+ logger.debug("No server version information available")
137
+ return
138
+
139
+ # Check each component's software version
140
+ soc_info = server_info.get("soc", {})
141
+ software_version = soc_info.get("software_version", {})
142
+ if software_version is not None:
143
+ software_version_int = int(software_version)
144
+ if software_version_int < dexcontrol.MIN_SOC_SOFTWARE_VERSION:
145
+ show_server_version_warning(
146
+ [("soc", software_version_int)], dexcontrol.MIN_SOC_SOFTWARE_VERSION
147
+ )
148
+
149
+
150
+ def show_server_version_warning(
151
+ components: list[tuple[str, int]], min_version: int
152
+ ) -> None:
153
+ """Display server version warning to user.
154
+
155
+ Args:
156
+ components: List of (component_name, version) tuples for components below minimum.
157
+ min_version: Minimum required server software version.
158
+ """
159
+ components_str = "\n".join(
160
+ f" - {name}: version {version}" for name, version in components
161
+ )
162
+
163
+ logger.error(
164
+ f"🚨 SERVER VERSION TOO OLD! 🚨\n"
165
+ f"The following server components are below minimum version {min_version}:\n"
166
+ f"{components_str}\n"
167
+ f"\n"
168
+ f"⚠️ Your robot's firmware may be outdated and some features may not work correctly!\n"
169
+ f"📦 Please contact your robot admin or check https://github.com/dexmate-ai/vega-firmware.\n"
170
+ )
171
+
172
+
173
+ def compare_versions(version1: str, version2: str) -> int:
174
+ """Compare two semantic version strings.
175
+
176
+ Args:
177
+ version1: First version string (e.g., "1.2.3")
178
+ version2: Second version string (e.g., "1.1.0")
179
+
180
+ Returns:
181
+ -1 if version1 < version2
182
+ 0 if version1 == version2
183
+ 1 if version1 > version2
184
+ """
185
+ try:
186
+ # Clean version strings (remove 'v' prefix, handle pre-release suffixes)
187
+ def clean_version(v: str) -> list[int]:
188
+ v = v.strip().lower()
189
+ if v.startswith("v"):
190
+ v = v[1:]
191
+ # Split by dots and take only numeric parts
192
+ parts = v.split(".")
193
+ numeric_parts = []
194
+ for part in parts:
195
+ # Remove any non-numeric suffixes (like -alpha, -rc1, etc.)
196
+ numeric_part = ""
197
+ for char in part:
198
+ if char.isdigit():
199
+ numeric_part += char
200
+ else:
201
+ break
202
+ if numeric_part:
203
+ numeric_parts.append(int(numeric_part))
204
+ return numeric_parts
205
+
206
+ parts1 = clean_version(version1)
207
+ parts2 = clean_version(version2)
208
+
209
+ # Pad shorter version with zeros
210
+ max_len = max(len(parts1), len(parts2))
211
+ parts1.extend([0] * (max_len - len(parts1)))
212
+ parts2.extend([0] * (max_len - len(parts2)))
213
+
214
+ # Compare part by part
215
+ for p1, p2 in zip(parts1, parts2):
216
+ if p1 < p2:
217
+ return -1
218
+ elif p1 > p2:
219
+ return 1
220
+
221
+ return 0
222
+
223
+ except Exception as e:
224
+ logger.debug(f"Version comparison error: {e}")
225
+ # Fallback to string comparison
226
+ return -1 if version1 < version2 else (1 if version1 > version2 else 0)
@@ -13,35 +13,13 @@
13
13
  from enum import Enum
14
14
  from typing import Any, Literal
15
15
 
16
- from dexcontrol.proto import dexcontrol_query_pb2
16
+ from dexcomm.serialization.protobuf import control_query_pb2
17
17
 
18
18
  TYPE_SOFTWARE_VERSION = dict[
19
19
  Literal["hardware_version", "software_version", "main_hash", "compile_time"], Any
20
20
  ]
21
21
 
22
22
 
23
- def software_version_to_dict(
24
- version_msg: dexcontrol_query_pb2.SoftwareVersion,
25
- ) -> dict[str, TYPE_SOFTWARE_VERSION]:
26
- """Convert a SoftwareVersion protobuf message to a dictionary.
27
-
28
- Args:
29
- version_msg: SoftwareVersion protobuf message.
30
-
31
- Returns:
32
- Dictionary containing version information with component names as keys.
33
- """
34
- return {
35
- key: {
36
- "hardware_version": value.hardware_version,
37
- "software_version": value.software_version,
38
- "main_hash": value.main_hash,
39
- "compile_time": value.compile_time,
40
- }
41
- for key, value in version_msg.firmware_version.items()
42
- }
43
-
44
-
45
23
  class ComponentStatus(Enum):
46
24
  """Enum representing the status of a component."""
47
25
 
@@ -50,7 +28,7 @@ class ComponentStatus(Enum):
50
28
  ERROR = 2
51
29
 
52
30
 
53
- def status_to_enum(status: dexcontrol_query_pb2.ComponentStatus) -> ComponentStatus:
31
+ def status_to_enum(status: control_query_pb2.ComponentStatus) -> ComponentStatus:
54
32
  """Convert a ComponentStatus protobuf message to a ComponentStatus enum.
55
33
 
56
34
  Args:
@@ -63,9 +41,9 @@ def status_to_enum(status: dexcontrol_query_pb2.ComponentStatus) -> ComponentSta
63
41
  ValueError: If the status value is not recognized.
64
42
  """
65
43
  status_map = {
66
- dexcontrol_query_pb2.ComponentStatus.NORMAL: ComponentStatus.NORMAL,
67
- dexcontrol_query_pb2.ComponentStatus.NA: ComponentStatus.NA,
68
- dexcontrol_query_pb2.ComponentStatus.ERROR: ComponentStatus.ERROR,
44
+ control_query_pb2.ComponentStatus.NORMAL: ComponentStatus.NORMAL,
45
+ control_query_pb2.ComponentStatus.NA: ComponentStatus.NA,
46
+ control_query_pb2.ComponentStatus.ERROR: ComponentStatus.ERROR,
69
47
  }
70
48
 
71
49
  if status not in status_map:
@@ -75,7 +53,7 @@ def status_to_enum(status: dexcontrol_query_pb2.ComponentStatus) -> ComponentSta
75
53
 
76
54
 
77
55
  def status_to_dict(
78
- status_msg: dexcontrol_query_pb2.ComponentStates,
56
+ status_msg: control_query_pb2.ComponentStates,
79
57
  ) -> dict[str, dict[str, Any]]:
80
58
  """Convert a ComponentStates protobuf message to a dictionary.
81
59
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dexcontrol
3
- Version: 0.2.12
3
+ Version: 0.3.4
4
4
  Summary: A Python library of Sensing and Control for Dexmate's Robot
5
5
  Project-URL: Repository, https://github.com/dexmate-ai/dexcontrol
6
6
  Author-email: Dexmate <contact@dexmate.ai>
@@ -202,13 +202,13 @@ Classifier: Programming Language :: Python :: 3.13
202
202
  Classifier: Typing :: Typed
203
203
  Requires-Python: <3.14,>=3.10
204
204
  Requires-Dist: aiortc
205
+ Requires-Dist: dexcomm>=0.1.18
205
206
  Requires-Dist: eclipse-zenoh>=1.2.0
206
207
  Requires-Dist: hydra-core==1.3.2
207
208
  Requires-Dist: jaxtyping>=0.2.38
208
209
  Requires-Dist: loguru>=0.7.3
209
210
  Requires-Dist: numpy>=1.26.4
210
211
  Requires-Dist: opencv-python>=4.11.0
211
- Requires-Dist: protobuf>=6.31.0
212
212
  Requires-Dist: rich
213
213
  Requires-Dist: uvloop>=0.17.0; sys_platform != 'win32'
214
214
  Requires-Dist: websockets
@@ -231,7 +231,7 @@ Requires-Dist: dexmotion>=0.2.1; extra == 'example'
231
231
  Requires-Dist: dualsense-controller>=0.3.1; extra == 'example'
232
232
  Requires-Dist: matplotlib>=3.8.0; extra == 'example'
233
233
  Requires-Dist: pytransform3d==3.13.0; extra == 'example'
234
- Requires-Dist: ruckig; extra == 'example'
234
+ Requires-Dist: scipy>=1.16.1; extra == 'example'
235
235
  Requires-Dist: tyro; extra == 'example'
236
236
  Description-Content-Type: text/markdown
237
237
 
@@ -253,6 +253,19 @@ To run the examples in this repo, you can try:
253
253
  pip install dexcontrol[example]
254
254
  ```
255
255
 
256
+ ## ⚠️ Version Compatibility
257
+
258
+ **Important:** `dexcontrol >= 0.3.0` requires robot firmware with SoC version `286` or higher.
259
+
260
+ **Before upgrading, check your current firmware version:**
261
+ ```shell
262
+ dextop firmware info
263
+ ```
264
+
265
+ If your firmware is outdated, please update it before installing the new version to ensure full compatibility. Please contact the Dexmate team if you do not know how to do it.
266
+
267
+ **📋 See [CHANGELOG.md](./CHANGELOG.md) for detailed release notes and version history.**
268
+
256
269
  ## 📄 Licensing
257
270
 
258
271
  This project is **dual-licensed**:
@@ -0,0 +1,62 @@
1
+ dexcontrol/__init__.py,sha256=SqdTD3v-qOX6oOGNUcLWEzc5EzY_morOB3TEs-7yv6Y,1955
2
+ dexcontrol/robot.py,sha256=mXezG10UMVBYynE-WD5_XBOjvnjVBhYZjarP_W09TPs,40471
3
+ dexcontrol/apps/dualsense_teleop_base.py,sha256=HJ5aB9zaXdEUQtkd8Vrd0dQqYZrKH1nEjcSGSlDpYD4,12686
4
+ dexcontrol/comm/__init__.py,sha256=YV8Sfv15vuUUqR2lg_H97RCHWUaOblxbI5NgigP4kzc,1272
5
+ dexcontrol/comm/rtc.py,sha256=I5CQz2RuSdE4MyKYraDoQ1E1MSbyYA-rp1kmjxRX9T0,13072
6
+ dexcontrol/comm/subscribers.py,sha256=3rD_YUC5DH3rH_JN8iGjgIkblXcl_pI51dVQ4iQOQQc,8900
7
+ dexcontrol/config/__init__.py,sha256=UVLNpzGD14e8g68rUZFXTh0B7FRx6uS0Eg_MecjinYM,520
8
+ dexcontrol/config/vega.py,sha256=Uh14vBOZoMAmFXQgjh-IK9x_W0j8YvqgUsoDNHx1ZsE,8443
9
+ dexcontrol/config/core/__init__.py,sha256=Ym2R1hr1iMKQuXcg16BpZfQtTb0hQ5Q7smUIMlwKfho,637
10
+ dexcontrol/config/core/arm.py,sha256=5hN1dQMe2H6oufaqgtZqx9vuB969DxM26leJqPsKEiA,1471
11
+ dexcontrol/config/core/chassis.py,sha256=2FjyFujg2q7aw8J9BklNM7eeLxscY9BSTlBvz-tLwOM,1092
12
+ dexcontrol/config/core/hand.py,sha256=r6XVyGCuwv7MFmaMLn7l3iPZUH376NZSmtsfLnznAgw,1033
13
+ dexcontrol/config/core/head.py,sha256=SLwZE-lYEOk8XAmW-Ex7VkLF2w5HLItwsA3Dc7n5FtE,1061
14
+ dexcontrol/config/core/misc.py,sha256=zHkJ144b6kbmMFE63wy_fgfo_6V-4XmM19hr6BUtQ0Y,1567
15
+ dexcontrol/config/core/torso.py,sha256=DCTFgN1_Gn4THkKy23sIHOedACQtQ7cET3g4AmkVPco,1460
16
+ dexcontrol/config/sensors/__init__.py,sha256=bYPMLxbbn5QeuPyA6OPGDS2JTYpnVvaZJT8PeILFjQY,252
17
+ dexcontrol/config/sensors/vega_sensors.py,sha256=m_Z5ywKxGBvP7pUr6dxLNnGEPI2jWt2hDtxln4uFnY8,2675
18
+ dexcontrol/config/sensors/cameras/__init__.py,sha256=GmwRW9ovZ_JcpD2QmzTO_in_LRBoRDorjMVGY6XgGI8,383
19
+ dexcontrol/config/sensors/cameras/rgb_camera.py,sha256=MN4SjyZlfbrQ3JKDDkT8HhC0Aiyc0bWfDLt4ik0Xcvs,1448
20
+ dexcontrol/config/sensors/cameras/zed_camera.py,sha256=UGAjXlOu5E0M3vjMSIOqdvNjK8mhx52OIDgs5RksqUc,1895
21
+ dexcontrol/config/sensors/imu/__init__.py,sha256=fW-DlevCvf_W8HV_fvLe9yIe-XL5op2mggoTKh-6fGQ,328
22
+ dexcontrol/config/sensors/imu/chassis_imu.py,sha256=3OlTTBH6k1QGM5c5bcg8NL3XUXzYA8gCLM8lpCq2KFM,559
23
+ dexcontrol/config/sensors/imu/zed_imu.py,sha256=y-dPI-XS6Kyq0WOf0wwuc2BgVnMN2hwCMxb0Vmwt4O4,550
24
+ dexcontrol/config/sensors/lidar/__init__.py,sha256=j8vFkF675Z7zKtCztJcyG7oSA_XqrD8OeQLEK0GACug,288
25
+ dexcontrol/config/sensors/lidar/rplidar.py,sha256=ybuT_f1ADWF3oGH1gi6D2F80TbJEm4vbm68Fe108OAA,541
26
+ dexcontrol/config/sensors/ultrasonic/__init__.py,sha256=-q83RhIMZJGVFVPYaA4hOugoG6wZw8EL6wJg7-HTSxU,294
27
+ dexcontrol/config/sensors/ultrasonic/ultrasonic.py,sha256=7b4dm1QOhy5_5RFVpY-frXZyDzqok0K1u7ed9gf3PL0,552
28
+ dexcontrol/core/__init__.py,sha256=bYPMLxbbn5QeuPyA6OPGDS2JTYpnVvaZJT8PeILFjQY,252
29
+ dexcontrol/core/arm.py,sha256=iwAFy6C7fxwp8t5ieJNMq1Iulq-OB2L0mzpQCEgl9W0,16211
30
+ dexcontrol/core/chassis.py,sha256=vllwQQB7DUere4Y77qrKhOa_GAckPXmNlW_HfPkz9YE,24188
31
+ dexcontrol/core/component.py,sha256=qXhGsNwa9EHO5DaGybylgFoGJmUUppNznH5JHmH08sQ,36296
32
+ dexcontrol/core/hand.py,sha256=P_UGAqT71j_9k_wP_YQZep_cU5bR0loIxdRb3IH42w8,9595
33
+ dexcontrol/core/head.py,sha256=axqxiqdec9TDpYCt9_QSvhEu2Dy3bf2n196FGkpt710,9925
34
+ dexcontrol/core/misc.py,sha256=AjOgLRSvQqxGC6VsJiewtkOchzawpqW3VZ7eTrNt8iI,30867
35
+ dexcontrol/core/robot_query_interface.py,sha256=IiIpPNQ9uMopuo0z4m0ErrQtbY8RtwBOkj4dLPXOLlM,17628
36
+ dexcontrol/core/torso.py,sha256=XSNu5O8DmbtBVVcJtGr6JFdYrs8vgNFkJkK1gAC43II,8767
37
+ dexcontrol/sensors/__init__.py,sha256=Dp06cuO_3xC6i4u5rHqfK5NqlIC5kaCue_bAtTC6JEE,960
38
+ dexcontrol/sensors/manager.py,sha256=uhP_matbXMzG_HQv9fmcGbw_rm9xloMoKUeNe3KBmTU,6590
39
+ dexcontrol/sensors/ultrasonic.py,sha256=uFiPl0js49PFcx9yLSUesFdm1U9IsR8KCtoDtEn1E6k,2890
40
+ dexcontrol/sensors/camera/__init__.py,sha256=Vwe98I4Lvdv3F2UslOzKkeUkt5Rl2jSqbKlU6gIBeF0,609
41
+ dexcontrol/sensors/camera/base_camera.py,sha256=flmpoLP8rC-NZg7TFHFLqXJNHRT45jwqsVPk-L1G6oc,4808
42
+ dexcontrol/sensors/camera/rgb_camera.py,sha256=Mcd51BXOBatfK5fcIjsNuJsClXhdnVR2ck-wgyJYKnQ,6363
43
+ dexcontrol/sensors/camera/zed_camera.py,sha256=BYLAlxuHSZKTVpHMP2eKwWfbHOxWXhT18VG3aXAN0sY,14164
44
+ dexcontrol/sensors/imu/__init__.py,sha256=bBC7_NSLJ5qLMvUYu2-9yXKO2bRpQLC0HyywBwnbM0A,768
45
+ dexcontrol/sensors/imu/chassis_imu.py,sha256=RzaY6VhhGEjzrFNxDcXL43SdIwoozW5PctKdUxfc_2k,5565
46
+ dexcontrol/sensors/imu/zed_imu.py,sha256=rGT0S2TIj0JGdlJMQKNldtCclOYunCmS0xdzvjAhq9A,5628
47
+ dexcontrol/sensors/lidar/__init__.py,sha256=frF16HmeQnfbvH0dVJ4pPjD4TySF13wCk-O9L3Memeg,317
48
+ dexcontrol/sensors/lidar/rplidar.py,sha256=MrmxP99-YsfoRlYUZTCcmvNbF-YCOLynhoe2tCMpDnE,4191
49
+ dexcontrol/utils/__init__.py,sha256=bYPMLxbbn5QeuPyA6OPGDS2JTYpnVvaZJT8PeILFjQY,252
50
+ dexcontrol/utils/comm_helper.py,sha256=PDB_Qyo39BdtR0d5-k0zPkAq6nwGV9eGMMXo3i7CFDw,3541
51
+ dexcontrol/utils/constants.py,sha256=uzR6AW5LNU3Otmf0G8M4yg-0iaHLhKtJ5e-OPuqxr9g,783
52
+ dexcontrol/utils/error_code.py,sha256=MQJHfM76YgRmE_7rAj0qSSHQf9P71oRUBa50m-3-Pwc,7296
53
+ dexcontrol/utils/io_utils.py,sha256=4TYV33ufECo8fuQivrZR9vtSdwWYUiPvpAUSneEzOOs,850
54
+ dexcontrol/utils/os_utils.py,sha256=LBye18I-I7mDYuTf_zDB5k-KQAx7Pt11ibgyH5F36mc,7586
55
+ dexcontrol/utils/pb_utils.py,sha256=fMJJQgfCPtGlij0KdLHnPjElW0_DCwPpuSM2VMqhrK4,2504
56
+ dexcontrol/utils/timer.py,sha256=1sOYYEapbZ5aBqJwknClsxgjDx0FDRQuGEdcTGnYTCI,3948
57
+ dexcontrol/utils/trajectory_utils.py,sha256=TURFb0DeDey0416z4L7AXiWcKJYsgg_bB5AE_JPSpXY,1879
58
+ dexcontrol/utils/viz_utils.py,sha256=rKtZfu32-9D9CS4cSiil-oLub_MiKTJV6hURvJbKd0s,6295
59
+ dexcontrol-0.3.4.dist-info/METADATA,sha256=THlzSihnxku-i8wXM0q8fFUeITImxjX8KNv2lvI6D6g,37338
60
+ dexcontrol-0.3.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
61
+ dexcontrol-0.3.4.dist-info/licenses/LICENSE,sha256=0J2KCMNNnW5WZPK5x8xUiCxApBf7h83693ggSJYiue0,31745
62
+ dexcontrol-0.3.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any