kuavo-humanoid-sdk 1.2.2__20250922181216-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.

Files changed (137) hide show
  1. kuavo_humanoid_sdk/__init__.py +6 -0
  2. kuavo_humanoid_sdk/common/logger.py +45 -0
  3. kuavo_humanoid_sdk/interfaces/__init__.py +4 -0
  4. kuavo_humanoid_sdk/interfaces/data_types.py +276 -0
  5. kuavo_humanoid_sdk/interfaces/end_effector.py +62 -0
  6. kuavo_humanoid_sdk/interfaces/robot.py +22 -0
  7. kuavo_humanoid_sdk/interfaces/robot_info.py +56 -0
  8. kuavo_humanoid_sdk/kuavo/__init__.py +11 -0
  9. kuavo_humanoid_sdk/kuavo/core/audio.py +32 -0
  10. kuavo_humanoid_sdk/kuavo/core/core.py +612 -0
  11. kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py +114 -0
  12. kuavo_humanoid_sdk/kuavo/core/leju_claw_control.py +67 -0
  13. kuavo_humanoid_sdk/kuavo/core/ros/audio.py +92 -0
  14. kuavo_humanoid_sdk/kuavo/core/ros/control.py +1309 -0
  15. kuavo_humanoid_sdk/kuavo/core/ros/observation.py +94 -0
  16. kuavo_humanoid_sdk/kuavo/core/ros/param.py +183 -0
  17. kuavo_humanoid_sdk/kuavo/core/ros/sat_utils.py +103 -0
  18. kuavo_humanoid_sdk/kuavo/core/ros/state.py +605 -0
  19. kuavo_humanoid_sdk/kuavo/core/ros/tools.py +219 -0
  20. kuavo_humanoid_sdk/kuavo/core/ros/vision.py +234 -0
  21. kuavo_humanoid_sdk/kuavo/core/ros_env.py +237 -0
  22. kuavo_humanoid_sdk/kuavo/dexterous_hand.py +201 -0
  23. kuavo_humanoid_sdk/kuavo/leju_claw.py +235 -0
  24. kuavo_humanoid_sdk/kuavo/robot.py +465 -0
  25. kuavo_humanoid_sdk/kuavo/robot_arm.py +210 -0
  26. kuavo_humanoid_sdk/kuavo/robot_audio.py +39 -0
  27. kuavo_humanoid_sdk/kuavo/robot_head.py +50 -0
  28. kuavo_humanoid_sdk/kuavo/robot_info.py +113 -0
  29. kuavo_humanoid_sdk/kuavo/robot_observation.py +64 -0
  30. kuavo_humanoid_sdk/kuavo/robot_state.py +299 -0
  31. kuavo_humanoid_sdk/kuavo/robot_tool.py +82 -0
  32. kuavo_humanoid_sdk/kuavo/robot_vision.py +83 -0
  33. kuavo_humanoid_sdk/kuavo_strategy/__init__.py +2 -0
  34. kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +1126 -0
  35. kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +104 -0
  36. kuavo_humanoid_sdk/msg/__init__.py +4 -0
  37. kuavo_humanoid_sdk/msg/kuavo_msgs/__init__.py +7 -0
  38. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetection.py +306 -0
  39. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetectionArray.py +437 -0
  40. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_JoySticks.py +191 -0
  41. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_Metadata.py +199 -0
  42. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_RobotActionState.py +112 -0
  43. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_TFArray.py +323 -0
  44. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +48 -0
  45. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armHandPose.py +160 -0
  46. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armHandPoseFree.py +171 -0
  47. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armPoseWithTimeStamp.py +168 -0
  48. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armTargetPoses.py +151 -0
  49. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_bezierCurveCubicPoint.py +178 -0
  50. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandCommand.py +229 -0
  51. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandTouchState.py +256 -0
  52. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_endEffectorData.py +227 -0
  53. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPose.py +123 -0
  54. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoseTargetTrajectories.py +301 -0
  55. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoses.py +149 -0
  56. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_fullBodyTargetTrajectories.py +258 -0
  57. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gaitTimeName.py +147 -0
  58. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureInfo.py +218 -0
  59. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureTask.py +149 -0
  60. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_handPose.py +136 -0
  61. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_headBodyPose.py +145 -0
  62. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveError.py +171 -0
  63. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveParam.py +140 -0
  64. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_imuData.py +165 -0
  65. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointBezierTrajectory.py +201 -0
  66. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointCmd.py +390 -0
  67. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointData.py +205 -0
  68. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawCommand.py +320 -0
  69. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawState.py +341 -0
  70. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_motorParam.py +122 -0
  71. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_planArmState.py +120 -0
  72. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_questJoySticks.py +191 -0
  73. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_qv.py +121 -0
  74. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotArmQVVD.py +177 -0
  75. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHandPosition.py +225 -0
  76. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHeadMotionData.py +128 -0
  77. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotState.py +222 -0
  78. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_sensorsData.py +495 -0
  79. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_switchGaitByName.py +200 -0
  80. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_touchSensorStatus.py +162 -0
  81. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPose.py +272 -0
  82. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmd.py +315 -0
  83. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmdFree.py +338 -0
  84. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseFree.py +299 -0
  85. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloDetection.py +251 -0
  86. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloOutputData.py +168 -0
  87. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_ExecuteArmAction.py +281 -0
  88. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_RepublishTFs.py +373 -0
  89. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetJoyTopic.py +282 -0
  90. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SpeechSynthesis.py +270 -0
  91. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +29 -0
  92. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlMode.py +275 -0
  93. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlModeKuavo.py +236 -0
  94. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeMotorParam.py +299 -0
  95. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeTorsoCtrlMode.py +274 -0
  96. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_controlLejuClaw.py +408 -0
  97. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_enableHandTouchSensor.py +304 -0
  98. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_fkSrv.py +394 -0
  99. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_footPoseTargetTrajectoriesSrv.py +409 -0
  100. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecute.py +339 -0
  101. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecuteState.py +257 -0
  102. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureList.py +418 -0
  103. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getCurrentGaitName.py +253 -0
  104. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getMotorParam.py +299 -0
  105. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_handForceLevel.py +330 -0
  106. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_jointMoveTo.py +302 -0
  107. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryBezierCurve.py +421 -0
  108. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryCubicSpline.py +490 -0
  109. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_playmusic.py +268 -0
  110. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setHwIntialState.py +304 -0
  111. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMmCtrlFrame.py +273 -0
  112. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMotorEncoderRoundService.py +283 -0
  113. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setTagId.py +275 -0
  114. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_singleStepControl.py +444 -0
  115. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdFreeSrv.py +716 -0
  116. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdSrv.py +662 -0
  117. kuavo_humanoid_sdk/msg/motion_capture_ik/__init__.py +7 -0
  118. kuavo_humanoid_sdk/msg/ocs2_msgs/__init__.py +7 -0
  119. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/__init__.py +12 -0
  120. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_constraint.py +142 -0
  121. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_controller_data.py +121 -0
  122. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_lagrangian_metrics.py +148 -0
  123. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mode_schedule.py +150 -0
  124. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_flattened_controller.py +666 -0
  125. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_input.py +122 -0
  126. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_observation.py +209 -0
  127. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_performance_indices.py +140 -0
  128. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_solver_data.py +886 -0
  129. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_state.py +122 -0
  130. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_target_trajectories.py +239 -0
  131. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_multiplier.py +148 -0
  132. kuavo_humanoid_sdk/msg/ocs2_msgs/srv/__init__.py +1 -0
  133. kuavo_humanoid_sdk/msg/ocs2_msgs/srv/_reset.py +376 -0
  134. kuavo_humanoid_sdk-1.2.2.dist-info/METADATA +291 -0
  135. kuavo_humanoid_sdk-1.2.2.dist-info/RECORD +137 -0
  136. kuavo_humanoid_sdk-1.2.2.dist-info/WHEEL +6 -0
  137. kuavo_humanoid_sdk-1.2.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1309 @@
1
+ import os
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from kuavo_humanoid_sdk.common.logger import SDKLogger
5
+ from kuavo_humanoid_sdk.interfaces.data_types import (KuavoArmCtrlMode, KuavoIKParams, KuavoPose,
6
+ KuavoManipulationMpcControlFlow, KuavoManipulationMpcCtrlMode
7
+ ,KuavoManipulationMpcFrame, KuavoMotorParam)
8
+ from kuavo_humanoid_sdk.kuavo.core.ros.sat_utils import RotatingRectangle
9
+ from kuavo_humanoid_sdk.kuavo.core.ros.param import EndEffectorType
10
+
11
+ import rospy
12
+ from geometry_msgs.msg import Twist
13
+ from sensor_msgs.msg import JointState, Joy
14
+ from kuavo_humanoid_sdk.msg.kuavo_msgs.msg import (gestureTask,robotHandPosition, robotHeadMotionData, armTargetPoses, switchGaitByName,
15
+ footPose, footPoseTargetTrajectories, dexhandCommand, motorParam)
16
+ from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import (gestureExecute, gestureExecuteRequest,gestureList, gestureListRequest,
17
+ controlLejuClaw, controlLejuClawRequest, changeArmCtrlMode, changeArmCtrlModeRequest,
18
+ changeTorsoCtrlMode, changeTorsoCtrlModeRequest, setMmCtrlFrame, setMmCtrlFrameRequest,
19
+ setTagId, setTagIdRequest, getMotorParam, getMotorParamRequest,
20
+ changeMotorParam, changeMotorParamRequest)
21
+ from kuavo_humanoid_sdk.msg.kuavo_msgs.msg import twoArmHandPoseCmd, ikSolveParam, armHandPose
22
+ from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import twoArmHandPoseCmdSrv, fkSrv
23
+ from std_srvs.srv import SetBool, SetBoolRequest
24
+
25
+
26
+
27
+
28
+ class ControlEndEffector:
29
+ def __init__(self, eef_type: str = EndEffectorType.QIANGNAO):
30
+ self._eef_type = eef_type
31
+ self._pubs = []
32
+ if self._eef_type == EndEffectorType.QIANGNAO:
33
+ self._pub_ctrl_robot_hand = rospy.Publisher('/control_robot_hand_position', robotHandPosition, queue_size=10)
34
+ # publisher, name, require
35
+ self._pubs.append((self._pub_ctrl_robot_hand, False))
36
+ elif self._eef_type == EndEffectorType.QIANGNAO_TOUCH:
37
+ self._pub_ctrl_robot_hand = rospy.Publisher('/control_robot_hand_position', robotHandPosition, queue_size=10)
38
+ self._pub_dexhand_command = rospy.Publisher('/dexhand/command', dexhandCommand, queue_size=10)
39
+ self._pub_dexhand_right_command = rospy.Publisher('/dexhand/right/command', dexhandCommand, queue_size=10)
40
+ self._pub_dexhand_left_command = rospy.Publisher('/dexhand/left/command', dexhandCommand, queue_size=10)
41
+ # publisher, name, require
42
+ self._pubs.append((self._pub_dexhand_command, False))
43
+ self._pubs.append((self._pub_dexhand_right_command, False))
44
+ self._pubs.append((self._pub_dexhand_left_command, False))
45
+
46
+ def connect(self, timeout:float=1.0)-> bool:
47
+ start_time = rospy.Time.now()
48
+
49
+ success = True
50
+ for pub, require in self._pubs:
51
+ while pub.get_num_connections() == 0:
52
+ if (rospy.Time.now() - start_time).to_sec() > timeout:
53
+ if require:
54
+ SDKLogger.error(f"Timeout waiting for {pub.name} connection")
55
+ success = False
56
+ break
57
+ rospy.sleep(0.1)
58
+
59
+ return success
60
+
61
+ """ Control Kuavo Robot Dexhand """
62
+ def pub_control_robot_dexhand(self, left_position:list, right_position:list)->bool:
63
+ if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
64
+ SDKLogger.warning(f"{self._eef_type} not support control dexhand")
65
+ return False
66
+ try :
67
+ hand_pose_msg = robotHandPosition()
68
+ hand_pose_msg.left_hand_position = bytes(left_position)
69
+ hand_pose_msg.right_hand_position = bytes(right_position)
70
+ self._pub_ctrl_robot_hand.publish(hand_pose_msg)
71
+ SDKLogger.debug(f"publish robot dexhand: {left_position}, {right_position}")
72
+ return True
73
+ except Exception as e:
74
+ SDKLogger.error(f"publish robot dexhand: {e}")
75
+ return False
76
+
77
+ def pub_dexhand_command(self, data:list, ctrl_mode, hand_side)->bool:
78
+ """
79
+ ctrl_mode: 0 --> POSITION, 1 --> VELOCITY
80
+ hand_side: 0 --> left, 1 --> right, 2-->dual
81
+ """
82
+ if not self._eef_type == EndEffectorType.QIANGNAO_TOUCH:
83
+ SDKLogger.warning(f"{self._eef_type} not support pub_left_dexhand_command")
84
+ return False
85
+ try:
86
+ if hand_side != 2 and len(data) != 6:
87
+ SDKLogger.warning("Data length should be 6")
88
+ return False
89
+ if hand_side == 2 and len(data) != 12:
90
+ SDKLogger.warning("Data length should be 12")
91
+ return False
92
+ if ctrl_mode not in [dexhandCommand.POSITION_CONTROL, dexhandCommand.VELOCITY_CONTROL]:
93
+ SDKLogger.error(f"Invalid mode for pub_left_dexhand_command: {ctrl_mode}")
94
+ return False
95
+ msg = dexhandCommand()
96
+ msg.data = [int(d) for d in data] # Convert data to integers
97
+ msg.control_mode = ctrl_mode
98
+ if hand_side == 0:
99
+ self._pub_dexhand_left_command.publish(msg)
100
+ elif hand_side == 1:
101
+ self._pub_dexhand_right_command.publish(msg)
102
+ else:
103
+ self._pub_dexhand_command.publish(msg)
104
+ return True
105
+ except Exception as e:
106
+ SDKLogger.error(f"Failed to publish left dexhand command: {e}")
107
+ return False
108
+
109
+ def srv_execute_gesture(self, gestures:list)->bool:
110
+ if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
111
+ SDKLogger.warning(f"{self._eef_type} not support control dexhand")
112
+ return False
113
+ try:
114
+ service_name = 'gesture/execute'
115
+ rospy.wait_for_service(service=service_name, timeout=2.0)
116
+ # create service proxy
117
+ gesture_service = rospy.ServiceProxy(service_name, gestureExecute)
118
+
119
+ # request
120
+ request = gestureExecuteRequest()
121
+ for gs in gestures:
122
+ gesture = gestureTask(gesture_name=gs["gesture_name"], hand_side=gs["hand_side"])
123
+ request.gestures.append(gesture)
124
+
125
+ # call service
126
+ response = gesture_service(request)
127
+ if not response.success:
128
+ SDKLogger.error(f"Failed to execute gesture '{gestures}': {response.message}")
129
+ return response.success
130
+ except rospy.ServiceException as e:
131
+ SDKLogger.error(f"Service call failed: {e}")
132
+ except rospy.ROSException as e:
133
+ SDKLogger.error(f"Service call failed: {e}")
134
+ except Exception as e:
135
+ SDKLogger.error(f"Service call failed: {e}")
136
+ return False
137
+
138
+ def srv_get_gesture_names(self)->list:
139
+ if not self._eef_type.startswith(EndEffectorType.QIANGNAO): # qiangnao, qiangnao_touch
140
+ SDKLogger.warning(f"{self._eef_type} not support control dexhand")
141
+ return []
142
+ try:
143
+ service_name = 'gesture/list'
144
+ rospy.wait_for_service(service=service_name, timeout=2.0)
145
+ gesture_service = rospy.ServiceProxy(service_name, gestureList)
146
+ request = gestureListRequest()
147
+ response = gesture_service(request)
148
+ gestures = []
149
+ for gesture_info in response.gesture_infos:
150
+ gestures.append(gesture_info.gesture_name)
151
+ for alias in gesture_info.alias:
152
+ gestures.append(alias)
153
+ return list(set(gestures))
154
+ except rospy.ServiceException as e:
155
+ SDKLogger.error(f"Service call failed: {e}")
156
+ except Exception as e:
157
+ SDKLogger.error(f"Service call failed: {e}")
158
+ return []
159
+
160
+ def srv_control_leju_claw(self, postions:list, velocities:list, torques:list) ->bool:
161
+ if self._eef_type != 'lejuclaw':
162
+ SDKLogger.warning(f"{self._eef_type} not support control lejuclaw.")
163
+ return False
164
+ try:
165
+ # ros service
166
+ service_name = 'control_robot_leju_claw'
167
+ rospy.wait_for_service(service_name, timeout=2.0)
168
+ control_lejucalw_srv = rospy.ServiceProxy(service_name, controlLejuClaw)
169
+
170
+ # request
171
+ request = controlLejuClawRequest()
172
+ request.data.position = postions
173
+ request.data.velocity = velocities
174
+ request.data.effort = torques
175
+
176
+ response = control_lejucalw_srv(request)
177
+ if not response.success:
178
+ SDKLogger.error(f"Failed to control leju claw: {response.message}")
179
+ return response.success
180
+ except rospy.ServiceException as e:
181
+ SDKLogger.error(f"Service `control_robot_leju_claw` call failed: {e}")
182
+ except rospy.ROSException as e:
183
+ SDKLogger.error(f"Service `control_robot_leju_claw` call failed: {e}")
184
+ except Exception as e:
185
+ SDKLogger.error(f"Service `control_robot_leju_claw` call failed: {e}")
186
+ return False
187
+
188
+ class ControlRobotArm:
189
+ def __init__(self):
190
+ self._pub_ctrl_arm_traj = rospy.Publisher('/kuavo_arm_traj', JointState, queue_size=10)
191
+ self._pub_ctrl_arm_target_poses = rospy.Publisher('/kuavo_arm_target_poses', armTargetPoses, queue_size=10)
192
+ self._pub_ctrl_hand_pose_cmd = rospy.Publisher('/mm/two_arm_hand_pose_cmd', twoArmHandPoseCmd, queue_size=10)
193
+
194
+ def connect(self, timeout:float=1.0)-> bool:
195
+ start_time = rospy.Time.now()
196
+ publishers = [
197
+ (self._pub_ctrl_arm_traj, "arm trajectory publisher"),
198
+ (self._pub_ctrl_arm_target_poses, "arm target poses publisher")
199
+ ]
200
+
201
+ success = True
202
+ for pub, name in publishers:
203
+ while pub.get_num_connections() == 0:
204
+ if (rospy.Time.now() - start_time).to_sec() > timeout:
205
+ SDKLogger.error(f"Timeout waiting for {name} connection, '{pub.name}'")
206
+ success = False
207
+ break
208
+ rospy.sleep(0.1)
209
+ return success
210
+
211
+ def pub_control_robot_arm_traj(self, joint_q: list)->bool:
212
+ try:
213
+ msg = JointState()
214
+ msg.name = ["arm_joint_" + str(i) for i in range(0, 14)]
215
+ msg.header.stamp = rospy.Time.now()
216
+ msg.position = 180.0 / np.pi * np.array(joint_q) # convert to degree
217
+ self._pub_ctrl_arm_traj.publish(msg)
218
+ return True
219
+ except Exception as e:
220
+ SDKLogger.error(f"publish robot arm traj: {e}")
221
+ return False
222
+
223
+ def pub_arm_target_poses(self, times:list, joint_q:list):
224
+ try:
225
+ msg = armTargetPoses()
226
+ msg.times = times
227
+ for i in range(len(joint_q)):
228
+ degs = [q for q in joint_q[i]]
229
+ msg.values.extend(degs)
230
+ self._pub_ctrl_arm_target_poses.publish(msg)
231
+ return True
232
+ except Exception as e:
233
+ SDKLogger.error(f"publish arm target poses: {e}")
234
+ return False
235
+ def pub_end_effector_pose_cmd(self, left_pose: KuavoPose, right_pose: KuavoPose, frame: KuavoManipulationMpcFrame)->bool:
236
+ try:
237
+ msg = twoArmHandPoseCmd()
238
+ left_pose_msg = armHandPose()
239
+ left_pose_msg.pos_xyz = left_pose.position
240
+ left_pose_msg.quat_xyzw = left_pose.orientation
241
+ right_pose_msg = armHandPose()
242
+ right_pose_msg.pos_xyz = right_pose.position
243
+ right_pose_msg.quat_xyzw = right_pose.orientation
244
+ msg.hand_poses.left_pose = left_pose_msg
245
+ msg.hand_poses.right_pose = right_pose_msg
246
+ if frame.value not in [0, 1, 2, 3, 4]:
247
+ SDKLogger.error(f"Invalid frame: {frame}")
248
+ return False
249
+ msg.frame = frame.value
250
+ self._pub_ctrl_hand_pose_cmd.publish(msg)
251
+ return True
252
+ except Exception as e:
253
+ SDKLogger.error(f"publish arm target poses: {e}")
254
+ return False
255
+
256
+ def srv_change_manipulation_mpc_frame(self, frame: KuavoManipulationMpcFrame)->bool:
257
+ try:
258
+ service_name = '/set_mm_ctrl_frame'
259
+ rospy.wait_for_service(service_name, timeout=2.0)
260
+ set_frame_srv = rospy.ServiceProxy(service_name, setMmCtrlFrame)
261
+
262
+ req = setMmCtrlFrameRequest()
263
+ req.frame = frame.value
264
+
265
+ resp = set_frame_srv(req)
266
+ if not resp.result:
267
+ SDKLogger.error(f"Failed to change manipulation mpc frame to {frame}: {resp.message}")
268
+ return resp.result
269
+ except rospy.ServiceException as e:
270
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
271
+ except rospy.ROSException as e: # For timeout from wait_for_service
272
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
273
+ except Exception as e:
274
+ SDKLogger.error(f"Failed to change manipulation mpc frame: {e}")
275
+ return False
276
+
277
+ def srv_change_manipulation_mpc_ctrl_mode(self, ctrl_mode: KuavoManipulationMpcCtrlMode)->bool:
278
+ try:
279
+ service_name = '/mobile_manipulator_mpc_control'
280
+ rospy.wait_for_service(service_name, timeout=2.0)
281
+ set_mode_srv = rospy.ServiceProxy(service_name, changeTorsoCtrlMode)
282
+
283
+ req = changeTorsoCtrlModeRequest()
284
+ req.control_mode = ctrl_mode.value
285
+
286
+ resp = set_mode_srv(req)
287
+ if not resp.result:
288
+ SDKLogger.error(f"Failed to change manipulation mpc control mode to {ctrl_mode}: {resp.message}")
289
+ return resp.result
290
+ except rospy.ServiceException as e:
291
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
292
+ except rospy.ROSException as e: # For timeout from wait_for_service
293
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
294
+ except Exception as e:
295
+ SDKLogger.error(f"Failed to change manipulation mpc control mode: {e}")
296
+ return False
297
+
298
+ def srv_change_manipulation_mpc_control_flow(self, ctrl_flow: KuavoManipulationMpcControlFlow)-> bool:
299
+ try:
300
+ service_name = '/enable_mm_wbc_arm_trajectory_control'
301
+ rospy.wait_for_service(service_name, timeout=2.0)
302
+ set_mode_srv = rospy.ServiceProxy(service_name, changeArmCtrlMode)
303
+
304
+ req = changeArmCtrlModeRequest()
305
+ req.control_mode = ctrl_flow.value
306
+
307
+ resp = set_mode_srv(req)
308
+ if not resp.result:
309
+ SDKLogger.error(f"Failed to change manipulation mpc wbc arm trajectory control to {ctrl_flow}: {resp.message}")
310
+ return resp.result
311
+ except rospy.ServiceException as e:
312
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
313
+ except rospy.ROSException as e: # For timeout from wait_for_service
314
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
315
+ except Exception as e:
316
+ SDKLogger.error(f"Failed to change manipulation mpc control flow: {e}")
317
+ return False
318
+
319
+ def srv_get_manipulation_mpc_ctrl_mode(self, )->KuavoManipulationMpcCtrlMode:
320
+ try:
321
+ service_name = '/mobile_manipulator_get_mpc_control_mode'
322
+ rospy.wait_for_service(service_name, timeout=2.0)
323
+ get_mode_srv = rospy.ServiceProxy(service_name, changeTorsoCtrlMode)
324
+
325
+ req = changeTorsoCtrlModeRequest()
326
+
327
+ resp = get_mode_srv(req)
328
+ if not resp.result:
329
+ SDKLogger.error(f"Failed to get manipulation mpc control mode: {resp.message}")
330
+ return KuavoManipulationMpcCtrlMode.ERROR
331
+ return KuavoManipulationMpcCtrlMode(resp.mode)
332
+ except rospy.ServiceException as e:
333
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
334
+ except rospy.ROSException as e: # For timeout from wait_for_service
335
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
336
+ except Exception as e:
337
+ SDKLogger.error(f"Failed to get manipulation mpc control mode: {e}")
338
+ return KuavoManipulationMpcCtrlMode.ERROR
339
+
340
+ def srv_get_manipulation_mpc_frame(self, )->KuavoManipulationMpcFrame:
341
+ try:
342
+ service_name = '/get_mm_ctrl_frame'
343
+ rospy.wait_for_service(service_name, timeout=2.0)
344
+ get_frame_srv = rospy.ServiceProxy(service_name, setMmCtrlFrame)
345
+
346
+ req = setMmCtrlFrameRequest()
347
+
348
+ resp = get_frame_srv(req)
349
+ if not resp.result:
350
+ SDKLogger.error(f"Failed to get manipulation mpc frame: {resp.message}")
351
+ return KuavoManipulationMpcFrame.ERROR
352
+ return KuavoManipulationMpcFrame(resp.currentFrame)
353
+ except rospy.ServiceException as e:
354
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
355
+ except rospy.ROSException as e: # For timeout from wait_for_service
356
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
357
+ except Exception as e:
358
+ SDKLogger.error(f"Failed to get manipulation mpc frame: {e}")
359
+ return KuavoManipulationMpcFrame.ERROR
360
+
361
+ def srv_get_manipulation_mpc_control_flow(self, )->KuavoManipulationMpcControlFlow:
362
+ try:
363
+ service_name = '/get_mm_wbc_arm_trajectory_control'
364
+ rospy.wait_for_service(service_name, timeout=2.0)
365
+ get_mode_srv = rospy.ServiceProxy(service_name, changeArmCtrlMode)
366
+
367
+ req = changeArmCtrlModeRequest()
368
+
369
+ resp = get_mode_srv(req)
370
+ if not resp.result:
371
+ SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {resp.message}")
372
+ return KuavoManipulationMpcControlFlow.ERROR
373
+ return KuavoManipulationMpcControlFlow(resp.mode)
374
+ except rospy.ServiceException as e:
375
+ SDKLogger.error(f"Service call to {service_name} failed: {e}")
376
+ except rospy.ROSException as e: # For timeout from wait_for_service
377
+ SDKLogger.error(f"Failed to connect to service {service_name}: {e}")
378
+ except Exception as e:
379
+ SDKLogger.error(f"Failed to get manipulation mpc wbc arm trajectory control mode: {e}")
380
+ return KuavoManipulationMpcControlFlow.ERROR
381
+
382
+
383
+ def srv_change_arm_ctrl_mode(self, mode: KuavoArmCtrlMode)->bool:
384
+ try:
385
+ rospy.wait_for_service('/arm_traj_change_mode', timeout=2.0)
386
+ change_arm_ctrl_mode_srv = rospy.ServiceProxy('/arm_traj_change_mode', changeArmCtrlMode)
387
+ req = changeArmCtrlModeRequest()
388
+ req.control_mode = mode.value
389
+ resp = change_arm_ctrl_mode_srv(req)
390
+ return resp.result
391
+ except rospy.ServiceException as e:
392
+ SDKLogger.error(f"Service call failed: {e}")
393
+ except Exception as e:
394
+ SDKLogger.error(f"[Error] change arm ctrl mode: {e}")
395
+ return False
396
+
397
+ def srv_get_arm_ctrl_mode(self)-> KuavoArmCtrlMode:
398
+ try:
399
+ rospy.wait_for_service('/humanoid_get_arm_ctrl_mode')
400
+ get_arm_ctrl_mode_srv = rospy.ServiceProxy('/humanoid_get_arm_ctrl_mode', changeArmCtrlMode)
401
+ req = changeArmCtrlModeRequest()
402
+ resp = get_arm_ctrl_mode_srv(req)
403
+ return KuavoArmCtrlMode(resp.control_mode)
404
+ except rospy.ServiceException as e:
405
+ SDKLogger.error(f"Service call failed: {e}")
406
+ except Exception as e:
407
+ SDKLogger.error(f"[Error] get arm ctrl mode: {e}")
408
+ return None
409
+
410
+ """ Control Robot Head """
411
+ class ControlRobotHead:
412
+ def __init__(self):
413
+ self._pub_ctrl_robot_head = rospy.Publisher('/robot_head_motion_data', robotHeadMotionData, queue_size=10)
414
+
415
+ def connect(self, timeout:float=1.0)->bool:
416
+ start_time = rospy.Time.now()
417
+ publishers = [
418
+ # (self._pub_ctrl_robot_head, "robot head publisher") # not need check!
419
+ ]
420
+ for pub, name in publishers:
421
+ while pub.get_num_connections() == 0:
422
+ if (rospy.Time.now() - start_time).to_sec() > timeout:
423
+ SDKLogger.error(f"Timeout waiting for {name} connection, '{pub.name}'")
424
+ return False
425
+ rospy.sleep(0.1)
426
+ return True
427
+ def pub_control_robot_head(self, yaw:float, pitch:float)->bool:
428
+ try :
429
+ msg = robotHeadMotionData()
430
+ msg.joint_data = [yaw, pitch]
431
+ self._pub_ctrl_robot_head.publish(msg)
432
+ return True
433
+ except Exception as e:
434
+ SDKLogger.error(f"[Error] publish robot head: {e}")
435
+ return False
436
+
437
+ def srv_enable_head_tracking(self, target_id: int)->bool:
438
+ """Enable the head tracking for a specific tag ID.
439
+
440
+ Args:
441
+ target_id: The ID of the tag to track
442
+
443
+ Returns:
444
+ bool: True if successful, False otherwise
445
+ """
446
+ try:
447
+ # 首先设置追踪目标ID
448
+ service_name = '/set_target_tag_id'
449
+ rospy.wait_for_service(service_name, timeout=2.0)
450
+ set_tag_id_srv = rospy.ServiceProxy(service_name, setTagId)
451
+
452
+ req = setTagIdRequest()
453
+ req.tag_id = target_id
454
+
455
+ resp = set_tag_id_srv(req)
456
+ if not resp.success:
457
+ SDKLogger.error(f"Failed to set target tag ID: {resp.message}")
458
+ return False
459
+
460
+ SDKLogger.info(f"Successfully set target tag ID to {target_id}: {resp.message}")
461
+
462
+ # 然后启动连续追踪
463
+ service_name = '/continuous_track'
464
+ rospy.wait_for_service(service_name, timeout=2.0)
465
+ continuous_track_srv = rospy.ServiceProxy(service_name, SetBool)
466
+
467
+ req = SetBoolRequest()
468
+ req.data = True
469
+
470
+ resp = continuous_track_srv(req)
471
+ if not resp.success:
472
+ SDKLogger.error(f"Failed to start continuous tracking: {resp.message}")
473
+ return False
474
+
475
+ SDKLogger.info(f"Successfully started continuous tracking: {resp.message}")
476
+ return True
477
+
478
+ except rospy.ServiceException as e:
479
+ SDKLogger.error(f"Service call failed: {e}")
480
+ except rospy.ROSException as e:
481
+ SDKLogger.error(f"Failed to connect to service: {e}")
482
+ except Exception as e:
483
+ SDKLogger.error(f"Failed to enable head tracking: {e}")
484
+
485
+ return False
486
+
487
+ def srv_disable_head_tracking(self)->bool:
488
+ """Disable the head tracking.
489
+
490
+ Returns:
491
+ bool: True if successful, False otherwise
492
+ """
493
+ try:
494
+ service_name = '/continuous_track'
495
+ rospy.wait_for_service(service_name, timeout=2.0)
496
+ continuous_track_srv = rospy.ServiceProxy(service_name, SetBool)
497
+
498
+ req = SetBoolRequest()
499
+ req.data = False
500
+
501
+ resp = continuous_track_srv(req)
502
+ if not resp.success:
503
+ SDKLogger.error(f"Failed to stop continuous tracking: {resp.message}")
504
+ return False
505
+
506
+ SDKLogger.info(f"Successfully stopped continuous tracking: {resp.message}")
507
+ return True
508
+
509
+ except rospy.ServiceException as e:
510
+ SDKLogger.error(f"Service call failed: {e}")
511
+ except rospy.ROSException as e:
512
+ SDKLogger.error(f"Failed to connect to service: {e}")
513
+ except Exception as e:
514
+ SDKLogger.error(f"Failed to disable head tracking: {e}")
515
+
516
+ return False
517
+
518
+ def srv_enable_head_tracking(self, target_id: int)->bool:
519
+ """Enable the head tracking for a specific tag ID.
520
+
521
+ Args:
522
+ target_id: The ID of the tag to track
523
+
524
+ Returns:
525
+ bool: True if successful, False otherwise
526
+ """
527
+ try:
528
+ # 首先设置追踪目标ID
529
+ service_name = '/set_target_tag_id'
530
+ rospy.wait_for_service(service_name, timeout=2.0)
531
+ set_tag_id_srv = rospy.ServiceProxy(service_name, setTagId)
532
+
533
+ req = setTagIdRequest()
534
+ req.tag_id = target_id
535
+
536
+ resp = set_tag_id_srv(req)
537
+ if not resp.success:
538
+ SDKLogger.error(f"Failed to set target tag ID: {resp.message}")
539
+ return False
540
+
541
+ SDKLogger.info(f"Successfully set target tag ID to {target_id}: {resp.message}")
542
+
543
+ # 然后启动连续追踪
544
+ service_name = '/continuous_track'
545
+ rospy.wait_for_service(service_name, timeout=2.0)
546
+ continuous_track_srv = rospy.ServiceProxy(service_name, SetBool)
547
+
548
+ req = SetBoolRequest()
549
+ req.data = True
550
+
551
+ resp = continuous_track_srv(req)
552
+ if not resp.success:
553
+ SDKLogger.error(f"Failed to start continuous tracking: {resp.message}")
554
+ return False
555
+
556
+ SDKLogger.info(f"Successfully started continuous tracking: {resp.message}")
557
+ return True
558
+
559
+ except rospy.ServiceException as e:
560
+ SDKLogger.error(f"Service call failed: {e}")
561
+ except rospy.ROSException as e:
562
+ SDKLogger.error(f"Failed to connect to service: {e}")
563
+ except Exception as e:
564
+ SDKLogger.error(f"Failed to enable head tracking: {e}")
565
+
566
+ return False
567
+
568
+ def srv_disable_head_tracking(self)->bool:
569
+ """Disable the head tracking.
570
+
571
+ Returns:
572
+ bool: True if successful, False otherwise
573
+ """
574
+ try:
575
+ service_name = '/continuous_track'
576
+ rospy.wait_for_service(service_name, timeout=2.0)
577
+ continuous_track_srv = rospy.ServiceProxy(service_name, SetBool)
578
+
579
+ req = SetBoolRequest()
580
+ req.data = False
581
+
582
+ resp = continuous_track_srv(req)
583
+ if not resp.success:
584
+ SDKLogger.error(f"Failed to stop continuous tracking: {resp.message}")
585
+ return False
586
+
587
+ SDKLogger.info(f"Successfully stopped continuous tracking: {resp.message}")
588
+ return True
589
+
590
+ except rospy.ServiceException as e:
591
+ SDKLogger.error(f"Service call failed: {e}")
592
+ except rospy.ROSException as e:
593
+ SDKLogger.error(f"Failed to connect to service: {e}")
594
+ except Exception as e:
595
+ SDKLogger.error(f"Failed to disable head tracking: {e}")
596
+
597
+ return False
598
+
599
+
600
+ """ Control Robot Motion """
601
+
602
+ # JoyButton constants
603
+ BUTTON_A = 0
604
+ BUTTON_B = 1
605
+ BUTTON_X = 2
606
+ BUTTON_Y = 3
607
+ BUTTON_LB = 4
608
+ BUTTON_RB = 5
609
+ BUTTON_BACK = 6
610
+ BUTTON_START = 7
611
+
612
+ # JoyAxis constants
613
+ AXIS_LEFT_STICK_Y = 0
614
+ AXIS_LEFT_STICK_X = 1
615
+ AXIS_LEFT_LT = 2 # 1 -> (-1)
616
+ AXIS_RIGHT_STICK_YAW = 3
617
+ AXIS_RIGHT_STICK_Z = 4
618
+ AXIS_RIGHT_RT = 5 # 1 -> (-1)
619
+ AXIS_LEFT_RIGHT_TRIGGER = 6
620
+ AXIS_FORWARD_BACK_TRIGGER = 7
621
+
622
+
623
+ class ControlRobotMotion:
624
+ def __init__(self):
625
+ self._pub_cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
626
+ self._pub_cmd_pose = rospy.Publisher('/cmd_pose', Twist, queue_size=10)
627
+ self._pub_cmd_pose_world = rospy.Publisher('/cmd_pose_world', Twist, queue_size=10)
628
+ self._pub_joy = rospy.Publisher('/joy', Joy, queue_size=10)
629
+ self._pub_switch_gait = rospy.Publisher('/humanoid_switch_gait_by_name', switchGaitByName, queue_size=10)
630
+ self._pub_step_ctrl = rospy.Publisher('/humanoid_mpc_foot_pose_target_trajectories', footPoseTargetTrajectories, queue_size=10)
631
+
632
+ def connect(self, timeout:float=2.0)-> bool:
633
+ start_time = rospy.Time.now()
634
+ publishers = [
635
+ # (self._pub_joy, "joy publisher"),
636
+ (self._pub_cmd_vel, "cmd_vel publisher"),
637
+ (self._pub_cmd_pose, "cmd_pose publisher"),
638
+ (self._pub_step_ctrl, "step_ctrl publisher"),
639
+ (self._pub_switch_gait, "switch_gait publisher"),
640
+ (self._pub_cmd_pose_world, "cmd_pose_world publisher"),
641
+ ]
642
+
643
+ success = True
644
+ for pub, name in publishers:
645
+ while pub.get_num_connections() == 0:
646
+ if (rospy.Time.now() - start_time).to_sec() > timeout:
647
+ SDKLogger.error(f"Timeout waiting for {name} connection, '{pub.name}'")
648
+ success = False
649
+ break
650
+ rospy.sleep(0.1)
651
+ return success
652
+
653
+ def pub_cmd_vel(self, linear_x: float, linear_y: float, angular_z: float)->bool:
654
+ try:
655
+ twist = Twist()
656
+ twist.linear.x = linear_x
657
+ twist.linear.y = linear_y
658
+ twist.angular.z = angular_z
659
+ self._pub_cmd_vel.publish(twist)
660
+ return True
661
+ except Exception as e:
662
+ SDKLogger.error(f"[Error] publish cmd vel: {e}")
663
+ return False
664
+
665
+ def pub_cmd_pose(self, twist)->bool:
666
+ try:
667
+ self._pub_cmd_pose.publish(twist)
668
+ return True
669
+ except Exception as e:
670
+ SDKLogger.error(f"[Error] publish cmd pose: {e}")
671
+ return False
672
+
673
+ def pub_cmd_pose_world(self, twist:Twist)->bool:
674
+ try:
675
+ self._pub_cmd_pose_world.publish(twist)
676
+ return True
677
+ except Exception as e:
678
+ SDKLogger.error(f"[Error] publish cmd pose world: {e}")
679
+ return False
680
+
681
+ def _create_joy_msg(self)->Joy:
682
+ joy_msg = Joy()
683
+ joy_msg.axes = [0.0] * 8 # Initialize 8 axes
684
+ joy_msg.buttons = [0] * 16 # Initialize 16 buttons
685
+ return joy_msg
686
+
687
+ def _pub_joy_command(self, button_index: int, command_name: str) -> bool:
688
+ try:
689
+ joy_msg = self._create_joy_msg()
690
+ joy_msg.buttons[button_index] = 1
691
+ self._pub_joy.publish(joy_msg)
692
+ SDKLogger.debug(f"Published {command_name} command")
693
+ return True
694
+ except Exception as e:
695
+ SDKLogger.error(f"[Error] publish {command_name}: {e}")
696
+ return False
697
+
698
+ def _pub_switch_gait_by_name(self, gait_name: str) -> bool:
699
+ try:
700
+ msg = switchGaitByName()
701
+ msg.header.stamp = rospy.Time.now()
702
+ msg.gait_name = gait_name
703
+ self._pub_switch_gait.publish(msg)
704
+ # print(f"Published {gait_name} gait")
705
+ return True
706
+ except Exception as e:
707
+ SDKLogger.error(f"[Error] publish switch gait {gait_name}: {e}")
708
+ return False
709
+
710
+ def pub_walk_command(self) -> bool:
711
+ # return self._pub_joy_command(BUTTON_Y, "walk")
712
+ return self._pub_switch_gait_by_name("walk")
713
+
714
+ def pub_stance_command(self) -> bool:
715
+ try:
716
+ self.pub_cmd_vel(linear_x=0.0, linear_y=0.0, angular_z=0.0)
717
+ # return self._pub_joy_command(BUTTON_A, "stance")
718
+ return self._pub_switch_gait_by_name("stance")
719
+ except Exception as e:
720
+ SDKLogger.error(f"[Error] publish stance: {e}")
721
+ return False
722
+
723
+ def pub_trot_command(self) -> bool:
724
+ # return self._pub_joy_command(BUTTON_B, "trot")
725
+ return self._pub_switch_gait_by_name("walk")
726
+
727
+ def pub_step_ctrl(self, msg)->bool:
728
+ try:
729
+ self._pub_step_ctrl.publish(msg)
730
+ return True
731
+ except Exception as e:
732
+ SDKLogger.error(f"[Error] publish step ctrl: {e}")
733
+ return False
734
+
735
+ class KuavoRobotArmIKFK:
736
+ def __init__(self):
737
+ pass
738
+ def arm_ik(self,
739
+ left_pose: KuavoPose,
740
+ right_pose: KuavoPose,
741
+ left_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
742
+ right_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
743
+ arm_q0: list = None,
744
+ params: KuavoIKParams=None) -> list:
745
+ eef_pose_msg = twoArmHandPoseCmd()
746
+ if arm_q0 is None:
747
+ eef_pose_msg.joint_angles_as_q0 = False
748
+ else:
749
+ eef_pose_msg.joint_angles_as_q0 = True
750
+ eef_pose_msg.joint_angles = arm_q0
751
+
752
+ if params is None:
753
+ eef_pose_msg.use_custom_ik_param = False
754
+ else:
755
+ eef_pose_msg.use_custom_ik_param = True
756
+ eef_pose_msg.ik_param.major_optimality_tol = params.major_optimality_tol
757
+ eef_pose_msg.ik_param.major_feasibility_tol = params.major_feasibility_tol
758
+ eef_pose_msg.ik_param.minor_feasibility_tol = params.minor_feasibility_tol
759
+ eef_pose_msg.ik_param.major_iterations_limit = params.major_iterations_limit
760
+ eef_pose_msg.ik_param.oritation_constraint_tol= params.oritation_constraint_tol
761
+ eef_pose_msg.ik_param.pos_constraint_tol = params.pos_constraint_tol
762
+ eef_pose_msg.ik_param.pos_cost_weight = params.pos_cost_weight
763
+
764
+ # left hand
765
+ eef_pose_msg.hand_poses.left_pose.pos_xyz = left_pose.position
766
+ eef_pose_msg.hand_poses.left_pose.quat_xyzw = left_pose.orientation
767
+ eef_pose_msg.hand_poses.left_pose.elbow_pos_xyz = left_elbow_pos_xyz
768
+
769
+ # right hand
770
+ eef_pose_msg.hand_poses.right_pose.pos_xyz = right_pose.position
771
+ eef_pose_msg.hand_poses.right_pose.quat_xyzw = right_pose.orientation
772
+ eef_pose_msg.hand_poses.right_pose.elbow_pos_xyz = right_elbow_pos_xyz
773
+
774
+ return self._srv_arm_ik(eef_pose_msg)
775
+
776
+ def arm_fk(self, q: list) -> Tuple[KuavoPose, KuavoPose]:
777
+ return self._srv_arm_fk(q)
778
+
779
+ def _srv_arm_ik(self, eef_pose_msg)->list:
780
+ try:
781
+ rospy.wait_for_service('/ik/two_arm_hand_pose_cmd_srv',timeout=1.0)
782
+ ik_srv = rospy.ServiceProxy('/ik/two_arm_hand_pose_cmd_srv', twoArmHandPoseCmdSrv)
783
+ res = ik_srv(eef_pose_msg)
784
+ # print(eef_pose_msg)
785
+ if res.success:
786
+ return res.hand_poses.left_pose.joint_angles + res.hand_poses.right_pose.joint_angles
787
+ else:
788
+ return None
789
+ except rospy.ServiceException as e:
790
+ print("Service call failed: %s"%e)
791
+ return None
792
+ except Exception as e:
793
+ print(f"Failed to call ik/fk_srv: {e}")
794
+ return None
795
+ def _srv_arm_fk(self, q: list) -> Tuple[KuavoPose, KuavoPose]:
796
+ try:
797
+ rospy.wait_for_service('/ik/fk_srv',timeout=1.0)
798
+ ik_srv = rospy.ServiceProxy('/ik/fk_srv', fkSrv)
799
+ res = ik_srv(q)
800
+ if res.success:
801
+ return KuavoPose(position=res.hand_poses.left_pose.pos_xyz, orientation=res.hand_poses.left_pose.quat_xyzw), \
802
+ KuavoPose(position=res.hand_poses.right_pose.pos_xyz, orientation=res.hand_poses.right_pose.quat_xyzw),
803
+ else:
804
+ return None
805
+ except rospy.ServiceException as e:
806
+ print("Service call failed: %s"%e)
807
+ return None
808
+ except Exception as e:
809
+ print(f"Failed to call ik/fk_srv: {e}")
810
+ return None
811
+
812
+
813
+
814
+ """
815
+ Kuavo Robot Control
816
+ """
817
+ class KuavoRobotControl:
818
+ _instance = None
819
+
820
+ def __new__(cls, *args, **kwargs):
821
+ if not cls._instance:
822
+ cls._instance = super().__new__(cls)
823
+ if not rospy.core.is_initialized():
824
+ if not rospy.get_node_uri():
825
+ rospy.init_node(f'kuavo_sdk_node_{os.getpid()}', anonymous=True, disable_signals=True)
826
+ return cls._instance
827
+
828
+ def __init__(self):
829
+ if not hasattr(self, '_initialized'):
830
+ self._initialized = True
831
+ self.kuavo_eef_control = None
832
+ self.kuavo_head_control = ControlRobotHead()
833
+ self.kuavo_arm_control = ControlRobotArm()
834
+ self.kuavo_motion_control = ControlRobotMotion()
835
+ self.kuavo_arm_ik_fk = KuavoRobotArmIKFK()
836
+ # SDKLogger.debug("KuavoRobotControl initialized.")
837
+
838
+ def initialize(self, eef_type:str=None, debug:bool=False, timeout:float=1.0)-> Tuple[bool, str]:
839
+ # init eef control
840
+ if eef_type is None:
841
+ self.kuavo_eef_control = None
842
+ else:
843
+ self.kuavo_eef_control = ControlEndEffector(eef_type=eef_type)
844
+
845
+ connect_success = True
846
+ err_msg = ''
847
+ if not self.kuavo_arm_control.connect(timeout):
848
+ connect_success = False
849
+ err_msg = "Failed to connect to arm control topics, \n"
850
+ if not self.kuavo_head_control.connect(timeout):
851
+ connect_success = False
852
+ err_msg += "Failed to connect to head control topics, \n"
853
+ if not self.kuavo_motion_control.connect(timeout):
854
+ err_msg += "Failed to connect to motion control topics, \n"
855
+ connect_success = False
856
+
857
+ if self.kuavo_eef_control is not None and not self.kuavo_eef_control.connect(timeout):
858
+ connect_success = False
859
+ err_msg += "Failed to connect to end effector control topics."
860
+
861
+ if connect_success:
862
+ err_msg = 'success'
863
+ return connect_success, err_msg
864
+
865
+ """ End Effector Control"""
866
+ def control_robot_dexhand(self, left_position:list, right_position:list)->bool:
867
+ """
868
+ Control robot dexhand
869
+ Args:
870
+ left_position: list of 6 floats between 0 and 100
871
+ right_position: list of 6 floats between 0 and 100
872
+ """
873
+ if self.kuavo_eef_control is None:
874
+ SDKLogger.error("End effector control is not initialized.")
875
+ return False
876
+
877
+ if len(left_position) != 6 or len(right_position) != 6:
878
+ raise ValueError("Position lists must have a length of 6.")
879
+
880
+ for position in left_position + right_position:
881
+ if position < 0.0 or position > 100.0:
882
+ raise ValueError("All position values must be in the range [0.0, 100.0].")
883
+
884
+ SDKLogger.debug(f"Control robot dexhand: {left_position}, {right_position}")
885
+ return self.kuavo_eef_control.pub_control_robot_dexhand(left_position, right_position)
886
+
887
+ def robot_dexhand_command(self, data, ctrl_mode, hand_side):
888
+ """
889
+ Publish dexhand command
890
+ Args:
891
+ - data: list of 6 floats between 0 and 100
892
+ - ctrl_mode: int between 0(position), 1(velocity)
893
+ - hand_side: int between 0(left), 1(right), 2(dual)
894
+ """
895
+ if self.kuavo_eef_control is None:
896
+ SDKLogger.error("End effector control is not initialized.")
897
+ return False
898
+ return self.kuavo_eef_control.pub_dexhand_command(data, ctrl_mode, hand_side)
899
+
900
+ def execute_gesture(self, gestures:list)->bool:
901
+ """
902
+ Execute gestures
903
+ Arguments:
904
+ - gestures: list of dicts with keys 'gesture_name' and 'hand_side'
905
+ e.g. [{'gesture_name': 'fist', 'hand_side': 0},]
906
+ """
907
+ if self.kuavo_eef_control is None:
908
+ SDKLogger.warn("End effectors control is not initialized.")
909
+ return False
910
+ return self.kuavo_eef_control.srv_execute_gesture(gestures)
911
+
912
+ def get_gesture_names(self)->list:
913
+ """
914
+ Get the names of all gestures.
915
+ """
916
+ if self.kuavo_eef_control is None:
917
+ SDKLogger.warn("End effectors control is not initialized.")
918
+ return []
919
+ return self.kuavo_eef_control.srv_get_gesture_names()
920
+
921
+ def control_leju_claw(self, postions:list, velocities:list=[90, 90], torques:list=[1.0, 1.0]) ->bool:
922
+ """
923
+ Control leju claw
924
+ Arguments:
925
+ - postions: list of positions for left and right claw
926
+ - velocities: list of velocities for left and right claw
927
+ - torques: list of torques for left and right claw
928
+ """
929
+ if self.kuavo_eef_control is None:
930
+ SDKLogger.warn("End effectors control is not initialized.")
931
+ return False
932
+ SDKLogger.debug(f"Control leju claw: {postions}, {velocities}, {torques}")
933
+ if len(postions) != 2 or len(velocities) != 2 or len(torques) != 2:
934
+ raise ValueError("Position, velocity, and torque lists must have a length of 2.")
935
+ return self.kuavo_eef_control.srv_control_leju_claw(postions, velocities, torques)
936
+ """--------------------------------------------------------------------------------------------"""
937
+ def control_robot_head(self, yaw:float, pitch:float)->bool:
938
+ """
939
+ Control robot head
940
+ Arguments:
941
+ - yaw: yaw angle, radian
942
+ - pitch: pitch angle, radian
943
+ """
944
+ SDKLogger.debug(f"Control robot head: {yaw}, {pitch}")
945
+ return self.kuavo_head_control.pub_control_robot_head(yaw, pitch)
946
+
947
+ def enable_head_tracking(self, target_id: int)->bool:
948
+ """Enable the head tracking for a specific tag ID.
949
+
950
+ Args:
951
+ target_id: The ID of the tag to track
952
+
953
+ Returns:
954
+ bool: True if successful, False otherwise
955
+ """
956
+ SDKLogger.debug(f"Enable head tracking: {target_id}")
957
+ return self.kuavo_head_control.srv_enable_head_tracking(target_id)
958
+
959
+ def disable_head_tracking(self)->bool:
960
+ """Disable the head tracking.
961
+
962
+ Returns:
963
+ bool: True if successful, False otherwise
964
+ """
965
+ SDKLogger.debug(f"Disable head tracking")
966
+ return self.kuavo_head_control.srv_disable_head_tracking()
967
+
968
+ def control_robot_arm_joint_positions(self, joint_data:list)->bool:
969
+ """
970
+ Control robot arm joint positions
971
+ Arguments:
972
+ - joint_data: list of joint data (degrees)
973
+ """
974
+ # SDKLogger.debug(f"[ROS] Control robot arm trajectory: {joint_data}")
975
+ return self.kuavo_arm_control.pub_control_robot_arm_traj(joint_data)
976
+
977
+ def control_robot_arm_joint_trajectory(self, times:list, joint_q:list)->bool:
978
+ """
979
+ Control robot arm joint trajectory
980
+ Arguments:
981
+ - times: list of times (seconds)
982
+ - joint_q: list of joint data (degrees)
983
+ """
984
+ if len(times) != len(joint_q):
985
+ raise ValueError("Times and joint_q must have the same length.")
986
+ elif len(times) == 0:
987
+ raise ValueError("Times and joint_q must not be empty.")
988
+
989
+ return self.kuavo_arm_control.pub_arm_target_poses(times=times, joint_q=joint_q)
990
+
991
+ def control_robot_end_effector_pose(self, left_pose: KuavoPose, right_pose: KuavoPose, frame: KuavoManipulationMpcFrame)->bool:
992
+ """
993
+ Control robot end effector pose
994
+ Arguments:
995
+ - left_pose: left end effector pose
996
+ - right_pose: right end effector pose
997
+ - frame: frame of the end effector pose, 0: keep current frame, 1: world frame, 2: local frame, 3: VR frame, 4: manipulation world frame
998
+ """
999
+ return self.kuavo_arm_control.pub_end_effector_pose_cmd(left_pose, right_pose, frame)
1000
+
1001
+ def change_manipulation_mpc_frame(self, frame: KuavoManipulationMpcFrame)->bool:
1002
+ """
1003
+ Change manipulation mpc frame
1004
+ Arguments:
1005
+ - frame: frame of the manipulation mpc
1006
+ """
1007
+ return self.kuavo_arm_control.srv_change_manipulation_mpc_frame(frame)
1008
+
1009
+ def change_manipulation_mpc_ctrl_mode(self, ctrl_mode: KuavoManipulationMpcCtrlMode)->bool:
1010
+ """
1011
+ Change manipulation mpc control mode
1012
+ Arguments:
1013
+ - control_mode: control mode of the manipulation mpc
1014
+ """
1015
+ return self.kuavo_arm_control.srv_change_manipulation_mpc_ctrl_mode(ctrl_mode)
1016
+
1017
+ def change_manipulation_mpc_control_flow(self, ctrl_flow: KuavoManipulationMpcControlFlow)->bool:
1018
+ """
1019
+ Change manipulation mpc wbc arm traj control mode, control signal will be sent to wbc directly
1020
+ Arguments:
1021
+ - control_mode: control mode of the manipulation mpc wbc arm traj
1022
+ """
1023
+ return self.kuavo_arm_control.srv_change_manipulation_mpc_control_flow(ctrl_flow)
1024
+
1025
+ def get_manipulation_mpc_ctrl_mode(self)->KuavoManipulationMpcCtrlMode:
1026
+ """
1027
+ Get manipulation mpc control mode
1028
+ """
1029
+ return self.kuavo_arm_control.srv_get_manipulation_mpc_ctrl_mode()
1030
+
1031
+ def get_manipulation_mpc_frame(self)-> KuavoManipulationMpcFrame:
1032
+ """
1033
+ Get manipulation mpc frame
1034
+ """
1035
+ return self.kuavo_arm_control.srv_get_manipulation_mpc_frame()
1036
+
1037
+ def get_manipulation_mpc_control_flow(self)->KuavoManipulationMpcControlFlow:
1038
+ """
1039
+ Get manipulation mpc wbc arm traj control mode
1040
+ """
1041
+ return self.kuavo_arm_control.srv_get_manipulation_mpc_control_flow()
1042
+
1043
+ def change_robot_arm_ctrl_mode(self, mode:KuavoArmCtrlMode)->bool:
1044
+ """
1045
+ Change robot arm control mode
1046
+ Arguments:
1047
+ - mode: arm control mode
1048
+ """
1049
+ SDKLogger.debug(f"[ROS] Change robot arm control mode: {mode}")
1050
+ return self.kuavo_arm_control.srv_change_arm_ctrl_mode(mode)
1051
+
1052
+ def get_robot_arm_ctrl_mode(self)->int:
1053
+ """
1054
+ Get robot arm control mode
1055
+ """
1056
+ return self.kuavo_arm_control.srv_get_arm_ctrl_mode()
1057
+
1058
+ def arm_ik(self, left_pose: KuavoPose, right_pose: KuavoPose,
1059
+ left_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
1060
+ right_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
1061
+ arm_q0: list = None, params: KuavoIKParams=None) -> list:
1062
+ return self.kuavo_arm_ik_fk.arm_ik(left_pose, right_pose, left_elbow_pos_xyz, right_elbow_pos_xyz, arm_q0, params)
1063
+
1064
+
1065
+ def arm_fk(self, q: list) -> Tuple[KuavoPose, KuavoPose]:
1066
+ return self.kuavo_arm_ik_fk.arm_fk(q)
1067
+
1068
+ """ Motion """
1069
+ def robot_stance(self)->bool:
1070
+ return self.kuavo_motion_control.pub_stance_command()
1071
+
1072
+ def robot_trot(self)->bool:
1073
+ return self.kuavo_motion_control.pub_trot_command()
1074
+
1075
+ def robot_walk(self, linear_x:float, linear_y:float, angular_z:float)->bool:
1076
+ return self.kuavo_motion_control.pub_cmd_vel(linear_x, linear_y, angular_z)
1077
+
1078
+ def control_torso_height(self, height:float, pitch:float=0.0)->bool:
1079
+ com_msg = Twist()
1080
+ com_msg.linear.z = height
1081
+ com_msg.angular.y = pitch
1082
+ return self.kuavo_motion_control.pub_cmd_pose(com_msg)
1083
+
1084
+ def control_command_pose_world(self, target_pose_x:float, target_pose_y:float, target_pose_z:float, target_pose_yaw:float)->bool:
1085
+ """
1086
+ odom下的机器人cmd_pose_world
1087
+ """
1088
+ com_msg = Twist()
1089
+ com_msg.linear.x = target_pose_x
1090
+ com_msg.linear.y = target_pose_y
1091
+ com_msg.linear.z = target_pose_z
1092
+ com_msg.angular.z = target_pose_yaw
1093
+ return self.kuavo_motion_control.pub_cmd_pose_world(com_msg)
1094
+
1095
+ def control_command_pose(self, target_pose_x:float, target_pose_y:float, target_pose_z:float, target_pose_yaw:float)->bool:
1096
+ """
1097
+ base_link下的机器人cmd_pose
1098
+ """
1099
+ com_msg = Twist()
1100
+ com_msg.linear.x = target_pose_x
1101
+ com_msg.linear.y = target_pose_y
1102
+ com_msg.linear.z = target_pose_z
1103
+ com_msg.angular.z = target_pose_yaw
1104
+ return self.kuavo_motion_control.pub_cmd_pose(com_msg)
1105
+
1106
+ def step_control(self, body_poses:list, dt:float, is_left_first_default:bool=True, collision_check:bool=True)->bool:
1107
+ """
1108
+ Step control
1109
+ Arguments:
1110
+ - body_poses: list of body poses (x, y, z, yaw), meters and degrees
1111
+ - dt: time step (seconds)
1112
+ - is_left_first_default: whether to start with left foot
1113
+ - collision_check: whether to check for collisions
1114
+ """
1115
+ if len(body_poses) == 0:
1116
+ raise ValueError("Body poses must not be empty.")
1117
+ if dt <= 0.0:
1118
+ raise ValueError("Time step must be greater than 0.0.")
1119
+ for bp in body_poses:
1120
+ if len(bp) != 4:
1121
+ raise ValueError("Body pose must have 4 elements: [x, y, z, yaw]")
1122
+
1123
+ msg = get_multiple_steps_msg(body_poses, dt, is_left_first_default, collision_check)
1124
+ return self.kuavo_motion_control.pub_step_ctrl(msg)
1125
+
1126
+ def change_motor_param(self, motor_param:list)->Tuple[bool, str]:
1127
+ """
1128
+ Change motor param
1129
+ """
1130
+ try:
1131
+ service_name = '/hardware/change_motor_param'
1132
+ rospy.wait_for_service(service=service_name, timeout=2.0)
1133
+ change_motor_param_service = rospy.ServiceProxy(service_name, changeMotorParam)
1134
+
1135
+ # request
1136
+ request = changeMotorParamRequest()
1137
+ for param in motor_param:
1138
+ request.data.append(motorParam(Kp=param.Kp, Kd=param.Kd, id=param.id))
1139
+
1140
+ # call service
1141
+ response = change_motor_param_service(request)
1142
+ if not response.success:
1143
+ SDKLogger.error(f"Failed to change motor param: {response.message}")
1144
+ return False, response.message
1145
+ return True, 'success'
1146
+ except rospy.ServiceException as e:
1147
+ SDKLogger.error(f"Service call failed: {e}")
1148
+ except rospy.ROSException as e:
1149
+ SDKLogger.error(f"Service call failed: {e}")
1150
+ except Exception as e:
1151
+ SDKLogger.error(f"Service call failed: {e}")
1152
+ return False, 'failed'
1153
+
1154
+ def get_motor_param(self)->Tuple[bool, list, str]:
1155
+ try:
1156
+ service_name = '/hardware/get_motor_param'
1157
+ rospy.wait_for_service(service=service_name, timeout=2.0)
1158
+ motor_param_service = rospy.ServiceProxy(service_name, getMotorParam)
1159
+
1160
+ # request
1161
+ request = getMotorParamRequest()
1162
+ response = motor_param_service(request)
1163
+ if not response.success:
1164
+ SDKLogger.error(f"Failed to get motor param: {response.message}")
1165
+ return False, None, response.message
1166
+ params = []
1167
+ for param in response.data:
1168
+ params.append(KuavoMotorParam(Kp=param.Kp, Kd=param.Kd, id=param.id))
1169
+ return True, params, 'success'
1170
+ except rospy.ServiceException as e:
1171
+ SDKLogger.error(f"Service call failed: {e}")
1172
+ except rospy.ROSException as e:
1173
+ SDKLogger.error(f"Service call failed: {e}")
1174
+ except Exception as e:
1175
+ SDKLogger.error(f"Service call failed: {e}")
1176
+ return False, None, 'failed'
1177
+
1178
+
1179
+ """ ------------------------------------------------------------------------------"""
1180
+
1181
+
1182
+
1183
+
1184
+ def euler_to_rotation_matrix(yaw, pitch, roll):
1185
+ # 计算各轴的旋转矩阵
1186
+ R_yaw = np.array([[np.cos(yaw), -np.sin(yaw), 0],
1187
+ [np.sin(yaw), np.cos(yaw), 0],
1188
+ [0, 0, 1]])
1189
+
1190
+ R_pitch = np.array([[np.cos(pitch), 0, np.sin(pitch)],
1191
+ [0, 1, 0],
1192
+ [-np.sin(pitch), 0, np.cos(pitch)]])
1193
+
1194
+ R_roll = np.array([[1, 0, 0],
1195
+ [0, np.cos(roll), -np.sin(roll)],
1196
+ [0, np.sin(roll), np.cos(roll)]])
1197
+
1198
+ # 按照 Yaw-Pitch-Roll 的顺序组合旋转矩阵
1199
+ R = np.dot(R_roll, np.dot(R_pitch, R_yaw))
1200
+ return R
1201
+
1202
+ def get_foot_pose_traj_msg(time_traj:list, foot_idx_traj:list, foot_traj:list, torso_traj:list):
1203
+ num = len(time_traj)
1204
+
1205
+ msg = footPoseTargetTrajectories()
1206
+ msg.timeTrajectory = time_traj
1207
+ msg.footIndexTrajectory = foot_idx_traj
1208
+ msg.footPoseTrajectory = []
1209
+
1210
+ for i in range(num):
1211
+ foot_pose_msg = footPose()
1212
+ foot_pose_msg.footPose = foot_traj[i]
1213
+ foot_pose_msg.torsoPose = torso_traj[i]
1214
+ msg.footPoseTrajectory.append(foot_pose_msg)
1215
+
1216
+ return msg
1217
+
1218
+ def generate_steps(torso_pos, torso_yaw, foot_bias):
1219
+ l_foot_bias = np.array([0, foot_bias, -torso_pos[2]])
1220
+ r_foot_bias = np.array([0, -foot_bias, -torso_pos[2]])
1221
+ R_z = np.array([
1222
+ [np.cos(torso_yaw), -np.sin(torso_yaw), 0],
1223
+ [np.sin(torso_yaw), np.cos(torso_yaw), 0],
1224
+ [0, 0, 1]
1225
+ ])
1226
+ l_foot = torso_pos + R_z.dot(l_foot_bias)
1227
+ r_foot = torso_pos + R_z.dot(r_foot_bias)
1228
+ return l_foot, r_foot
1229
+
1230
+ def get_multiple_steps_msg(body_poses:list, dt:float, is_left_first:bool=True, collision_check:bool=True):
1231
+ num_steps = 2*len(body_poses)
1232
+ time_traj = []
1233
+ foot_idx_traj = []
1234
+ foot_traj = []
1235
+ torso_traj = []
1236
+ l_foot_rect_last = RotatingRectangle(center=(0, 0.1), width=0.24, height=0.1, angle=0)
1237
+ r_foot_rect_last = RotatingRectangle(center=(0,-0.1), width=0.24, height=0.1, angle=0)
1238
+ torso_pose_last = np.array([0, 0, 0, 0])
1239
+ for i in range(num_steps):
1240
+ time_traj.append(dt * (i+1))
1241
+ body_pose = body_poses[i//2]
1242
+ torso_pos = np.asarray(body_pose[:3])
1243
+ torso_yaw = np.radians(body_pose[3])
1244
+ l_foot, r_foot = generate_steps(torso_pos, torso_yaw, 0.1)
1245
+ l_foot = [*l_foot[:3], torso_yaw]
1246
+ r_foot = [*r_foot[:3], torso_yaw]
1247
+
1248
+ if(i%2 == 0):
1249
+ torso_pose = np.array([*body_pose[:3], torso_yaw])
1250
+ R_wl = euler_to_rotation_matrix(torso_pose_last[3], 0, 0)
1251
+ delta_pos = R_wl.T @ (torso_pose[:3] - torso_pose_last[:3])
1252
+ # print("delta_pos:", delta_pos)
1253
+ if(torso_yaw > 0.0 or delta_pos[1] > 0.0):
1254
+ is_left_first = True
1255
+ else:
1256
+ is_left_first = False
1257
+
1258
+ if(collision_check and i%2 == 0):
1259
+ l_foot_rect_next = RotatingRectangle(center=(l_foot[0],l_foot[1]), width=0.24, height=0.1, angle=torso_yaw)
1260
+ r_foot_rect_next = RotatingRectangle(center=(r_foot[0],r_foot[1]), width=0.24, height=0.1, angle=torso_yaw)
1261
+ l_collision = l_foot_rect_next.is_collision(r_foot_rect_last)
1262
+ r_collision = r_foot_rect_next.is_collision(l_foot_rect_last)
1263
+ if l_collision and r_collision:
1264
+ SDKLogger.error("[Control] Detect collision, Please adjust your body_poses input!!!")
1265
+ break
1266
+ elif l_collision:
1267
+ SDKLogger.warn("[Control] Left foot is in collision, switch to right foot")
1268
+ is_left_first = False
1269
+ elif r_collision:
1270
+ SDKLogger.warn("[Control] Right foot is in collision, switch to left foot")
1271
+ is_left_first = True
1272
+ l_foot_rect_last = l_foot_rect_next
1273
+ r_foot_rect_last = r_foot_rect_next
1274
+ if(i%2 == 0):
1275
+ torso_traj.append((torso_pose_last + torso_pose)/2.0)
1276
+ if is_left_first:
1277
+ foot_idx_traj.append(0)
1278
+ foot_traj.append(l_foot)
1279
+ else:
1280
+ foot_idx_traj.append(1)
1281
+ foot_traj.append(r_foot)
1282
+ else:
1283
+ torso_traj.append(torso_pose)
1284
+ if is_left_first:
1285
+ foot_idx_traj.append(1)
1286
+ foot_traj.append(r_foot)
1287
+ else:
1288
+ foot_idx_traj.append(0)
1289
+ foot_traj.append(l_foot)
1290
+ torso_pose_last = torso_traj[-1]
1291
+ # print("time_traj:", time_traj)
1292
+ # print("foot_idx_traj:", foot_idx_traj)
1293
+ # print("foot_traj:", foot_traj)
1294
+ # print("torso_traj:", torso_traj)
1295
+ return get_foot_pose_traj_msg(time_traj, foot_idx_traj, foot_traj, torso_traj)
1296
+ """ ------------------------------------------------------------------------------"""
1297
+
1298
+
1299
+ # if __name__ == "__main__":
1300
+ # control = KuavoRobotControl()
1301
+ # control.change_manipulation_mpc_frame(KuavoManipulationMpcFrame.KeepCurrentFrame)
1302
+ # control.change_manipulation_mpc_ctrl_mode(KuavoManipulationMpcCtrlMode.ArmOnly)
1303
+ # control.change_manipulation_mpc_control_flow(KuavoManipulationMpcControlFlow.DirectToWbc)
1304
+ # print(control.get_manipulation_mpc_ctrl_mode())
1305
+ # print(control.get_manipulation_mpc_frame())
1306
+ # print(control.get_manipulation_mpc_control_flow())
1307
+ # control.change_manipulation_mpc_frame(KuavoManipulationMpcFrame.WorldFrame)
1308
+ # control.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl)
1309
+ # control.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)