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