dexcontrol 0.3.0__py3-none-any.whl → 0.3.1__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.
Potentially problematic release.
This version of dexcontrol might be problematic. Click here for more details.
- dexcontrol/__init__.py +16 -7
- dexcontrol/apps/dualsense_teleop_base.py +1 -1
- dexcontrol/comm/__init__.py +51 -0
- dexcontrol/comm/base.py +421 -0
- dexcontrol/comm/rtc.py +400 -0
- dexcontrol/comm/subscribers.py +329 -0
- dexcontrol/config/sensors/cameras/__init__.py +1 -2
- dexcontrol/config/sensors/cameras/zed_camera.py +2 -2
- dexcontrol/config/sensors/vega_sensors.py +12 -18
- dexcontrol/core/arm.py +29 -25
- dexcontrol/core/chassis.py +3 -12
- dexcontrol/core/component.py +68 -43
- dexcontrol/core/hand.py +50 -52
- dexcontrol/core/head.py +14 -26
- dexcontrol/core/misc.py +188 -166
- dexcontrol/core/robot_query_interface.py +137 -114
- dexcontrol/core/torso.py +0 -4
- dexcontrol/robot.py +15 -37
- dexcontrol/sensors/__init__.py +1 -2
- dexcontrol/sensors/camera/__init__.py +0 -2
- dexcontrol/sensors/camera/base_camera.py +144 -0
- dexcontrol/sensors/camera/rgb_camera.py +67 -63
- dexcontrol/sensors/camera/zed_camera.py +89 -147
- dexcontrol/sensors/imu/chassis_imu.py +76 -56
- dexcontrol/sensors/imu/zed_imu.py +54 -43
- dexcontrol/sensors/lidar/rplidar.py +16 -20
- dexcontrol/sensors/manager.py +4 -11
- dexcontrol/sensors/ultrasonic.py +14 -27
- dexcontrol/utils/__init__.py +0 -11
- dexcontrol/utils/comm_helper.py +111 -0
- dexcontrol/utils/constants.py +1 -1
- dexcontrol/utils/os_utils.py +8 -22
- {dexcontrol-0.3.0.dist-info → dexcontrol-0.3.1.dist-info}/METADATA +2 -1
- dexcontrol-0.3.1.dist-info/RECORD +68 -0
- dexcontrol/config/sensors/cameras/luxonis_camera.py +0 -51
- dexcontrol/sensors/camera/luxonis_camera.py +0 -169
- dexcontrol/utils/rate_limiter.py +0 -172
- dexcontrol/utils/rtc_utils.py +0 -144
- dexcontrol/utils/subscribers/__init__.py +0 -52
- dexcontrol/utils/subscribers/base.py +0 -281
- dexcontrol/utils/subscribers/camera.py +0 -332
- dexcontrol/utils/subscribers/decoders.py +0 -88
- dexcontrol/utils/subscribers/generic.py +0 -110
- dexcontrol/utils/subscribers/imu.py +0 -175
- dexcontrol/utils/subscribers/lidar.py +0 -172
- dexcontrol/utils/subscribers/protobuf.py +0 -111
- dexcontrol/utils/subscribers/rtc.py +0 -316
- dexcontrol/utils/zenoh_utils.py +0 -369
- dexcontrol-0.3.0.dist-info/RECORD +0 -76
- {dexcontrol-0.3.0.dist-info → dexcontrol-0.3.1.dist-info}/WHEEL +0 -0
- {dexcontrol-0.3.0.dist-info → dexcontrol-0.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,30 +8,32 @@
|
|
|
8
8
|
# 2. Commercial License
|
|
9
9
|
# For commercial licensing terms, contact: contact@dexmate.ai
|
|
10
10
|
|
|
11
|
-
"""
|
|
11
|
+
"""Query utilities for robot communication using DexComm.
|
|
12
12
|
|
|
13
|
-
This module provides the
|
|
14
|
-
queries
|
|
15
|
-
including hand type detection, version information, status queries, and control
|
|
13
|
+
This module provides the RobotQueryInterface class that encapsulates all communication
|
|
14
|
+
queries with the robot server using DexComm's service pattern. It handles various query
|
|
15
|
+
types including hand type detection, version information, status queries, and control
|
|
16
|
+
operations.
|
|
16
17
|
"""
|
|
17
18
|
|
|
18
19
|
import json
|
|
19
20
|
import time
|
|
20
21
|
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
# Use DexComm for all communication
|
|
24
|
+
from dexcomm import call_service
|
|
23
25
|
from loguru import logger
|
|
24
26
|
|
|
25
27
|
from dexcontrol.config.vega import VegaConfig, get_vega_config
|
|
26
28
|
from dexcontrol.core.hand import HandType
|
|
27
29
|
from dexcontrol.proto import dexcontrol_query_pb2
|
|
30
|
+
from dexcontrol.utils.comm_helper import get_zenoh_config_path
|
|
28
31
|
from dexcontrol.utils.os_utils import resolve_key_name
|
|
29
32
|
from dexcontrol.utils.pb_utils import (
|
|
30
33
|
ComponentStatus,
|
|
31
34
|
status_to_dict,
|
|
32
35
|
)
|
|
33
36
|
from dexcontrol.utils.viz_utils import show_component_status
|
|
34
|
-
from dexcontrol.utils.zenoh_utils import compute_ntp_stats, create_zenoh_session
|
|
35
37
|
|
|
36
38
|
if TYPE_CHECKING:
|
|
37
39
|
from dexcontrol.config.vega import VegaConfig
|
|
@@ -49,63 +51,47 @@ class RobotQueryInterface:
|
|
|
49
51
|
... version_info = interface.get_version_info()
|
|
50
52
|
"""
|
|
51
53
|
|
|
52
|
-
def __init__(self,
|
|
53
|
-
"""Initialize the RobotQueryInterface
|
|
54
|
+
def __init__(self, configs: "VegaConfig"):
|
|
55
|
+
"""Initialize the RobotQueryInterface.
|
|
54
56
|
|
|
55
57
|
Args:
|
|
56
|
-
zenoh_session: Active zenoh session for communication.
|
|
57
58
|
configs: Robot configuration containing query names.
|
|
58
59
|
"""
|
|
59
|
-
|
|
60
|
+
# Session parameter kept for compatibility but not used
|
|
60
61
|
self._configs = configs
|
|
61
62
|
self._owns_session = False
|
|
62
63
|
|
|
63
64
|
@classmethod
|
|
64
|
-
def create(
|
|
65
|
-
|
|
66
|
-
zenoh_config_file: str | None = None,
|
|
67
|
-
) -> "RobotQueryInterface":
|
|
68
|
-
"""Create a standalone RobotQueryInterface with its own zenoh session.
|
|
65
|
+
def create(cls) -> "RobotQueryInterface":
|
|
66
|
+
"""Create a standalone RobotQueryInterface.
|
|
69
67
|
|
|
70
68
|
This class method provides a convenient way to create a RobotQueryInterface
|
|
71
|
-
without requiring the full Robot class.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Args:
|
|
75
|
-
zenoh_config_file: Path to zenoh configuration file. If None,
|
|
76
|
-
uses the default configuration path.
|
|
77
|
-
robot_config_path: Path to robot configuration file. If None,
|
|
78
|
-
uses default configuration for detected robot model.
|
|
69
|
+
without requiring the full Robot class. DexComm handles all session
|
|
70
|
+
management internally.
|
|
79
71
|
|
|
80
72
|
Returns:
|
|
81
73
|
RobotQueryInterface instance ready for use.
|
|
82
74
|
|
|
83
|
-
Raises:
|
|
84
|
-
RuntimeError: If zenoh session initialization fails.
|
|
85
|
-
ValueError: If robot configuration cannot be loaded.
|
|
86
|
-
|
|
87
75
|
Example:
|
|
88
|
-
>>> query_interface = RobotQueryInterface.
|
|
76
|
+
>>> query_interface = RobotQueryInterface.create()
|
|
89
77
|
>>> version_info = query_interface.get_version_info()
|
|
90
78
|
>>> query_interface.close()
|
|
91
79
|
"""
|
|
92
|
-
|
|
93
|
-
session = create_zenoh_session(zenoh_config_file)
|
|
80
|
+
# DexComm handles session internally, we just need config
|
|
94
81
|
config: VegaConfig = get_vega_config()
|
|
95
|
-
|
|
96
|
-
instance = cls(session, config)
|
|
82
|
+
instance = cls(config)
|
|
97
83
|
instance._owns_session = True
|
|
98
84
|
return instance
|
|
99
85
|
|
|
100
86
|
def close(self) -> None:
|
|
101
|
-
"""Close the
|
|
87
|
+
"""Close the communication session if owned by this instance.
|
|
102
88
|
|
|
103
89
|
This method should be called when done using a standalone
|
|
104
90
|
RobotQueryInterface to properly clean up resources.
|
|
105
91
|
"""
|
|
106
|
-
if self._owns_session
|
|
107
|
-
|
|
108
|
-
|
|
92
|
+
if self._owns_session:
|
|
93
|
+
# DexComm cleanup is handled automatically
|
|
94
|
+
logger.debug("DexComm session cleanup handled automatically")
|
|
109
95
|
|
|
110
96
|
def __enter__(self) -> "RobotQueryInterface":
|
|
111
97
|
"""Enter context manager."""
|
|
@@ -128,30 +114,35 @@ class RobotQueryInterface:
|
|
|
128
114
|
RuntimeError: If hand type information cannot be retrieved.
|
|
129
115
|
"""
|
|
130
116
|
try:
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
# Query hand type using DexComm service
|
|
118
|
+
full_topic = resolve_key_name(self._configs.hand_info_query_name)
|
|
119
|
+
|
|
120
|
+
response = call_service(
|
|
121
|
+
full_topic,
|
|
122
|
+
timeout=5.0,
|
|
123
|
+
config=get_zenoh_config_path(),
|
|
124
|
+
request_serializer=None,
|
|
125
|
+
response_deserializer=None,
|
|
135
126
|
)
|
|
136
127
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
128
|
+
if response:
|
|
129
|
+
# Parse JSON response directly
|
|
130
|
+
if isinstance(response, bytes):
|
|
131
|
+
payload_str = response.decode("utf-8")
|
|
132
|
+
else:
|
|
133
|
+
payload_str = response
|
|
134
|
+
|
|
135
|
+
hand_info = json.loads(payload_str)
|
|
136
|
+
|
|
137
|
+
# Validate the expected format
|
|
138
|
+
if isinstance(hand_info, dict):
|
|
139
|
+
logger.info(f"End effector hand types: {hand_info}")
|
|
140
|
+
return {
|
|
141
|
+
"left": HandType(hand_info["left"]),
|
|
142
|
+
"right": HandType(hand_info["right"]),
|
|
143
|
+
}
|
|
144
|
+
else:
|
|
145
|
+
logger.warning(f"Invalid hand type format received: {hand_info}")
|
|
155
146
|
|
|
156
147
|
# If no valid response received, assume v1 for backward compatibility
|
|
157
148
|
return {"left": HandType.HandF5D6_V1, "right": HandType.HandF5D6_V1}
|
|
@@ -189,23 +180,29 @@ class RobotQueryInterface:
|
|
|
189
180
|
time_offset = []
|
|
190
181
|
time_rtt = []
|
|
191
182
|
|
|
192
|
-
querier = self._zenoh_session.declare_querier(ntp_key, timeout=timeout)
|
|
193
|
-
time.sleep(0.1)
|
|
194
|
-
|
|
195
183
|
reply_count = 0
|
|
196
184
|
for i in range(sample_count):
|
|
197
185
|
request = dexcontrol_query_pb2.NTPRequest()
|
|
198
186
|
request.client_send_time_ns = time.time_ns()
|
|
199
187
|
request.sample_count = sample_count
|
|
200
188
|
request.sample_index = i
|
|
201
|
-
replies = querier.get(payload=request.SerializeToString())
|
|
202
189
|
|
|
203
|
-
for
|
|
204
|
-
|
|
205
|
-
|
|
190
|
+
# Use call_service for NTP query
|
|
191
|
+
try:
|
|
192
|
+
response_data = call_service(
|
|
193
|
+
ntp_key,
|
|
194
|
+
request=request,
|
|
195
|
+
timeout=timeout,
|
|
196
|
+
config=get_zenoh_config_path(),
|
|
197
|
+
request_serializer=lambda x: x.SerializeToString(),
|
|
198
|
+
response_deserializer=None,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if response_data:
|
|
202
|
+
reply_count += 1
|
|
206
203
|
client_receive_time_ns = time.time_ns()
|
|
207
204
|
response = dexcontrol_query_pb2.NTPResponse()
|
|
208
|
-
response.ParseFromString(
|
|
205
|
+
response.ParseFromString(response_data)
|
|
209
206
|
t0 = request.client_send_time_ns
|
|
210
207
|
t1 = response.server_receive_time_ns
|
|
211
208
|
t2 = response.server_send_time_ns
|
|
@@ -214,16 +211,25 @@ class RobotQueryInterface:
|
|
|
214
211
|
rtt = (t3 - t0) / 1e9
|
|
215
212
|
time_offset.append(offset)
|
|
216
213
|
time_rtt.append(rtt)
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logger.debug(f"NTP query {i} failed: {e}")
|
|
216
|
+
|
|
217
217
|
if i < sample_count - 1:
|
|
218
218
|
time.sleep(0.01)
|
|
219
|
-
|
|
220
|
-
querier.undeclare()
|
|
221
219
|
if reply_count == 0:
|
|
222
|
-
return {"success": False, "offset": 0, "rtt": 0}
|
|
220
|
+
return {"success": False, "offset": 0.0, "rtt": 0.0}
|
|
221
|
+
|
|
222
|
+
# Compute simple NTP statistics
|
|
223
|
+
import numpy as np
|
|
223
224
|
|
|
224
|
-
stats =
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
stats = {
|
|
226
|
+
"offset (mean)": float(np.mean(time_offset)) if time_offset else 0.0,
|
|
227
|
+
"round_trip_time (mean)": float(np.mean(time_rtt)) if time_rtt else 0.0,
|
|
228
|
+
"offset (std)": float(np.std(time_offset)) if time_offset else 0.0,
|
|
229
|
+
"round_trip_time (std)": float(np.std(time_rtt)) if time_rtt else 0.0,
|
|
230
|
+
}
|
|
231
|
+
offset = float(stats["offset (mean)"])
|
|
232
|
+
rtt = float(stats["round_trip_time (mean)"])
|
|
227
233
|
if show:
|
|
228
234
|
from dexcontrol.utils.viz_utils import show_ntp_stats
|
|
229
235
|
|
|
@@ -263,34 +269,38 @@ class RobotQueryInterface:
|
|
|
263
269
|
RuntimeError: If version information cannot be retrieved.
|
|
264
270
|
"""
|
|
265
271
|
try:
|
|
266
|
-
|
|
267
|
-
resolve_key_name(self._configs.version_info_name),
|
|
272
|
+
response = call_service(
|
|
273
|
+
resolve_key_name(self._configs.version_info_name),
|
|
274
|
+
timeout=5.0,
|
|
275
|
+
config=get_zenoh_config_path(),
|
|
276
|
+
request_serializer=None,
|
|
277
|
+
response_deserializer=None,
|
|
268
278
|
)
|
|
269
279
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
280
|
+
if response:
|
|
281
|
+
try:
|
|
282
|
+
# Parse JSON response directly
|
|
283
|
+
if isinstance(response, bytes):
|
|
284
|
+
payload_str = response.decode("utf-8")
|
|
285
|
+
else:
|
|
286
|
+
payload_str = response
|
|
287
|
+
version_info = json.loads(payload_str)
|
|
288
|
+
|
|
289
|
+
# Validate expected structure
|
|
290
|
+
if (
|
|
291
|
+
isinstance(version_info, dict)
|
|
292
|
+
and "server" in version_info
|
|
293
|
+
and "client" in version_info
|
|
294
|
+
):
|
|
295
|
+
if show:
|
|
296
|
+
self._show_version_info(version_info)
|
|
297
|
+
return version_info
|
|
298
|
+
else:
|
|
299
|
+
logger.warning(
|
|
300
|
+
f"Invalid version info format received: {version_info}"
|
|
301
|
+
)
|
|
302
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as e:
|
|
303
|
+
logger.warning(f"Failed to parse version info response: {e}")
|
|
294
304
|
|
|
295
305
|
raise RuntimeError("No valid version information received from server")
|
|
296
306
|
|
|
@@ -312,19 +322,22 @@ class RobotQueryInterface:
|
|
|
312
322
|
RuntimeError: If status information cannot be retrieved.
|
|
313
323
|
"""
|
|
314
324
|
try:
|
|
315
|
-
|
|
316
|
-
resolve_key_name(self._configs.status_info_name)
|
|
325
|
+
response = call_service(
|
|
326
|
+
resolve_key_name(self._configs.status_info_name),
|
|
327
|
+
timeout=2.0,
|
|
328
|
+
config=get_zenoh_config_path(),
|
|
329
|
+
request_serializer=None,
|
|
330
|
+
response_deserializer=None,
|
|
317
331
|
)
|
|
332
|
+
|
|
318
333
|
status_dict = {}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
status_dict = status_to_dict(status_msg)
|
|
327
|
-
break
|
|
334
|
+
if response:
|
|
335
|
+
# Parse protobuf response directly
|
|
336
|
+
status_msg = cast(
|
|
337
|
+
dexcontrol_query_pb2.ComponentStates,
|
|
338
|
+
dexcontrol_query_pb2.ComponentStates.FromString(response),
|
|
339
|
+
)
|
|
340
|
+
status_dict = status_to_dict(status_msg)
|
|
328
341
|
|
|
329
342
|
if show:
|
|
330
343
|
show_component_status(status_dict)
|
|
@@ -358,9 +371,14 @@ class RobotQueryInterface:
|
|
|
358
371
|
query_msg = dexcontrol_query_pb2.RebootComponent(
|
|
359
372
|
component=component_map[part]
|
|
360
373
|
)
|
|
361
|
-
|
|
374
|
+
|
|
375
|
+
call_service(
|
|
362
376
|
resolve_key_name(self._configs.reboot_query_name),
|
|
363
|
-
|
|
377
|
+
request=query_msg,
|
|
378
|
+
timeout=2.0,
|
|
379
|
+
config=get_zenoh_config_path(),
|
|
380
|
+
request_serializer=lambda x: x.SerializeToString(),
|
|
381
|
+
response_deserializer=None,
|
|
364
382
|
)
|
|
365
383
|
logger.info(f"Rebooting component: {part}")
|
|
366
384
|
except Exception as e:
|
|
@@ -391,11 +409,16 @@ class RobotQueryInterface:
|
|
|
391
409
|
|
|
392
410
|
try:
|
|
393
411
|
query_msg = dexcontrol_query_pb2.ClearError(component=component_map[part])
|
|
394
|
-
|
|
412
|
+
|
|
413
|
+
call_service(
|
|
395
414
|
resolve_key_name(self._configs.clear_error_query_name),
|
|
396
|
-
|
|
397
|
-
|
|
415
|
+
request=query_msg,
|
|
416
|
+
timeout=2.0,
|
|
417
|
+
config=get_zenoh_config_path(),
|
|
418
|
+
request_serializer=lambda x: x.SerializeToString(),
|
|
419
|
+
response_deserializer=None,
|
|
398
420
|
)
|
|
421
|
+
logger.info(f"Cleared error of {part}")
|
|
399
422
|
except Exception as e:
|
|
400
423
|
raise RuntimeError(
|
|
401
424
|
f"Failed to clear error for component {part}: {e}"
|
dexcontrol/core/torso.py
CHANGED
|
@@ -15,7 +15,6 @@ communication. It handles joint position and velocity control and state monitori
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import numpy as np
|
|
18
|
-
import zenoh
|
|
19
18
|
from jaxtyping import Float
|
|
20
19
|
|
|
21
20
|
from dexcontrol.config.core import TorsoConfig
|
|
@@ -37,20 +36,17 @@ class Torso(RobotJointComponent):
|
|
|
37
36
|
def __init__(
|
|
38
37
|
self,
|
|
39
38
|
configs: TorsoConfig,
|
|
40
|
-
zenoh_session: zenoh.Session,
|
|
41
39
|
) -> None:
|
|
42
40
|
"""Initialize the torso controller.
|
|
43
41
|
|
|
44
42
|
Args:
|
|
45
43
|
configs: Torso configuration parameters containing communication topics
|
|
46
44
|
and default velocity settings.
|
|
47
|
-
zenoh_session: Active Zenoh communication session for message passing.
|
|
48
45
|
"""
|
|
49
46
|
super().__init__(
|
|
50
47
|
state_sub_topic=configs.state_sub_topic,
|
|
51
48
|
control_pub_topic=configs.control_pub_topic,
|
|
52
49
|
state_message_type=dexcontrol_msg_pb2.MotorStateWithCurrent,
|
|
53
|
-
zenoh_session=zenoh_session,
|
|
54
50
|
joint_name=configs.joint_name,
|
|
55
51
|
joint_limit=configs.joint_limit
|
|
56
52
|
if hasattr(configs, "joint_limit")
|
dexcontrol/robot.py
CHANGED
|
@@ -25,7 +25,6 @@ from __future__ import annotations
|
|
|
25
25
|
import os
|
|
26
26
|
import signal
|
|
27
27
|
import sys
|
|
28
|
-
import threading
|
|
29
28
|
import time
|
|
30
29
|
import weakref
|
|
31
30
|
from typing import TYPE_CHECKING, Any, Final, Literal, cast
|
|
@@ -33,7 +32,8 @@ from typing import TYPE_CHECKING, Any, Final, Literal, cast
|
|
|
33
32
|
import hydra.utils
|
|
34
33
|
import numpy as np
|
|
35
34
|
import omegaconf
|
|
36
|
-
import
|
|
35
|
+
from dexcomm import cleanup_session
|
|
36
|
+
from dexcomm.utils import RateLimiter
|
|
37
37
|
from loguru import logger
|
|
38
38
|
from rich.console import Console
|
|
39
39
|
from rich.table import Table
|
|
@@ -47,13 +47,7 @@ from dexcontrol.core.robot_query_interface import RobotQueryInterface
|
|
|
47
47
|
from dexcontrol.sensors import Sensors
|
|
48
48
|
from dexcontrol.utils.constants import ROBOT_NAME_ENV_VAR
|
|
49
49
|
from dexcontrol.utils.os_utils import check_version_compatibility, get_robot_model
|
|
50
|
-
from dexcontrol.utils.rate_limiter import RateLimiter
|
|
51
50
|
from dexcontrol.utils.trajectory_utils import generate_linear_trajectory
|
|
52
|
-
from dexcontrol.utils.zenoh_utils import (
|
|
53
|
-
close_zenoh_session_with_timeout,
|
|
54
|
-
create_zenoh_session,
|
|
55
|
-
wait_for_zenoh_cleanup,
|
|
56
|
-
)
|
|
57
51
|
|
|
58
52
|
if TYPE_CHECKING:
|
|
59
53
|
from dexcontrol.core.arm import Arm
|
|
@@ -142,7 +136,6 @@ class Robot(RobotQueryInterface):
|
|
|
142
136
|
self,
|
|
143
137
|
robot_model: str | None = None,
|
|
144
138
|
configs: VegaConfig | None = None,
|
|
145
|
-
zenoh_config_file: str | None = None,
|
|
146
139
|
auto_shutdown: bool = True,
|
|
147
140
|
) -> None:
|
|
148
141
|
"""Initializes the Robot with the given configuration.
|
|
@@ -153,8 +146,6 @@ class Robot(RobotQueryInterface):
|
|
|
153
146
|
Ignored if configs is provided.
|
|
154
147
|
configs: Configuration parameters for all robot components.
|
|
155
148
|
If None, will use the configuration specified by robot_model.
|
|
156
|
-
zenoh_config_file: Optional path to the zenoh config file.
|
|
157
|
-
Defaults to None to use system defaults.
|
|
158
149
|
auto_shutdown: Whether to automatically register signal handlers for
|
|
159
150
|
graceful shutdown on program interruption. Default is True.
|
|
160
151
|
|
|
@@ -168,19 +159,18 @@ class Robot(RobotQueryInterface):
|
|
|
168
159
|
robot_model = get_robot_model()
|
|
169
160
|
self._robot_model: Final[str] = robot_model
|
|
170
161
|
|
|
171
|
-
# Load configuration
|
|
162
|
+
# Load configuration
|
|
172
163
|
self._configs: Final[VegaConfig] = configs or get_vega_config(robot_model)
|
|
173
|
-
self._zenoh_session: zenoh.Session = create_zenoh_session(zenoh_config_file)
|
|
174
164
|
|
|
175
|
-
|
|
176
|
-
super().__init__(self._zenoh_session, self._configs)
|
|
165
|
+
super().__init__(self._configs)
|
|
177
166
|
|
|
178
167
|
self._robot_name: Final[str] = os.getenv(ROBOT_NAME_ENV_VAR, "robot")
|
|
179
168
|
self._pv_components: list[str] = [
|
|
180
169
|
"head",
|
|
181
170
|
"torso",
|
|
182
171
|
]
|
|
183
|
-
|
|
172
|
+
# Note: zenoh_session no longer needed as DexComm handles sessions
|
|
173
|
+
self._log_subscriber = ServerLogSubscriber()
|
|
184
174
|
self._hand_types: dict[str, HandType] = {}
|
|
185
175
|
|
|
186
176
|
# Register for automatic shutdown on signals if enabled
|
|
@@ -280,7 +270,8 @@ class Robot(RobotQueryInterface):
|
|
|
280
270
|
|
|
281
271
|
def _initialize_sensors(self) -> None:
|
|
282
272
|
"""Initialize sensors and wait for activation."""
|
|
283
|
-
|
|
273
|
+
# Note: zenoh_session no longer needed as DexComm handles sessions
|
|
274
|
+
self.sensors = Sensors(self._configs.sensors)
|
|
284
275
|
self.sensors.wait_for_all_active()
|
|
285
276
|
|
|
286
277
|
def _initialize_robot_components(self) -> None:
|
|
@@ -290,7 +281,6 @@ class Robot(RobotQueryInterface):
|
|
|
290
281
|
|
|
291
282
|
initialized_components = []
|
|
292
283
|
failed_components = []
|
|
293
|
-
|
|
294
284
|
for component_name, component_config in config_dict.items():
|
|
295
285
|
if component_name == "sensors":
|
|
296
286
|
continue
|
|
@@ -335,9 +325,8 @@ class Robot(RobotQueryInterface):
|
|
|
335
325
|
temp_config["hand_type"] = hand_type
|
|
336
326
|
|
|
337
327
|
# Instantiate component with error handling
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
328
|
+
# Note: zenoh_session no longer needed as DexComm handles sessions
|
|
329
|
+
component_instance = hydra.utils.instantiate(temp_config)
|
|
341
330
|
|
|
342
331
|
# Store component instance both as attribute and in tracking dictionaries
|
|
343
332
|
setattr(self, str(component_name), component_instance)
|
|
@@ -347,7 +336,6 @@ class Robot(RobotQueryInterface):
|
|
|
347
336
|
logger.error(f"Failed to initialize component {component_name}: {e}")
|
|
348
337
|
failed_components.append(component_name)
|
|
349
338
|
# Continue with other components rather than failing completely
|
|
350
|
-
|
|
351
339
|
# Report initialization summary
|
|
352
340
|
if failed_components:
|
|
353
341
|
logger.warning(
|
|
@@ -614,23 +602,13 @@ class Robot(RobotQueryInterface):
|
|
|
614
602
|
except Exception as e: # pylint: disable=broad-except
|
|
615
603
|
logger.debug(f"Error shutting down log subscriber: {e}")
|
|
616
604
|
|
|
617
|
-
#
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
605
|
+
# Cleanup DexComm shared session
|
|
606
|
+
try:
|
|
607
|
+
cleanup_session()
|
|
608
|
+
except Exception as e:
|
|
609
|
+
logger.debug(f"Session cleanup note: {e}")
|
|
622
610
|
logger.info("Robot shutdown complete")
|
|
623
611
|
|
|
624
|
-
def _assist_clean_exit_if_needed(self) -> None:
|
|
625
|
-
"""Assist with clean exit if this is the last robot and we're exiting."""
|
|
626
|
-
if (
|
|
627
|
-
not _active_robots # No more active robots
|
|
628
|
-
and threading.current_thread() is threading.main_thread() # In main thread
|
|
629
|
-
and not hasattr(sys, "ps1") # Not in interactive mode
|
|
630
|
-
):
|
|
631
|
-
logger.debug("Assisting clean exit due to lingering Zenoh threads")
|
|
632
|
-
sys.exit(0)
|
|
633
|
-
|
|
634
612
|
def is_shutdown(self) -> bool:
|
|
635
613
|
"""Check if the robot has been shutdown.
|
|
636
614
|
|
dexcontrol/sensors/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ using Zenoh subscribers for data communication.
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
# Import camera sensors
|
|
18
|
-
from .camera import
|
|
18
|
+
from .camera import RGBCameraSensor, ZedCameraSensor
|
|
19
19
|
|
|
20
20
|
# Import IMU sensors
|
|
21
21
|
from .imu import ChassisIMUSensor, ZedIMUSensor
|
|
@@ -31,7 +31,6 @@ __all__ = [
|
|
|
31
31
|
# Camera sensors
|
|
32
32
|
"RGBCameraSensor",
|
|
33
33
|
"ZedCameraSensor",
|
|
34
|
-
"LuxonisCameraSensor",
|
|
35
34
|
|
|
36
35
|
# IMU sensors
|
|
37
36
|
"ChassisIMUSensor",
|
|
@@ -14,12 +14,10 @@ This module provides camera sensor classes that use the specialized camera
|
|
|
14
14
|
subscribers for RGB and RGBD camera data, matching the dexsensor structure.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
from .luxonis_camera import LuxonisCameraSensor
|
|
18
17
|
from .rgb_camera import RGBCameraSensor
|
|
19
18
|
from .zed_camera import ZedCameraSensor
|
|
20
19
|
|
|
21
20
|
__all__ = [
|
|
22
21
|
"RGBCameraSensor",
|
|
23
22
|
"ZedCameraSensor",
|
|
24
|
-
"LuxonisCameraSensor",
|
|
25
23
|
]
|