kuavo-humanoid-sdk 1.1.2a924__py3-none-any.whl → 1.1.3a1226__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 kuavo-humanoid-sdk might be problematic. Click here for more details.
- kuavo_humanoid_sdk/common/global_config.py +15 -0
- kuavo_humanoid_sdk/common/websocket_kuavo_sdk.py +23 -0
- kuavo_humanoid_sdk/interfaces/data_types.py +46 -0
- kuavo_humanoid_sdk/kuavo/__init__.py +3 -0
- kuavo_humanoid_sdk/kuavo/core/audio.py +33 -0
- kuavo_humanoid_sdk/kuavo/core/core.py +16 -6
- kuavo_humanoid_sdk/kuavo/core/ros/audio.py +87 -0
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +645 -19
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +142 -4
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +329 -15
- kuavo_humanoid_sdk/kuavo/core/ros/tools.py +149 -0
- kuavo_humanoid_sdk/kuavo/core/ros/vision.py +272 -0
- kuavo_humanoid_sdk/kuavo/core/ros_env.py +229 -1
- kuavo_humanoid_sdk/kuavo/dexterous_hand.py +6 -2
- kuavo_humanoid_sdk/kuavo/leju_claw.py +6 -2
- kuavo_humanoid_sdk/kuavo/robot.py +43 -22
- kuavo_humanoid_sdk/kuavo/robot_audio.py +39 -0
- kuavo_humanoid_sdk/kuavo/robot_info.py +7 -2
- kuavo_humanoid_sdk/kuavo/robot_state.py +6 -2
- kuavo_humanoid_sdk/kuavo/robot_tool.py +62 -0
- kuavo_humanoid_sdk/kuavo/robot_vision.py +87 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetection.py +306 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetectionArray.py +437 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +9 -0
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_armHandPose.py +2 -2
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_handPose.py +2 -2
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_ikSolveError.py +13 -13
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_ikSolveParam.py +2 -2
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_robotArmQVVD.py +2 -2
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_twoArmHandPose.py +13 -13
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/msg/_twoArmHandPoseCmd.py +15 -15
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SpeechSynthesis.py +270 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +5 -0
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/srv/_changeArmCtrlModeKuavo.py +5 -5
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/srv/_fkSrv.py +13 -13
- kuavo_humanoid_sdk/msg/{motion_capture_ik/srv/_changeArmCtrlMode.py → kuavo_msgs/srv/_playmusic.py} +97 -98
- kuavo_humanoid_sdk/msg/{motion_capture_ik → kuavo_msgs}/srv/_twoArmHandPoseCmdSrv.py +23 -23
- {kuavo_humanoid_sdk-1.1.2a924.dist-info → kuavo_humanoid_sdk-1.1.3a1226.dist-info}/METADATA +2 -1
- {kuavo_humanoid_sdk-1.1.2a924.dist-info → kuavo_humanoid_sdk-1.1.3a1226.dist-info}/RECORD +41 -33
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/__init__.py +0 -9
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/_headBodyPose.py +0 -145
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/_robotHandPosition.py +0 -225
- kuavo_humanoid_sdk/msg/motion_capture_ik/srv/__init__.py +0 -4
- {kuavo_humanoid_sdk-1.1.2a924.dist-info → kuavo_humanoid_sdk-1.1.3a1226.dist-info}/WHEEL +0 -0
- {kuavo_humanoid_sdk-1.1.2a924.dist-info → kuavo_humanoid_sdk-1.1.3a1226.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
from kuavo_humanoid_sdk.common.global_config import GlobalConfig
|
|
2
|
+
try:
|
|
3
|
+
import rospy
|
|
4
|
+
except ImportError:
|
|
5
|
+
pass
|
|
2
6
|
import json
|
|
3
7
|
import xml.etree.ElementTree as ET
|
|
4
8
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
5
|
-
|
|
9
|
+
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
6
10
|
# End effector types
|
|
7
11
|
class EndEffectorType:
|
|
8
12
|
QIANGNAO = "qiangnao"
|
|
@@ -64,7 +68,126 @@ class RosParameter:
|
|
|
64
68
|
return None
|
|
65
69
|
return rospy.get_param('/initial_state')
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
import roslibpy
|
|
72
|
+
class RosParamWebsocket:
|
|
73
|
+
def __init__(self):
|
|
74
|
+
self.websocket = WebSocketKuavoSDK()
|
|
75
|
+
if not self.websocket.client.is_connected:
|
|
76
|
+
SDKLogger.error("Failed to connect to WebSocket server")
|
|
77
|
+
raise ConnectionError("Failed to connect to WebSocket server")
|
|
78
|
+
|
|
79
|
+
def robot_version(self)->str:
|
|
80
|
+
try:
|
|
81
|
+
param_service = roslibpy.Param(self.websocket.client, 'robot_version')
|
|
82
|
+
param = param_service.get()
|
|
83
|
+
if param is None:
|
|
84
|
+
SDKLogger.error("robot_version parameter not found")
|
|
85
|
+
return None
|
|
86
|
+
return param
|
|
87
|
+
except Exception as e:
|
|
88
|
+
SDKLogger.error(f"Failed to get robot_version: {e}")
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
def arm_dof(self)->int:
|
|
92
|
+
try:
|
|
93
|
+
param_service = roslibpy.Param(self.websocket.client, 'armRealDof')
|
|
94
|
+
param = param_service.get()
|
|
95
|
+
if param is None:
|
|
96
|
+
SDKLogger.error("armRealDof parameter not found")
|
|
97
|
+
return None
|
|
98
|
+
return param
|
|
99
|
+
except Exception as e:
|
|
100
|
+
SDKLogger.error(f"Failed to get armRealDof: {e}")
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def head_dof(self)->int:
|
|
104
|
+
try:
|
|
105
|
+
param_service = roslibpy.Param(self.websocket.client, 'headRealDof')
|
|
106
|
+
param = param_service.get()
|
|
107
|
+
if param is None:
|
|
108
|
+
SDKLogger.error("headRealDof parameter not found")
|
|
109
|
+
return None
|
|
110
|
+
return param
|
|
111
|
+
except Exception as e:
|
|
112
|
+
SDKLogger.error(f"Failed to get headRealDof: {e}")
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def leg_dof(self)->int:
|
|
116
|
+
try:
|
|
117
|
+
param_service = roslibpy.Param(self.websocket.client, 'legRealDof')
|
|
118
|
+
param = param_service.get()
|
|
119
|
+
if param is None:
|
|
120
|
+
SDKLogger.error("legRealDof parameter not found")
|
|
121
|
+
return None
|
|
122
|
+
return param
|
|
123
|
+
except Exception as e:
|
|
124
|
+
SDKLogger.error(f"Failed to get legRealDof: {e}")
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
def end_effector_type(self)->str:
|
|
128
|
+
try:
|
|
129
|
+
param_service = roslibpy.Param(self.websocket.client, 'end_effector_type')
|
|
130
|
+
param = param_service.get()
|
|
131
|
+
if param is None:
|
|
132
|
+
SDKLogger.error("end_effector_type parameter not found")
|
|
133
|
+
return None
|
|
134
|
+
return param
|
|
135
|
+
except Exception as e:
|
|
136
|
+
SDKLogger.error(f"Failed to get end_effector_type: {e}")
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
def humanoid_description(self)->str:
|
|
140
|
+
try:
|
|
141
|
+
param_service = roslibpy.Param(self.websocket.client, 'humanoid_description')
|
|
142
|
+
param = param_service.get()
|
|
143
|
+
if param is None:
|
|
144
|
+
SDKLogger.error("humanoid_description parameter not found")
|
|
145
|
+
return None
|
|
146
|
+
return param
|
|
147
|
+
except Exception as e:
|
|
148
|
+
SDKLogger.error(f"Failed to get humanoid_description: {e}")
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
def model_path(self)->str:
|
|
152
|
+
try:
|
|
153
|
+
param_service = roslibpy.Param(self.websocket.client, 'modelPath')
|
|
154
|
+
param = param_service.get()
|
|
155
|
+
if param is None:
|
|
156
|
+
SDKLogger.error("modelPath parameter not found")
|
|
157
|
+
return None
|
|
158
|
+
return param
|
|
159
|
+
except Exception as e:
|
|
160
|
+
SDKLogger.error(f"Failed to get modelPath: {e}")
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
def kuavo_config(self)->str:
|
|
164
|
+
try:
|
|
165
|
+
param_service = roslibpy.Param(self.websocket.client, 'kuavo_configuration')
|
|
166
|
+
param = param_service.get()
|
|
167
|
+
if param is None:
|
|
168
|
+
SDKLogger.error("kuavo_configuration parameter not found")
|
|
169
|
+
return None
|
|
170
|
+
return param
|
|
171
|
+
except Exception as e:
|
|
172
|
+
SDKLogger.error(f"Failed to get kuavo_configuration: {e}")
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
def initial_state(self)->str:
|
|
176
|
+
try:
|
|
177
|
+
param_service = roslibpy.Param(self.websocket.client, 'initial_state')
|
|
178
|
+
param = param_service.get()
|
|
179
|
+
if param is None:
|
|
180
|
+
SDKLogger.error("initial_state parameter not found")
|
|
181
|
+
return None
|
|
182
|
+
return param
|
|
183
|
+
except Exception as e:
|
|
184
|
+
SDKLogger.error(f"Failed to get initial_state: {e}")
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
# if GlobalConfig.use_websocket:
|
|
188
|
+
# kuavo_ros_param = RosParamWebsocket()
|
|
189
|
+
# else:
|
|
190
|
+
# kuavo_ros_param = RosParameter()
|
|
68
191
|
|
|
69
192
|
def joint_names()->dict:
|
|
70
193
|
leg_link_names = [
|
|
@@ -78,6 +201,11 @@ def joint_names()->dict:
|
|
|
78
201
|
head_link_names = [
|
|
79
202
|
'zhead_1_link', 'zhead_2_link'
|
|
80
203
|
]
|
|
204
|
+
if GlobalConfig.use_websocket:
|
|
205
|
+
kuavo_ros_param = RosParamWebsocket()
|
|
206
|
+
else:
|
|
207
|
+
kuavo_ros_param = RosParameter()
|
|
208
|
+
|
|
81
209
|
robot_desc = kuavo_ros_param.humanoid_description()
|
|
82
210
|
if robot_desc is None:
|
|
83
211
|
return None
|
|
@@ -135,6 +263,11 @@ kuavo_ros_info = None
|
|
|
135
263
|
|
|
136
264
|
def end_frames_names()->dict:
|
|
137
265
|
default = ["torso", "zarm_l7_link", "zarm_r7_link", "zarm_l4_link", "zarm_r4_link"]
|
|
266
|
+
if GlobalConfig.use_websocket:
|
|
267
|
+
kuavo_ros_param = RosParamWebsocket()
|
|
268
|
+
else:
|
|
269
|
+
kuavo_ros_param = RosParameter()
|
|
270
|
+
|
|
138
271
|
kuavo_json = kuavo_ros_param.kuavo_config()
|
|
139
272
|
if kuavo_json is None:
|
|
140
273
|
return default
|
|
@@ -154,6 +287,11 @@ def make_robot_param()->dict:
|
|
|
154
287
|
if kuavo_ros_info is not None:
|
|
155
288
|
return kuavo_ros_info
|
|
156
289
|
|
|
290
|
+
if GlobalConfig.use_websocket:
|
|
291
|
+
kuavo_ros_param = RosParamWebsocket()
|
|
292
|
+
else:
|
|
293
|
+
kuavo_ros_param = RosParameter()
|
|
294
|
+
|
|
157
295
|
kuavo_ros_info = {
|
|
158
296
|
'robot_version': kuavo_ros_param.robot_version(),
|
|
159
297
|
'arm_dof': kuavo_ros_param.arm_dof(),
|
|
@@ -174,4 +312,4 @@ def make_robot_param()->dict:
|
|
|
174
312
|
|
|
175
313
|
if __name__ == "__main__":
|
|
176
314
|
rospy.init_node("kuavo_ros_param_test")
|
|
177
|
-
print(make_robot_param())
|
|
315
|
+
print(make_robot_param())
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import roslibpy
|
|
2
2
|
import copy
|
|
3
3
|
import time
|
|
4
4
|
from typing import Tuple
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import rospy
|
|
8
|
+
from std_msgs.msg import Float64
|
|
9
|
+
from nav_msgs.msg import Odometry
|
|
10
|
+
from sensor_msgs.msg import JointState
|
|
11
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.msg import sensorsData, lejuClawState, gaitTimeName, dexhandTouchState
|
|
12
|
+
from kuavo_msgs.srv import changeArmCtrlMode, changeArmCtrlModeRequest, getCurrentGaitName, getCurrentGaitNameRequest
|
|
13
|
+
from kuavo_humanoid_sdk.msg.ocs2_msgs.msg import mpc_observation
|
|
14
|
+
except:
|
|
15
|
+
pass
|
|
16
|
+
|
|
11
17
|
from kuavo_humanoid_sdk.interfaces.data_types import (KuavoImuData, KuavoJointData, KuavoOdometry,
|
|
12
18
|
KuavoArmCtrlMode, EndEffectorState, KuavoDexHandTouchState)
|
|
13
19
|
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
14
20
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
21
|
+
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
15
22
|
|
|
16
23
|
from collections import deque
|
|
17
24
|
from typing import Tuple, Optional
|
|
@@ -50,6 +57,7 @@ class GaitManager:
|
|
|
50
57
|
return "No_Gait"
|
|
51
58
|
return self._gait_time_names[-1][1]
|
|
52
59
|
|
|
60
|
+
|
|
53
61
|
class KuavoRobotStateCore:
|
|
54
62
|
_instance = None
|
|
55
63
|
|
|
@@ -242,10 +250,10 @@ class KuavoRobotStateCore:
|
|
|
242
250
|
self._gait_changed_callbacks.append(callback)
|
|
243
251
|
|
|
244
252
|
""" ------------------------------- callback ------------------------------- """
|
|
245
|
-
def _terrain_height_callback(self, msg
|
|
253
|
+
def _terrain_height_callback(self, msg)->None:
|
|
246
254
|
self._terrain_height = msg.data
|
|
247
255
|
|
|
248
|
-
def _sensors_data_raw_callback(self, msg
|
|
256
|
+
def _sensors_data_raw_callback(self, msg)->None:
|
|
249
257
|
# update imu data
|
|
250
258
|
self._imu_data = KuavoImuData(
|
|
251
259
|
gyro = (msg.imu_data.gyro.x, msg.imu_data.gyro.y, msg.imu_data.gyro.z),
|
|
@@ -261,7 +269,7 @@ class KuavoRobotStateCore:
|
|
|
261
269
|
acceleration = copy.deepcopy(msg.joint_data.joint_current if hasattr(msg.joint_data, 'joint_current') else msg.joint_data.joint_torque)
|
|
262
270
|
)
|
|
263
271
|
|
|
264
|
-
def _odom_callback(self, msg
|
|
272
|
+
def _odom_callback(self, msg)->None:
|
|
265
273
|
# update odom data
|
|
266
274
|
self._odom_data = KuavoOdometry(
|
|
267
275
|
position = (msg.pose.pose.position.x, msg.pose.pose.position.y, msg.pose.pose.position.z),
|
|
@@ -270,7 +278,7 @@ class KuavoRobotStateCore:
|
|
|
270
278
|
angular = (msg.twist.twist.angular.x, msg.twist.twist.angular.y, msg.twist.twist.angular.z)
|
|
271
279
|
)
|
|
272
280
|
|
|
273
|
-
def _lejuclaw_state_callback(self, msg
|
|
281
|
+
def _lejuclaw_state_callback(self, msg)->None:
|
|
274
282
|
self._eef_state = (EndEffectorState(
|
|
275
283
|
# left claw
|
|
276
284
|
position = [msg.data.position[0]],
|
|
@@ -285,7 +293,7 @@ class KuavoRobotStateCore:
|
|
|
285
293
|
state=EndEffectorState.GraspingState(msg.state[1])
|
|
286
294
|
))
|
|
287
295
|
|
|
288
|
-
def _dexterous_hand_state_callback(self, msg
|
|
296
|
+
def _dexterous_hand_state_callback(self, msg)->None:
|
|
289
297
|
self._eef_state = (EndEffectorState(
|
|
290
298
|
# left hand
|
|
291
299
|
position = list(msg.position[:len(msg.position)//2]),
|
|
@@ -300,7 +308,7 @@ class KuavoRobotStateCore:
|
|
|
300
308
|
state=EndEffectorState.GraspingState.UNKNOWN
|
|
301
309
|
))
|
|
302
310
|
|
|
303
|
-
def _dexhand_touch_state_callback(self, msg
|
|
311
|
+
def _dexhand_touch_state_callback(self, msg)->None:
|
|
304
312
|
# Update touch state for both hands
|
|
305
313
|
self._dexhand_touch_state = (
|
|
306
314
|
KuavoDexHandTouchState(
|
|
@@ -323,7 +331,7 @@ class KuavoRobotStateCore:
|
|
|
323
331
|
) # Right hand touch state
|
|
324
332
|
)
|
|
325
333
|
|
|
326
|
-
def _humanoid_mpc_gait_changed_callback(self, msg
|
|
334
|
+
def _humanoid_mpc_gait_changed_callback(self, msg):
|
|
327
335
|
"""
|
|
328
336
|
Callback function for gait change messages.
|
|
329
337
|
Updates the current gait name when a gait change occurs.
|
|
@@ -331,7 +339,7 @@ class KuavoRobotStateCore:
|
|
|
331
339
|
SDKLogger.debug(f"[State] Received gait change message: {msg.gait_name} at time {msg.start_time}")
|
|
332
340
|
self._gait_manager.add(msg.start_time, msg.gait_name)
|
|
333
341
|
|
|
334
|
-
def _humanoid_mpc_observation_callback(self, msg
|
|
342
|
+
def _humanoid_mpc_observation_callback(self, msg) -> None:
|
|
335
343
|
"""
|
|
336
344
|
Callback function for MPC observation messages.
|
|
337
345
|
Updates the current MPC state and input data.
|
|
@@ -378,3 +386,309 @@ class KuavoRobotStateCore:
|
|
|
378
386
|
except Exception as e:
|
|
379
387
|
SDKLogger.error(f"Service call failed: {e}")
|
|
380
388
|
return None
|
|
389
|
+
|
|
390
|
+
class KuavoRobotStateCoreWebsocket:
|
|
391
|
+
_instance = None
|
|
392
|
+
|
|
393
|
+
def __new__(cls, *args, **kwargs):
|
|
394
|
+
if not cls._instance:
|
|
395
|
+
cls._instance = super().__new__(cls)
|
|
396
|
+
return cls._instance
|
|
397
|
+
|
|
398
|
+
def __init__(self):
|
|
399
|
+
if not hasattr(self, '_initialized'):
|
|
400
|
+
try:
|
|
401
|
+
self.websocket = WebSocketKuavoSDK()
|
|
402
|
+
if not self.websocket.client.is_connected:
|
|
403
|
+
SDKLogger.error("Failed to connect to WebSocket server")
|
|
404
|
+
raise ConnectionError("Failed to connect to WebSocket server")
|
|
405
|
+
|
|
406
|
+
# Initialize subscribers
|
|
407
|
+
self._sub_sensors_data = roslibpy.Topic(self.websocket.client, '/sensors_data_raw', 'kuavo_msgs/sensorsData')
|
|
408
|
+
self._sub_odom = roslibpy.Topic(self.websocket.client, '/odom', 'nav_msgs/Odometry')
|
|
409
|
+
self._sub_terrain_height = roslibpy.Topic(self.websocket.client, '/humanoid/mpc/terrainHeight', 'std_msgs/Float64')
|
|
410
|
+
self._sub_gait_time_name = roslibpy.Topic(self.websocket.client, '/humanoid_mpc_gait_time_name', 'kuavo_msgs/gaitTimeName')
|
|
411
|
+
self._sub_mpc_observation = roslibpy.Topic(self.websocket.client, '/humanoid_mpc_observation', 'ocs2_msgs/mpc_observation')
|
|
412
|
+
|
|
413
|
+
# service calls are time-consuming after subscription, place them before subscription
|
|
414
|
+
kuavo_info = make_robot_param()
|
|
415
|
+
|
|
416
|
+
# Subscribe to topics
|
|
417
|
+
self._sub_sensors_data.subscribe(self._sensors_data_raw_callback)
|
|
418
|
+
self._sub_odom.subscribe(self._odom_callback)
|
|
419
|
+
self._sub_terrain_height.subscribe(self._terrain_height_callback)
|
|
420
|
+
self._sub_gait_time_name.subscribe(self._humanoid_mpc_gait_changed_callback)
|
|
421
|
+
self._sub_mpc_observation.subscribe(self._humanoid_mpc_observation_callback)
|
|
422
|
+
|
|
423
|
+
if kuavo_info is None:
|
|
424
|
+
SDKLogger.error("Failed to get robot parameters")
|
|
425
|
+
raise RuntimeError("Failed to get robot parameters")
|
|
426
|
+
|
|
427
|
+
self._ee_type = kuavo_info['end_effector_type']
|
|
428
|
+
if self._ee_type == EndEffectorType.LEJUCLAW:
|
|
429
|
+
self._sub_lejuclaw_state = roslibpy.Topic(self.websocket.client, '/leju_claw_state', 'kuavo_msgs/lejuClawState')
|
|
430
|
+
self._sub_lejuclaw_state.subscribe(self._lejuclaw_state_callback)
|
|
431
|
+
elif self._ee_type == EndEffectorType.QIANGNAO:
|
|
432
|
+
self._sub_dexhand_state = roslibpy.Topic(self.websocket.client, '/dexhand/state', 'sensor_msgs/JointState')
|
|
433
|
+
self._sub_dexhand_state.subscribe(self._dexterous_hand_state_callback)
|
|
434
|
+
elif self._ee_type == EndEffectorType.QIANGNAO_TOUCH:
|
|
435
|
+
self._sub_dexhand_state = roslibpy.Topic(self.websocket.client, '/dexhand/state', 'sensor_msgs/JointState')
|
|
436
|
+
self._sub_dexhand_touch_state = roslibpy.Topic(self.websocket.client, '/dexhand/touch_state', 'kuavo_msgs/dexhandTouchState')
|
|
437
|
+
self._sub_dexhand_state.subscribe(self._dexterous_hand_state_callback)
|
|
438
|
+
self._sub_dexhand_touch_state.subscribe(self._dexhand_touch_state_callback)
|
|
439
|
+
# Initialize touch state for both hands
|
|
440
|
+
self._dexhand_touch_state = (
|
|
441
|
+
KuavoDexHandTouchState(
|
|
442
|
+
data=(KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
443
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
444
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
445
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
446
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
|
447
|
+
),
|
|
448
|
+
KuavoDexHandTouchState(
|
|
449
|
+
data=(KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
450
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
451
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
452
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
453
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
""" data """
|
|
458
|
+
self._terrain_height = 0.0
|
|
459
|
+
self._imu_data = KuavoImuData(
|
|
460
|
+
gyro = (0.0, 0.0, 0.0),
|
|
461
|
+
acc = (0.0, 0.0, 0.0),
|
|
462
|
+
free_acc = (0.0, 0.0, 0.0),
|
|
463
|
+
quat = (0.0, 0.0, 0.0, 0.0)
|
|
464
|
+
)
|
|
465
|
+
self._joint_data = KuavoJointData(
|
|
466
|
+
position = [0.0] * 28,
|
|
467
|
+
velocity = [0.0] * 28,
|
|
468
|
+
torque = [0.0] * 28,
|
|
469
|
+
acceleration = [0.0] * 28
|
|
470
|
+
)
|
|
471
|
+
self._odom_data = KuavoOdometry(
|
|
472
|
+
position = (0.0, 0.0, 0.0),
|
|
473
|
+
orientation = (0.0, 0.0, 0.0, 0.0),
|
|
474
|
+
linear = (0.0, 0.0, 0.0),
|
|
475
|
+
angular = (0.0, 0.0, 0.0)
|
|
476
|
+
)
|
|
477
|
+
self._eef_state = (EndEffectorState(
|
|
478
|
+
position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
479
|
+
velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
480
|
+
effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
481
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
482
|
+
), EndEffectorState(
|
|
483
|
+
position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
484
|
+
velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
485
|
+
effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
486
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
487
|
+
))
|
|
488
|
+
|
|
489
|
+
# gait manager
|
|
490
|
+
self._gait_manager = GaitManager()
|
|
491
|
+
self._prev_gait_name = self.gait_name
|
|
492
|
+
|
|
493
|
+
# Wait for first MPC observation data
|
|
494
|
+
self._mpc_observation_data = None
|
|
495
|
+
start_time = time.time()
|
|
496
|
+
while self._mpc_observation_data is None:
|
|
497
|
+
if time.time() - start_time > 1.0: # 1.0s timeout
|
|
498
|
+
SDKLogger.warn("Timeout waiting for MPC observation data")
|
|
499
|
+
break
|
|
500
|
+
SDKLogger.debug("Waiting for first MPC observation data...")
|
|
501
|
+
time.sleep(0.1)
|
|
502
|
+
|
|
503
|
+
if self._mpc_observation_data is not None:
|
|
504
|
+
if self._gait_manager.is_empty:
|
|
505
|
+
self._prev_gait_name = self.gait_name()
|
|
506
|
+
SDKLogger.debug(f"[State] Adding initial gait state: {self._prev_gait_name} at time {self._mpc_observation_data['time']}")
|
|
507
|
+
self._gait_manager.add(self._mpc_observation_data['time'], self._prev_gait_name)
|
|
508
|
+
|
|
509
|
+
# 获取当前手臂控制模式
|
|
510
|
+
self._arm_ctrl_mode = self._srv_get_arm_ctrl_mode()
|
|
511
|
+
self._initialized = True
|
|
512
|
+
except Exception as e:
|
|
513
|
+
SDKLogger.error(f"Failed to initialize KuavoRobotStateCoreWebsocket: {e}")
|
|
514
|
+
raise
|
|
515
|
+
|
|
516
|
+
@property
|
|
517
|
+
def com_height(self)->float:
|
|
518
|
+
return self._odom_data.position[2] - self._terrain_height
|
|
519
|
+
|
|
520
|
+
@property
|
|
521
|
+
def imu_data(self)->KuavoImuData:
|
|
522
|
+
return self._imu_data
|
|
523
|
+
|
|
524
|
+
@property
|
|
525
|
+
def joint_data(self)->KuavoJointData:
|
|
526
|
+
return self._joint_data
|
|
527
|
+
|
|
528
|
+
@property
|
|
529
|
+
def odom_data(self)->KuavoOdometry:
|
|
530
|
+
return self._odom_data
|
|
531
|
+
|
|
532
|
+
@property
|
|
533
|
+
def arm_control_mode(self) -> KuavoArmCtrlMode:
|
|
534
|
+
mode = self._srv_get_arm_ctrl_mode()
|
|
535
|
+
if mode is not None:
|
|
536
|
+
self._arm_ctrl_mode = mode
|
|
537
|
+
return self._arm_ctrl_mode
|
|
538
|
+
|
|
539
|
+
@property
|
|
540
|
+
def eef_state(self)->Tuple[EndEffectorState, EndEffectorState]:
|
|
541
|
+
return self._eef_state
|
|
542
|
+
|
|
543
|
+
@property
|
|
544
|
+
def dexhand_touch_state(self)-> Tuple[KuavoDexHandTouchState, KuavoDexHandTouchState]:
|
|
545
|
+
if self._ee_type != EndEffectorType.QIANGNAO_TOUCH:
|
|
546
|
+
raise Exception("This robot does not support touch state")
|
|
547
|
+
return self._dexhand_touch_state
|
|
548
|
+
|
|
549
|
+
@property
|
|
550
|
+
def current_observation_time(self) -> float:
|
|
551
|
+
if self._mpc_observation_data is None:
|
|
552
|
+
return None
|
|
553
|
+
return self._mpc_observation_data.time
|
|
554
|
+
|
|
555
|
+
@property
|
|
556
|
+
def current_gait_mode(self) -> int:
|
|
557
|
+
if self._mpc_observation_data is None:
|
|
558
|
+
return None
|
|
559
|
+
return self._mpc_observation_data.mode
|
|
560
|
+
|
|
561
|
+
def gait_name(self)->str:
|
|
562
|
+
return self._srv_get_current_gait_name()
|
|
563
|
+
|
|
564
|
+
def is_gait(self, gait_name: str) -> bool:
|
|
565
|
+
return self._gait_manager.get_gait(self._mpc_observation_data['time']) == gait_name
|
|
566
|
+
|
|
567
|
+
def register_gait_changed_callback(self, callback):
|
|
568
|
+
if not hasattr(self, '_gait_changed_callbacks'):
|
|
569
|
+
self._gait_changed_callbacks = []
|
|
570
|
+
|
|
571
|
+
from inspect import signature
|
|
572
|
+
sig = signature(callback)
|
|
573
|
+
if len(sig.parameters) != 2:
|
|
574
|
+
raise ValueError("Callback must accept 2 parameters: current_time (float), gait_name (str)")
|
|
575
|
+
if callback not in self._gait_changed_callbacks:
|
|
576
|
+
self._gait_changed_callbacks.append(callback)
|
|
577
|
+
|
|
578
|
+
def _terrain_height_callback(self, msg)->None:
|
|
579
|
+
self._terrain_height = msg['data']
|
|
580
|
+
|
|
581
|
+
def _sensors_data_raw_callback(self, msg)->None:
|
|
582
|
+
# update imu data
|
|
583
|
+
self._imu_data = KuavoImuData(
|
|
584
|
+
gyro = (msg['imu_data']['gyro']['x'], msg['imu_data']['gyro']['y'], msg['imu_data']['gyro']['z']),
|
|
585
|
+
acc = (msg['imu_data']['acc']['x'], msg['imu_data']['acc']['y'], msg['imu_data']['acc']['z']),
|
|
586
|
+
free_acc = (msg['imu_data']['free_acc']['x'], msg['imu_data']['free_acc']['y'], msg['imu_data']['free_acc']['z']),
|
|
587
|
+
quat = (msg['imu_data']['quat']['x'], msg['imu_data']['quat']['y'], msg['imu_data']['quat']['z'], msg['imu_data']['quat']['w'])
|
|
588
|
+
)
|
|
589
|
+
# update joint data
|
|
590
|
+
self._joint_data = KuavoJointData(
|
|
591
|
+
position = copy.deepcopy(msg['joint_data']['joint_q']),
|
|
592
|
+
velocity = copy.deepcopy(msg['joint_data']['joint_v']),
|
|
593
|
+
torque = copy.deepcopy(msg['joint_data']['joint_vd']),
|
|
594
|
+
acceleration = copy.deepcopy(msg['joint_data'].get('joint_current', msg['joint_data']['joint_torque']))
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
def _odom_callback(self, msg)->None:
|
|
598
|
+
# update odom data
|
|
599
|
+
self._odom_data = KuavoOdometry(
|
|
600
|
+
position = (msg['pose']['pose']['position']['x'], msg['pose']['pose']['position']['y'], msg['pose']['pose']['position']['z']),
|
|
601
|
+
orientation = (msg['pose']['pose']['orientation']['x'], msg['pose']['pose']['orientation']['y'], msg['pose']['pose']['orientation']['z'], msg['pose']['pose']['orientation']['w']),
|
|
602
|
+
linear = (msg['twist']['twist']['linear']['x'], msg['twist']['twist']['linear']['y'], msg['twist']['twist']['linear']['z']),
|
|
603
|
+
angular = (msg['twist']['twist']['angular']['x'], msg['twist']['twist']['angular']['y'], msg['twist']['twist']['angular']['z'])
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
def _lejuclaw_state_callback(self, msg)->None:
|
|
607
|
+
self._eef_state = (EndEffectorState(
|
|
608
|
+
position = [msg['data']['position'][0]],
|
|
609
|
+
velocity = [msg['data']['velocity'][0]],
|
|
610
|
+
effort = [msg['data']['effort'][0]],
|
|
611
|
+
state=EndEffectorState.GraspingState(msg['state'][0])
|
|
612
|
+
), EndEffectorState(
|
|
613
|
+
position = [msg['data']['position'][1]],
|
|
614
|
+
velocity = [msg['data']['velocity'][1]],
|
|
615
|
+
effort = [msg['data']['effort'][1]],
|
|
616
|
+
state=EndEffectorState.GraspingState(msg['state'][1])
|
|
617
|
+
))
|
|
618
|
+
|
|
619
|
+
def _dexterous_hand_state_callback(self, msg)->None:
|
|
620
|
+
self._eef_state = (EndEffectorState(
|
|
621
|
+
position = list(msg['position'][:len(msg['position'])//2]),
|
|
622
|
+
velocity = list(msg['velocity'][:len(msg['velocity'])//2]),
|
|
623
|
+
effort = list(msg['effort'][:len(msg['effort'])//2]),
|
|
624
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
625
|
+
), EndEffectorState(
|
|
626
|
+
position = list(msg['position'][len(msg['position'])//2:]),
|
|
627
|
+
velocity = list(msg['velocity'][len(msg['velocity'])//2:]),
|
|
628
|
+
effort = list(msg['effort'][len(msg['effort'])//2:]),
|
|
629
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
630
|
+
))
|
|
631
|
+
|
|
632
|
+
def _dexhand_touch_state_callback(self, msg)->None:
|
|
633
|
+
self._dexhand_touch_state = (
|
|
634
|
+
KuavoDexHandTouchState(
|
|
635
|
+
data=tuple(KuavoDexHandTouchState.KuavoTouchState(
|
|
636
|
+
sensor['normal_force1'], sensor['normal_force2'], sensor['normal_force3'],
|
|
637
|
+
sensor['tangential_force1'], sensor['tangential_force2'], sensor['tangential_force3'],
|
|
638
|
+
sensor['tangential_direction1'], sensor['tangential_direction2'], sensor['tangential_direction3'],
|
|
639
|
+
sensor['self_proximity1'], sensor['self_proximity2'], sensor['mutual_proximity'],
|
|
640
|
+
sensor['status']
|
|
641
|
+
) for sensor in msg['left_hand'])
|
|
642
|
+
),
|
|
643
|
+
KuavoDexHandTouchState(
|
|
644
|
+
data=tuple(KuavoDexHandTouchState.KuavoTouchState(
|
|
645
|
+
sensor['normal_force1'], sensor['normal_force2'], sensor['normal_force3'],
|
|
646
|
+
sensor['tangential_force1'], sensor['tangential_force2'], sensor['tangential_force3'],
|
|
647
|
+
sensor['tangential_direction1'], sensor['tangential_direction2'], sensor['tangential_direction3'],
|
|
648
|
+
sensor['self_proximity1'], sensor['self_proximity2'], sensor['mutual_proximity'],
|
|
649
|
+
sensor['status']
|
|
650
|
+
) for sensor in msg['right_hand'])
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
def _humanoid_mpc_gait_changed_callback(self, msg):
|
|
655
|
+
SDKLogger.debug(f"[State] Received gait change message: {msg['gait_name']} at time {msg['start_time']}")
|
|
656
|
+
self._gait_manager.add(msg['start_time'], msg['gait_name'])
|
|
657
|
+
|
|
658
|
+
def _humanoid_mpc_observation_callback(self, msg) -> None:
|
|
659
|
+
try:
|
|
660
|
+
SDKLogger.debug(f"[State] Received MPC observation message: {msg}")
|
|
661
|
+
self._mpc_observation_data = msg
|
|
662
|
+
if hasattr(self, '_initialized'):
|
|
663
|
+
curr_time = self._mpc_observation_data['time']
|
|
664
|
+
current_gait = self._gait_manager.get_gait(curr_time)
|
|
665
|
+
if self._prev_gait_name != current_gait:
|
|
666
|
+
SDKLogger.debug(f"[State] Gait changed to: {current_gait} at time {curr_time}")
|
|
667
|
+
self._prev_gait_name = current_gait
|
|
668
|
+
if hasattr(self, '_gait_changed_callbacks') and self._gait_changed_callbacks is not None:
|
|
669
|
+
for callback in self._gait_changed_callbacks:
|
|
670
|
+
callback(curr_time, current_gait)
|
|
671
|
+
except Exception as e:
|
|
672
|
+
SDKLogger.error(f"Error processing MPC observation: {e}")
|
|
673
|
+
|
|
674
|
+
def _srv_get_arm_ctrl_mode(self)-> KuavoArmCtrlMode:
|
|
675
|
+
try:
|
|
676
|
+
service = roslibpy.Service(self.websocket.client, '/humanoid_get_arm_ctrl_mode', 'kuavo_msgs/changeArmCtrlMode')
|
|
677
|
+
request = {}
|
|
678
|
+
response = service.call(request)
|
|
679
|
+
return KuavoArmCtrlMode(response.get('mode', 0))
|
|
680
|
+
except Exception as e:
|
|
681
|
+
SDKLogger.error(f"Service call failed: {e}")
|
|
682
|
+
return None
|
|
683
|
+
|
|
684
|
+
def _srv_get_current_gait_name(self)->str:
|
|
685
|
+
try:
|
|
686
|
+
service = roslibpy.Service(self.websocket.client, '/humanoid_get_current_gait_name', 'kuavo_msgs/getCurrentGaitName')
|
|
687
|
+
request = {}
|
|
688
|
+
response = service.call(request)
|
|
689
|
+
if response.get('success', False):
|
|
690
|
+
return response['gait_name']
|
|
691
|
+
return None
|
|
692
|
+
except Exception as e:
|
|
693
|
+
SDKLogger.error(f"Service call failed: {e}")
|
|
694
|
+
return None
|