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
dexcontrol/core/component.py
CHANGED
|
@@ -8,24 +8,27 @@
|
|
|
8
8
|
# 2. Commercial License
|
|
9
9
|
# For commercial licensing terms, contact: contact@dexmate.ai
|
|
10
10
|
|
|
11
|
-
"""Base module for robot components
|
|
11
|
+
"""Base module for robot components using DexComm communication.
|
|
12
12
|
|
|
13
|
-
This module provides base classes for robot components that
|
|
14
|
-
It includes RobotComponent for state-only components
|
|
15
|
-
components that also support control commands.
|
|
13
|
+
This module provides base classes for robot components that use DexComm's
|
|
14
|
+
Raw API for communication. It includes RobotComponent for state-only components
|
|
15
|
+
and RobotJointComponent for components that also support control commands.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import time
|
|
19
|
-
from typing import Any, Final, Mapping, TypeVar
|
|
19
|
+
from typing import Any, Final, Mapping, Optional, TypeVar
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
# Use DexComm for all communication
|
|
24
|
+
from dexcomm import Publisher, Subscriber
|
|
25
|
+
from dexcomm.serialization import deserialize_protobuf, serialize_protobuf
|
|
23
26
|
from google.protobuf.message import Message
|
|
24
27
|
from jaxtyping import Float
|
|
25
28
|
from loguru import logger
|
|
26
29
|
|
|
30
|
+
from dexcontrol.utils.comm_helper import get_zenoh_config_path
|
|
27
31
|
from dexcontrol.utils.os_utils import resolve_key_name
|
|
28
|
-
from dexcontrol.utils.subscribers import ProtobufZenohSubscriber
|
|
29
32
|
|
|
30
33
|
# Type variable for Message subclasses
|
|
31
34
|
M = TypeVar("M", bound=Message)
|
|
@@ -47,41 +50,55 @@ class RobotComponent:
|
|
|
47
50
|
def __init__(
|
|
48
51
|
self,
|
|
49
52
|
state_sub_topic: str,
|
|
50
|
-
zenoh_session: zenoh.Session,
|
|
51
53
|
state_message_type: type[M],
|
|
52
54
|
) -> None:
|
|
53
55
|
"""Initializes RobotComponent.
|
|
54
56
|
|
|
55
57
|
Args:
|
|
56
58
|
state_sub_topic: Topic to subscribe to for state updates.
|
|
57
|
-
zenoh_session: Active Zenoh session for communication.
|
|
58
59
|
state_message_type: Protobuf message class for component state.
|
|
59
60
|
"""
|
|
60
61
|
self._state_message_type = state_message_type
|
|
61
|
-
self.
|
|
62
|
-
self.
|
|
62
|
+
self._latest_state: Optional[M] = None
|
|
63
|
+
self._is_active = False
|
|
64
|
+
self._init_subscriber(state_sub_topic, state_message_type)
|
|
63
65
|
|
|
64
66
|
def _init_subscriber(
|
|
65
67
|
self,
|
|
66
68
|
state_sub_topic: str,
|
|
67
69
|
state_message_type: type[M],
|
|
68
|
-
zenoh_session: zenoh.Session,
|
|
69
70
|
) -> None:
|
|
70
|
-
"""Initialize the
|
|
71
|
+
"""Initialize the subscriber for state updates using DexComm.
|
|
71
72
|
|
|
72
73
|
Args:
|
|
73
74
|
state_sub_topic: Topic to subscribe to for state updates.
|
|
74
75
|
state_message_type: Protobuf message class for component state.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
"""
|
|
77
|
+
# Resolve topic with robot namespace
|
|
78
|
+
full_topic = resolve_key_name(state_sub_topic)
|
|
79
|
+
|
|
80
|
+
# Create DexComm subscriber with protobuf deserialization
|
|
81
|
+
self._subscriber = Subscriber(
|
|
82
|
+
topic=full_topic,
|
|
83
|
+
callback=self._on_state_update,
|
|
84
|
+
deserializer=lambda data: deserialize_protobuf(data, state_message_type),
|
|
85
|
+
config=get_zenoh_config_path(),
|
|
83
86
|
)
|
|
84
87
|
|
|
88
|
+
logger.debug(
|
|
89
|
+
f"Created subscriber for {self.__class__.__name__} on {full_topic}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def _on_state_update(self, state: M) -> None:
|
|
93
|
+
"""Handle incoming state updates.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
state: Deserialized protobuf state message.
|
|
97
|
+
"""
|
|
98
|
+
self._latest_state = state
|
|
99
|
+
if state:
|
|
100
|
+
self._is_active = True
|
|
101
|
+
|
|
85
102
|
def _get_state(self) -> M:
|
|
86
103
|
"""Gets the current state of the component.
|
|
87
104
|
|
|
@@ -91,10 +108,9 @@ class RobotComponent:
|
|
|
91
108
|
Raises:
|
|
92
109
|
None: If no state data is available.
|
|
93
110
|
"""
|
|
94
|
-
|
|
95
|
-
if state is None:
|
|
111
|
+
if self._latest_state is None:
|
|
96
112
|
logger.error(f"No state data available for {self.__class__.__name__}")
|
|
97
|
-
return
|
|
113
|
+
return self._latest_state
|
|
98
114
|
|
|
99
115
|
def wait_for_active(self, timeout: float = 5.0) -> bool:
|
|
100
116
|
"""Waits for the component to start receiving state updates.
|
|
@@ -105,7 +121,12 @@ class RobotComponent:
|
|
|
105
121
|
Returns:
|
|
106
122
|
True if component becomes active, False if timeout is reached.
|
|
107
123
|
"""
|
|
108
|
-
|
|
124
|
+
start_time = time.time()
|
|
125
|
+
while time.time() - start_time < timeout:
|
|
126
|
+
if self._is_active:
|
|
127
|
+
return True
|
|
128
|
+
time.sleep(0.1)
|
|
129
|
+
return False
|
|
109
130
|
|
|
110
131
|
def is_active(self) -> bool:
|
|
111
132
|
"""Check if component is receiving state updates.
|
|
@@ -113,7 +134,7 @@ class RobotComponent:
|
|
|
113
134
|
Returns:
|
|
114
135
|
True if component is active, False otherwise.
|
|
115
136
|
"""
|
|
116
|
-
return self.
|
|
137
|
+
return self._is_active
|
|
117
138
|
|
|
118
139
|
def shutdown(self) -> None:
|
|
119
140
|
"""Cleans up Zenoh resources."""
|
|
@@ -149,7 +170,7 @@ class RobotJointComponent(RobotComponent):
|
|
|
149
170
|
Extends RobotComponent to add APIs for interacting with joints.
|
|
150
171
|
|
|
151
172
|
Attributes:
|
|
152
|
-
_publisher:
|
|
173
|
+
_publisher: Publisher for control commands (Zenoh or dexcomm).
|
|
153
174
|
_joint_name: List of joint names for this component.
|
|
154
175
|
_pose_pool: Dictionary of predefined poses for this component.
|
|
155
176
|
"""
|
|
@@ -178,7 +199,6 @@ class RobotJointComponent(RobotComponent):
|
|
|
178
199
|
state_sub_topic: str,
|
|
179
200
|
control_pub_topic: str,
|
|
180
201
|
state_message_type: type[M],
|
|
181
|
-
zenoh_session: zenoh.Session,
|
|
182
202
|
joint_name: list[str] | None = None,
|
|
183
203
|
joint_limit: list[list[float]] | None = None,
|
|
184
204
|
joint_vel_limit: list[float] | None = None,
|
|
@@ -190,16 +210,24 @@ class RobotJointComponent(RobotComponent):
|
|
|
190
210
|
state_sub_topic: Topic to subscribe to for state updates.
|
|
191
211
|
control_pub_topic: Topic to publish control commands.
|
|
192
212
|
state_message_type: Protobuf message class for component state.
|
|
193
|
-
zenoh_session: Active Zenoh session for communication.
|
|
194
213
|
joint_name: List of joint names for this component.
|
|
214
|
+
joint_limit: Joint position limits.
|
|
215
|
+
joint_vel_limit: Joint velocity limits.
|
|
195
216
|
pose_pool: Dictionary of predefined poses for this component.
|
|
196
217
|
"""
|
|
197
|
-
super().__init__(state_sub_topic,
|
|
218
|
+
super().__init__(state_sub_topic, state_message_type)
|
|
219
|
+
|
|
220
|
+
# Resolve topic with robot namespace
|
|
221
|
+
full_topic = resolve_key_name(control_pub_topic)
|
|
198
222
|
|
|
199
|
-
|
|
200
|
-
self._publisher: Final[
|
|
201
|
-
|
|
223
|
+
# Create DexComm publisher with protobuf serialization
|
|
224
|
+
self._publisher: Final[Publisher] = Publisher(
|
|
225
|
+
topic=full_topic,
|
|
226
|
+
serializer=serialize_protobuf,
|
|
227
|
+
config=get_zenoh_config_path(),
|
|
202
228
|
)
|
|
229
|
+
|
|
230
|
+
logger.debug(f"Created publisher for {self.__class__.__name__} on {full_topic}")
|
|
203
231
|
self._joint_name: list[str] | None = joint_name
|
|
204
232
|
self._joint_limit: np.ndarray | None = (
|
|
205
233
|
np.array(joint_limit) if joint_limit else None
|
|
@@ -218,22 +246,19 @@ class RobotJointComponent(RobotComponent):
|
|
|
218
246
|
Args:
|
|
219
247
|
control_msg: Protobuf control message to publish.
|
|
220
248
|
"""
|
|
221
|
-
|
|
222
|
-
self._publisher.
|
|
249
|
+
# DexComm publisher with protobuf serializer handles this
|
|
250
|
+
self._publisher.publish(control_msg)
|
|
223
251
|
|
|
224
252
|
def shutdown(self) -> None:
|
|
225
|
-
"""Cleans up all
|
|
253
|
+
"""Cleans up all communication resources."""
|
|
226
254
|
super().shutdown()
|
|
227
255
|
try:
|
|
228
256
|
if hasattr(self, "_publisher") and self._publisher:
|
|
229
|
-
self._publisher.
|
|
257
|
+
self._publisher.shutdown()
|
|
230
258
|
except Exception as e:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
logger.warning(
|
|
235
|
-
f"Error undeclaring publisher for {self.__class__.__name__}: {e}"
|
|
236
|
-
)
|
|
259
|
+
logger.warning(
|
|
260
|
+
f"Error shutting down publisher for {self.__class__.__name__}: {e}"
|
|
261
|
+
)
|
|
237
262
|
|
|
238
263
|
@property
|
|
239
264
|
def joint_name(self) -> list[str]:
|
dexcontrol/core/hand.py
CHANGED
|
@@ -18,8 +18,8 @@ from enum import Enum
|
|
|
18
18
|
from typing import Any, cast
|
|
19
19
|
|
|
20
20
|
import numpy as np
|
|
21
|
-
import zenoh
|
|
22
21
|
from jaxtyping import Float
|
|
22
|
+
from loguru import logger
|
|
23
23
|
|
|
24
24
|
from dexcontrol.config.core.hand import HandConfig
|
|
25
25
|
from dexcontrol.core.component import RobotComponent, RobotJointComponent
|
|
@@ -42,7 +42,6 @@ class Hand(RobotJointComponent):
|
|
|
42
42
|
def __init__(
|
|
43
43
|
self,
|
|
44
44
|
configs: HandConfig,
|
|
45
|
-
zenoh_session: zenoh.Session,
|
|
46
45
|
hand_type: HandType = HandType.HandF5D6_V1,
|
|
47
46
|
) -> None:
|
|
48
47
|
"""Initialize the hand controller.
|
|
@@ -50,13 +49,11 @@ class Hand(RobotJointComponent):
|
|
|
50
49
|
Args:
|
|
51
50
|
configs: Hand configuration parameters containing communication topics
|
|
52
51
|
and predefined hand positions.
|
|
53
|
-
zenoh_session: Active Zenoh communication session for message passing.
|
|
54
52
|
"""
|
|
55
53
|
super().__init__(
|
|
56
54
|
state_sub_topic=configs.state_sub_topic,
|
|
57
55
|
control_pub_topic=configs.control_pub_topic,
|
|
58
56
|
state_message_type=dexcontrol_msg_pb2.MotorStateWithCurrent,
|
|
59
|
-
zenoh_session=zenoh_session,
|
|
60
57
|
joint_name=configs.joint_name,
|
|
61
58
|
)
|
|
62
59
|
|
|
@@ -129,17 +126,14 @@ class HandF5D6(Hand):
|
|
|
129
126
|
def __init__(
|
|
130
127
|
self,
|
|
131
128
|
configs: HandConfig,
|
|
132
|
-
zenoh_session: zenoh.Session,
|
|
133
129
|
hand_type: HandType = HandType.HandF5D6_V1,
|
|
134
130
|
) -> None:
|
|
135
|
-
super().__init__(configs
|
|
131
|
+
super().__init__(configs)
|
|
136
132
|
|
|
137
133
|
# Initialize touch sensor for F5D6_V2 hands
|
|
138
134
|
self._hand_type = hand_type
|
|
139
135
|
if self._hand_type == HandType.HandF5D6_V2:
|
|
140
|
-
self._touch_sensor = HandF5D6TouchSensor(
|
|
141
|
-
configs.touch_sensor_sub_topic, zenoh_session
|
|
142
|
-
)
|
|
136
|
+
self._touch_sensor = HandF5D6TouchSensor(configs.touch_sensor_sub_topic)
|
|
143
137
|
elif self._hand_type == HandType.HandF5D6_V1:
|
|
144
138
|
self._touch_sensor = None
|
|
145
139
|
else:
|
|
@@ -164,27 +158,30 @@ class HandF5D6(Hand):
|
|
|
164
158
|
exit_on_reach_kwargs: dict[str, Any] | None = None,
|
|
165
159
|
) -> None:
|
|
166
160
|
"""Close the hand fully using a two-step approach for better control."""
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
161
|
+
try:
|
|
162
|
+
if self.is_joint_pos_reached(self._joint_pos_close, tolerance=0.1):
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
# First step: Move to intermediate position
|
|
166
|
+
intermediate_pos = self._get_intermediate_close_position()
|
|
167
|
+
first_step_wait_time = 0.8
|
|
168
|
+
self.set_joint_pos(
|
|
169
|
+
intermediate_pos,
|
|
170
|
+
wait_time=first_step_wait_time,
|
|
171
|
+
exit_on_reach=exit_on_reach,
|
|
172
|
+
exit_on_reach_kwargs=exit_on_reach_kwargs,
|
|
173
|
+
)
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
175
|
+
# Second step: Move to final closed position
|
|
176
|
+
remaining_wait_time = max(0.0, wait_time - first_step_wait_time)
|
|
177
|
+
self.set_joint_pos(
|
|
178
|
+
self._joint_pos_close,
|
|
179
|
+
wait_time=remaining_wait_time,
|
|
180
|
+
exit_on_reach=exit_on_reach,
|
|
181
|
+
exit_on_reach_kwargs=exit_on_reach_kwargs,
|
|
182
|
+
)
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logger.warning(f"Failed to close hand: {e}")
|
|
188
185
|
|
|
189
186
|
def open_hand(
|
|
190
187
|
self,
|
|
@@ -193,27 +190,30 @@ class HandF5D6(Hand):
|
|
|
193
190
|
exit_on_reach_kwargs: dict[str, Any] | None = None,
|
|
194
191
|
) -> None:
|
|
195
192
|
"""Open the hand fully using a two-step approach for better control."""
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
193
|
+
try:
|
|
194
|
+
if self.is_joint_pos_reached(self._joint_pos_open, tolerance=0.1):
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
# First step: Move to intermediate position
|
|
198
|
+
intermediate_pos = self._get_intermediate_open_position()
|
|
199
|
+
first_step_wait_time = 0.3
|
|
200
|
+
self.set_joint_pos(
|
|
201
|
+
intermediate_pos,
|
|
202
|
+
wait_time=first_step_wait_time,
|
|
203
|
+
exit_on_reach=exit_on_reach,
|
|
204
|
+
exit_on_reach_kwargs=exit_on_reach_kwargs,
|
|
205
|
+
)
|
|
208
206
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
# Second step: Move to final open position
|
|
208
|
+
remaining_wait_time = max(0.0, wait_time - first_step_wait_time)
|
|
209
|
+
self.set_joint_pos(
|
|
210
|
+
self._joint_pos_open,
|
|
211
|
+
wait_time=remaining_wait_time,
|
|
212
|
+
exit_on_reach=exit_on_reach,
|
|
213
|
+
exit_on_reach_kwargs=exit_on_reach_kwargs,
|
|
214
|
+
)
|
|
215
|
+
except Exception as e:
|
|
216
|
+
logger.warning(f"Failed to open hand: {e}")
|
|
217
217
|
|
|
218
218
|
def _get_intermediate_close_position(self) -> np.ndarray:
|
|
219
219
|
"""Get intermediate position for closing hand.
|
|
@@ -254,16 +254,14 @@ class HandF5D6TouchSensor(RobotComponent):
|
|
|
254
254
|
This class provides methods to read wrench sensor data through Zenoh communication.
|
|
255
255
|
"""
|
|
256
256
|
|
|
257
|
-
def __init__(self, state_sub_topic: str
|
|
257
|
+
def __init__(self, state_sub_topic: str) -> None:
|
|
258
258
|
"""Initialize the wrench sensor reader.
|
|
259
259
|
|
|
260
260
|
Args:
|
|
261
261
|
state_sub_topic: Topic to subscribe to for wrench sensor data.
|
|
262
|
-
zenoh_session: Active Zenoh communication session for message passing.
|
|
263
262
|
"""
|
|
264
263
|
super().__init__(
|
|
265
264
|
state_sub_topic=state_sub_topic,
|
|
266
|
-
zenoh_session=zenoh_session,
|
|
267
265
|
state_message_type=dexcontrol_msg_pb2.HandTouchSensorState,
|
|
268
266
|
)
|
|
269
267
|
|
dexcontrol/core/head.py
CHANGED
|
@@ -15,17 +15,16 @@ communication. It handles joint position and velocity control, mode setting, and
|
|
|
15
15
|
state monitoring.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
import
|
|
19
|
-
from typing import Final, Literal
|
|
18
|
+
from typing import Literal
|
|
20
19
|
|
|
21
20
|
import numpy as np
|
|
22
|
-
import
|
|
21
|
+
from dexcomm import call_service
|
|
23
22
|
from jaxtyping import Float
|
|
24
|
-
from loguru import logger
|
|
25
23
|
|
|
26
24
|
from dexcontrol.config.core import HeadConfig
|
|
27
25
|
from dexcontrol.core.component import RobotJointComponent
|
|
28
26
|
from dexcontrol.proto import dexcontrol_msg_pb2, dexcontrol_query_pb2
|
|
27
|
+
from dexcontrol.utils.comm_helper import get_zenoh_config_path
|
|
29
28
|
from dexcontrol.utils.os_utils import resolve_key_name
|
|
30
29
|
|
|
31
30
|
|
|
@@ -44,19 +43,16 @@ class Head(RobotJointComponent):
|
|
|
44
43
|
def __init__(
|
|
45
44
|
self,
|
|
46
45
|
configs: HeadConfig,
|
|
47
|
-
zenoh_session: zenoh.Session,
|
|
48
46
|
) -> None:
|
|
49
47
|
"""Initialize the head controller.
|
|
50
48
|
|
|
51
49
|
Args:
|
|
52
50
|
configs: Configuration parameters for the head including communication topics.
|
|
53
|
-
zenoh_session: Active Zenoh communication session for message passing.
|
|
54
51
|
"""
|
|
55
52
|
super().__init__(
|
|
56
53
|
state_sub_topic=configs.state_sub_topic,
|
|
57
54
|
control_pub_topic=configs.control_pub_topic,
|
|
58
55
|
state_message_type=dexcontrol_msg_pb2.MotorStateWithTorque,
|
|
59
|
-
zenoh_session=zenoh_session,
|
|
60
56
|
joint_name=configs.joint_name,
|
|
61
57
|
joint_limit=configs.joint_limit
|
|
62
58
|
if hasattr(configs, "joint_limit")
|
|
@@ -67,9 +63,8 @@ class Head(RobotJointComponent):
|
|
|
67
63
|
pose_pool=configs.pose_pool,
|
|
68
64
|
)
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
)
|
|
66
|
+
# Store the query topic for later use with DexComm
|
|
67
|
+
self._mode_query_topic = resolve_key_name(configs.set_mode_query)
|
|
73
68
|
assert self._joint_vel_limit is not None, "joint_vel_limit is not set"
|
|
74
69
|
|
|
75
70
|
def set_joint_pos(
|
|
@@ -198,13 +193,15 @@ class Head(RobotJointComponent):
|
|
|
198
193
|
|
|
199
194
|
query_msg = dexcontrol_query_pb2.SetHeadMode()
|
|
200
195
|
query_msg.mode = mode_map[mode]
|
|
201
|
-
replies = self.mode_querier.get(payload=query_msg.SerializeToString())
|
|
202
196
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
197
|
+
call_service(
|
|
198
|
+
self._mode_query_topic,
|
|
199
|
+
request=query_msg,
|
|
200
|
+
timeout=1.0,
|
|
201
|
+
config=get_zenoh_config_path(),
|
|
202
|
+
request_serializer=lambda x: x.SerializeToString(),
|
|
203
|
+
response_deserializer=None,
|
|
204
|
+
)
|
|
208
205
|
|
|
209
206
|
def get_joint_limit(self) -> Float[np.ndarray, "3 2"] | None:
|
|
210
207
|
"""Get the joint limits of the head.
|
|
@@ -225,16 +222,7 @@ class Head(RobotJointComponent):
|
|
|
225
222
|
"""Clean up Zenoh resources for the head component."""
|
|
226
223
|
self.stop()
|
|
227
224
|
super().shutdown()
|
|
228
|
-
|
|
229
|
-
if hasattr(self, "mode_querier") and self.mode_querier:
|
|
230
|
-
self.mode_querier.undeclare()
|
|
231
|
-
except Exception as e:
|
|
232
|
-
# Don't log "Undeclared querier" errors as warnings - they're expected during shutdown
|
|
233
|
-
error_msg = str(e).lower()
|
|
234
|
-
if not ("undeclared" in error_msg or "closed" in error_msg):
|
|
235
|
-
logger.warning(
|
|
236
|
-
f"Error undeclaring mode querier for {self.__class__.__name__}: {e}"
|
|
237
|
-
)
|
|
225
|
+
# No need to undeclare queriers when using DexComm
|
|
238
226
|
|
|
239
227
|
def _process_joint_velocities(
|
|
240
228
|
self,
|