kuavo-humanoid-sdk-ws 1.3.2__20260122221834-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.
- kuavo_humanoid_sdk/__init__.py +6 -0
- kuavo_humanoid_sdk/common/launch_robot_tool.py +170 -0
- kuavo_humanoid_sdk/common/logger.py +45 -0
- kuavo_humanoid_sdk/common/websocket_kuavo_sdk.py +26 -0
- kuavo_humanoid_sdk/interfaces/__init__.py +4 -0
- kuavo_humanoid_sdk/interfaces/data_types.py +293 -0
- kuavo_humanoid_sdk/interfaces/end_effector.py +62 -0
- kuavo_humanoid_sdk/interfaces/robot.py +22 -0
- kuavo_humanoid_sdk/interfaces/robot_info.py +56 -0
- kuavo_humanoid_sdk/kuavo/__init__.py +12 -0
- kuavo_humanoid_sdk/kuavo/core/audio.py +32 -0
- kuavo_humanoid_sdk/kuavo/core/core.py +755 -0
- kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py +114 -0
- kuavo_humanoid_sdk/kuavo/core/leju_claw_control.py +67 -0
- kuavo_humanoid_sdk/kuavo/core/ros/audio.py +86 -0
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +1325 -0
- kuavo_humanoid_sdk/kuavo/core/ros/observation.py +125 -0
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +335 -0
- kuavo_humanoid_sdk/kuavo/core/ros/sat_utils.py +103 -0
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +426 -0
- kuavo_humanoid_sdk/kuavo/core/ros/tools.py +197 -0
- kuavo_humanoid_sdk/kuavo/core/ros/vision.py +280 -0
- kuavo_humanoid_sdk/kuavo/core/ros_env.py +236 -0
- kuavo_humanoid_sdk/kuavo/dexterous_hand.py +198 -0
- kuavo_humanoid_sdk/kuavo/leju_claw.py +232 -0
- kuavo_humanoid_sdk/kuavo/robot.py +550 -0
- kuavo_humanoid_sdk/kuavo/robot_arm.py +235 -0
- kuavo_humanoid_sdk/kuavo/robot_audio.py +39 -0
- kuavo_humanoid_sdk/kuavo/robot_head.py +39 -0
- kuavo_humanoid_sdk/kuavo/robot_info.py +235 -0
- kuavo_humanoid_sdk/kuavo/robot_observation.py +69 -0
- kuavo_humanoid_sdk/kuavo/robot_state.py +346 -0
- kuavo_humanoid_sdk/kuavo/robot_tool.py +58 -0
- kuavo_humanoid_sdk/kuavo/robot_vision.py +82 -0
- kuavo_humanoid_sdk/kuavo/robot_waist.py +53 -0
- kuavo_humanoid_sdk/kuavo_strategy/__init__.py +2 -0
- kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +418 -0
- kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +63 -0
- kuavo_humanoid_sdk/msg/__init__.py +4 -0
- kuavo_humanoid_sdk_ws-1.3.2.dist-info/METADATA +276 -0
- kuavo_humanoid_sdk_ws-1.3.2.dist-info/RECORD +43 -0
- kuavo_humanoid_sdk_ws-1.3.2.dist-info/WHEEL +6 -0
- kuavo_humanoid_sdk_ws-1.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import time
|
|
4
|
+
import copy
|
|
5
|
+
from typing import Tuple
|
|
6
|
+
from kuavo_humanoid_sdk.interfaces.data_types import (
|
|
7
|
+
KuavoImuData, KuavoJointData, KuavoOdometry, KuavoArmCtrlMode,EndEffectorState,
|
|
8
|
+
KuavoManipulationMpcControlFlow, KuavoManipulationMpcCtrlMode, KuavoManipulationMpcFrame)
|
|
9
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCoreWebsocket
|
|
10
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param
|
|
11
|
+
|
|
12
|
+
class KuavoRobotState:
|
|
13
|
+
def __init__(self, robot_type: str = "kuavo"):
|
|
14
|
+
self._rs_core = KuavoRobotStateCoreWebsocket()
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def imu_data(self) -> KuavoImuData:
|
|
18
|
+
"""Get Robot IMU Data.
|
|
19
|
+
|
|
20
|
+
Gets the current IMU sensor data from the robot, including gyroscope, accelerometer,
|
|
21
|
+
free acceleration and orientation quaternion measurements.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
:class:`KuavoImuData`: IMU data containing:
|
|
25
|
+
* gyro (:obj:`tuple` of :obj:`float`): Gyroscope measurements (x, y, z) in rad/s
|
|
26
|
+
* acc (:obj:`tuple` of :obj:`float`): Accelerometer measurements (x, y, z) in m/s^2
|
|
27
|
+
* free_acc (:obj:`tuple` of :obj:`float`): Free acceleration (x, y, z) in m/s^2
|
|
28
|
+
* quat (:obj:`tuple` of :obj:`float`): Orientation quaternion (x, y, z, w)
|
|
29
|
+
"""
|
|
30
|
+
return self._rs_core.imu_data
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def joint_state(self) -> KuavoJointData:
|
|
34
|
+
"""Get Robot Joint Data.
|
|
35
|
+
|
|
36
|
+
Get Robot Joint Data, including joint positions, velocities, torques and accelerations.
|
|
37
|
+
|
|
38
|
+
The data includes:
|
|
39
|
+
- Joint positions (angles) in radians
|
|
40
|
+
- Joint velocities in radians/second
|
|
41
|
+
- Joint torques/efforts in Newton-meters, A
|
|
42
|
+
- Joint acceleration
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
KuavoJointData: A dictionary containing joint state data with the following keys:
|
|
46
|
+
position (list[float]): Joint positions, length = joint_dof(28)
|
|
47
|
+
velocity (list[float]): Joint velocities, length = joint_dof(28)
|
|
48
|
+
torque (list[float]): Joint torques, length = joint_dof(28)
|
|
49
|
+
acceleration (list[float]): Joint accelerations, length = joint_dof(28)
|
|
50
|
+
"""
|
|
51
|
+
return self._rs_core.joint_data
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def com_height(self)->float:
|
|
55
|
+
"""Get the height of the robot's center of mass.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
float: The height of the robot's center of mass in meters.
|
|
59
|
+
"""
|
|
60
|
+
return self._rs_core.com_height
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def odometry(self) -> KuavoOdometry:
|
|
64
|
+
"""Get Robot Odometry Data.
|
|
65
|
+
|
|
66
|
+
Gets the current odometry data from the robot, including position, orientation,
|
|
67
|
+
linear velocity and angular velocity measurements.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
KuavoOdometry: A dictionary containing odometry data with the following keys:
|
|
71
|
+
position (tuple): Position (x, y, z) in meters
|
|
72
|
+
orientation (tuple): Orientation as quaternion (x, y, z, w)
|
|
73
|
+
linear (tuple): Linear velocity (x, y, z) in m/s
|
|
74
|
+
angular (tuple): Angular velocity (x, y, z) in rad/s
|
|
75
|
+
"""
|
|
76
|
+
return self._rs_core.odom_data
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def robot_position(self) -> Tuple[float, float, float]:
|
|
80
|
+
"""Returns the robot's position in world coordinates.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Tuple[float, float, float]: Position (x, y, z) in meters.
|
|
84
|
+
"""
|
|
85
|
+
return tuple(self._rs_core.odom_data.position)
|
|
86
|
+
|
|
87
|
+
def robot_orientation(self) -> Tuple[float, float, float, float]:
|
|
88
|
+
"""Returns the robot's orientation in world coordinates.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Tuple[float, float, float, float]: Orientation as quaternion (x, y, z, w).
|
|
92
|
+
"""
|
|
93
|
+
return tuple(self._rs_core.odom_data.orientation)
|
|
94
|
+
|
|
95
|
+
def linear_velocity(self) -> Tuple[float, float, float]:
|
|
96
|
+
"""Returns the robot's linear velocity in world coordinates.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Tuple[float, float, float]: Linear velocity (x, y, z) in m/s.
|
|
100
|
+
"""
|
|
101
|
+
return tuple(self._rs_core.odom_data.linear)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def angular_velocity(self) -> Tuple[float, float, float]:
|
|
105
|
+
"""Returns the robot's angular velocity in world coordinates.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Tuple[float, float, float]: Angular velocity (x, y, z).
|
|
109
|
+
"""
|
|
110
|
+
return tuple(self._rs_core.odom_data.angular)
|
|
111
|
+
|
|
112
|
+
def arm_joint_state(self) -> KuavoJointData:
|
|
113
|
+
"""Get the current state of the robot arm joints.
|
|
114
|
+
|
|
115
|
+
Get the current state of the robot arm joints, including:
|
|
116
|
+
- Joint positions (angles) in radians
|
|
117
|
+
- Joint velocities in radians/second
|
|
118
|
+
- Joint torques/efforts in Newton-meters, A
|
|
119
|
+
- Joint acceleration
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
KuavoJointData: Arm joint data containing:
|
|
123
|
+
position: list[float] * arm_dof(14)
|
|
124
|
+
velocity: list[float] * arm_dof(14)
|
|
125
|
+
torque: list[float] * arm_dof(14)
|
|
126
|
+
acceleration: list[float] * arm_dof(14)
|
|
127
|
+
"""
|
|
128
|
+
# Get robot parameters to determine joint indices
|
|
129
|
+
robot_params = make_robot_param()
|
|
130
|
+
arm_dof = robot_params.get('arm_dof')
|
|
131
|
+
leg_dof = robot_params.get('leg_dof')
|
|
132
|
+
waist_dof = robot_params.get('waist_dof', 0) # Default to 0 if not found
|
|
133
|
+
|
|
134
|
+
if arm_dof is None or leg_dof is None or waist_dof is None:
|
|
135
|
+
raise ValueError("Failed to get DOF values from robot parameters")
|
|
136
|
+
|
|
137
|
+
# Calculate arm joint start index: leg_dof + waist_dof
|
|
138
|
+
arm_start_idx = leg_dof + waist_dof
|
|
139
|
+
arm_joint_indices = range(arm_start_idx, arm_start_idx + arm_dof)
|
|
140
|
+
|
|
141
|
+
return KuavoJointData(
|
|
142
|
+
position=[self._rs_core.joint_data.position[i] for i in arm_joint_indices],
|
|
143
|
+
velocity=[self._rs_core.joint_data.velocity[i] for i in arm_joint_indices],
|
|
144
|
+
torque=[self._rs_core.joint_data.torque[i] for i in arm_joint_indices],
|
|
145
|
+
acceleration=[self._rs_core.joint_data.acceleration[i] for i in arm_joint_indices]
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def arm_control_mode(self) -> KuavoArmCtrlMode:
|
|
149
|
+
"""Get the current control mode of the robot arm.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
KuavoArmCtrlMode: Current arm control mode:
|
|
153
|
+
ArmFixed: 0 - The robot arm is in a fixed position.
|
|
154
|
+
AutoSwing: 1 - The robot arm is in automatic swing mode.
|
|
155
|
+
ExternalControl: 2 - The robot arm is controlled externally.
|
|
156
|
+
or None.
|
|
157
|
+
"""
|
|
158
|
+
return KuavoArmCtrlMode(self._rs_core.arm_control_mode)
|
|
159
|
+
|
|
160
|
+
def manipulation_mpc_ctrl_mode(self) -> KuavoManipulationMpcCtrlMode:
|
|
161
|
+
"""Get the current control mode of the robot manipulation MPC.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
KuavoManipulationMpcCtrlMode: Current manipulation MPC control mode.
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
return self._rs_core.manipulation_mpc_ctrl_mode
|
|
168
|
+
|
|
169
|
+
def manipulation_mpc_control_flow(self) -> KuavoManipulationMpcControlFlow:
|
|
170
|
+
"""Get the current control flow of the robot manipulation.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
KuavoManipulationMpcControlFlow: Current manipulation control flow.
|
|
174
|
+
"""
|
|
175
|
+
return self._rs_core.manipulation_mpc_control_flow
|
|
176
|
+
|
|
177
|
+
def manipulation_mpc_frame(self) -> KuavoManipulationMpcFrame:
|
|
178
|
+
"""Get the current frame of the robot manipulation MPC.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
KuavoManipulationMpcFrame: Current manipulation MPC frame.
|
|
182
|
+
"""
|
|
183
|
+
return self._rs_core.manipulation_mpc_frame
|
|
184
|
+
|
|
185
|
+
def head_joint_state(self) -> KuavoJointData:
|
|
186
|
+
"""Get the current state of the robot head joints.
|
|
187
|
+
|
|
188
|
+
Gets the current state data for the robot's head joints, including position,
|
|
189
|
+
velocity, torque and acceleration values.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
KuavoJointData: A data structure containing the head joint states:
|
|
193
|
+
position (list[float]): Joint positions in radians, length=head_dof(2)
|
|
194
|
+
velocity (list[float]): Joint velocities in rad/s, length=head_dof(2)
|
|
195
|
+
torque (list[float]): Joint torques in Nm, length=head_dof(2)
|
|
196
|
+
acceleration (list[float]): Joint accelerations in rad/s^2, length=head_dof(2)
|
|
197
|
+
|
|
198
|
+
The joint order is [yaw, pitch].
|
|
199
|
+
"""
|
|
200
|
+
# Get head joint states from last 2 indices
|
|
201
|
+
head_joint_indices = range(len(self._rs_core.joint_data.position)-2, len(self._rs_core.joint_data.position))
|
|
202
|
+
return KuavoJointData(
|
|
203
|
+
position=[self._rs_core.joint_data.position[i] for i in head_joint_indices],
|
|
204
|
+
velocity=[self._rs_core.joint_data.velocity[i] for i in head_joint_indices],
|
|
205
|
+
torque=[self._rs_core.joint_data.torque[i] for i in head_joint_indices],
|
|
206
|
+
acceleration=[self._rs_core.joint_data.acceleration[i] for i in head_joint_indices]
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def waist_joint_state(self, waist_dof:int) -> KuavoJointData:
|
|
210
|
+
"""获取机器人腰部关节的当前状态
|
|
211
|
+
获取机器人头部关节的当前状态数据,包括位置、速度、扭矩和加速度值。
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
KuavoJointData: 包含头部关节状态的数据结构:
|
|
215
|
+
* position (list[float]): 关节位置,单位为弧度,长度=waist_dof
|
|
216
|
+
* velocity (list[float]): 关节速度,单位为rad/s,长度=waist_dof
|
|
217
|
+
* torque (list[float]): 关节扭矩,单位为Nm,长度=waist_dof
|
|
218
|
+
* acceleration (list[float]): 关节加速度,单位为rad/s^2,长度=waist_dof
|
|
219
|
+
|
|
220
|
+
"""
|
|
221
|
+
# 环境判断
|
|
222
|
+
if env == 'real':
|
|
223
|
+
jointData = self._rs_core.joint_data
|
|
224
|
+
elif env == 'mujoco':
|
|
225
|
+
jointData = self._rs_core.joint_data
|
|
226
|
+
elif env == 'gazebo':
|
|
227
|
+
jointData = self._rs_core.joint_data_shm
|
|
228
|
+
else:
|
|
229
|
+
raise ValueError(f"Invalid environment: {self.env}")
|
|
230
|
+
|
|
231
|
+
# Get waist joint states from 13 indices
|
|
232
|
+
waist_joint_indices = range(12, 12+waist_dof)
|
|
233
|
+
return KuavoJointData(
|
|
234
|
+
position=[jointData.position[i] for i in waist_joint_indices],
|
|
235
|
+
velocity=[jointData.velocity[i] for i in waist_joint_indices],
|
|
236
|
+
torque=[jointData.torque[i] for i in waist_joint_indices],
|
|
237
|
+
acceleration=[jointData.acceleration[i] for i in waist_joint_indices]
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def eef_state(self)->Tuple[EndEffectorState, EndEffectorState]:
|
|
241
|
+
"""Get the current state of the robot's end effectors.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Tuple[EndEffectorState, EndEffectorState]: A tuple containing the state of the left and right end effectors.
|
|
245
|
+
Each EndEffectorState contains:
|
|
246
|
+
- position: (float, float, float) - XYZ position in meters
|
|
247
|
+
- orientation: (float, float, float, float) - Quaternion orientation
|
|
248
|
+
- state: EndEffectorState.GraspingState - Current grasping state (UNKNOWN, OPEN, CLOSED)
|
|
249
|
+
"""
|
|
250
|
+
return copy.deepcopy(self._rs_core.eef_state)
|
|
251
|
+
|
|
252
|
+
def gait_name(self)->str:
|
|
253
|
+
"""Get the current gait name of the robot.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
str: The name of the current gait, e.g. 'trot', 'walk', 'stance', 'custom_gait'.
|
|
257
|
+
"""
|
|
258
|
+
return self._rs_core.gait_name()
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def is_stance(self) -> bool:
|
|
262
|
+
"""Check if the robot is currently in stance mode.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
bool: True if robot is in stance mode, False otherwise.
|
|
266
|
+
"""
|
|
267
|
+
return self._rs_core.is_gait('stance')
|
|
268
|
+
|
|
269
|
+
def is_walk(self) -> bool:
|
|
270
|
+
"""Check if the robot is currently in walk mode.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
bool: True if robot is in walk mode, False otherwise.
|
|
274
|
+
"""
|
|
275
|
+
return self._rs_core.is_gait('walk')
|
|
276
|
+
|
|
277
|
+
def is_step_control(self) -> bool:
|
|
278
|
+
"""Check if the robot is currently in step control mode.
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
bool: True if robot is in step control mode, False otherwise.
|
|
282
|
+
"""
|
|
283
|
+
return self._rs_core.is_gait('custom_gait')
|
|
284
|
+
|
|
285
|
+
def wait_for_stance(self, timeout:float=5.0)->bool:
|
|
286
|
+
"""Wait for the robot to enter stance state.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
timeout (float): The maximum time to wait for the robot to enter stance state in seconds.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
bool: True if the robot enters stance state within the specified timeout, False otherwise.
|
|
293
|
+
"""
|
|
294
|
+
wait_time = 0
|
|
295
|
+
while not self._rs_core.is_gait('stance') and wait_time < timeout:
|
|
296
|
+
time.sleep(0.1)
|
|
297
|
+
wait_time += 0.1
|
|
298
|
+
return self._rs_core.is_gait('stance')
|
|
299
|
+
|
|
300
|
+
def wait_for_trot(self, timeout:float=5.0)->bool:
|
|
301
|
+
"""Wait for the robot to enter trot state.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
timeout (float): The maximum time to wait for the robot to enter trot state in seconds.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
bool: True if the robot enters trot state within the specified timeout, False otherwise.
|
|
308
|
+
"""
|
|
309
|
+
return self.wait_for_walk(timeout=timeout)
|
|
310
|
+
|
|
311
|
+
def wait_for_walk(self, timeout:float=5.0)->bool:
|
|
312
|
+
"""Wait for the robot to enter walk state.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
timeout (float): The maximum time to wait for the robot to enter walk state in seconds.
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
bool: True if the robot enters walk state within the specified timeout, False otherwise.
|
|
319
|
+
"""
|
|
320
|
+
wait_time = 0
|
|
321
|
+
while not self._rs_core.is_gait('walk') and wait_time < timeout:
|
|
322
|
+
time.sleep(0.1)
|
|
323
|
+
wait_time += 0.1
|
|
324
|
+
return self._rs_core.is_gait('walk')
|
|
325
|
+
|
|
326
|
+
def wait_for_step_control(self, timeout:float=5.0)->bool:
|
|
327
|
+
"""Wait for the robot to enter step control state.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
timeout (float): The maximum time to wait for the robot to enter step control state in seconds.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
bool: True if the robot enters step control state within the specified timeout, False otherwise.
|
|
334
|
+
"""
|
|
335
|
+
wait_time = 0
|
|
336
|
+
while not self._rs_core.is_gait('custom_gait') and wait_time < timeout:
|
|
337
|
+
time.sleep(0.1)
|
|
338
|
+
wait_time += 0.1
|
|
339
|
+
return self._rs_core.is_gait('custom_gait')
|
|
340
|
+
|
|
341
|
+
# if __name__ == "__main__":
|
|
342
|
+
# state = KuavoRobotState()
|
|
343
|
+
# print(state.manipulation_mpc_frame())
|
|
344
|
+
# print(state.manipulation_mpc_control_flow())
|
|
345
|
+
# print(state.manipulation_mpc_ctrl_mode())
|
|
346
|
+
# print(state.arm_control_mode())
|
|
@@ -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
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import math
|
|
4
|
+
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
5
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class KuavoRobotWaist:
|
|
9
|
+
"""
|
|
10
|
+
Control the waist of the robot.
|
|
11
|
+
|
|
12
|
+
The waist has 1 DOF: yaw (rotation around Z-axis).
|
|
13
|
+
The value is published to the topic `/robot_waist_motion_data`
|
|
14
|
+
as a Float64MultiArray: [yaw_degrees]
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self._kuavo_core = KuavoRobotCore()
|
|
19
|
+
|
|
20
|
+
# Waist angle limit in degrees (recommended: -180° to +180°)
|
|
21
|
+
self.WAIST_LIMIT_DEG = 180
|
|
22
|
+
|
|
23
|
+
def control_waist(self, yaw: float) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Control the waist of the robot.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
yaw (float): The yaw angle of the waist in **degrees**.
|
|
29
|
+
Valid range: [-180, 180] degrees.
|
|
30
|
+
Values outside this range will be automatically limited.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
bool: True if the waist is controlled successfully, False otherwise.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# Normalize input: must be float
|
|
37
|
+
if not isinstance(yaw, (int, float)):
|
|
38
|
+
raise TypeError("yaw must be a float value representing degrees.")
|
|
39
|
+
|
|
40
|
+
# --- Check yaw limit (degrees) ---
|
|
41
|
+
if yaw < -self.WAIST_LIMIT_DEG or yaw > self.WAIST_LIMIT_DEG:
|
|
42
|
+
SDKLogger.warn(
|
|
43
|
+
f"[Robot] waist yaw {yaw}° exceeds limit "
|
|
44
|
+
f"[{-self.WAIST_LIMIT_DEG}, {self.WAIST_LIMIT_DEG}]°, will be limited"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Apply limits
|
|
48
|
+
limited_yaw = min(self.WAIST_LIMIT_DEG, max(-self.WAIST_LIMIT_DEG, yaw))
|
|
49
|
+
|
|
50
|
+
# Convert to list format expected by lower-level interface
|
|
51
|
+
yaw_list = [limited_yaw]
|
|
52
|
+
|
|
53
|
+
return self._kuavo_core.control_robot_waist(yaw_list)
|