kuavo-humanoid-sdk 0.1.2__py3-none-any.whl → 1.1.2a921__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 +1 -0
- kuavo_humanoid_sdk/interfaces/data_types.py +30 -7
- kuavo_humanoid_sdk/interfaces/end_effector.py +23 -4
- kuavo_humanoid_sdk/kuavo/__init__.py +1 -1
- kuavo_humanoid_sdk/kuavo/core/core.py +21 -13
- kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py +44 -15
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +72 -16
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +6 -0
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +89 -34
- kuavo_humanoid_sdk/kuavo/core/ros_env.py +48 -10
- kuavo_humanoid_sdk/kuavo/dexterous_hand.py +40 -25
- kuavo_humanoid_sdk/kuavo/leju_claw.py +24 -17
- kuavo_humanoid_sdk/kuavo/robot.py +42 -15
- kuavo_humanoid_sdk/kuavo/robot_arm.py +6 -0
- kuavo_humanoid_sdk/kuavo/robot_info.py +1 -0
- {kuavo_humanoid_sdk-0.1.2.dist-info → kuavo_humanoid_sdk-1.1.2a921.dist-info}/METADATA +73 -20
- kuavo_humanoid_sdk-1.1.2a921.dist-info/RECORD +27 -0
- {kuavo_humanoid_sdk-0.1.2.dist-info → kuavo_humanoid_sdk-1.1.2a921.dist-info}/WHEEL +1 -1
- kuavo_humanoid_sdk-0.1.2.dist-info/RECORD +0 -27
- {kuavo_humanoid_sdk-0.1.2.dist-info → kuavo_humanoid_sdk-1.1.2a921.dist-info}/top_level.txt +0 -0
kuavo_humanoid_sdk/__init__.py
CHANGED
|
@@ -65,13 +65,13 @@ class EndEffectorState:
|
|
|
65
65
|
"""Data class representing the state of the end effector.
|
|
66
66
|
|
|
67
67
|
Args:
|
|
68
|
-
position (
|
|
69
|
-
velocity (
|
|
70
|
-
effort (
|
|
68
|
+
position (list): float, Position of the end effector, range: [0, 100]
|
|
69
|
+
velocity (list): float, ...
|
|
70
|
+
effort (list): float, ...
|
|
71
71
|
"""
|
|
72
|
-
position:
|
|
73
|
-
velocity:
|
|
74
|
-
effort:
|
|
72
|
+
position: list
|
|
73
|
+
velocity: list
|
|
74
|
+
effort: list
|
|
75
75
|
class GraspingState(Enum):
|
|
76
76
|
"""Enum class representing the grasping states of the end effector.
|
|
77
77
|
|
|
@@ -119,4 +119,27 @@ class KuavoIKParams:
|
|
|
119
119
|
# constraint and cost params
|
|
120
120
|
oritation_constraint_tol: float = 1e-3
|
|
121
121
|
pos_constraint_tol: float = 1e-3 # 0.001m, work when pos_cost_weight==0.0
|
|
122
|
-
pos_cost_weight: float = 0.0 # If U need high accuracy, set this to 0.0 !!!
|
|
122
|
+
pos_cost_weight: float = 0.0 # If U need high accuracy, set this to 0.0 !!!
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class KuavoDexHandTouchState:
|
|
126
|
+
"""Data class representing the touch state of the dexterous hand."""
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class KuavoTouchState:
|
|
130
|
+
"""Data class representing the touch state of the dexterous hand."""
|
|
131
|
+
normal_force1: int # 法向力1
|
|
132
|
+
normal_force2: int # 法向力2
|
|
133
|
+
normal_force3: int # 法向力3
|
|
134
|
+
tangential_force1: int # 切向力1
|
|
135
|
+
tangential_force2: int # 切向力2
|
|
136
|
+
tangential_force3: int # 切向力3
|
|
137
|
+
tangential_direction1: int # 切向力方向1
|
|
138
|
+
tangential_direction2: int # 切向力方向2
|
|
139
|
+
tangential_direction3: int # 切向力方向3
|
|
140
|
+
self_proximity1: int # 自电容接近传感器1
|
|
141
|
+
self_proximity2: int # 自电容接近传感器2
|
|
142
|
+
mutual_proximity: int # 互电容接近传感器
|
|
143
|
+
status: int # 传感器状态
|
|
144
|
+
# 5 fingers
|
|
145
|
+
data: Tuple[KuavoTouchState, KuavoTouchState, KuavoTouchState, KuavoTouchState, KuavoTouchState]
|
|
@@ -4,8 +4,27 @@ from kuavo_humanoid_sdk.interfaces.data_types import EndEffectorSide, EndEffecto
|
|
|
4
4
|
|
|
5
5
|
class EndEffector(ABC):
|
|
6
6
|
def __init__(self, joint_names: list):
|
|
7
|
-
self.
|
|
7
|
+
self._joint_names = joint_names
|
|
8
|
+
|
|
9
|
+
def joint_names(self)->list:
|
|
10
|
+
"""Returns the joint names of the end effector.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
list: The joint names of the end effector.
|
|
14
|
+
"""
|
|
15
|
+
return self._joint_names
|
|
16
|
+
|
|
17
|
+
def joint_count(self) -> int:
|
|
18
|
+
"""Returns the total number of joints in the end effector.
|
|
8
19
|
|
|
20
|
+
The joint_names list contains joints for both left and right end effectors.
|
|
21
|
+
For a single end effector, the number of joints would be joint_names.size/2.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
int: The total number of joints in the end effector.
|
|
25
|
+
"""
|
|
26
|
+
return len(self._joint_names)
|
|
27
|
+
|
|
9
28
|
@abstractmethod
|
|
10
29
|
def control(self, target_positions:list, target_velocities:list, target_torques:list)->bool:
|
|
11
30
|
pass
|
|
@@ -27,15 +46,15 @@ class EndEffector(ABC):
|
|
|
27
46
|
pass
|
|
28
47
|
|
|
29
48
|
@abstractmethod
|
|
30
|
-
def get_position(self)->Tuple[
|
|
49
|
+
def get_position(self)->Tuple[list, list]:
|
|
31
50
|
pass
|
|
32
51
|
|
|
33
52
|
@abstractmethod
|
|
34
|
-
def get_velocity(self)->Tuple[
|
|
53
|
+
def get_velocity(self)->Tuple[list, list]:
|
|
35
54
|
pass
|
|
36
55
|
|
|
37
56
|
@abstractmethod
|
|
38
|
-
def get_effort(self)->Tuple[
|
|
57
|
+
def get_effort(self)->Tuple[list, list]:
|
|
39
58
|
pass
|
|
40
59
|
|
|
41
60
|
@abstractmethod
|
|
@@ -3,5 +3,5 @@ from .robot_info import KuavoRobotInfo
|
|
|
3
3
|
from .robot_state import KuavoRobotState
|
|
4
4
|
from .robot_arm import KuavoRobotArm
|
|
5
5
|
from .robot_head import KuavoRobotHead
|
|
6
|
-
from .dexterous_hand import DexterousHand
|
|
6
|
+
from .dexterous_hand import DexterousHand, TouchDexterousHand
|
|
7
7
|
from .leju_claw import LejuClaw
|
|
@@ -28,7 +28,7 @@ from transitions import Machine, State
|
|
|
28
28
|
from kuavo_humanoid_sdk.interfaces.data_types import KuavoArmCtrlMode, KuavoIKParams, KuavoPose
|
|
29
29
|
from kuavo_humanoid_sdk.kuavo.core.ros.control import KuavoRobotControl
|
|
30
30
|
from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
|
|
31
|
-
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param
|
|
31
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param
|
|
32
32
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
33
33
|
|
|
34
34
|
# Define robot states
|
|
@@ -78,7 +78,6 @@ class KuavoRobotCore:
|
|
|
78
78
|
raise RuntimeError if initialize failed.
|
|
79
79
|
"""
|
|
80
80
|
try:
|
|
81
|
-
info = make_robot_param()
|
|
82
81
|
# init state by gait_name
|
|
83
82
|
gait_name = self._rb_state.gait_name()
|
|
84
83
|
if gait_name is not None:
|
|
@@ -173,15 +172,20 @@ class KuavoRobotCore:
|
|
|
173
172
|
SDKLogger.warn(f"[Core] control torso height failed, robot is not in stance state({self.state})!")
|
|
174
173
|
return False
|
|
175
174
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
MIN_HEIGHT = -0.35
|
|
176
|
+
MAX_HEIGHT = 0.0
|
|
177
|
+
MIN_PITCH = -0.4
|
|
178
|
+
MAX_PITCH = 0.4
|
|
180
179
|
|
|
181
|
-
# Limit
|
|
182
|
-
|
|
183
|
-
if
|
|
184
|
-
SDKLogger.warn(f"[Core]
|
|
180
|
+
# Limit height range
|
|
181
|
+
limited_height = min(MAX_HEIGHT, max(MIN_HEIGHT, height))
|
|
182
|
+
if height > MAX_HEIGHT or height < MIN_HEIGHT:
|
|
183
|
+
SDKLogger.warn(f"[Core] height {height} exceeds limit [{MIN_HEIGHT}, {MAX_HEIGHT}], will be limited")
|
|
184
|
+
|
|
185
|
+
# Limit pitch range
|
|
186
|
+
limited_pitch = min(MAX_PITCH, max(MIN_PITCH, pitch))
|
|
187
|
+
if abs(pitch) > MAX_PITCH:
|
|
188
|
+
SDKLogger.warn(f"[Core] pitch {pitch} exceeds limit [{MIN_PITCH}, {MAX_PITCH}], will be limited")
|
|
185
189
|
|
|
186
190
|
return self._control.control_torso_height(limited_height, limited_pitch)
|
|
187
191
|
|
|
@@ -238,9 +242,9 @@ class KuavoRobotCore:
|
|
|
238
242
|
max_y_step = 0.20
|
|
239
243
|
max_yaw_step = 90
|
|
240
244
|
else:
|
|
241
|
-
max_x_step = 0.
|
|
242
|
-
max_y_step = 0.
|
|
243
|
-
max_yaw_step =
|
|
245
|
+
max_x_step = 0.15
|
|
246
|
+
max_y_step = 0.15
|
|
247
|
+
max_yaw_step = 45
|
|
244
248
|
|
|
245
249
|
body_poses = []
|
|
246
250
|
|
|
@@ -294,6 +298,10 @@ class KuavoRobotCore:
|
|
|
294
298
|
def control_robot_dexhand(self, left_position:list, right_position:list)->bool:
|
|
295
299
|
return self._control.control_robot_dexhand(left_position, right_position)
|
|
296
300
|
|
|
301
|
+
def robot_dexhand_command(self, data, ctrl_mode, hand_side):
|
|
302
|
+
return self._control.robot_dexhand_command(data, ctrl_mode, hand_side)
|
|
303
|
+
|
|
304
|
+
|
|
297
305
|
def control_leju_claw(self, postions:list, velocities:list=[90, 90], torques:list=[1.0, 1.0]) ->bool:
|
|
298
306
|
return self._control.control_leju_claw(postions, velocities, torques)
|
|
299
307
|
|
|
@@ -4,6 +4,7 @@ from queue import Queue
|
|
|
4
4
|
from kuavo_humanoid_sdk.interfaces.data_types import EndEffectorSide
|
|
5
5
|
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
6
6
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
7
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
7
8
|
class DexHandControl:
|
|
8
9
|
_instance = None
|
|
9
10
|
|
|
@@ -19,6 +20,8 @@ class DexHandControl:
|
|
|
19
20
|
self.thread = threading.Thread(target=self._process_queue) # Create a thread to process the queue
|
|
20
21
|
self.thread.daemon = True # Set the thread as a daemon so it will exit when the main program exits
|
|
21
22
|
self.thread.start() # Start the thread
|
|
23
|
+
kuavo_info = make_robot_param()
|
|
24
|
+
self._ee_type = kuavo_info['end_effector_type']
|
|
22
25
|
# Initialize last command position, torque, and velocity
|
|
23
26
|
self.last_cmd_position = {EndEffectorSide.LEFT: [0] * 6, EndEffectorSide.RIGHT: [0] * 6}
|
|
24
27
|
self._initialized = True
|
|
@@ -26,6 +29,9 @@ class DexHandControl:
|
|
|
26
29
|
def control(self, target_positions: list, side: EndEffectorSide):
|
|
27
30
|
self.queue.put(('position', EndEffectorSide(side.value), target_positions))
|
|
28
31
|
|
|
32
|
+
def control_velocity(self, target_velocities: list, side: EndEffectorSide):
|
|
33
|
+
self.queue.put(('velocity', EndEffectorSide(side.value), target_velocities))
|
|
34
|
+
|
|
29
35
|
def make_gestures(self, gestures:list)->bool:
|
|
30
36
|
"""
|
|
31
37
|
Make a gesture for the dexhand.
|
|
@@ -60,26 +66,49 @@ class DexHandControl:
|
|
|
60
66
|
return None
|
|
61
67
|
return gs
|
|
62
68
|
|
|
69
|
+
|
|
70
|
+
def _process_dexhand_command(self, command, side, data):
|
|
71
|
+
if command == 'position':
|
|
72
|
+
pos = self.last_cmd_position[EndEffectorSide.LEFT] + self.last_cmd_position[EndEffectorSide.RIGHT]
|
|
73
|
+
if side == EndEffectorSide.BOTH:
|
|
74
|
+
pos = copy.deepcopy(data)
|
|
75
|
+
elif side == EndEffectorSide.LEFT:
|
|
76
|
+
pos[:6] = data
|
|
77
|
+
elif side == EndEffectorSide.RIGHT:
|
|
78
|
+
pos[6:] = data
|
|
79
|
+
else:
|
|
80
|
+
return
|
|
81
|
+
self._kuavo_core.control_robot_dexhand(left_position=pos[:6], right_position=pos[6:])
|
|
82
|
+
self.last_cmd_position[EndEffectorSide.LEFT] = pos[:6]
|
|
83
|
+
self.last_cmd_position[EndEffectorSide.RIGHT] = pos[6:]
|
|
84
|
+
|
|
85
|
+
def _process_touch_dexhand_command(self, command, side, data):
|
|
86
|
+
if command == 'position':
|
|
87
|
+
ctrl_mode = 0
|
|
88
|
+
if side == EndEffectorSide.BOTH:
|
|
89
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 2)
|
|
90
|
+
elif side == EndEffectorSide.LEFT:
|
|
91
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 0)
|
|
92
|
+
elif side == EndEffectorSide.RIGHT:
|
|
93
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 1)
|
|
94
|
+
elif command == 'velocity':
|
|
95
|
+
ctrl_mode = 0
|
|
96
|
+
if side == EndEffectorSide.BOTH:
|
|
97
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 2)
|
|
98
|
+
elif side == EndEffectorSide.LEFT:
|
|
99
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 0)
|
|
100
|
+
elif side == EndEffectorSide.RIGHT:
|
|
101
|
+
self._kuavo_core.robot_dexhand_command(data, ctrl_mode, 1)
|
|
102
|
+
|
|
63
103
|
def _process_queue(self):
|
|
64
104
|
while True:
|
|
65
105
|
try:
|
|
66
106
|
command, side, data = self.queue.get() # This will block until an item is available in the queue
|
|
67
107
|
SDKLogger.debug(f'[DexHandControl] Received command: {command}, for side: {side}, with data: {data}')
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
elif side == EndEffectorSide.LEFT:
|
|
73
|
-
pos[:6] = data
|
|
74
|
-
elif side == EndEffectorSide.RIGHT:
|
|
75
|
-
pos[6:] = data
|
|
76
|
-
else:
|
|
77
|
-
return
|
|
78
|
-
self._kuavo_core.control_robot_dexhand(left_position=pos[:6], right_position=pos[6:])
|
|
79
|
-
self.last_cmd_position[EndEffectorSide.LEFT] = pos[:6]
|
|
80
|
-
self.last_cmd_position[EndEffectorSide.RIGHT] = pos[6:]
|
|
81
|
-
|
|
82
|
-
# task done.
|
|
108
|
+
if self._ee_type == EndEffectorType.QIANGNAO:
|
|
109
|
+
self._process_dexhand_command(command, side, data)
|
|
110
|
+
elif self._ee_type == EndEffectorType.QIANGNAO_TOUCH:
|
|
111
|
+
self._process_touch_dexhand_command(command, side, data)
|
|
83
112
|
self.queue.task_done()
|
|
84
113
|
except KeyboardInterrupt:
|
|
85
114
|
break
|
|
@@ -1,33 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
import os
|
|
2
2
|
import rospy
|
|
3
3
|
import numpy as np
|
|
4
4
|
from typing import Tuple
|
|
5
5
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
6
6
|
from kuavo_humanoid_sdk.interfaces.data_types import KuavoArmCtrlMode, KuavoIKParams, KuavoPose
|
|
7
7
|
from kuavo_humanoid_sdk.kuavo.core.ros.sat_utils import RotatingRectangle
|
|
8
|
-
|
|
8
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.param import EndEffectorType
|
|
9
9
|
from geometry_msgs.msg import Twist
|
|
10
10
|
from sensor_msgs.msg import JointState, Joy
|
|
11
|
-
from kuavo_msgs.msg import gestureTask,robotHandPosition, robotHeadMotionData, armTargetPoses, switchGaitByName
|
|
12
|
-
|
|
13
|
-
from kuavo_msgs.srv import (gestureExecute, gestureExecuteRequest,gestureList, gestureListRequest,
|
|
11
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.msg import (gestureTask,robotHandPosition, robotHeadMotionData, armTargetPoses, switchGaitByName,
|
|
12
|
+
footPose, footPoseTargetTrajectories, dexhandCommand)
|
|
13
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import (gestureExecute, gestureExecuteRequest,gestureList, gestureListRequest,
|
|
14
14
|
controlLejuClaw, controlLejuClawRequest, changeArmCtrlMode, changeArmCtrlModeRequest)
|
|
15
|
-
from motion_capture_ik.msg import twoArmHandPoseCmd, ikSolveParam
|
|
16
|
-
from motion_capture_ik.srv import twoArmHandPoseCmdSrv, fkSrv
|
|
15
|
+
from kuavo_humanoid_sdk.msg.motion_capture_ik.msg import twoArmHandPoseCmd, ikSolveParam
|
|
16
|
+
from kuavo_humanoid_sdk.msg.motion_capture_ik.srv import twoArmHandPoseCmdSrv, fkSrv
|
|
17
17
|
|
|
18
18
|
class ControlEndEffector:
|
|
19
|
-
def __init__(self, eef_type: str =
|
|
20
|
-
self._pubs = []
|
|
19
|
+
def __init__(self, eef_type: str = EndEffectorType.QIANGNAO):
|
|
21
20
|
self._eef_type = eef_type
|
|
22
|
-
|
|
21
|
+
self._pubs = []
|
|
22
|
+
if self._eef_type == EndEffectorType.QIANGNAO:
|
|
23
|
+
self._pub_ctrl_robot_hand = rospy.Publisher('/control_robot_hand_position', robotHandPosition, queue_size=10)
|
|
24
|
+
# publisher, name, require
|
|
25
|
+
self._pubs.append((self._pub_ctrl_robot_hand, True))
|
|
26
|
+
elif self._eef_type == EndEffectorType.QIANGNAO_TOUCH:
|
|
23
27
|
self._pub_ctrl_robot_hand = rospy.Publisher('/control_robot_hand_position', robotHandPosition, queue_size=10)
|
|
24
|
-
self.
|
|
28
|
+
self._pub_dexhand_command = rospy.Publisher('/dexhand/command', dexhandCommand, queue_size=10)
|
|
29
|
+
self._pub_dexhand_right_command = rospy.Publisher('/dexhand/right/command', dexhandCommand, queue_size=10)
|
|
30
|
+
self._pub_dexhand_left_command = rospy.Publisher('/dexhand/left/command', dexhandCommand, queue_size=10)
|
|
31
|
+
# publisher, name, require
|
|
32
|
+
self._pubs.append((self._pub_dexhand_command, True))
|
|
33
|
+
self._pubs.append((self._pub_dexhand_right_command, True))
|
|
34
|
+
self._pubs.append((self._pub_dexhand_left_command, True))
|
|
35
|
+
|
|
25
36
|
|
|
26
37
|
def connect(self, timeout:float=1.0)-> bool:
|
|
27
38
|
start_time = rospy.Time.now()
|
|
28
39
|
|
|
29
40
|
success = True
|
|
30
|
-
for pub in self._pubs:
|
|
41
|
+
for pub, require in self._pubs:
|
|
31
42
|
while pub.get_num_connections() == 0:
|
|
32
43
|
if (rospy.Time.now() - start_time).to_sec() > timeout:
|
|
33
44
|
SDKLogger.error(f"Timeout waiting for {pub.name} connection")
|
|
@@ -39,7 +50,7 @@ class ControlEndEffector:
|
|
|
39
50
|
|
|
40
51
|
""" Control Kuavo Robot Dexhand """
|
|
41
52
|
def pub_control_robot_dexhand(self, left_position:list, right_position:list)->bool:
|
|
42
|
-
if self._eef_type
|
|
53
|
+
if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
|
|
43
54
|
SDKLogger.warning(f"{self._eef_type} not support control dexhand")
|
|
44
55
|
return False
|
|
45
56
|
try :
|
|
@@ -52,9 +63,41 @@ class ControlEndEffector:
|
|
|
52
63
|
except Exception as e:
|
|
53
64
|
SDKLogger.error(f"publish robot dexhand: {e}")
|
|
54
65
|
return False
|
|
66
|
+
|
|
67
|
+
def pub_dexhand_command(self, data:list, ctrl_mode, hand_side)->bool:
|
|
68
|
+
"""
|
|
69
|
+
ctrl_mode: 0 --> POSITION, 1 --> VELOCITY
|
|
70
|
+
hand_side: 0 --> left, 1 --> right, 2-->dual
|
|
71
|
+
"""
|
|
72
|
+
if not self._eef_type == EndEffectorType.QIANGNAO_TOUCH:
|
|
73
|
+
SDKLogger.warning(f"{self._eef_type} not support pub_left_dexhand_command")
|
|
74
|
+
return False
|
|
75
|
+
try:
|
|
76
|
+
if hand_side != 2 and len(data) != 6:
|
|
77
|
+
SDKLogger.warning("Data length should be 6")
|
|
78
|
+
return False
|
|
79
|
+
if hand_side == 2 and len(data) != 12:
|
|
80
|
+
SDKLogger.warning("Data length should be 12")
|
|
81
|
+
return False
|
|
82
|
+
if ctrl_mode not in [dexhandCommand.POSITION_CONTROL, dexhandCommand.VELOCITY_CONTROL]:
|
|
83
|
+
SDKLogger.error(f"Invalid mode for pub_left_dexhand_command: {ctrl_mode}")
|
|
84
|
+
return False
|
|
85
|
+
msg = dexhandCommand()
|
|
86
|
+
msg.data = [int(d) for d in data] # Convert data to integers
|
|
87
|
+
msg.control_mode = ctrl_mode
|
|
88
|
+
if hand_side == 0:
|
|
89
|
+
self._pub_dexhand_left_command.publish(msg)
|
|
90
|
+
elif hand_side == 1:
|
|
91
|
+
self._pub_dexhand_right_command.publish(msg)
|
|
92
|
+
else:
|
|
93
|
+
self._pub_dexhand_command.publish(msg)
|
|
94
|
+
return True
|
|
95
|
+
except Exception as e:
|
|
96
|
+
SDKLogger.error(f"Failed to publish left dexhand command: {e}")
|
|
97
|
+
return False
|
|
55
98
|
|
|
56
99
|
def srv_execute_gesture(self, gestures:list)->bool:
|
|
57
|
-
if self._eef_type
|
|
100
|
+
if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
|
|
58
101
|
SDKLogger.warning(f"{self._eef_type} not support control dexhand")
|
|
59
102
|
return False
|
|
60
103
|
try:
|
|
@@ -83,7 +126,7 @@ class ControlEndEffector:
|
|
|
83
126
|
return False
|
|
84
127
|
|
|
85
128
|
def srv_get_gesture_names(self)->list:
|
|
86
|
-
if self._eef_type
|
|
129
|
+
if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
|
|
87
130
|
SDKLogger.warning(f"{self._eef_type} not support control dexhand")
|
|
88
131
|
return []
|
|
89
132
|
try:
|
|
@@ -264,7 +307,7 @@ class ControlRobotMotion:
|
|
|
264
307
|
self._pub_switch_gait = rospy.Publisher('/humanoid_switch_gait_by_name', switchGaitByName, queue_size=10)
|
|
265
308
|
self._pub_step_ctrl = rospy.Publisher('/humanoid_mpc_foot_pose_target_trajectories', footPoseTargetTrajectories, queue_size=10)
|
|
266
309
|
|
|
267
|
-
def connect(self, timeout:float=
|
|
310
|
+
def connect(self, timeout:float=2.0)-> bool:
|
|
268
311
|
start_time = rospy.Time.now()
|
|
269
312
|
publishers = [
|
|
270
313
|
# (self._pub_joy, "joy publisher"),
|
|
@@ -510,6 +553,19 @@ class KuavoRobotControl:
|
|
|
510
553
|
SDKLogger.debug(f"Control robot dexhand: {left_position}, {right_position}")
|
|
511
554
|
return self.kuavo_eef_control.pub_control_robot_dexhand(left_position, right_position)
|
|
512
555
|
|
|
556
|
+
def robot_dexhand_command(self, data, ctrl_mode, hand_side):
|
|
557
|
+
"""
|
|
558
|
+
Publish dexhand command
|
|
559
|
+
Args:
|
|
560
|
+
- data: list of 6 floats between 0 and 100
|
|
561
|
+
- ctrl_mode: int between 0(position), 1(velocity)
|
|
562
|
+
- hand_side: int between 0(left), 1(right), 2(dual)
|
|
563
|
+
"""
|
|
564
|
+
if self.kuavo_eef_control is None:
|
|
565
|
+
SDKLogger.error("End effector control is not initialized.")
|
|
566
|
+
return False
|
|
567
|
+
return self.kuavo_eef_control.pub_dexhand_command(data, ctrl_mode, hand_side)
|
|
568
|
+
|
|
513
569
|
def execute_gesture(self, gestures:list)->bool:
|
|
514
570
|
"""
|
|
515
571
|
Execute gestures
|
|
@@ -2,6 +2,12 @@ import rospy
|
|
|
2
2
|
import json
|
|
3
3
|
import xml.etree.ElementTree as ET
|
|
4
4
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
5
|
+
|
|
6
|
+
# End effector types
|
|
7
|
+
class EndEffectorType:
|
|
8
|
+
QIANGNAO = "qiangnao"
|
|
9
|
+
QIANGNAO_TOUCH = "qiangnao_touch"
|
|
10
|
+
LEJUCLAW = "lejuclaw"
|
|
5
11
|
class RosParameter:
|
|
6
12
|
def __init__(self):
|
|
7
13
|
pass
|
|
@@ -4,12 +4,13 @@ import time
|
|
|
4
4
|
from typing import Tuple
|
|
5
5
|
from std_msgs.msg import Float64
|
|
6
6
|
from nav_msgs.msg import Odometry
|
|
7
|
-
from
|
|
8
|
-
|
|
7
|
+
from sensor_msgs.msg import JointState
|
|
8
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.msg import sensorsData, lejuClawState, gaitTimeName, dexhandTouchState
|
|
9
9
|
from kuavo_msgs.srv import changeArmCtrlMode, changeArmCtrlModeRequest, getCurrentGaitName, getCurrentGaitNameRequest
|
|
10
|
-
from ocs2_msgs.msg import mpc_observation
|
|
11
|
-
from kuavo_humanoid_sdk.interfaces.data_types import KuavoImuData, KuavoJointData, KuavoOdometry,
|
|
12
|
-
|
|
10
|
+
from kuavo_humanoid_sdk.msg.ocs2_msgs.msg import mpc_observation
|
|
11
|
+
from kuavo_humanoid_sdk.interfaces.data_types import (KuavoImuData, KuavoJointData, KuavoOdometry,
|
|
12
|
+
KuavoArmCtrlMode, EndEffectorState, KuavoDexHandTouchState)
|
|
13
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param, EndEffectorType
|
|
13
14
|
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
14
15
|
|
|
15
16
|
from collections import deque
|
|
@@ -66,12 +67,32 @@ class KuavoRobotStateCore:
|
|
|
66
67
|
rospy.Subscriber("/humanoid_mpc_observation", mpc_observation, self._humanoid_mpc_observation_callback)
|
|
67
68
|
|
|
68
69
|
kuavo_info = make_robot_param()
|
|
69
|
-
|
|
70
|
+
self._ee_type = kuavo_info['end_effector_type']
|
|
71
|
+
if self._ee_type == EndEffectorType.LEJUCLAW:
|
|
70
72
|
rospy.Subscriber("/leju_claw_state", lejuClawState, self._lejuclaw_state_callback)
|
|
71
|
-
elif
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
elif self._ee_type == EndEffectorType.QIANGNAO:
|
|
74
|
+
rospy.Subscriber("/dexhand/state", JointState, self._dexterous_hand_state_callback)
|
|
75
|
+
elif self._ee_type == EndEffectorType.QIANGNAO_TOUCH:
|
|
76
|
+
rospy.Subscriber("/dexhand/state", JointState, self._dexterous_hand_state_callback)
|
|
77
|
+
rospy.Subscriber("/dexhand/touch_state", dexhandTouchState, self._dexhand_touch_state_callback)
|
|
78
|
+
# Initialize touch state for both hands with empty KuavoDexHandTouchState instances
|
|
79
|
+
self._dexhand_touch_state = (
|
|
80
|
+
KuavoDexHandTouchState(
|
|
81
|
+
data=(KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
82
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
83
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
84
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
85
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
|
86
|
+
), # Left hand touch state
|
|
87
|
+
KuavoDexHandTouchState(
|
|
88
|
+
data=(KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
89
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
90
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
91
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
92
|
+
KuavoDexHandTouchState.KuavoTouchState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
|
93
|
+
) # Right hand touch state
|
|
94
|
+
)
|
|
95
|
+
|
|
75
96
|
""" data """
|
|
76
97
|
self._terrain_height = 0.0
|
|
77
98
|
self._imu_data = KuavoImuData(
|
|
@@ -93,17 +114,17 @@ class KuavoRobotStateCore:
|
|
|
93
114
|
angular = (0.0, 0.0, 0.0)
|
|
94
115
|
)
|
|
95
116
|
self._eef_state = (EndEffectorState(
|
|
96
|
-
position = 0.0,
|
|
97
|
-
velocity = 0.0,
|
|
98
|
-
effort = 0.0,
|
|
117
|
+
position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
118
|
+
velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
119
|
+
effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
99
120
|
state=EndEffectorState.GraspingState.UNKNOWN
|
|
100
121
|
), EndEffectorState(
|
|
101
|
-
position = 0.0,
|
|
102
|
-
velocity = 0.0,
|
|
103
|
-
effort = 0.0,
|
|
122
|
+
position = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
123
|
+
velocity = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
124
|
+
effort = [0.0] * 12 if kuavo_info['end_effector_type'].startswith('qiangnao') else [0.0] * 2,
|
|
104
125
|
state=EndEffectorState.GraspingState.UNKNOWN
|
|
105
126
|
))
|
|
106
|
-
|
|
127
|
+
|
|
107
128
|
# gait manager
|
|
108
129
|
self._gait_manager = GaitManager()
|
|
109
130
|
self._prev_gait_name = self.gait_name
|
|
@@ -156,6 +177,12 @@ class KuavoRobotStateCore:
|
|
|
156
177
|
def eef_state(self)->Tuple[EndEffectorState, EndEffectorState]:
|
|
157
178
|
return self._eef_state
|
|
158
179
|
|
|
180
|
+
@property
|
|
181
|
+
def dexhand_touch_state(self)-> Tuple[KuavoDexHandTouchState, KuavoDexHandTouchState]:
|
|
182
|
+
if self._ee_type != EndEffectorType.QIANGNAO_TOUCH:
|
|
183
|
+
raise Exception("This robot does not support touch state")
|
|
184
|
+
return self._dexhand_touch_state
|
|
185
|
+
|
|
159
186
|
@property
|
|
160
187
|
def current_observation_time(self) -> float:
|
|
161
188
|
"""Get the current observation time from MPC.
|
|
@@ -231,7 +258,7 @@ class KuavoRobotStateCore:
|
|
|
231
258
|
position = copy.deepcopy(msg.joint_data.joint_q),
|
|
232
259
|
velocity = copy.deepcopy(msg.joint_data.joint_v),
|
|
233
260
|
torque = copy.deepcopy(msg.joint_data.joint_vd),
|
|
234
|
-
acceleration = copy.deepcopy(msg.joint_data.joint_current)
|
|
261
|
+
acceleration = copy.deepcopy(msg.joint_data.joint_current if hasattr(msg.joint_data, 'joint_current') else msg.joint_data.joint_torque)
|
|
235
262
|
)
|
|
236
263
|
|
|
237
264
|
def _odom_callback(self, msg:Odometry)->None:
|
|
@@ -245,29 +272,57 @@ class KuavoRobotStateCore:
|
|
|
245
272
|
|
|
246
273
|
def _lejuclaw_state_callback(self, msg:lejuClawState)->None:
|
|
247
274
|
self._eef_state = (EndEffectorState(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
275
|
+
# left claw
|
|
276
|
+
position = [msg.data.position[0]],
|
|
277
|
+
velocity = [msg.data.velocity[0]],
|
|
278
|
+
effort = [msg.data.effort[0]],
|
|
251
279
|
state=EndEffectorState.GraspingState(msg.state[0])
|
|
252
280
|
), EndEffectorState(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
281
|
+
# right claw
|
|
282
|
+
position = [msg.data.position[1]],
|
|
283
|
+
velocity = [msg.data.velocity[1]],
|
|
284
|
+
effort = [msg.data.effort[1]],
|
|
256
285
|
state=EndEffectorState.GraspingState(msg.state[1])
|
|
257
286
|
))
|
|
258
287
|
|
|
259
|
-
def _dexterous_hand_state_callback(self, msg)->None:
|
|
288
|
+
def _dexterous_hand_state_callback(self, msg:JointState)->None:
|
|
260
289
|
self._eef_state = (EndEffectorState(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
290
|
+
# left hand
|
|
291
|
+
position = list(msg.position[:len(msg.position)//2]),
|
|
292
|
+
velocity = list(msg.velocity[:len(msg.velocity)//2]),
|
|
293
|
+
effort = list(msg.effort[:len(msg.effort)//2]),
|
|
294
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
265
295
|
), EndEffectorState(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
296
|
+
# right hand
|
|
297
|
+
position = list(msg.position[len(msg.position)//2:]),
|
|
298
|
+
velocity = list(msg.velocity[len(msg.velocity)//2:]),
|
|
299
|
+
effort = list(msg.effort[len(msg.effort)//2:]),
|
|
300
|
+
state=EndEffectorState.GraspingState.UNKNOWN
|
|
270
301
|
))
|
|
302
|
+
|
|
303
|
+
def _dexhand_touch_state_callback(self, msg:dexhandTouchState)->None:
|
|
304
|
+
# Update touch state for both hands
|
|
305
|
+
self._dexhand_touch_state = (
|
|
306
|
+
KuavoDexHandTouchState(
|
|
307
|
+
data=tuple(KuavoDexHandTouchState.KuavoTouchState(
|
|
308
|
+
sensor.normal_force1, sensor.normal_force2, sensor.normal_force3,
|
|
309
|
+
sensor.tangential_force1, sensor.tangential_force2, sensor.tangential_force3,
|
|
310
|
+
sensor.tangential_direction1, sensor.tangential_direction2, sensor.tangential_direction3,
|
|
311
|
+
sensor.self_proximity1, sensor.self_proximity2, sensor.mutual_proximity,
|
|
312
|
+
sensor.status
|
|
313
|
+
) for sensor in msg.left_hand)
|
|
314
|
+
), # Left hand touch state
|
|
315
|
+
KuavoDexHandTouchState(
|
|
316
|
+
data=tuple(KuavoDexHandTouchState.KuavoTouchState(
|
|
317
|
+
sensor.normal_force1, sensor.normal_force2, sensor.normal_force3,
|
|
318
|
+
sensor.tangential_force1, sensor.tangential_force2, sensor.tangential_force3,
|
|
319
|
+
sensor.tangential_direction1, sensor.tangential_direction2, sensor.tangential_direction3,
|
|
320
|
+
sensor.self_proximity1, sensor.self_proximity2, sensor.mutual_proximity,
|
|
321
|
+
sensor.status
|
|
322
|
+
) for sensor in msg.right_hand)
|
|
323
|
+
) # Right hand touch state
|
|
324
|
+
)
|
|
325
|
+
|
|
271
326
|
def _humanoid_mpc_gait_changed_callback(self, msg: gaitTimeName):
|
|
272
327
|
"""
|
|
273
328
|
Callback function for gait change messages.
|
|
@@ -322,4 +377,4 @@ class KuavoRobotStateCore:
|
|
|
322
377
|
return None
|
|
323
378
|
except Exception as e:
|
|
324
379
|
SDKLogger.error(f"Service call failed: {e}")
|
|
325
|
-
return None
|
|
380
|
+
return None
|