kuavo-humanoid-sdk 1.1.5__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/__init__.py +0 -2
- kuavo_humanoid_sdk/interfaces/data_types.py +0 -90
- kuavo_humanoid_sdk/kuavo/__init__.py +0 -3
- kuavo_humanoid_sdk/kuavo/core/core.py +20 -238
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +27 -1087
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +4 -142
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +19 -556
- 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 +27 -150
- kuavo_humanoid_sdk/kuavo/robot_arm.py +7 -53
- kuavo_humanoid_sdk/kuavo/robot_head.py +0 -10
- kuavo_humanoid_sdk/kuavo/robot_info.py +2 -7
- kuavo_humanoid_sdk/kuavo/robot_state.py +4 -41
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +0 -7
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +0 -5
- 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 +30 -34
- kuavo_humanoid_sdk/msg/motion_capture_ik/srv/__init__.py +4 -0
- kuavo_humanoid_sdk/msg/{kuavo_msgs/srv/_setMmCtrlFrame.py → motion_capture_ik/srv/_changeArmCtrlMode.py} +37 -35
- 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 +37 -38
- {kuavo_humanoid_sdk-1.1.5.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/METADATA +1 -2
- {kuavo_humanoid_sdk-1.1.5.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/RECORD +37 -46
- 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 -283
- 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/kuavo_strategy/__init__.py +0 -2
- kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +0 -418
- kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +0 -63
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SpeechSynthesis.py +0 -270
- {kuavo_humanoid_sdk-1.1.5.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/WHEEL +0 -0
- {kuavo_humanoid_sdk-1.1.5.dist-info → kuavo_humanoid_sdk-1.1.6.dist-info}/top_level.txt +0 -0
|
@@ -2,15 +2,10 @@
|
|
|
2
2
|
# coding: utf-8
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
|
-
|
|
6
|
-
import rospy
|
|
7
|
-
except ImportError:
|
|
8
|
-
pass
|
|
5
|
+
import rospy
|
|
9
6
|
import subprocess
|
|
10
7
|
import atexit
|
|
11
8
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
12
|
-
from kuavo_humanoid_sdk.common.websocket_kuavo_sdk import WebSocketKuavoSDK
|
|
13
|
-
import roslibpy
|
|
14
9
|
|
|
15
10
|
class KuavoROSEnv:
|
|
16
11
|
_instance = None
|
|
@@ -237,226 +232,3 @@ class KuavoROSEnv:
|
|
|
237
232
|
except Exception as e:
|
|
238
233
|
SDKLogger.error(f"Error checking if node {node_name} exists: {e}")
|
|
239
234
|
return False
|
|
240
|
-
|
|
241
|
-
class KuavoROSEnvWebsocket:
|
|
242
|
-
_instance = None
|
|
243
|
-
_processes = [] # Store all subprocess instances
|
|
244
|
-
|
|
245
|
-
def __new__(cls):
|
|
246
|
-
if cls._instance is None:
|
|
247
|
-
cls._instance = super(KuavoROSEnvWebsocket, cls).__new__(cls)
|
|
248
|
-
cls._instance._initialized = False
|
|
249
|
-
cls._instance._init_success = False # Add flag to track successful Init() call
|
|
250
|
-
# Register cleanup handler
|
|
251
|
-
atexit.register(cls._cleanup_processes)
|
|
252
|
-
return cls._instance
|
|
253
|
-
|
|
254
|
-
def __init__(self):
|
|
255
|
-
if not self._initialized:
|
|
256
|
-
self._initialized = True
|
|
257
|
-
self.websocket = None
|
|
258
|
-
|
|
259
|
-
@classmethod
|
|
260
|
-
def _cleanup_processes(cls):
|
|
261
|
-
"""Cleanup all registered processes on exit"""
|
|
262
|
-
for process in cls._processes:
|
|
263
|
-
if process.poll() is None: # Process is still running
|
|
264
|
-
process.terminate()
|
|
265
|
-
try:
|
|
266
|
-
process.wait(timeout=3) # Wait for process to terminate
|
|
267
|
-
except subprocess.TimeoutExpired:
|
|
268
|
-
process.kill() # Force kill if not terminated
|
|
269
|
-
cls._processes.clear()
|
|
270
|
-
|
|
271
|
-
def _get_kuavo_ws_root(self) -> str:
|
|
272
|
-
# For WebSocket version, we'll use environment variable instead of ROS param
|
|
273
|
-
model_path = os.environ.get('KUAVO_MODEL_PATH')
|
|
274
|
-
if not model_path:
|
|
275
|
-
raise Exception("KUAVO_MODEL_PATH environment variable not found")
|
|
276
|
-
|
|
277
|
-
if not os.path.exists(model_path):
|
|
278
|
-
raise Exception(f"Model path {model_path} not found")
|
|
279
|
-
|
|
280
|
-
# ws
|
|
281
|
-
return model_path.replace('/src/kuavo_assets/models', '')
|
|
282
|
-
|
|
283
|
-
def Init(self) -> bool:
|
|
284
|
-
"""
|
|
285
|
-
Initialize the WebSocket environment.
|
|
286
|
-
Raises:
|
|
287
|
-
Exception: If the KUAVO_MODEL_PATH environment variable is not found or the path is not valid.
|
|
288
|
-
"""
|
|
289
|
-
# if generate docs, skip init.
|
|
290
|
-
if 'GEN_KUAVO_HUMANOID_SDK_DOCS' in os.environ:
|
|
291
|
-
return True
|
|
292
|
-
|
|
293
|
-
# Return directly if already initialized successfully
|
|
294
|
-
if self._init_success:
|
|
295
|
-
return True
|
|
296
|
-
|
|
297
|
-
# Check if WebSocket server is running
|
|
298
|
-
try:
|
|
299
|
-
|
|
300
|
-
self.websocket = WebSocketKuavoSDK()
|
|
301
|
-
if not self.websocket.client.is_connected:
|
|
302
|
-
print(f"\033[31m\nError: Can't connect to WebSocket server. Please ensure the server is running.\033[0m"
|
|
303
|
-
"\nMaybe manually launch the app first?"
|
|
304
|
-
"\n - for example(sim): roslaunch humanoid_controller load_kuavo_mujoco_sim.launch, "
|
|
305
|
-
"\n - for example(real): roslaunch humanoid_controller load_kuavo_real.launch\n")
|
|
306
|
-
exit(1)
|
|
307
|
-
except Exception as e:
|
|
308
|
-
print(f"\033[31m\nError: Failed to connect to WebSocket server: {e}\033[0m")
|
|
309
|
-
exit(1)
|
|
310
|
-
|
|
311
|
-
# Only check nodes exist when Init SDK, if not, tips user manually launch nodes.
|
|
312
|
-
deps_nodes = ['/humanoid_gait_switch_by_name']
|
|
313
|
-
for node in deps_nodes:
|
|
314
|
-
if not self.check_rosnode_exists(node):
|
|
315
|
-
print(f"\033[31m\nError: Node {node} not found. Please launch it manually.\033[0m")
|
|
316
|
-
exit(1)
|
|
317
|
-
|
|
318
|
-
self._init_success = True # Set flag after successful initialization
|
|
319
|
-
|
|
320
|
-
return True
|
|
321
|
-
|
|
322
|
-
def _launch_ros_node(self, node_name, launch_cmd, log_name):
|
|
323
|
-
"""Launch a ROS node with the given command and log the output.
|
|
324
|
-
|
|
325
|
-
Args:
|
|
326
|
-
node_name (str): Name of the node to launch
|
|
327
|
-
launch_cmd (str): Full launch command including source and roslaunch
|
|
328
|
-
log_name (str): Name for the log file
|
|
329
|
-
|
|
330
|
-
Raises:
|
|
331
|
-
Exception: If node launch fails
|
|
332
|
-
"""
|
|
333
|
-
# Launch in background and check if successful
|
|
334
|
-
try:
|
|
335
|
-
os.makedirs('/var/log/kuavo_humanoid_sdk', exist_ok=True)
|
|
336
|
-
log_path = f'/var/log/kuavo_humanoid_sdk/{log_name}.log'
|
|
337
|
-
except PermissionError:
|
|
338
|
-
os.makedirs('log/kuavo_humanoid_sdk', exist_ok=True)
|
|
339
|
-
log_path = f'log/kuavo_humanoid_sdk/{log_name}.log'
|
|
340
|
-
|
|
341
|
-
with open(log_path, 'w') as log_file:
|
|
342
|
-
process = subprocess.Popen(launch_cmd, shell=True, executable='/bin/bash', stdout=log_file, stderr=log_file)
|
|
343
|
-
self._processes.append(process) # Add process to tracking list
|
|
344
|
-
|
|
345
|
-
if process.returncode is not None and process.returncode != 0:
|
|
346
|
-
raise Exception(f"Failed to launch {node_name}, return code: {process.returncode}")
|
|
347
|
-
|
|
348
|
-
SDKLogger.info(f"{node_name} launched successfully")
|
|
349
|
-
|
|
350
|
-
def _get_setup_file(self, ws_root=None):
|
|
351
|
-
"""Get the appropriate ROS setup file path based on shell type.
|
|
352
|
-
|
|
353
|
-
Args:
|
|
354
|
-
ws_root (str, optional): ROS workspace root path. If None, uses ROS_WORKSPACE.
|
|
355
|
-
|
|
356
|
-
Returns:
|
|
357
|
-
str: Path to the setup file
|
|
358
|
-
|
|
359
|
-
Raises:
|
|
360
|
-
Exception: If setup file not found
|
|
361
|
-
"""
|
|
362
|
-
is_zsh = 'zsh' in os.environ.get('SHELL', '')
|
|
363
|
-
|
|
364
|
-
if ws_root is None:
|
|
365
|
-
ws_root = os.environ['ROS_WORKSPACE']
|
|
366
|
-
|
|
367
|
-
setup_files = {
|
|
368
|
-
'zsh': os.path.join(ws_root, 'devel/setup.zsh'),
|
|
369
|
-
'bash': os.path.join(ws_root, 'devel/setup.bash')
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
setup_file = setup_files['zsh'] if is_zsh else setup_files['bash']
|
|
373
|
-
if not os.path.exists(setup_file):
|
|
374
|
-
setup_file = setup_file.replace('devel', 'install')
|
|
375
|
-
if not os.path.exists(setup_file):
|
|
376
|
-
raise Exception(f"Setup file not found in either devel or install: {setup_file}")
|
|
377
|
-
|
|
378
|
-
return setup_file
|
|
379
|
-
|
|
380
|
-
def launch_ik_node(self):
|
|
381
|
-
# nodes: /arms_ik_node
|
|
382
|
-
# services: /ik/two_arm_hand_pose_cmd_srv, /ik/fk_srv
|
|
383
|
-
try:
|
|
384
|
-
if not self.websocket or not self.websocket.client.is_connected:
|
|
385
|
-
raise Exception("WebSocket server is not running")
|
|
386
|
-
except Exception as e:
|
|
387
|
-
raise Exception(f"WebSocket server is not running: {e}")
|
|
388
|
-
|
|
389
|
-
# Check if IK node and services exist
|
|
390
|
-
try:
|
|
391
|
-
# Check if arms_ik_node is running using roslibpy
|
|
392
|
-
service = roslibpy.Service(self.websocket.client, '/rosnode/list', 'rosapi/Nodes')
|
|
393
|
-
response = service.call({})
|
|
394
|
-
nodes = response.get('nodes', [])
|
|
395
|
-
|
|
396
|
-
if '/arms_ik_node' not in nodes:
|
|
397
|
-
# Launch IK node if not running
|
|
398
|
-
kuavo_ws_root = self._get_kuavo_ws_root()
|
|
399
|
-
setup_file = self._get_setup_file(kuavo_ws_root)
|
|
400
|
-
source_cmd = f"source {setup_file}"
|
|
401
|
-
|
|
402
|
-
# Get robot version from environment variable
|
|
403
|
-
robot_version = os.environ.get('ROBOT_VERSION')
|
|
404
|
-
if robot_version is None:
|
|
405
|
-
raise Exception("Failed to get ROBOT_VERSION from environment variables")
|
|
406
|
-
|
|
407
|
-
# Launch IK node
|
|
408
|
-
launch_cmd = f"roslaunch motion_capture_ik ik_node.launch robot_version:={robot_version}"
|
|
409
|
-
full_cmd = f"{source_cmd} && {launch_cmd}"
|
|
410
|
-
|
|
411
|
-
self._launch_ros_node('IK node', full_cmd, 'launch_ik')
|
|
412
|
-
|
|
413
|
-
return True
|
|
414
|
-
|
|
415
|
-
except Exception as e:
|
|
416
|
-
raise Exception(f"Failed to verify IK node and services: {e}")
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
def launch_gait_switch_node(self)-> bool:
|
|
420
|
-
"""Verify that the gait switch node is running, launch if not."""
|
|
421
|
-
try:
|
|
422
|
-
# Check if node exists using roslibpy
|
|
423
|
-
service = roslibpy.Service(self.websocket.client, '/rosnode/list', 'rosapi/Nodes')
|
|
424
|
-
response = service.call({})
|
|
425
|
-
nodes = response.get('nodes', [])
|
|
426
|
-
|
|
427
|
-
if '/humanoid_gait_switch_by_name' not in nodes:
|
|
428
|
-
kuavo_ws_root = self._get_kuavo_ws_root()
|
|
429
|
-
setup_file = self._get_setup_file(kuavo_ws_root)
|
|
430
|
-
source_cmd = f"source {setup_file}"
|
|
431
|
-
|
|
432
|
-
# Launch gait switch node
|
|
433
|
-
launch_cmd = "roslaunch humanoid_interface_ros humanoid_switch_gait.launch"
|
|
434
|
-
full_cmd = f"{source_cmd} && {launch_cmd}"
|
|
435
|
-
|
|
436
|
-
self._launch_ros_node('Gait switch node', full_cmd, 'launch_gait_switch')
|
|
437
|
-
|
|
438
|
-
except Exception as e:
|
|
439
|
-
raise Exception(f"Failed to launch gait_switch node: {e}")
|
|
440
|
-
|
|
441
|
-
@staticmethod
|
|
442
|
-
def check_rosnode_exists(node_name):
|
|
443
|
-
"""Check if a ROS node is running using roslibpy.
|
|
444
|
-
|
|
445
|
-
Args:
|
|
446
|
-
node_name (str): Name of the node to check
|
|
447
|
-
|
|
448
|
-
Returns:
|
|
449
|
-
bool: True if node is running, False otherwise
|
|
450
|
-
"""
|
|
451
|
-
websocket = WebSocketKuavoSDK()
|
|
452
|
-
try:
|
|
453
|
-
if not websocket or not websocket.client.is_connected:
|
|
454
|
-
return False
|
|
455
|
-
|
|
456
|
-
service = roslibpy.Service(websocket.client, '/rosapi/nodes', 'rosapi/Nodes')
|
|
457
|
-
response = service.call({})
|
|
458
|
-
nodes = response.get('nodes', [])
|
|
459
|
-
return node_name in nodes
|
|
460
|
-
except Exception as e:
|
|
461
|
-
SDKLogger.error(f"Error checking if node {node_name} exists: {e}")
|
|
462
|
-
return False
|
|
@@ -4,8 +4,7 @@ from typing import Tuple
|
|
|
4
4
|
from kuavo_humanoid_sdk.interfaces.end_effector import EndEffector
|
|
5
5
|
from kuavo_humanoid_sdk.interfaces.data_types import EndEffectorSide, EndEffectorState, KuavoDexHandTouchState
|
|
6
6
|
from kuavo_humanoid_sdk.kuavo.core.dex_hand_control import DexHandControl
|
|
7
|
-
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
|
|
8
|
-
from kuavo_humanoid_sdk.common.global_config import GlobalConfig
|
|
7
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
|
|
9
8
|
|
|
10
9
|
class DexterousHand(EndEffector):
|
|
11
10
|
def __init__(self):
|
|
@@ -13,10 +12,7 @@ class DexterousHand(EndEffector):
|
|
|
13
12
|
'r_thumb', 'r_thumb_aux', 'r_index', 'r_middle', 'r_ring', 'r_pinky',]
|
|
14
13
|
super().__init__(joint_names=joint_names)
|
|
15
14
|
self.dex_hand_control = DexHandControl()
|
|
16
|
-
|
|
17
|
-
self._rb_state = KuavoRobotStateCoreWebsocket()
|
|
18
|
-
else:
|
|
19
|
-
self._rb_state = KuavoRobotStateCore()
|
|
15
|
+
self._rb_state = KuavoRobotStateCore()
|
|
20
16
|
|
|
21
17
|
def control(self, target_positions:list, target_velocities:list=None, target_torques:list=None)->bool:
|
|
22
18
|
"""Set the position of the hand.
|
|
@@ -5,17 +5,13 @@ from typing import Tuple
|
|
|
5
5
|
from kuavo_humanoid_sdk.interfaces.end_effector import EndEffector
|
|
6
6
|
from kuavo_humanoid_sdk.interfaces.data_types import EndEffectorSide, EndEffectorState
|
|
7
7
|
from kuavo_humanoid_sdk.kuavo.core.leju_claw_control import LejuClawControl
|
|
8
|
-
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
|
|
9
|
-
from kuavo_humanoid_sdk.common.global_config import GlobalConfig
|
|
8
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
|
|
10
9
|
|
|
11
10
|
class LejuClaw(EndEffector):
|
|
12
11
|
def __init__(self):
|
|
13
12
|
super().__init__(joint_names=['left_claw', 'right_claw'])
|
|
14
13
|
self.leju_claw_control = LejuClawControl()
|
|
15
|
-
|
|
16
|
-
self._rb_state = KuavoRobotStateCoreWebsocket()
|
|
17
|
-
else:
|
|
18
|
-
self._rb_state = KuavoRobotStateCore()
|
|
14
|
+
self._rb_state = KuavoRobotStateCore()
|
|
19
15
|
|
|
20
16
|
def control(self, target_positions: list, target_velocities:list=None, target_torques: list=None)->bool:
|
|
21
17
|
"""Control the claws to grip.
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# coding: utf-8
|
|
3
|
-
from kuavo_humanoid_sdk.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
from
|
|
9
|
-
from kuavo_humanoid_sdk.kuavo.
|
|
10
|
-
|
|
11
|
-
from
|
|
12
|
-
from kuavo_humanoid_sdk.kuavo.
|
|
13
|
-
from kuavo_humanoid_sdk.
|
|
14
|
-
from kuavo_humanoid_sdk.
|
|
3
|
+
from kuavo_humanoid_sdk.kuavo.core.ros_env import KuavoROSEnv
|
|
4
|
+
kuavo_ros_env = KuavoROSEnv()
|
|
5
|
+
if not kuavo_ros_env.Init():
|
|
6
|
+
raise RuntimeError("Failed to initialize ROS environment")
|
|
7
|
+
else:
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from kuavo_humanoid_sdk.kuavo.robot_info import KuavoRobotInfo
|
|
10
|
+
from kuavo_humanoid_sdk.kuavo.robot_arm import KuavoRobotArm
|
|
11
|
+
from kuavo_humanoid_sdk.kuavo.robot_head import KuavoRobotHead
|
|
12
|
+
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
13
|
+
from kuavo_humanoid_sdk.interfaces.robot import RobotBase
|
|
14
|
+
from kuavo_humanoid_sdk.interfaces.data_types import KuavoPose, KuavoIKParams
|
|
15
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger, disable_sdk_logging
|
|
15
16
|
|
|
16
17
|
"""
|
|
17
18
|
Kuavo SDK - Python Interface for Kuavo Robot Control
|
|
@@ -44,30 +45,19 @@ class KuavoSDK:
|
|
|
44
45
|
pass
|
|
45
46
|
|
|
46
47
|
@staticmethod
|
|
47
|
-
def Init(options:int=Options.Normal, log_level: str = "INFO"
|
|
48
|
-
websocket_mode: bool = False, websocket_host='127.0.0.1', websocket_port=9090, websocket_timeout=5)-> bool:
|
|
48
|
+
def Init(options:int=Options.Normal, log_level: str = "INFO")-> bool:
|
|
49
49
|
"""Initialize the SDK.
|
|
50
|
+
|
|
50
51
|
Args:
|
|
51
52
|
log_level (str): The logging level to use. Can be "ERROR", "WARN", "INFO", "DEBUG".
|
|
52
53
|
Defaults to "INFO".
|
|
53
|
-
|
|
54
|
-
the SDK will connect to ROS through websocket instead of direct ROS connection.
|
|
55
|
-
Defaults to False.
|
|
56
|
-
websocket_host (str): The host address of the rosbridge websocket server when using
|
|
57
|
-
websocket mode. Defaults to "127.0.0.1".
|
|
58
|
-
websocket_port (int): The port number of the rosbridge websocket server when using
|
|
59
|
-
websocket mode. Defaults to 9090.
|
|
60
|
-
websocket_timeout (int): The timeout for the websocket connection. Defaults to 5.
|
|
54
|
+
|
|
61
55
|
Returns:
|
|
62
56
|
bool: True if initialization is successful, False otherwise.
|
|
63
57
|
|
|
64
58
|
Raises:
|
|
65
59
|
RuntimeError: If the initialization fails.
|
|
66
60
|
"""
|
|
67
|
-
GlobalConfig.use_websocket = websocket_mode
|
|
68
|
-
GlobalConfig.websocket_host = websocket_host
|
|
69
|
-
GlobalConfig.websocket_port = websocket_port
|
|
70
|
-
GlobalConfig.websocket_timeout = websocket_timeout
|
|
71
61
|
SDKLogger.setLevel(log_level.upper())
|
|
72
62
|
# Initialize core components, connect ROS Topics...
|
|
73
63
|
kuavo_core = KuavoRobotCore()
|
|
@@ -75,18 +65,12 @@ class KuavoSDK:
|
|
|
75
65
|
debug = True
|
|
76
66
|
else:
|
|
77
67
|
debug = False
|
|
78
|
-
# Check if IK option is enabled
|
|
79
|
-
if GlobalConfig.use_websocket:
|
|
80
|
-
if options & KuavoSDK.Options.WithIK:
|
|
81
|
-
if not KuavoROSEnvWebsocket.check_rosnode_exists('/arms_ik_node'):
|
|
82
|
-
print("\033[31m\nError:WithIK option is enabled but ik_node is not running, please run `roslaunch motion_capture_ik ik_node.launch`\033[0m")
|
|
83
|
-
exit(1)
|
|
84
|
-
else:
|
|
85
|
-
if options & KuavoSDK.Options.WithIK:
|
|
86
|
-
if not KuavoROSEnv.check_rosnode_exists('/arms_ik_node'):
|
|
87
|
-
print("\033[31m\nError:WithIK option is enabled but ik_node is not running, please run `roslaunch motion_capture_ik ik_node.launch`\033[0m")
|
|
88
|
-
exit(1)
|
|
89
68
|
|
|
69
|
+
# Check if IK option is enabled
|
|
70
|
+
if options & KuavoSDK.Options.WithIK:
|
|
71
|
+
if not KuavoROSEnv.check_rosnode_exists('/arms_ik_node'):
|
|
72
|
+
print("\033[31m\nError:WithIK option is enabled but ik_node is not running, please run `roslaunch motion_capture_ik ik_node.launch`\033[0m")
|
|
73
|
+
exit(1)
|
|
90
74
|
|
|
91
75
|
if not kuavo_core.initialize(debug=debug):
|
|
92
76
|
SDKLogger.error("[SDK] Failed to initialize core components.")
|
|
@@ -102,16 +86,11 @@ class KuavoSDK:
|
|
|
102
86
|
class KuavoRobot(RobotBase):
|
|
103
87
|
def __init__(self):
|
|
104
88
|
super().__init__(robot_type="kuavo")
|
|
105
|
-
|
|
106
|
-
if not GlobalConfig.use_websocket:
|
|
107
|
-
kuavo_ros_env = KuavoROSEnv()
|
|
108
|
-
if not kuavo_ros_env.Init():
|
|
109
|
-
raise RuntimeError("Failed to initialize ROS environment")
|
|
110
|
-
|
|
111
89
|
self._robot_info = KuavoRobotInfo()
|
|
112
90
|
self._robot_arm = KuavoRobotArm()
|
|
113
91
|
self._robot_head = KuavoRobotHead()
|
|
114
92
|
self._kuavo_core = KuavoRobotCore()
|
|
93
|
+
|
|
115
94
|
def stance(self)->bool:
|
|
116
95
|
"""Put the robot into 'stance' mode.
|
|
117
96
|
|
|
@@ -219,46 +198,6 @@ class KuavoRobot(RobotBase):
|
|
|
219
198
|
raise ValueError(f"[Robot] target_pose length must be 4 (x, y, z, yaw), but got {len(target_pose)}")
|
|
220
199
|
|
|
221
200
|
return self._kuavo_core.step_control(target_pose, dt, is_left_first_default, collision_check)
|
|
222
|
-
|
|
223
|
-
def control_command_pose(self, target_pose_x: float, target_pose_y: float, target_pose_z: float, target_pose_yaw: float) -> bool:
|
|
224
|
-
"""Control robot pose in base_link frame.
|
|
225
|
-
|
|
226
|
-
Args:
|
|
227
|
-
target_pose_x (float): The target x position in meters.
|
|
228
|
-
target_pose_y (float): The target y position in meters.
|
|
229
|
-
target_pose_z (float): The target z position in meters.
|
|
230
|
-
target_pose_yaw (float): The target yaw angle in radians.
|
|
231
|
-
|
|
232
|
-
Returns:
|
|
233
|
-
bool: True if the command was sent successfully, False otherwise.
|
|
234
|
-
|
|
235
|
-
Raises:
|
|
236
|
-
RuntimeError: If the robot is not in stance state when trying to control pose.
|
|
237
|
-
|
|
238
|
-
Note:
|
|
239
|
-
This command changes the robot state to 'command_pose'.
|
|
240
|
-
"""
|
|
241
|
-
return self._kuavo_core.control_command_pose(target_pose_x, target_pose_y, target_pose_z, target_pose_yaw)
|
|
242
|
-
|
|
243
|
-
def control_command_pose_world(self, target_pose_x: float, target_pose_y: float, target_pose_z: float, target_pose_yaw: float) -> bool:
|
|
244
|
-
"""Control robot pose in odom (world) frame.
|
|
245
|
-
|
|
246
|
-
Args:
|
|
247
|
-
target_pose_x (float): The target x position in meters.
|
|
248
|
-
target_pose_y (float): The target y position in meters.
|
|
249
|
-
target_pose_z (float): The target z position in meters.
|
|
250
|
-
target_pose_yaw (float): The target yaw angle in radians.
|
|
251
|
-
|
|
252
|
-
Returns:
|
|
253
|
-
bool: True if the command was sent successfully, False otherwise.
|
|
254
|
-
|
|
255
|
-
Raises:
|
|
256
|
-
RuntimeError: If the robot is not in stance state when trying to control pose.
|
|
257
|
-
|
|
258
|
-
Note:
|
|
259
|
-
This command changes the robot state to 'command_pose_world'.
|
|
260
|
-
"""
|
|
261
|
-
return self._kuavo_core.control_command_pose_world(target_pose_x, target_pose_y, target_pose_z, target_pose_yaw)
|
|
262
201
|
|
|
263
202
|
def control_head(self, yaw: float, pitch: float)->bool:
|
|
264
203
|
"""Control the head of the robot.
|
|
@@ -272,16 +211,6 @@ class KuavoRobot(RobotBase):
|
|
|
272
211
|
"""
|
|
273
212
|
return self._robot_head.control_head(yaw=yaw, pitch=pitch)
|
|
274
213
|
|
|
275
|
-
def enable_head_tracking(self, target_id: int)->bool:
|
|
276
|
-
"""Enable the head tracking.
|
|
277
|
-
"""
|
|
278
|
-
return self._robot_head.enable_head_tracking(target_id)
|
|
279
|
-
|
|
280
|
-
def disable_head_tracking(self)->bool:
|
|
281
|
-
"""Disable the head tracking.
|
|
282
|
-
"""
|
|
283
|
-
return self._robot_head.disable_head_tracking()
|
|
284
|
-
|
|
285
214
|
""" Robot Arm Control """
|
|
286
215
|
def arm_reset(self)->bool:
|
|
287
216
|
"""Reset the robot arm.
|
|
@@ -290,16 +219,8 @@ class KuavoRobot(RobotBase):
|
|
|
290
219
|
bool: True if the arm is reset successfully, False otherwise.
|
|
291
220
|
"""
|
|
292
221
|
return self._robot_arm.arm_reset()
|
|
293
|
-
|
|
294
|
-
def manipulation_mpc_reset(self)->bool:
|
|
295
|
-
"""Reset the robot arm.
|
|
296
222
|
|
|
297
|
-
|
|
298
|
-
bool: True if the arm is reset successfully, False otherwise.
|
|
299
|
-
"""
|
|
300
|
-
return self._robot_arm.manipulation_mpc_reset()
|
|
301
|
-
|
|
302
|
-
def control_arm_joint_positions(self, joint_positions:list)->bool:
|
|
223
|
+
def control_arm_position(self, joint_positions:list)->bool:
|
|
303
224
|
"""Control the position of the arm.
|
|
304
225
|
|
|
305
226
|
Args:
|
|
@@ -317,9 +238,9 @@ class KuavoRobot(RobotBase):
|
|
|
317
238
|
print("The length of the position list must be equal to the number of DOFs of the arm.")
|
|
318
239
|
return False
|
|
319
240
|
|
|
320
|
-
return self._robot_arm.
|
|
241
|
+
return self._robot_arm.control_arm_position(joint_positions)
|
|
321
242
|
|
|
322
|
-
def
|
|
243
|
+
def control_arm_target_poses(self, times:list, q_frames:list)->bool:
|
|
323
244
|
"""Control the target poses of the robot arm.
|
|
324
245
|
|
|
325
246
|
Args:
|
|
@@ -339,7 +260,7 @@ class KuavoRobot(RobotBase):
|
|
|
339
260
|
This is an asynchronous interface. The function returns immediately after sending the command.
|
|
340
261
|
Users need to wait for the motion to complete on their own.
|
|
341
262
|
"""
|
|
342
|
-
return self._robot_arm.
|
|
263
|
+
return self._robot_arm.control_arm_target_poses(times, q_frames)
|
|
343
264
|
|
|
344
265
|
def set_fixed_arm_mode(self) -> bool:
|
|
345
266
|
"""Freezes the robot arm.
|
|
@@ -365,30 +286,6 @@ class KuavoRobot(RobotBase):
|
|
|
365
286
|
"""
|
|
366
287
|
return self._robot_arm.set_external_control_arm_mode()
|
|
367
288
|
|
|
368
|
-
def set_manipulation_mpc_mode(self, ctrl_mode: KuavoManipulationMpcCtrlMode) -> bool:
|
|
369
|
-
"""
|
|
370
|
-
Set the manipulation mpc mode.
|
|
371
|
-
Returns:
|
|
372
|
-
bool: True if the manipulation mpc mode is set successfully, False otherwise.
|
|
373
|
-
"""
|
|
374
|
-
return self._robot_arm.set_manipulation_mpc_mode(ctrl_mode)
|
|
375
|
-
|
|
376
|
-
def set_manipulation_mpc_control_flow(self, control_flow: KuavoManipulationMpcControlFlow) -> bool:
|
|
377
|
-
"""
|
|
378
|
-
Set the manipulation mpc control flow.
|
|
379
|
-
Returns:
|
|
380
|
-
bool: True if the manipulation mpc control flow is set successfully, False otherwise.
|
|
381
|
-
"""
|
|
382
|
-
return self._robot_arm.set_manipulation_mpc_control_flow(control_flow)
|
|
383
|
-
|
|
384
|
-
def set_manipulation_mpc_frame(self, frame: KuavoManipulationMpcFrame) -> bool:
|
|
385
|
-
"""
|
|
386
|
-
Set the manipulation mpc frame.
|
|
387
|
-
Returns:
|
|
388
|
-
bool: True if the manipulation mpc frame is set successfully, False otherwise.
|
|
389
|
-
"""
|
|
390
|
-
return self._robot_arm.set_manipulation_mpc_frame(frame)
|
|
391
|
-
|
|
392
289
|
""" Arm Forward kinematics && Arm Inverse kinematics """
|
|
393
290
|
def arm_ik(self,
|
|
394
291
|
left_pose: KuavoPose,
|
|
@@ -436,24 +333,4 @@ class KuavoRobot(RobotBase):
|
|
|
436
333
|
Warning:
|
|
437
334
|
This function requires initializing the SDK with the :attr:`KuavoSDK.Options.WithIK`.
|
|
438
335
|
"""
|
|
439
|
-
return self._robot_arm.arm_fk(q)
|
|
440
|
-
|
|
441
|
-
def control_robot_end_effector_pose(self, left_pose: KuavoPose, right_pose: KuavoPose, frame: KuavoManipulationMpcFrame)->bool:
|
|
442
|
-
"""Control the end effector pose of the robot arm.
|
|
443
|
-
|
|
444
|
-
Args:
|
|
445
|
-
left_pose (KuavoPose): Pose of the robot left arm, xyz and quat.
|
|
446
|
-
right_pose (KuavoPose): Pose of the robot right arm, xyz and quat.
|
|
447
|
-
frame (KuavoManipulationMpcFrame): Frame of the robot arm.
|
|
448
|
-
|
|
449
|
-
Returns:
|
|
450
|
-
bool: True if the end effector pose is controlled successfully, False otherwise.
|
|
451
|
-
"""
|
|
452
|
-
return self._robot_arm.control_robot_end_effector_pose(left_pose, right_pose, frame)
|
|
453
|
-
|
|
454
|
-
if __name__ == "__main__":
|
|
455
|
-
robot = KuavoRobot()
|
|
456
|
-
robot.set_manipulation_mpc_mode(KuavoManipulationMpcCtrlMode.ArmOnly)
|
|
457
|
-
robot.set_manipulation_mpc_control_flow(KuavoManipulationMpcControlFlow.DirectToWbc)
|
|
458
|
-
robot.set_manipulation_mpc_frame(KuavoManipulationMpcFrame.WorldFrame)
|
|
459
|
-
robot.control_robot_end_effector_pose(KuavoPose(position=[0.3, 0.4, 0.9], orientation=[0.0, 0.0, 0.0, 1.0]), KuavoPose(position=[0.3, -0.5, 1.0], orientation=[0.0, 0.0, 0.0, 1.0]), KuavoManipulationMpcFrame.WorldFrame)
|
|
336
|
+
return self._robot_arm.arm_fk(q)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import math
|
|
5
5
|
from typing import Tuple
|
|
6
|
-
from kuavo_humanoid_sdk.interfaces.data_types import KuavoArmCtrlMode, KuavoIKParams, KuavoPose
|
|
6
|
+
from kuavo_humanoid_sdk.interfaces.data_types import KuavoArmCtrlMode, KuavoIKParams, KuavoPose
|
|
7
7
|
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
8
8
|
from kuavo_humanoid_sdk.kuavo.robot_info import KuavoRobotInfo
|
|
9
9
|
|
|
@@ -14,11 +14,8 @@ class KuavoRobotArm:
|
|
|
14
14
|
|
|
15
15
|
def arm_reset(self)-> bool:
|
|
16
16
|
return self._kuavo_core.robot_arm_reset()
|
|
17
|
-
|
|
18
|
-
def manipulation_mpc_reset(self)-> bool:
|
|
19
|
-
return self._kuavo_core.robot_manipulation_mpc_reset()
|
|
20
17
|
|
|
21
|
-
def
|
|
18
|
+
def control_arm_position(self, joint_position:list)->bool:
|
|
22
19
|
"""
|
|
23
20
|
Control the position of the robot arm joint.
|
|
24
21
|
Args:
|
|
@@ -38,9 +35,9 @@ class KuavoRobotArm:
|
|
|
38
35
|
if abs(pos) > math.pi:
|
|
39
36
|
raise ValueError(f"Joint position {pos} rad exceeds ±π rad (±180 deg) limit")
|
|
40
37
|
|
|
41
|
-
return self._kuavo_core.
|
|
38
|
+
return self._kuavo_core.control_robot_arm_traj(joint_data=joint_position)
|
|
42
39
|
|
|
43
|
-
def
|
|
40
|
+
def control_arm_target_poses(self, times:list, q_frames:list)->bool:
|
|
44
41
|
"""
|
|
45
42
|
Control the target poses of the robot arm.
|
|
46
43
|
Args:
|
|
@@ -54,12 +51,12 @@ class KuavoRobotArm:
|
|
|
54
51
|
Returns:
|
|
55
52
|
bool: True if the control was successful, False otherwise.
|
|
56
53
|
"""
|
|
57
|
-
if len(times) != len(
|
|
54
|
+
if len(times) != len(q_frames):
|
|
58
55
|
raise ValueError("Invalid input. times and joint_q must have thesame length.")
|
|
59
56
|
|
|
60
57
|
# Check if joint positions are within ±180 degrees (±π radians)
|
|
61
58
|
q_degs = []
|
|
62
|
-
for q in
|
|
59
|
+
for q in q_frames:
|
|
63
60
|
if any(abs(pos) > math.pi for pos in q):
|
|
64
61
|
raise ValueError("Joint positions must be within ±π rad (±180 deg)")
|
|
65
62
|
if len(q) != self._robot_info.arm_joint_dof:
|
|
@@ -67,19 +64,7 @@ class KuavoRobotArm:
|
|
|
67
64
|
# Convert joint positions from radians to degrees
|
|
68
65
|
q_degs.append([(p * 180.0 / math.pi) for p in q])
|
|
69
66
|
|
|
70
|
-
return self._kuavo_core.
|
|
71
|
-
|
|
72
|
-
def control_robot_end_effector_pose(self, left_pose: KuavoPose, right_pose: KuavoPose, frame: KuavoManipulationMpcFrame)->bool:
|
|
73
|
-
"""
|
|
74
|
-
Control the end effector pose of the robot arm.
|
|
75
|
-
Args:
|
|
76
|
-
left_pose (KuavoPose): Pose of the robot left arm, xyz and quat.
|
|
77
|
-
right_pose (KuavoPose): Pose of the robot right arm, xyz and quat.
|
|
78
|
-
frame (KuavoManipulationMpcFrame): Frame of the robot end effector pose.
|
|
79
|
-
Returns:
|
|
80
|
-
bool: True if the control was successful, False otherwise.
|
|
81
|
-
"""
|
|
82
|
-
return self._kuavo_core.control_robot_end_effector_pose(left_pose, right_pose, frame)
|
|
67
|
+
return self._kuavo_core.control_robot_arm_target_poses(times=times, joint_q=q_degs)
|
|
83
68
|
|
|
84
69
|
def set_fixed_arm_mode(self) -> bool:
|
|
85
70
|
"""
|
|
@@ -105,30 +90,6 @@ class KuavoRobotArm:
|
|
|
105
90
|
"""
|
|
106
91
|
return self._kuavo_core.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl)
|
|
107
92
|
|
|
108
|
-
def set_manipulation_mpc_mode(self, ctrl_mode: KuavoManipulationMpcCtrlMode) -> bool:
|
|
109
|
-
"""
|
|
110
|
-
Set the manipulation mpc mode.
|
|
111
|
-
Returns:
|
|
112
|
-
bool: True if the manipulation mpc mode is set successfully, False otherwise.
|
|
113
|
-
"""
|
|
114
|
-
return self._kuavo_core.change_manipulation_mpc_ctrl_mode(ctrl_mode)
|
|
115
|
-
|
|
116
|
-
def set_manipulation_mpc_control_flow(self, control_flow: KuavoManipulationMpcControlFlow) -> bool:
|
|
117
|
-
"""
|
|
118
|
-
Set the manipulation mpc control flow.
|
|
119
|
-
Returns:
|
|
120
|
-
bool: True if the manipulation mpc control flow is set successfully, False otherwise.
|
|
121
|
-
"""
|
|
122
|
-
return self._kuavo_core.change_manipulation_mpc_control_flow(control_flow)
|
|
123
|
-
|
|
124
|
-
def set_manipulation_mpc_frame(self, frame: KuavoManipulationMpcFrame) -> bool:
|
|
125
|
-
"""
|
|
126
|
-
Set the manipulation mpc frame.
|
|
127
|
-
Returns:
|
|
128
|
-
bool: True if the manipulation mpc frame is set successfully, False otherwise.
|
|
129
|
-
"""
|
|
130
|
-
return self._kuavo_core.change_manipulation_mpc_frame(frame)
|
|
131
|
-
|
|
132
93
|
""" Arm Forward kinematics && Arm Inverse kinematics """
|
|
133
94
|
def arm_ik(self,
|
|
134
95
|
left_pose: KuavoPose,
|
|
@@ -183,10 +144,3 @@ class KuavoRobotArm:
|
|
|
183
144
|
if result is None:
|
|
184
145
|
return None, None
|
|
185
146
|
return result
|
|
186
|
-
|
|
187
|
-
# if __name__ == "__main__":
|
|
188
|
-
# arm = KuavoRobotArm()
|
|
189
|
-
# arm.set_manipulation_mpc_mode(KuavoManipulationMpcCtrlMode.ArmOnly)
|
|
190
|
-
# arm.set_manipulation_mpc_control_flow(KuavoManipulationMpcControlFlow.DirectToWbc)
|
|
191
|
-
# arm.set_manipulation_mpc_frame(KuavoManipulationMpcFrame.WorldFrame)
|
|
192
|
-
# arm.control_robot_end_effector_pose(KuavoPose(position=[0.3, 0.4, 0.9], orientation=[0.0, 0.0, 0.0, 1.0]), KuavoPose(position=[0.3, -0.5, 1.0], orientation=[0.0, 0.0, 0.0, 1.0]), KuavoManipulationMpcFrame.WorldFrame)
|
|
@@ -27,13 +27,3 @@ class KuavoRobotHead:
|
|
|
27
27
|
SDKLogger.warn(f"[Robot] pitch {pitch} exceeds limit [-{math.pi/7.2:.3f}, {math.pi/7.2:.3f}] radians (-25 to 25 degrees), will be limited")
|
|
28
28
|
limited_pitch = min(math.pi/7.2, max(-math.pi/7.2, pitch))
|
|
29
29
|
return self._kuavo_core.control_robot_head(yaw=limited_yaw, pitch=limited_pitch)
|
|
30
|
-
|
|
31
|
-
def enable_head_tracking(self, target_id: int)->bool:
|
|
32
|
-
"""Enable the head tracking.
|
|
33
|
-
"""
|
|
34
|
-
return self._kuavo_core.enable_head_tracking(target_id)
|
|
35
|
-
|
|
36
|
-
def disable_head_tracking(self)->bool:
|
|
37
|
-
"""Disable the head tracking.
|
|
38
|
-
"""
|
|
39
|
-
return self._kuavo_core.disable_head_tracking()
|