kuavo-humanoid-sdk-ws 1.1.6b858__tar.gz → 1.1.6b1125__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/PKG-INFO +1 -1
  2. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/interfaces/data_types.py +22 -0
  3. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/__init__.py +2 -2
  4. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/audio.py +1 -1
  5. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/audio.py +3 -4
  6. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/state.py +6 -6
  7. kuavo_humanoid_sdk_ws-1.1.6b1125/kuavo_humanoid_sdk/kuavo/core/ros/tools.py +196 -0
  8. kuavo_humanoid_sdk_ws-1.1.6b1125/kuavo_humanoid_sdk/kuavo/core/ros/vision.py +280 -0
  9. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_audio.py +1 -1
  10. kuavo_humanoid_sdk_ws-1.1.6b1125/kuavo_humanoid_sdk/kuavo/robot_tool.py +58 -0
  11. kuavo_humanoid_sdk_ws-1.1.6b1125/kuavo_humanoid_sdk/kuavo/robot_vision.py +82 -0
  12. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk_ws.egg-info/PKG-INFO +1 -1
  13. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk_ws.egg-info/SOURCES.txt +4 -0
  14. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/setup.py +1 -1
  15. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/README.md +0 -0
  16. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/__init__.py +0 -0
  17. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/common/logger.py +0 -0
  18. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/common/websocket_kuavo_sdk.py +0 -0
  19. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/interfaces/__init__.py +0 -0
  20. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/interfaces/end_effector.py +0 -0
  21. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/interfaces/robot.py +0 -0
  22. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/interfaces/robot_info.py +0 -0
  23. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/core.py +0 -0
  24. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py +0 -0
  25. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/leju_claw_control.py +0 -0
  26. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/control.py +0 -0
  27. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/observation.py +0 -0
  28. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/param.py +0 -0
  29. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros/sat_utils.py +0 -0
  30. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/core/ros_env.py +0 -0
  31. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/dexterous_hand.py +0 -0
  32. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/leju_claw.py +0 -0
  33. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot.py +0 -0
  34. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_arm.py +0 -0
  35. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_head.py +0 -0
  36. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_info.py +0 -0
  37. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_observation.py +0 -0
  38. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo/robot_state.py +0 -0
  39. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo_strategy/__init__.py +0 -0
  40. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +0 -0
  41. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +0 -0
  42. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk/msg/__init__.py +0 -0
  43. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk_ws.egg-info/dependency_links.txt +0 -0
  44. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk_ws.egg-info/requires.txt +0 -0
  45. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/kuavo_humanoid_sdk_ws.egg-info/top_level.txt +0 -0
  46. {kuavo_humanoid_sdk_ws-1.1.6b858 → kuavo_humanoid_sdk_ws-1.1.6b1125}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kuavo_humanoid_sdk_ws
3
- Version: 1.1.6b858
3
+ Version: 1.1.6b1125
4
4
  Summary: A Python SDK for kuavo humanoid robot.
5
5
  Home-page: https://gitee.com/leju-robot/kuavo-ros-opensource/
6
6
  Author: ['lejurobot']
@@ -269,3 +269,25 @@ class KuavoTwist:
269
269
  """
270
270
  linear: Tuple[float, float, float]
271
271
  angular: Tuple[float, float, float]
272
+
273
+
274
+
275
+ @dataclass
276
+ class AprilTagDetection:
277
+ """表示AprilTag检测结果的数据类"""
278
+
279
+ @dataclass
280
+ class Point:
281
+ x: float
282
+ y: float
283
+ z: float
284
+
285
+ @dataclass
286
+ class Quaternion:
287
+ x: float
288
+ y: float
289
+ z: float
290
+ w: float
291
+
292
+ position: Point
293
+ orientation: Quaternion
@@ -1,8 +1,8 @@
1
1
  from .robot import KuavoSDK, KuavoRobot
2
2
  from .robot_info import KuavoRobotInfo
3
3
  from .robot_state import KuavoRobotState
4
- # from .robot_vision import KuavoRobotVision
5
- # from .robot_tool import KuavoRobotTools
4
+ from .robot_vision import KuavoRobotVision
5
+ from .robot_tool import KuavoRobotTools
6
6
  from .robot_arm import KuavoRobotArm
7
7
  from .robot_head import KuavoRobotHead
8
8
  from .robot_audio import KuavoRobotAudio
@@ -12,7 +12,7 @@ class KuavoRobotAudioCore:
12
12
  def __init__(self):
13
13
  self.robot_audio = AudioWebsocket()
14
14
 
15
- def play_audio(self, music_number: str, volume: float = 0.5, speed: float = 1.0) -> bool:
15
+ def play_audio(self, music_number: str, volume: int = 100, speed: float = 1.0) -> bool:
16
16
  """
17
17
  play music
18
18
  """
@@ -16,7 +16,7 @@ class AudioWebsocket:
16
16
  self._audio_stop_publisher = roslibpy.Topic(websocket.client, 'stop_music', 'std_msgs/Bool')
17
17
  self._audio_stop_publisher.advertise()
18
18
 
19
- def play_audio(self, file_name: str, volume: float = 0.5, speed: float = 1.0) -> bool:
19
+ def play_audio(self, file_name: str, volume: int = 100, speed: float = 1.0) -> bool:
20
20
  """Play the specified audio file through WebSocket.
21
21
 
22
22
  Args:
@@ -31,11 +31,10 @@ class AudioWebsocket:
31
31
  websocket = WebSocketKuavoSDK()
32
32
  service = roslibpy.Service(websocket.client, 'play_music', 'kuavo_msgs/playmusic')
33
33
 
34
- volume = min(max(volume, 0), 1.0)
34
+ volume = min(max(volume, 0), 100)
35
35
  request = {
36
36
  "music_number": file_name,
37
- "volume": volume,
38
- "speed": speed
37
+ "volume": volume
39
38
  }
40
39
 
41
40
  response = service.call(request)
@@ -133,14 +133,14 @@ class KuavoRobotStateCoreWebsocket:
133
133
  angular = (0.0, 0.0, 0.0)
134
134
  )
135
135
  self._eef_state = (EndEffectorState(
136
- position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
137
- velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
138
- effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
136
+ position = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
137
+ velocity = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
138
+ effort = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
139
139
  state=EndEffectorState.GraspingState.UNKNOWN
140
140
  ), EndEffectorState(
141
- position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
142
- velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
143
- effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
141
+ position = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
142
+ velocity = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
143
+ effort = [0.0] * 12 if kuavo_info['end_effector_type'] is not None and kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
144
144
  state=EndEffectorState.GraspingState.UNKNOWN
145
145
  ))
146
146
 
@@ -0,0 +1,196 @@
1
+ #! /usr/bin/env python3
2
+ # coding: utf-8
3
+
4
+ import copy
5
+ import time
6
+ import numpy as np
7
+ from typing import Tuple, Union
8
+ from kuavo_humanoid_sdk.common.logger import SDKLogger
9
+ from transforms3d import euler, quaternions
10
+ import roslibpy
11
+ from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
12
+ from kuavo_humanoid_sdk.interfaces.data_types import (PoseQuaternion, HomogeneousMatrix)
13
+ from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
14
+
15
+
16
+ class KuavoRobotToolsCoreWebsocket:
17
+ """Provides core ROS tools for Kuavo humanoid robot transformations.
18
+
19
+ Attributes:
20
+ tf_service (roslibpy.Service): Service proxy for tf2_web_republisher
21
+ _transform_cache (dict): Cache for storing recent transforms
22
+ """
23
+
24
+ def __init__(self):
25
+ """Initializes TF2 web republisher service proxy."""
26
+ if not hasattr(self, '_initialized'):
27
+ try:
28
+ # Initialize WebSocket connection
29
+ self.websocket = WebSocketKuavoSDK()
30
+
31
+ # Initialize TF2 web republisher service
32
+ self.tf_service = roslibpy.Service(
33
+ self.websocket.client,
34
+ '/republish_tfs',
35
+ 'kuavo_msgs/RepublishTFs'
36
+ )
37
+ self._transform_cache = {}
38
+ self._initialized = True
39
+ except Exception as e:
40
+ SDKLogger.error(f"Failed to initialize tf2_web_republisher: {str(e)}")
41
+ SDKLogger.error("Please make sure tf2_web_republisher node is running")
42
+ raise
43
+
44
+ def _get_tf_tree_transform(self, target_frame: str, source_frame: str,
45
+ time_=0.0, timeout=5.0,
46
+ return_type: str = "pose_quaternion") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
47
+ """Gets transform between coordinate frames using tf2_web_republisher.
48
+
49
+ Args:
50
+ target_frame (str): Target coordinate frame name
51
+ source_frame (str): Source coordinate frame name
52
+ time (float, optional): Time of transform. Defaults to 0.0.
53
+ timeout (float, optional): Wait timeout in seconds. Defaults to 5.0.
54
+ return_type (str, optional): Return data format. Options:
55
+ "pose_quaternion", "homogeneous". Defaults to "pose_quaternion".
56
+
57
+ Returns:
58
+ Union[PoseQuaternion, HomogeneousMatrix, None]: Requested transform data
59
+ or None if failed
60
+ """
61
+ try:
62
+
63
+ # 调用服务
64
+ request = {
65
+ 'source_frames': [source_frame],
66
+ 'target_frame': target_frame,
67
+ 'angular_thres': 0.01,
68
+ 'trans_thres': 0.01,
69
+ 'rate': 10.0,
70
+ 'timeout': {'secs': int(timeout), 'nsecs': int((timeout % 1) * 1e9)}
71
+ }
72
+
73
+ response = self.tf_service.call(request)
74
+ if response['status'] == -1:
75
+ SDKLogger.error(f"{source_frame} or {target_frame} not exist")
76
+ return None
77
+
78
+ # 检查话题是否发布
79
+ topic_list = self.websocket.client.get_topics()
80
+ if response['topic_name'] not in topic_list:
81
+ SDKLogger.error(f"Topic {response['topic_name']} not published")
82
+ return None
83
+
84
+ # 创建订阅者
85
+ transform_received = False
86
+ transform_data = None
87
+
88
+ def transform_callback(msg):
89
+ nonlocal transform_received, transform_data
90
+ transform_received = True
91
+ transform_data = msg
92
+
93
+ sub = roslibpy.Topic(self.websocket.client, response['topic_name'], 'kuavo_msgs/TFArray')
94
+ sub.subscribe(transform_callback)
95
+
96
+ # 等待接收数据
97
+ start_time = time.time()
98
+ while not transform_received and (time.time() - start_time) < timeout:
99
+ time.sleep(0.1)
100
+
101
+ # 取消订阅
102
+ sub.unsubscribe()
103
+
104
+ if not transform_received:
105
+ SDKLogger.error("No transform data received")
106
+ return None
107
+
108
+ # 从TFArray中获取对应的变换
109
+ for tf_msg in transform_data['transforms']:
110
+ if tf_msg['header']['frame_id'] == target_frame and tf_msg['child_frame_id'] == source_frame:
111
+ return self._parse_transform(tf_msg['transform'], return_type)
112
+
113
+ SDKLogger.error(f"No matching transform found in TFArray")
114
+ return None
115
+
116
+ except Exception as e:
117
+ SDKLogger.error(f"Transform error: {str(e)}")
118
+ return None
119
+
120
+ def _parse_transform(self, transform, return_type: str) -> Union[PoseQuaternion, HomogeneousMatrix, None]:
121
+ """Parses transform data to specified format.
122
+
123
+ Args:
124
+ transform (dict): Input transform data
125
+ return_type (str): Output format type. Valid values:
126
+ "pose_quaternion", "homogeneous"
127
+
128
+ Returns:
129
+ Union[PoseQuaternion, HomogeneousMatrix, None]: Parsed transform data
130
+ in requested format, or None if invalid input
131
+ """
132
+ if return_type == "pose_quaternion":
133
+ return PoseQuaternion(
134
+ position=(transform['translation']['x'],
135
+ transform['translation']['y'],
136
+ transform['translation']['z']),
137
+ orientation=(transform['rotation']['x'],
138
+ transform['rotation']['y'],
139
+ transform['rotation']['z'],
140
+ transform['rotation']['w'])
141
+ )
142
+ elif return_type == "homogeneous":
143
+ return HomogeneousMatrix(
144
+ matrix=self._transform_to_homogeneous(transform)
145
+ )
146
+ else:
147
+ SDKLogger.warn(f"Invalid return_type: {return_type}, using default(pose_quaternion)")
148
+ return self._parse_transform(transform, "pose_quaternion")
149
+
150
+ def _transform_to_homogeneous(self, transform) -> np.ndarray:
151
+ """Converts transform dict to homogeneous matrix.
152
+
153
+ Args:
154
+ transform (dict): Input transform message
155
+
156
+ Returns:
157
+ np.ndarray: 4x4 homogeneous transformation matrix (numpy.float32)
158
+ """
159
+ # 四元数转旋转矩阵
160
+ rotation = [
161
+ transform['rotation']['x'],
162
+ transform['rotation']['y'],
163
+ transform['rotation']['z'],
164
+ transform['rotation']['w']
165
+ ]
166
+
167
+ # Convert quaternion to rotation matrix using transforms3d
168
+ rot_matrix = np.eye(4)
169
+ rot_matrix[:3,:3] = quaternions.quat2mat([rotation[3], rotation[0], rotation[1], rotation[2]])
170
+
171
+ # 设置平移分量
172
+ translation = [
173
+ transform['translation']['x'],
174
+ transform['translation']['y'],
175
+ transform['translation']['z']
176
+ ]
177
+ rot_matrix[:3, 3] = translation
178
+
179
+ return rot_matrix.astype(np.float32) # 确保矩阵数据类型一致
180
+
181
+ # if __name__ == "__main__":
182
+ # robot_tools = KuavoRobotToolsCore()
183
+ # time.sleep(0.1)
184
+ # # 获取位姿信息
185
+ # pose = robot_tools._get_tf_tree_transform("odom", "base_link", return_type="pose_quaternion")
186
+ # print(f"Position: {pose.position}")
187
+ # print(f"Orientation: {pose.orientation}")
188
+
189
+ # # 获取齐次矩阵
190
+ # homogeneous = robot_tools._get_tf_tree_transform("odom", "base_link", return_type="homogeneous")
191
+ # print(f"Transformation matrix:\n{homogeneous.matrix}")
192
+
193
+ # # 矩阵运算示例
194
+ # transform_matrix = homogeneous.matrix
195
+ # inverse_matrix = np.linalg.inv(transform_matrix) # 求逆变换
196
+ # print(f"Inverse matrix:\n{inverse_matrix}")
@@ -0,0 +1,280 @@
1
+ #! /usr/bin/env python3
2
+ # coding: utf-8
3
+
4
+ import copy
5
+ import time
6
+ import numpy as np
7
+ from collections import deque
8
+ from typing import Tuple, Optional
9
+ from transforms3d import quaternions, euler
10
+
11
+ from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
12
+ from kuavo_humanoid_sdk.common.logger import SDKLogger
13
+ from kuavo_humanoid_sdk.interfaces.data_types import (AprilTagData, AprilTagDetection)
14
+ import roslibpy
15
+ from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
16
+
17
+ class KuavoRobotVisionCoreWebsocket:
18
+ """Handles vision-related data processing for Kuavo humanoid robot.
19
+
20
+ Attributes:
21
+ tf_client (roslibpy.Topic): TF client for coordinate transformations
22
+ tf_publisher (roslibpy.Topic): TF publisher for broadcasting transforms
23
+ """
24
+
25
+ def __init__(self):
26
+ """Initializes vision system components including TF and AprilTag subscribers."""
27
+ if not hasattr(self, '_initialized'):
28
+ # Initialize WebSocket connection
29
+ self.websocket = WebSocketKuavoSDK()
30
+
31
+ # Initialize AprilTag subscribers
32
+ self._apriltag_data_camera_sub = roslibpy.Topic(
33
+ self.websocket.client,
34
+ '/tag_detections',
35
+ 'apriltag_ros/AprilTagDetectionArray'
36
+ )
37
+ self._apriltag_data_camera_sub.subscribe(self._apriltag_data_callback_camera)
38
+
39
+ self._apriltag_data_base_sub = roslibpy.Topic(
40
+ self.websocket.client,
41
+ '/robot_tag_info',
42
+ 'apriltag_ros/AprilTagDetectionArray'
43
+ )
44
+ self._apriltag_data_base_sub.subscribe(self._apriltag_data_callback_base)
45
+
46
+ self._apriltag_data_odom_sub = roslibpy.Topic(
47
+ self.websocket.client,
48
+ '/robot_tag_info_odom',
49
+ 'apriltag_ros/AprilTagDetectionArray'
50
+ )
51
+ self._apriltag_data_odom_sub.subscribe(self._apriltag_data_callback_odom)
52
+
53
+ # Initialize data structures
54
+ self._apriltag_data_from_camera = AprilTagData(
55
+ id = [],
56
+ size = [],
57
+ pose = []
58
+ )
59
+
60
+ self._apriltag_data_from_base = AprilTagData(
61
+ id = [],
62
+ size = [],
63
+ pose = []
64
+ )
65
+
66
+ self._apriltag_data_from_odom = AprilTagData(
67
+ id = [],
68
+ size = [],
69
+ pose = []
70
+ )
71
+
72
+ self._initialized = True
73
+
74
+ def _tf_callback(self, msg):
75
+ """Callback for TF messages.
76
+
77
+ Args:
78
+ msg: TF message containing transforms
79
+ """
80
+ for transform in msg['transforms']:
81
+ key = (transform['header']['frame_id'], transform['child_frame_id'])
82
+ self._transforms[key] = transform
83
+
84
+ def _apriltag_data_callback_camera(self, data):
85
+ """Callback for processing AprilTag detections from camera.
86
+
87
+ Args:
88
+ data (dict): Raw detection data from camera
89
+ """
90
+ # 清空之前的数据
91
+ self._apriltag_data_from_camera.id = []
92
+ self._apriltag_data_from_camera.size = []
93
+ self._apriltag_data_from_camera.pose = []
94
+
95
+ # 处理每个标签检测
96
+ for detection in data['detections']:
97
+ # 添加ID
98
+ for id in detection['id']:
99
+ self._apriltag_data_from_camera.id.append(id)
100
+
101
+ # 添加尺寸
102
+ if detection.get('size') and len(detection['size']) > 0:
103
+ self._apriltag_data_from_camera.size.append(detection['size'][0])
104
+ else:
105
+ self._apriltag_data_from_camera.size.append(0.0)
106
+
107
+
108
+ # Convert pose dict to AprilTagDetection
109
+ pose_dict = detection['pose']['pose']['pose']
110
+
111
+ tag_detection = AprilTagDetection(
112
+ position=AprilTagDetection.Point(
113
+ x=float(pose_dict['position']['x']),
114
+ y=float(pose_dict['position']['y']),
115
+ z=float(pose_dict['position']['z'])
116
+ ),
117
+ orientation=AprilTagDetection.Quaternion(
118
+ x=float(pose_dict['orientation']['x']),
119
+ y=float(pose_dict['orientation']['y']),
120
+ z=float(pose_dict['orientation']['z']),
121
+ w=float(pose_dict['orientation']['w'])
122
+ ))
123
+ # 添加姿态
124
+ self._apriltag_data_from_camera.pose.append(tag_detection)
125
+
126
+ def _apriltag_data_callback_base(self, data):
127
+ """Callback for processing AprilTag detections from base link.
128
+
129
+ Args:
130
+ data (dict): Raw detection data from base frame
131
+ """
132
+ # 清空之前的数据
133
+ self._apriltag_data_from_base.id = []
134
+ self._apriltag_data_from_base.size = []
135
+ self._apriltag_data_from_base.pose = []
136
+
137
+ # 处理每个标签检测
138
+ for detection in data['detections']:
139
+ # 添加ID
140
+ for id in detection['id']:
141
+ self._apriltag_data_from_base.id.append(id)
142
+
143
+ # 添加尺寸
144
+ if detection.get('size') and len(detection['size']) > 0:
145
+ self._apriltag_data_from_base.size.append(detection['size'][0])
146
+ else:
147
+ self._apriltag_data_from_base.size.append(0.0)
148
+
149
+ # Convert pose dict to AprilTagDetection
150
+ pose_dict = detection['pose']['pose']['pose']
151
+
152
+ tag_detection = AprilTagDetection(
153
+ position=AprilTagDetection.Point(
154
+ x=float(pose_dict['position']['x']),
155
+ y=float(pose_dict['position']['y']),
156
+ z=float(pose_dict['position']['z'])
157
+ ),
158
+ orientation=AprilTagDetection.Quaternion(
159
+ x=float(pose_dict['orientation']['x']),
160
+ y=float(pose_dict['orientation']['y']),
161
+ z=float(pose_dict['orientation']['z']),
162
+ w=float(pose_dict['orientation']['w'])
163
+ ))
164
+
165
+ # 添加姿态
166
+ self._apriltag_data_from_base.pose.append(tag_detection)
167
+
168
+ def _apriltag_data_callback_odom(self, data):
169
+ """Callback for processing AprilTag detections from odom frame.
170
+
171
+ Args:
172
+ data (dict): Raw detection data from odom frame
173
+ """
174
+ # 清空之前的数据
175
+ self._apriltag_data_from_odom.id = []
176
+ self._apriltag_data_from_odom.size = []
177
+ self._apriltag_data_from_odom.pose = []
178
+
179
+ # 处理每个标签检测
180
+ for detection in data['detections']:
181
+ # 添加ID
182
+ for id in detection['id']:
183
+ self._apriltag_data_from_odom.id.append(id)
184
+
185
+ # 添加尺寸
186
+ if detection.get('size') and len(detection['size']) > 0:
187
+ self._apriltag_data_from_odom.size.append(detection['size'][0])
188
+ else:
189
+ self._apriltag_data_from_odom.size.append(0.0)
190
+
191
+ # Convert pose dict to AprilTagDetection
192
+ pose_dict = detection['pose']['pose']['pose']
193
+
194
+ tag_detection = AprilTagDetection(
195
+ position=AprilTagDetection.Point(
196
+ x=float(pose_dict['position']['x']),
197
+ y=float(pose_dict['position']['y']),
198
+ z=float(pose_dict['position']['z'])
199
+ ),
200
+ orientation=AprilTagDetection.Quaternion(
201
+ x=float(pose_dict['orientation']['x']),
202
+ y=float(pose_dict['orientation']['y']),
203
+ z=float(pose_dict['orientation']['z']),
204
+ w=float(pose_dict['orientation']['w'])
205
+ ))
206
+
207
+ # 添加姿态
208
+ self._apriltag_data_from_odom.pose.append(tag_detection)
209
+
210
+ @property
211
+ def apriltag_data_from_camera(self) -> AprilTagData:
212
+ """AprilTag detection data in camera coordinate frame.
213
+
214
+ Returns:
215
+ AprilTagData: Contains lists of tag IDs, sizes and poses
216
+ """
217
+ return self._apriltag_data_from_camera
218
+
219
+ @property
220
+ def apriltag_data_from_base(self) -> AprilTagData:
221
+ """AprilTag detection data in base_link coordinate frame.
222
+
223
+ Returns:
224
+ AprilTagData: Contains lists of tag IDs, sizes and poses
225
+ """
226
+ return self._apriltag_data_from_base
227
+
228
+ @property
229
+ def apriltag_data_from_odom(self) -> AprilTagData:
230
+ """AprilTag detection data in odom coordinate frame.
231
+
232
+ Returns:
233
+ AprilTagData: Contains lists of tag IDs, sizes and transformed poses
234
+ """
235
+ return self._apriltag_data_from_odom
236
+
237
+ def _get_data_by_id(self, target_id: int, data_source: str = "base") -> Optional[dict]:
238
+ """Retrieves AprilTag data by specific ID from selected source.
239
+
240
+ Args:
241
+ target_id (int): AprilTag ID to search for
242
+ data_source (str): Data source selector, valid options:
243
+ "camera", "base", "odom"
244
+
245
+ Returns:
246
+ Optional[dict]: Dictionary containing 'sizes' and 'poses' lists if found,
247
+ None if no matching data
248
+ """
249
+ data_map = {
250
+ "camera": self._apriltag_data_from_camera,
251
+ "base": self._apriltag_data_from_base,
252
+ "odom": self._apriltag_data_from_odom
253
+ }
254
+
255
+ if data_source not in data_map:
256
+ raise ValueError(f"Invalid data source: {data_source}")
257
+
258
+ data = data_map[data_source]
259
+
260
+ # 查找匹配的ID
261
+ try:
262
+ idx = data.id.index(target_id)
263
+ return {
264
+ 'sizes': [data.size[idx]],
265
+ 'poses': [data.pose[idx]]
266
+ }
267
+ except ValueError:
268
+ return None
269
+
270
+ # if __name__ == "__main__":
271
+
272
+ # kuavo_robot_vision_core = KuavoRobotVisionCoreWebsocket()
273
+ # time.sleep(5)
274
+ # print("apriltag_data_from_camera:")
275
+ # print(kuavo_robot_vision_core.apriltag_data_from_camera)
276
+ # print("apriltag_data_from_base:")
277
+ # print(kuavo_robot_vision_core.apriltag_data_from_base)
278
+ # print("apriltag_data_from_odom:")
279
+ # print(kuavo_robot_vision_core.apriltag_data_from_odom)
280
+ # rospy.spin()
@@ -12,7 +12,7 @@ class KuavoRobotAudio:
12
12
  """Initialize the audio system."""
13
13
  self.audio = KuavoRobotAudioCore()
14
14
 
15
- def play_audio(self, file_name: str, volume: float = 0.5, speed: float = 1.0) -> bool:
15
+ def play_audio(self, file_name: str, volume: int = 100, speed: float = 1.0) -> bool:
16
16
  """Play the specified audio file.
17
17
 
18
18
  Args:
@@ -0,0 +1,58 @@
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 KuavoRobotToolsCoreWebsocket
7
+ from typing import Union
8
+
9
+ class KuavoRobotTools:
10
+ """机器人工具类,提供坐标系转换接口。
11
+
12
+ 该类封装了不同机器人坐标系之间的坐标变换查询功能,支持多种返回数据格式。
13
+ """
14
+
15
+ def __init__(self):
16
+ self.tools_core = KuavoRobotToolsCoreWebsocket()
17
+
18
+ def get_tf_transform(self, target_frame: str, source_frame: str,
19
+ return_type: str = "pose_quaternion") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
20
+ """获取指定坐标系之间的变换。
21
+
22
+ Args:
23
+ target_frame (str): 目标坐标系名称
24
+ source_frame (str): 源坐标系名称
25
+ return_type (str, optional): 返回数据格式类型。有效值: \n
26
+ - "pose_quaternion" : 四元数姿态格式, \n
27
+ - "homogeneous" : 齐次矩阵格式。默认为"pose_quaternion"。\n
28
+
29
+ Returns:
30
+ Union[PoseQuaternion, HomogeneousMatrix, None]:
31
+ 指定格式的变换数据,如果失败则返回None
32
+
33
+ Raises:
34
+ ValueError: 如果提供了无效的 return_type
35
+ """
36
+ return self.tools_core._get_tf_tree_transform(target_frame, source_frame, return_type=return_type)
37
+
38
+ def get_base_to_odom(self, return_type: str = "pose_quaternion") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
39
+ """获取从base_link到odom坐标系的变换。
40
+
41
+ Args:
42
+ return_type (str, optional): 返回格式类型。与get_tf_transform相同,默认为"pose_quaternion"。
43
+
44
+ Returns:
45
+ Union[PoseQuaternion, HomogeneousMatrix, None]: 变换数据或 None
46
+ """
47
+ return self.get_tf_transform("odom", "base_link", return_type)
48
+
49
+ def get_camera_to_base(self, return_type: str = "homogeneous") -> Union[PoseQuaternion, HomogeneousMatrix, None]:
50
+ """获取从camera_link到base_link坐标系的变换。
51
+
52
+ Args:
53
+ return_type (str, optional): 返回格式类型。与get_tf_transform相同,默认为"homogeneous"。
54
+
55
+ Returns:
56
+ Union[PoseQuaternion, HomogeneousMatrix, None]: 变换数据或None
57
+ """
58
+ return self.get_tf_transform("base_link", "camera_link", return_type)
@@ -0,0 +1,82 @@
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 (AprilTagData)
6
+ from kuavo_humanoid_sdk.kuavo.core.ros.vision import KuavoRobotVisionCoreWebsocket
7
+
8
+
9
+ class KuavoRobotVision:
10
+ """Kuavo机器人视觉系统接口。
11
+
12
+ 提供从不同坐标系获取AprilTag检测数据的接口。
13
+ """
14
+
15
+ def __init__(self, robot_type: str = "kuavo"):
16
+ """初始化视觉系统。
17
+
18
+ Args:
19
+ robot_type (str, optional): 机器人类型标识符。默认为"kuavo"
20
+ """
21
+ if not hasattr(self, '_initialized'):
22
+ self._vision_core = KuavoRobotVisionCoreWebsocket()
23
+
24
+ def get_data_by_id(self, target_id: int, data_source: str = "base") -> dict:
25
+ """获取指定ID的AprilTag检测数据。
26
+
27
+ Args:
28
+ target_id (int): 要检索的AprilTag ID
29
+ data_source (str, optional): 数据源坐标系。可以是"base"、"camera"或"odom"。默认为"base"。
30
+
31
+ Returns:
32
+ dict: 包含位置、方向和元数据的检测数据
33
+ """
34
+ return self._vision_core._get_data_by_id(target_id, data_source)
35
+
36
+ def get_data_by_id_from_camera(self, target_id: int) -> dict:
37
+ """从相机坐标系获取AprilTag数据。
38
+
39
+ Args:
40
+ target_id (int): 要检索的AprilTag ID
41
+
42
+ Returns:
43
+ dict: 包含位置、方向和元数据的检测数据。参见 :meth:`get_data_by_id` 的返回格式说明。
44
+ """
45
+ return self._vision_core._get_data_by_id(target_id, "camera")
46
+
47
+ def get_data_by_id_from_base(self, target_id: int) -> dict:
48
+ """从基座坐标系获取AprilTag数据。
49
+
50
+ Args:
51
+ target_id (int): 要检索的AprilTag ID
52
+
53
+ Returns:
54
+ dict: 包含位置、方向和元数据的检测数据。参见 :meth:`get_data_by_id` 的返回格式说明。
55
+ """
56
+ return self._vision_core._get_data_by_id(target_id, "base")
57
+
58
+ def get_data_by_id_from_odom(self, target_id: int) -> dict:
59
+ """从里程计坐标系获取AprilTag数据。
60
+
61
+ Args:
62
+ target_id (int): 要检索的AprilTag ID
63
+
64
+ Returns:
65
+ dict: 包含位置、方向和元数据的检测数据。参见 :meth:`get_data_by_id` 的返回格式说明。
66
+ """
67
+ return self._vision_core._get_data_by_id(target_id, "odom")
68
+
69
+ @property
70
+ def apriltag_data_from_camera(self) -> AprilTagData:
71
+ """AprilTagData: 相机坐标系中检测到的所有AprilTag(属性)"""
72
+ return self._vision_core.apriltag_data_from_camera
73
+
74
+ @property
75
+ def apriltag_data_from_base(self) -> AprilTagData:
76
+ """AprilTagData: 基座坐标系中检测到的所有AprilTag(属性)"""
77
+ return self._vision_core.apriltag_data_from_base
78
+
79
+ @property
80
+ def apriltag_data_from_odom(self) -> AprilTagData:
81
+ """AprilTagData: 里程计坐标系中检测到的所有AprilTag(属性)"""
82
+ return self._vision_core.apriltag_data_from_odom
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kuavo-humanoid-sdk-ws
3
- Version: 1.1.6b858
3
+ Version: 1.1.6b1125
4
4
  Summary: A Python SDK for kuavo humanoid robot.
5
5
  Home-page: https://gitee.com/leju-robot/kuavo-ros-opensource/
6
6
  Author: ['lejurobot']
@@ -18,6 +18,8 @@ kuavo_humanoid_sdk/kuavo/robot_head.py
18
18
  kuavo_humanoid_sdk/kuavo/robot_info.py
19
19
  kuavo_humanoid_sdk/kuavo/robot_observation.py
20
20
  kuavo_humanoid_sdk/kuavo/robot_state.py
21
+ kuavo_humanoid_sdk/kuavo/robot_tool.py
22
+ kuavo_humanoid_sdk/kuavo/robot_vision.py
21
23
  kuavo_humanoid_sdk/kuavo/core/audio.py
22
24
  kuavo_humanoid_sdk/kuavo/core/core.py
23
25
  kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py
@@ -29,6 +31,8 @@ kuavo_humanoid_sdk/kuavo/core/ros/observation.py
29
31
  kuavo_humanoid_sdk/kuavo/core/ros/param.py
30
32
  kuavo_humanoid_sdk/kuavo/core/ros/sat_utils.py
31
33
  kuavo_humanoid_sdk/kuavo/core/ros/state.py
34
+ kuavo_humanoid_sdk/kuavo/core/ros/tools.py
35
+ kuavo_humanoid_sdk/kuavo/core/ros/vision.py
32
36
  kuavo_humanoid_sdk/kuavo_strategy/__init__.py
33
37
  kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py
34
38
  kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py
@@ -49,7 +49,7 @@ setup(
49
49
  install_requires=[
50
50
  "numpy",
51
51
  "transitions",
52
- "roslibpy"
52
+ "roslibpy",
53
53
  ],
54
54
  python_requires=">=3.8",
55
55
  classifiers=[