kuavo-humanoid-sdk 1.1.3a1252__py3-none-any.whl → 1.1.6__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/interfaces/data_types.py +0 -46
- kuavo_humanoid_sdk/kuavo/__init__.py +0 -3
- kuavo_humanoid_sdk/kuavo/core/core.py +6 -18
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +19 -645
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +4 -142
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +15 -329
- kuavo_humanoid_sdk/kuavo/core/ros_env.py +1 -229
- kuavo_humanoid_sdk/kuavo/dexterous_hand.py +2 -6
- kuavo_humanoid_sdk/kuavo/leju_claw.py +2 -6
- kuavo_humanoid_sdk/kuavo/robot.py +22 -43
- kuavo_humanoid_sdk/kuavo/robot_info.py +2 -7
- kuavo_humanoid_sdk/kuavo/robot_state.py +2 -6
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +0 -7
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +0 -4
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_playmusic.py +20 -26
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/__init__.py +9 -0
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_armHandPose.py +2 -2
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_handPose.py +2 -2
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/_headBodyPose.py +145 -0
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_ikSolveError.py +13 -13
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_ikSolveParam.py +2 -2
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_robotArmQVVD.py +2 -2
- kuavo_humanoid_sdk/msg/motion_capture_ik/msg/_robotHandPosition.py +225 -0
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_twoArmHandPose.py +13 -13
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/msg/_twoArmHandPoseCmd.py +15 -15
- kuavo_humanoid_sdk/msg/motion_capture_ik/srv/__init__.py +4 -0
- kuavo_humanoid_sdk/msg/{kuavo_msgs/srv/_SpeechSynthesis.py → motion_capture_ik/srv/_changeArmCtrlMode.py} +98 -93
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/srv/_changeArmCtrlModeKuavo.py +5 -5
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/srv/_fkSrv.py +13 -13
- kuavo_humanoid_sdk/msg/{kuavo_msgs → motion_capture_ik}/srv/_twoArmHandPoseCmdSrv.py +23 -23
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/METADATA +1 -2
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/RECORD +34 -39
- kuavo_humanoid_sdk/common/global_config.py +0 -16
- kuavo_humanoid_sdk/common/websocket_kuavo_sdk.py +0 -23
- kuavo_humanoid_sdk/kuavo/core/audio.py +0 -36
- kuavo_humanoid_sdk/kuavo/core/ros/audio.py +0 -176
- kuavo_humanoid_sdk/kuavo/core/ros/tools.py +0 -158
- kuavo_humanoid_sdk/kuavo/core/ros/vision.py +0 -522
- kuavo_humanoid_sdk/kuavo/robot_audio.py +0 -39
- kuavo_humanoid_sdk/kuavo/robot_tool.py +0 -62
- kuavo_humanoid_sdk/kuavo/robot_vision.py +0 -90
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/WHEEL +0 -0
- {kuavo_humanoid_sdk-1.1.3a1252.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/top_level.txt +0 -0
|
@@ -1,522 +0,0 @@
|
|
|
1
|
-
#! /usr/bin/env python3
|
|
2
|
-
# coding: utf-8
|
|
3
|
-
|
|
4
|
-
import copy
|
|
5
|
-
import time
|
|
6
|
-
from collections import deque
|
|
7
|
-
from typing import Tuple, Optional
|
|
8
|
-
|
|
9
|
-
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
10
|
-
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
11
|
-
from kuavo_humanoid_sdk.interfaces.data_types import (AprilTagData)
|
|
12
|
-
import roslibpy
|
|
13
|
-
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
14
|
-
|
|
15
|
-
try:
|
|
16
|
-
import rospy
|
|
17
|
-
from std_msgs.msg import Float64
|
|
18
|
-
from nav_msgs.msg import Odometry
|
|
19
|
-
from sensor_msgs.msg import JointState
|
|
20
|
-
from apriltag_ros.msg import AprilTagDetectionArray
|
|
21
|
-
from geometry_msgs.msg import TransformStamped, PoseStamped
|
|
22
|
-
import tf2_ros
|
|
23
|
-
import tf2_geometry_msgs
|
|
24
|
-
except ImportError:
|
|
25
|
-
pass
|
|
26
|
-
|
|
27
|
-
class KuavoRobotVisionCore:
|
|
28
|
-
"""Handles vision-related data processing for Kuavo humanoid robot.
|
|
29
|
-
|
|
30
|
-
Attributes:
|
|
31
|
-
tf_buffer (tf2_ros.Buffer): TF2 transform buffer
|
|
32
|
-
tf_listener (tf2_ros.TransformListener): TF2 transform listener
|
|
33
|
-
tf_broadcaster (tf2_ros.TransformBroadcaster): TF2 transform broadcaster
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
def __init__(self):
|
|
37
|
-
"""Initializes vision system components including TF and AprilTag subscribers."""
|
|
38
|
-
if not hasattr(self, '_initialized'):
|
|
39
|
-
self.tf_buffer = tf2_ros.Buffer()
|
|
40
|
-
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer)
|
|
41
|
-
self.tf_broadcaster = tf2_ros.TransformBroadcaster()
|
|
42
|
-
self._apriltag_data_camera_sub = rospy.Subscriber('/tag_detections', AprilTagDetectionArray, self._apriltag_data_callback_camera)
|
|
43
|
-
self._apriltag_data_base_sub = rospy.Subscriber('/robot_tag_info', AprilTagDetectionArray, self._apriltag_data_callback_base)
|
|
44
|
-
|
|
45
|
-
# 添加TF2监听器
|
|
46
|
-
self._tf_buffer = tf2_ros.Buffer()
|
|
47
|
-
self._tf_listener = tf2_ros.TransformListener(self._tf_buffer)
|
|
48
|
-
|
|
49
|
-
""" data """
|
|
50
|
-
self._apriltag_data_from_camera = AprilTagData(
|
|
51
|
-
id = [],
|
|
52
|
-
size = [],
|
|
53
|
-
pose = []
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
self._apriltag_data_from_base = AprilTagData(
|
|
57
|
-
id = [],
|
|
58
|
-
size = [],
|
|
59
|
-
pose = []
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
self._apriltag_data_from_odom = AprilTagData(
|
|
63
|
-
id = [],
|
|
64
|
-
size = [],
|
|
65
|
-
pose = []
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
def _apriltag_data_callback_camera(self, data):
|
|
69
|
-
"""Callback for processing AprilTag detections from camera.
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
data (AprilTagDetectionArray): Raw detection data from camera
|
|
73
|
-
"""
|
|
74
|
-
# 清空之前的数据
|
|
75
|
-
self._apriltag_data_from_camera.id = []
|
|
76
|
-
self._apriltag_data_from_camera.size = []
|
|
77
|
-
self._apriltag_data_from_camera.pose = []
|
|
78
|
-
|
|
79
|
-
# 处理每个标签检测
|
|
80
|
-
for detection in data.detections:
|
|
81
|
-
# 添加ID
|
|
82
|
-
for id in detection.id:
|
|
83
|
-
self._apriltag_data_from_camera.id.append(id)
|
|
84
|
-
|
|
85
|
-
# 添加尺寸 (从size数组中获取)
|
|
86
|
-
if detection.size and len(detection.size) > 0:
|
|
87
|
-
self._apriltag_data_from_camera.size.append(detection.size[0])
|
|
88
|
-
else:
|
|
89
|
-
self._apriltag_data_from_camera.size.append(0.0)
|
|
90
|
-
|
|
91
|
-
# 添加姿态
|
|
92
|
-
self._apriltag_data_from_camera.pose.append(detection.pose.pose.pose)
|
|
93
|
-
# # debug
|
|
94
|
-
# rospy.loginfo("Apriltag data from camera: %s", self._apriltag_data_from_camera)
|
|
95
|
-
|
|
96
|
-
def _apriltag_data_callback_base(self, data):
|
|
97
|
-
"""Callback for processing AprilTag detections from base link.
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
data (AprilTagDetectionArray): Raw detection data from base frame
|
|
101
|
-
"""
|
|
102
|
-
# 清空之前的数据
|
|
103
|
-
self._apriltag_data_from_base.id = []
|
|
104
|
-
self._apriltag_data_from_base.size = []
|
|
105
|
-
self._apriltag_data_from_base.pose = []
|
|
106
|
-
|
|
107
|
-
# 处理每个标签检测
|
|
108
|
-
for detection in data.detections:
|
|
109
|
-
# 添加ID
|
|
110
|
-
for id in detection.id:
|
|
111
|
-
self._apriltag_data_from_base.id.append(id)
|
|
112
|
-
|
|
113
|
-
# 添加尺寸 (从size数组中获取)
|
|
114
|
-
if detection.size and len(detection.size) > 0:
|
|
115
|
-
self._apriltag_data_from_base.size.append(detection.size[0])
|
|
116
|
-
else:
|
|
117
|
-
self._apriltag_data_from_base.size.append(0.0)
|
|
118
|
-
|
|
119
|
-
# 添加姿态
|
|
120
|
-
self._apriltag_data_from_base.pose.append(detection.pose.pose.pose)
|
|
121
|
-
|
|
122
|
-
# # debug
|
|
123
|
-
# rospy.loginfo("Apriltag data from base: %s", self._apriltag_data_from_base)
|
|
124
|
-
|
|
125
|
-
# 在基础数据处理完后,尝试进行odom坐标系的变换
|
|
126
|
-
self._transform_base_to_odom()
|
|
127
|
-
|
|
128
|
-
def _transform_base_to_odom(self):
|
|
129
|
-
"""Transforms AprilTag poses from base_link to odom coordinate frame.
|
|
130
|
-
|
|
131
|
-
Performs:
|
|
132
|
-
- Coordinate transformation using TF2
|
|
133
|
-
- TF broadcasting for transformed poses
|
|
134
|
-
- Data validation and error handling
|
|
135
|
-
|
|
136
|
-
Raises:
|
|
137
|
-
tf2_ros.LookupException: If transform is not available
|
|
138
|
-
tf2_ros.ConnectivityException: If transform chain is broken
|
|
139
|
-
tf2_ros.ExtrapolationException: If transform time is out of range
|
|
140
|
-
"""
|
|
141
|
-
# 添加节点状态检查
|
|
142
|
-
if rospy.is_shutdown():
|
|
143
|
-
return
|
|
144
|
-
|
|
145
|
-
# 清空之前的数据
|
|
146
|
-
self._apriltag_data_from_odom.id = []
|
|
147
|
-
self._apriltag_data_from_odom.size = []
|
|
148
|
-
self._apriltag_data_from_odom.pose = []
|
|
149
|
-
|
|
150
|
-
# 如果base数据为空,则不处理
|
|
151
|
-
if not self._apriltag_data_from_base.id:
|
|
152
|
-
SDKLogger.warn("No base tag data, skip transform")
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
try:
|
|
156
|
-
# 获取从base_link到odom的变换
|
|
157
|
-
transform = self._tf_buffer.lookup_transform(
|
|
158
|
-
"odom",
|
|
159
|
-
"base_link",
|
|
160
|
-
rospy.Time(0),
|
|
161
|
-
rospy.Duration(1.0)
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
# 复制ID和尺寸信息
|
|
165
|
-
self._apriltag_data_from_odom.id = self._apriltag_data_from_base.id.copy()
|
|
166
|
-
self._apriltag_data_from_odom.size = self._apriltag_data_from_base.size.copy()
|
|
167
|
-
|
|
168
|
-
# 对每个姿态进行变换
|
|
169
|
-
for idx, (tag_id, pose) in enumerate(zip(self._apriltag_data_from_base.id, self._apriltag_data_from_base.pose)):
|
|
170
|
-
# 创建PoseStamped消息
|
|
171
|
-
pose_stamped = PoseStamped()
|
|
172
|
-
pose_stamped.header.frame_id = "base_link"
|
|
173
|
-
pose_stamped.header.stamp = rospy.Time.now()
|
|
174
|
-
pose_stamped.pose = pose
|
|
175
|
-
|
|
176
|
-
# 执行变换
|
|
177
|
-
transformed_pose = tf2_geometry_msgs.do_transform_pose(pose_stamped, transform)
|
|
178
|
-
|
|
179
|
-
# 将变换后的姿态添加到odom数据中
|
|
180
|
-
self._apriltag_data_from_odom.pose.append(transformed_pose.pose)
|
|
181
|
-
|
|
182
|
-
# 创建并广播TF
|
|
183
|
-
transform_stamped = TransformStamped()
|
|
184
|
-
transform_stamped.header.stamp = rospy.Time.now()
|
|
185
|
-
transform_stamped.header.frame_id = "odom"
|
|
186
|
-
transform_stamped.child_frame_id = f"tag_odom_{tag_id}"
|
|
187
|
-
transform_stamped.transform.translation.x = transformed_pose.pose.position.x
|
|
188
|
-
transform_stamped.transform.translation.y = transformed_pose.pose.position.y
|
|
189
|
-
transform_stamped.transform.translation.z = transformed_pose.pose.position.z
|
|
190
|
-
transform_stamped.transform.rotation = transformed_pose.pose.orientation
|
|
191
|
-
|
|
192
|
-
# 发送变换前再次检查节点状态
|
|
193
|
-
if not rospy.is_shutdown():
|
|
194
|
-
self.tf_broadcaster.sendTransform(transform_stamped)
|
|
195
|
-
|
|
196
|
-
except (tf2_ros.LookupException,
|
|
197
|
-
tf2_ros.ConnectivityException,
|
|
198
|
-
tf2_ros.ExtrapolationException,
|
|
199
|
-
rospy.ROSException) as e: # 添加ROSException捕获
|
|
200
|
-
SDKLogger.warn(f"TF变换异常: {str(e)}")
|
|
201
|
-
|
|
202
|
-
@property
|
|
203
|
-
def apriltag_data_from_camera(self) -> AprilTagData:
|
|
204
|
-
"""AprilTag detection data in camera coordinate frame.
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
AprilTagData: Contains lists of tag IDs, sizes and poses
|
|
208
|
-
"""
|
|
209
|
-
return self._apriltag_data_from_camera
|
|
210
|
-
|
|
211
|
-
@property
|
|
212
|
-
def apriltag_data_from_base(self) -> AprilTagData:
|
|
213
|
-
"""AprilTag detection data in base_link coordinate frame.
|
|
214
|
-
|
|
215
|
-
Returns:
|
|
216
|
-
AprilTagData: Contains lists of tag IDs, sizes and poses
|
|
217
|
-
"""
|
|
218
|
-
return self._apriltag_data_from_base
|
|
219
|
-
|
|
220
|
-
@property
|
|
221
|
-
def apriltag_data_from_odom(self) -> AprilTagData:
|
|
222
|
-
"""AprilTag detection data in odom coordinate frame.
|
|
223
|
-
|
|
224
|
-
Returns:
|
|
225
|
-
AprilTagData: Contains lists of tag IDs, sizes and transformed poses
|
|
226
|
-
"""
|
|
227
|
-
return self._apriltag_data_from_odom
|
|
228
|
-
|
|
229
|
-
def _get_data_by_id(self, target_id: int, data_source: str = "base") -> Optional[dict]:
|
|
230
|
-
"""Retrieves AprilTag data by specific ID from selected source.
|
|
231
|
-
|
|
232
|
-
Args:
|
|
233
|
-
target_id (int): AprilTag ID to search for
|
|
234
|
-
data_source (str): Data source selector, valid options:
|
|
235
|
-
"camera", "base", "odom"
|
|
236
|
-
|
|
237
|
-
Returns:
|
|
238
|
-
Optional[dict]: Dictionary containing 'sizes' and 'poses' lists if found,
|
|
239
|
-
None if no matching data
|
|
240
|
-
|
|
241
|
-
Raises:
|
|
242
|
-
ValueError: If invalid data_source is specified
|
|
243
|
-
"""
|
|
244
|
-
data_map = {
|
|
245
|
-
"camera": self._apriltag_data_from_camera,
|
|
246
|
-
"base": self._apriltag_data_from_base,
|
|
247
|
-
"odom": self._apriltag_data_from_odom
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if data_source not in data_map:
|
|
251
|
-
SDKLogger.error(f"Invalid data source: {data_source}, must be one of {list(data_map.keys())}")
|
|
252
|
-
return None
|
|
253
|
-
|
|
254
|
-
data = data_map[data_source]
|
|
255
|
-
|
|
256
|
-
# 查找所有匹配的索引
|
|
257
|
-
indices = [i for i, tag_id in enumerate(data.id) if tag_id == target_id]
|
|
258
|
-
|
|
259
|
-
if not indices:
|
|
260
|
-
SDKLogger.debug(f"No data found for tag ID {target_id} in {data_source} source")
|
|
261
|
-
return None
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
"sizes": [data.size[i] for i in indices],
|
|
265
|
-
"poses": [data.pose[i] for i in indices]
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
class KuavoRobotVisionCoreWebsocket:
|
|
269
|
-
_instance = None
|
|
270
|
-
|
|
271
|
-
def __new__(cls, *args, **kwargs):
|
|
272
|
-
if not cls._instance:
|
|
273
|
-
cls._instance = super().__new__(cls)
|
|
274
|
-
return cls._instance
|
|
275
|
-
|
|
276
|
-
def __init__(self):
|
|
277
|
-
if not hasattr(self, '_initialized'):
|
|
278
|
-
try:
|
|
279
|
-
self.websocket = WebSocketKuavoSDK()
|
|
280
|
-
if not self.websocket.client.is_connected:
|
|
281
|
-
SDKLogger.error("Failed to connect to WebSocket server")
|
|
282
|
-
raise ConnectionError("Failed to connect to WebSocket server")
|
|
283
|
-
|
|
284
|
-
# Initialize subscribers for vision-related topics
|
|
285
|
-
self._sub_apriltag_camera = roslibpy.Topic(self.websocket.client, '/tag_detections', 'apriltag_ros/AprilTagDetectionArray')
|
|
286
|
-
self._sub_apriltag_base = roslibpy.Topic(self.websocket.client, '/robot_tag_info', 'apriltag_ros/AprilTagDetectionArray')
|
|
287
|
-
|
|
288
|
-
# Initialize TF-related topics
|
|
289
|
-
self._sub_tf = roslibpy.Topic(self.websocket.client, '/tf', 'tf2_msgs/TFMessage')
|
|
290
|
-
self._sub_tf_static = roslibpy.Topic(self.websocket.client, '/tf_static', 'tf2_msgs/TFMessage')
|
|
291
|
-
|
|
292
|
-
# Subscribe to topics
|
|
293
|
-
self._sub_apriltag_camera.subscribe(self._apriltag_camera_callback)
|
|
294
|
-
self._sub_apriltag_base.subscribe(self._apriltag_base_callback)
|
|
295
|
-
self._sub_tf.subscribe(self._tf_callback)
|
|
296
|
-
self._sub_tf_static.subscribe(self._tf_static_callback)
|
|
297
|
-
|
|
298
|
-
# Initialize data structures
|
|
299
|
-
self._apriltag_data_from_camera = AprilTagData(
|
|
300
|
-
id = [],
|
|
301
|
-
size = [],
|
|
302
|
-
pose = []
|
|
303
|
-
)
|
|
304
|
-
self._apriltag_data_from_base = AprilTagData(
|
|
305
|
-
id = [],
|
|
306
|
-
size = [],
|
|
307
|
-
pose = []
|
|
308
|
-
)
|
|
309
|
-
self._apriltag_data_from_odom = AprilTagData(
|
|
310
|
-
id = [],
|
|
311
|
-
size = [],
|
|
312
|
-
pose = []
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
# TF buffer for storing transforms
|
|
316
|
-
self._tf_buffer = {}
|
|
317
|
-
self._tf_static_buffer = {}
|
|
318
|
-
|
|
319
|
-
self._initialized = True
|
|
320
|
-
except Exception as e:
|
|
321
|
-
SDKLogger.error(f"Failed to initialize KuavoRobotVisionCoreWebsocket: {e}")
|
|
322
|
-
raise
|
|
323
|
-
|
|
324
|
-
def _tf_callback(self, msg):
|
|
325
|
-
"""Callback for TF messages."""
|
|
326
|
-
for transform in msg['transforms']:
|
|
327
|
-
key = (transform['header']['frame_id'], transform['child_frame_id'])
|
|
328
|
-
self._tf_buffer[key] = transform
|
|
329
|
-
|
|
330
|
-
def _tf_static_callback(self, msg):
|
|
331
|
-
"""Callback for static TF messages."""
|
|
332
|
-
for transform in msg['transforms']:
|
|
333
|
-
key = (transform['header']['frame_id'], transform['child_frame_id'])
|
|
334
|
-
self._tf_static_buffer[key] = transform
|
|
335
|
-
|
|
336
|
-
def _get_transform(self, target_frame, source_frame):
|
|
337
|
-
"""Get transform between two frames.
|
|
338
|
-
|
|
339
|
-
Args:
|
|
340
|
-
target_frame (str): Target frame ID
|
|
341
|
-
source_frame (str): Source frame ID
|
|
342
|
-
|
|
343
|
-
Returns:
|
|
344
|
-
dict: Transform data if found, None otherwise
|
|
345
|
-
"""
|
|
346
|
-
# Check both dynamic and static transforms
|
|
347
|
-
key = (source_frame, target_frame)
|
|
348
|
-
if key in self._tf_buffer:
|
|
349
|
-
return self._tf_buffer[key]
|
|
350
|
-
if key in self._tf_static_buffer:
|
|
351
|
-
return self._tf_static_buffer[key]
|
|
352
|
-
return None
|
|
353
|
-
|
|
354
|
-
def _transform_pose(self, pose, transform):
|
|
355
|
-
"""Transform a pose using the given transform.
|
|
356
|
-
|
|
357
|
-
Args:
|
|
358
|
-
pose (dict): Pose to transform
|
|
359
|
-
transform (dict): Transform to apply
|
|
360
|
-
|
|
361
|
-
Returns:
|
|
362
|
-
dict: Transformed pose
|
|
363
|
-
"""
|
|
364
|
-
# Extract transform components
|
|
365
|
-
t = transform['transform']
|
|
366
|
-
translation = t['translation']
|
|
367
|
-
rotation = t['rotation']
|
|
368
|
-
|
|
369
|
-
# Extract pose components
|
|
370
|
-
p = pose['position']
|
|
371
|
-
o = pose['orientation']
|
|
372
|
-
|
|
373
|
-
# TODO: Implement actual pose transformation
|
|
374
|
-
# This is a placeholder - actual implementation would involve
|
|
375
|
-
# proper quaternion and vector math
|
|
376
|
-
transformed_pose = {
|
|
377
|
-
'position': {
|
|
378
|
-
'x': p['x'] + translation['x'],
|
|
379
|
-
'y': p['y'] + translation['y'],
|
|
380
|
-
'z': p['z'] + translation['z']
|
|
381
|
-
},
|
|
382
|
-
'orientation': {
|
|
383
|
-
'x': o['x'],
|
|
384
|
-
'y': o['y'],
|
|
385
|
-
'z': o['z'],
|
|
386
|
-
'w': o['w']
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return transformed_pose
|
|
391
|
-
|
|
392
|
-
def _apriltag_camera_callback(self, msg):
|
|
393
|
-
"""Callback for AprilTag detections in camera frame."""
|
|
394
|
-
# Clear previous data
|
|
395
|
-
self._apriltag_data_from_camera.id = []
|
|
396
|
-
self._apriltag_data_from_camera.size = []
|
|
397
|
-
self._apriltag_data_from_camera.pose = []
|
|
398
|
-
|
|
399
|
-
# Process each detection
|
|
400
|
-
for detection in msg['detections']:
|
|
401
|
-
# Add ID
|
|
402
|
-
for tag_id in detection['id']:
|
|
403
|
-
self._apriltag_data_from_camera.id.append(tag_id)
|
|
404
|
-
|
|
405
|
-
# Add size
|
|
406
|
-
if detection.get('size') and len(detection['size']) > 0:
|
|
407
|
-
self._apriltag_data_from_camera.size.append(detection['size'][0])
|
|
408
|
-
else:
|
|
409
|
-
self._apriltag_data_from_camera.size.append(0.0)
|
|
410
|
-
|
|
411
|
-
# Add pose
|
|
412
|
-
self._apriltag_data_from_camera.pose.append(detection['pose']['pose']['pose'])
|
|
413
|
-
|
|
414
|
-
def _apriltag_base_callback(self, msg):
|
|
415
|
-
"""Callback for AprilTag detections in base frame."""
|
|
416
|
-
# Clear previous data
|
|
417
|
-
self._apriltag_data_from_base.id = []
|
|
418
|
-
self._apriltag_data_from_base.size = []
|
|
419
|
-
self._apriltag_data_from_base.pose = []
|
|
420
|
-
|
|
421
|
-
# Process each detection
|
|
422
|
-
for detection in msg['detections']:
|
|
423
|
-
# Add ID
|
|
424
|
-
for tag_id in detection['id']:
|
|
425
|
-
self._apriltag_data_from_base.id.append(tag_id)
|
|
426
|
-
|
|
427
|
-
# Add size
|
|
428
|
-
if detection.get('size') and len(detection['size']) > 0:
|
|
429
|
-
self._apriltag_data_from_base.size.append(detection['size'][0])
|
|
430
|
-
else:
|
|
431
|
-
self._apriltag_data_from_base.size.append(0.0)
|
|
432
|
-
|
|
433
|
-
# Add pose
|
|
434
|
-
self._apriltag_data_from_base.pose.append(detection['pose']['pose']['pose'])
|
|
435
|
-
|
|
436
|
-
# Transform base data to odom frame
|
|
437
|
-
self._transform_base_to_odom()
|
|
438
|
-
|
|
439
|
-
def _transform_base_to_odom(self):
|
|
440
|
-
"""Transform AprilTag poses from base_link to odom coordinate frame."""
|
|
441
|
-
# Clear previous odom data
|
|
442
|
-
self._apriltag_data_from_odom.id = []
|
|
443
|
-
self._apriltag_data_from_odom.size = []
|
|
444
|
-
self._apriltag_data_from_odom.pose = []
|
|
445
|
-
|
|
446
|
-
# If no base data, skip transformation
|
|
447
|
-
if not self._apriltag_data_from_base.id:
|
|
448
|
-
SDKLogger.warn("No base tag data, skip transform")
|
|
449
|
-
return
|
|
450
|
-
|
|
451
|
-
# Get transform from base_link to odom
|
|
452
|
-
transform = self._get_transform("odom", "base_link")
|
|
453
|
-
if not transform:
|
|
454
|
-
SDKLogger.warn("Transform from base_link to odom not available")
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
# Copy ID and size information
|
|
458
|
-
self._apriltag_data_from_odom.id = self._apriltag_data_from_base.id.copy()
|
|
459
|
-
self._apriltag_data_from_odom.size = self._apriltag_data_from_base.size.copy()
|
|
460
|
-
|
|
461
|
-
# Transform each pose
|
|
462
|
-
for pose in self._apriltag_data_from_base.pose:
|
|
463
|
-
transformed_pose = self._transform_pose(pose, transform)
|
|
464
|
-
self._apriltag_data_from_odom.pose.append(transformed_pose)
|
|
465
|
-
|
|
466
|
-
@property
|
|
467
|
-
def apriltag_data_from_camera(self):
|
|
468
|
-
return self._apriltag_data_from_camera
|
|
469
|
-
|
|
470
|
-
@property
|
|
471
|
-
def apriltag_data_from_base(self):
|
|
472
|
-
return self._apriltag_data_from_base
|
|
473
|
-
|
|
474
|
-
@property
|
|
475
|
-
def apriltag_data_from_odom(self):
|
|
476
|
-
return self._apriltag_data_from_odom
|
|
477
|
-
|
|
478
|
-
def get_data_by_id(self, tag_id: int, frame: str = "odom"):
|
|
479
|
-
"""Get AprilTag data for a specific tag ID from the specified frame.
|
|
480
|
-
|
|
481
|
-
Args:
|
|
482
|
-
tag_id (int): The ID of the AprilTag to get data for
|
|
483
|
-
frame (str): The frame to get data from ("camera", "base", or "odom")
|
|
484
|
-
|
|
485
|
-
Returns:
|
|
486
|
-
dict: The AprilTag data for the specified ID and frame, or None if not found
|
|
487
|
-
"""
|
|
488
|
-
if frame == "camera":
|
|
489
|
-
data = self._apriltag_data_from_camera
|
|
490
|
-
elif frame == "base":
|
|
491
|
-
data = self._apriltag_data_from_base
|
|
492
|
-
elif frame == "odom":
|
|
493
|
-
data = self._apriltag_data_from_odom
|
|
494
|
-
else:
|
|
495
|
-
SDKLogger.error(f"Invalid frame: {frame}")
|
|
496
|
-
return None
|
|
497
|
-
|
|
498
|
-
if not data or not data.id:
|
|
499
|
-
return None
|
|
500
|
-
|
|
501
|
-
# Find all matching indices
|
|
502
|
-
indices = [i for i, id in enumerate(data.id) if id == tag_id]
|
|
503
|
-
|
|
504
|
-
if not indices:
|
|
505
|
-
return None
|
|
506
|
-
|
|
507
|
-
return {
|
|
508
|
-
"sizes": [data.size[i] for i in indices],
|
|
509
|
-
"poses": [data.pose[i] for i in indices]
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
# if __name__ == "__main__":
|
|
513
|
-
|
|
514
|
-
# kuavo_robot_vision_core = KuavoRobotVisionCore()
|
|
515
|
-
# time.sleep(5)
|
|
516
|
-
# print("apriltag_data_from_camera:")
|
|
517
|
-
# print(kuavo_robot_vision_core.apriltag_data_from_camera)
|
|
518
|
-
# print("apriltag_data_from_base:")
|
|
519
|
-
# print(kuavo_robot_vision_core.apriltag_data_from_base)
|
|
520
|
-
# print("apriltag_data_from_odom:")
|
|
521
|
-
# print(kuavo_robot_vision_core.apriltag_data_from_odom)
|
|
522
|
-
# rospy.spin()
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# coding: utf-8
|
|
3
|
-
from kuavo_humanoid_sdk.kuavo.core.audio import KuavoRobotAudioCore
|
|
4
|
-
|
|
5
|
-
class KuavoRobotAudio:
|
|
6
|
-
"""Audio system interface for controlling audio playback functionality of Kuavo humanoid robot.
|
|
7
|
-
|
|
8
|
-
Provides functionality to play music files.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
def __init__(self):
|
|
12
|
-
"""Initialize the audio system."""
|
|
13
|
-
self.audio = KuavoRobotAudioCore()
|
|
14
|
-
|
|
15
|
-
def play_audio(self, file_name: str, volume: float = 0.5, speed: float = 1.0) -> bool:
|
|
16
|
-
"""Play the specified audio file.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
file_name (str): Name of the audio file to play
|
|
20
|
-
|
|
21
|
-
Returns:
|
|
22
|
-
bool: True if the play request was successfully sent, False otherwise
|
|
23
|
-
"""
|
|
24
|
-
return self.audio.play_audio(file_name, volume, speed)
|
|
25
|
-
|
|
26
|
-
def stop_music(self):
|
|
27
|
-
"""Stop the currently playing audio."""
|
|
28
|
-
return self.audio.stop_music()
|
|
29
|
-
|
|
30
|
-
def text_to_speech(self, text: str, volume: float = 0.5) -> bool:
|
|
31
|
-
"""Synthesize and play the specified text.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
text (str): Text to be played
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
bool: True if the play request was successfully sent, False otherwise
|
|
38
|
-
"""
|
|
39
|
-
return self.audio.text_to_speech(text, volume)
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# coding: utf-8
|
|
3
|
-
import math
|
|
4
|
-
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
5
|
-
from kuavo_humanoid_sdk.interfaces.data_types import (PoseQuaternion, HomogeneousMatrix)
|
|
6
|
-
from kuavo_humanoid_sdk.kuavo.core.ros.tools import KuavoRobotToolsCore
|
|
7
|
-
from typing import Union
|
|
8
|
-
|
|
9
|
-
class KuavoRobotTools:
|
|
10
|
-
"""Robot tools class providing coordinate frame transformation interfaces.
|
|
11
|
-
|
|
12
|
-
This class encapsulates coordinate transformation queries between different robot frames,
|
|
13
|
-
supporting multiple return data formats.
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
def __init__(self):
|
|
17
|
-
"""Initialize robot tools instance."""
|
|
18
|
-
self.tools_core = KuavoRobotToolsCore()
|
|
19
|
-
|
|
20
|
-
def get_tf_transform(self, target_frame: str, source_frame: str,
|
|
21
|
-
return_type: str = "pose_quaternion") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
|
|
22
|
-
"""Get transformation between specified coordinate frames.
|
|
23
|
-
|
|
24
|
-
Args:
|
|
25
|
-
target_frame (str): Name of target coordinate frame
|
|
26
|
-
source_frame (str): Name of source coordinate frame
|
|
27
|
-
return_type (str, optional): Return data format type. Valid values:
|
|
28
|
-
"pose_quaternion" - quaternion pose format,
|
|
29
|
-
"homogeneous" - homogeneous matrix format. Defaults to "pose_quaternion".
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
Union[PoseQuaternion, HomogeneousMatrix, None]:
|
|
33
|
-
Transformation data in specified format, or None if failed
|
|
34
|
-
|
|
35
|
-
Raises:
|
|
36
|
-
ValueError: If invalid return_type is provided
|
|
37
|
-
"""
|
|
38
|
-
return self.tools_core._get_tf_tree_transform(target_frame, source_frame, return_type=return_type)
|
|
39
|
-
|
|
40
|
-
def get_base_to_odom(self, return_type: str = "pose_quaternion") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
|
|
41
|
-
"""Get transformation from base_link to odom frame.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
return_type (str, optional): Return format type. Same as get_tf_transform.
|
|
45
|
-
Defaults to "pose_quaternion".
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
Union[PoseQuaternion, HomogeneousMatrix, None]: Transformation data or None
|
|
49
|
-
"""
|
|
50
|
-
return self.get_tf_transform("odom", "base_link", return_type)
|
|
51
|
-
|
|
52
|
-
def get_camera_to_base(self, return_type: str = "homogeneous") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
|
|
53
|
-
"""Get transformation from camera_link to base_link frame.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
return_type (str, optional): Return format type. Same as get_tf_transform.
|
|
57
|
-
Defaults to "homogeneous".
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
Union[PoseQuaternion, HomogeneousMatrix, None]: Transformation data or None
|
|
61
|
-
"""
|
|
62
|
-
return self.get_tf_transform("base_link", "camera_link", return_type)
|