kuavo-humanoid-sdk 1.1.6b1125__20250610230424-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 (132) hide show
  1. kuavo_humanoid_sdk/__init__.py +6 -0
  2. kuavo_humanoid_sdk/common/logger.py +42 -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 +617 -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 +606 -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 +460 -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 +464 -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/_Metadata.py +199 -0
  41. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_RobotActionState.py +112 -0
  42. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_TFArray.py +323 -0
  43. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +44 -0
  44. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armHandPose.py +160 -0
  45. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armPoseWithTimeStamp.py +168 -0
  46. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armTargetPoses.py +151 -0
  47. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_bezierCurveCubicPoint.py +178 -0
  48. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandCommand.py +229 -0
  49. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandTouchState.py +256 -0
  50. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_endEffectorData.py +227 -0
  51. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPose.py +123 -0
  52. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoseTargetTrajectories.py +301 -0
  53. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoses.py +149 -0
  54. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_fullBodyTargetTrajectories.py +258 -0
  55. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gaitTimeName.py +147 -0
  56. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureInfo.py +218 -0
  57. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureTask.py +149 -0
  58. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_handPose.py +136 -0
  59. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_headBodyPose.py +145 -0
  60. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveError.py +171 -0
  61. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveParam.py +140 -0
  62. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_imuData.py +165 -0
  63. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointBezierTrajectory.py +201 -0
  64. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointCmd.py +390 -0
  65. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointData.py +205 -0
  66. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawCommand.py +320 -0
  67. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawState.py +341 -0
  68. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_motorParam.py +122 -0
  69. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_planArmState.py +120 -0
  70. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_questJoySticks.py +191 -0
  71. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_qv.py +121 -0
  72. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotArmQVVD.py +177 -0
  73. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHandPosition.py +225 -0
  74. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHeadMotionData.py +128 -0
  75. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotState.py +222 -0
  76. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_sensorsData.py +495 -0
  77. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_switchGaitByName.py +200 -0
  78. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_touchSensorStatus.py +162 -0
  79. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPose.py +272 -0
  80. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmd.py +315 -0
  81. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloDetection.py +251 -0
  82. kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloOutputData.py +168 -0
  83. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_ExecuteArmAction.py +281 -0
  84. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_RepublishTFs.py +373 -0
  85. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetJoyTopic.py +282 -0
  86. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SpeechSynthesis.py +270 -0
  87. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +28 -0
  88. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlMode.py +275 -0
  89. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlModeKuavo.py +236 -0
  90. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeMotorParam.py +299 -0
  91. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeTorsoCtrlMode.py +274 -0
  92. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_controlLejuClaw.py +408 -0
  93. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_enableHandTouchSensor.py +304 -0
  94. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_fkSrv.py +394 -0
  95. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_footPoseTargetTrajectoriesSrv.py +409 -0
  96. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecute.py +339 -0
  97. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecuteState.py +257 -0
  98. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureList.py +418 -0
  99. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getCurrentGaitName.py +253 -0
  100. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getMotorParam.py +299 -0
  101. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_handForceLevel.py +330 -0
  102. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_jointMoveTo.py +302 -0
  103. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryBezierCurve.py +421 -0
  104. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryCubicSpline.py +490 -0
  105. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_playmusic.py +268 -0
  106. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setHwIntialState.py +304 -0
  107. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMmCtrlFrame.py +273 -0
  108. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMotorEncoderRoundService.py +283 -0
  109. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setTagId.py +275 -0
  110. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_singleStepControl.py +444 -0
  111. kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdSrv.py +662 -0
  112. kuavo_humanoid_sdk/msg/motion_capture_ik/__init__.py +7 -0
  113. kuavo_humanoid_sdk/msg/ocs2_msgs/__init__.py +7 -0
  114. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/__init__.py +12 -0
  115. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_constraint.py +142 -0
  116. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_controller_data.py +121 -0
  117. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_lagrangian_metrics.py +148 -0
  118. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mode_schedule.py +150 -0
  119. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_flattened_controller.py +666 -0
  120. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_input.py +122 -0
  121. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_observation.py +209 -0
  122. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_performance_indices.py +140 -0
  123. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_solver_data.py +886 -0
  124. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_state.py +122 -0
  125. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_target_trajectories.py +239 -0
  126. kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_multiplier.py +148 -0
  127. kuavo_humanoid_sdk/msg/ocs2_msgs/srv/__init__.py +1 -0
  128. kuavo_humanoid_sdk/msg/ocs2_msgs/srv/_reset.py +376 -0
  129. kuavo_humanoid_sdk-1.1.6b1125.dist-info/METADATA +291 -0
  130. kuavo_humanoid_sdk-1.1.6b1125.dist-info/RECORD +132 -0
  131. kuavo_humanoid_sdk-1.1.6b1125.dist-info/WHEEL +6 -0
  132. kuavo_humanoid_sdk-1.1.6b1125.dist-info/top_level.txt +1 -0
@@ -0,0 +1,617 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ """
4
+ This layer is responsible for robot state transitions.
5
+ The robot has three states:
6
+ - stance: Standing still state
7
+ - walk: Walking state
8
+ - trot: Trotting state
9
+
10
+ State transitions are managed by a state machine that ensures valid transitions between states.
11
+ The state machine enforces the following transitions:
12
+ - stance <-> walk
13
+ - stance <-> trot
14
+ - walk <-> trot
15
+
16
+ Each state has an entry callback that handles initialization when entering that state.
17
+ """
18
+
19
+
20
+ import time
21
+ import math
22
+ import threading
23
+ import numpy as np
24
+ from typing import Tuple
25
+ from transitions import Machine, State
26
+
27
+ from kuavo_humanoid_sdk.interfaces.data_types import KuavoArmCtrlMode, KuavoIKParams, KuavoPose, KuavoManipulationMpcFrame, KuavoManipulationMpcCtrlMode, KuavoManipulationMpcControlFlow
28
+ from kuavo_humanoid_sdk.kuavo.core.ros.control import KuavoRobotControl
29
+ from kuavo_humanoid_sdk.kuavo.core.ros.vision import KuavoRobotVisionCore
30
+ from kuavo_humanoid_sdk.kuavo.core.ros.tools import KuavoRobotToolsCore
31
+ from kuavo_humanoid_sdk.kuavo.core.ros.state import KuavoRobotStateCore
32
+ from kuavo_humanoid_sdk.kuavo.core.ros.param import make_robot_param
33
+ from kuavo_humanoid_sdk.common.logger import SDKLogger
34
+ # Define robot states
35
+ ROBOT_STATES = [
36
+ State(name='stance', on_enter=['_on_enter_stance']),
37
+ State(name='walk', on_enter=['_on_enter_walk']),
38
+ State(name='trot', on_enter=['_on_enter_trot']),
39
+ State(name='custom_gait', on_enter=['_on_enter_custom_gait']),
40
+ State(name='command_pose_world', on_enter=['_on_enter_command_pose_world']),
41
+ State(name='command_pose', on_enter=['_on_enter_command_pose']),
42
+ ]
43
+
44
+ # Define state transitions
45
+ ROBOT_TRANSITIONS = [
46
+ {'trigger': 'to_stance', 'source': ['walk', 'trot', 'custom_gait', 'command_pose_world', 'command_pose'], 'dest': 'stance'},
47
+ {'trigger': 'to_walk', 'source': ['stance', 'trot', 'custom_gait'], 'dest': 'walk'},
48
+ {'trigger': 'to_trot', 'source': ['stance', 'walk', 'custom_gait'], 'dest': 'trot'},
49
+ {'trigger': 'to_custom_gait', 'source': ['stance', 'custom_gait'], 'dest': 'custom_gait'},
50
+ {'trigger': 'to_command_pose_world', 'source': ['stance', 'command_pose_world'], 'dest': 'command_pose_world'},
51
+ {'trigger': 'to_command_pose', 'source': ['stance', 'command_pose'], 'dest': 'command_pose'},
52
+ ]
53
+
54
+ class KuavoRobotCore:
55
+ _instance = None
56
+
57
+ def __new__(cls):
58
+ if cls._instance is None:
59
+ cls._instance = super(KuavoRobotCore, cls).__new__(cls)
60
+ return cls._instance
61
+
62
+ def __init__(self):
63
+ if not hasattr(self, '_initialized'):
64
+ self.machine = Machine(
65
+ model=self,
66
+ states=ROBOT_STATES,
67
+ transitions=ROBOT_TRANSITIONS,
68
+ initial='stance',
69
+ send_event=True
70
+ )
71
+
72
+ self._control = KuavoRobotControl()
73
+ self._rb_state = KuavoRobotStateCore()
74
+
75
+ # robot vision
76
+ self._robot_vision = KuavoRobotVisionCore()
77
+ # robot ros tf
78
+ self._robot_tf_tool = KuavoRobotToolsCore()
79
+
80
+ # manipulation mpc
81
+ self._manipulation_mpc_frame = KuavoManipulationMpcFrame.KeepCurrentFrame
82
+ self._manipulation_mpc_ctrl_mode = KuavoManipulationMpcCtrlMode.NoControl
83
+ self._manipulation_mpc_control_flow = KuavoManipulationMpcControlFlow.ThroughFullBodyMpc
84
+
85
+ self._arm_ctrl_mode = KuavoArmCtrlMode.AutoSwing
86
+
87
+ # register gait changed callback
88
+ self._rb_state.register_gait_changed_callback(self._humanoid_gait_changed)
89
+ # initialized
90
+ self._initialized = True
91
+
92
+ def initialize(self, debug: bool=False)->bool:
93
+ """
94
+ raise RuntimeError if initialize failed.
95
+ """
96
+ try:
97
+ # init state by gait_name
98
+ gait_name = self._rb_state.gait_name()
99
+ if gait_name is not None:
100
+ to_method = f'to_{gait_name}'
101
+ if hasattr(self, to_method):
102
+ SDKLogger.debug(f"[Core] initialize state: {gait_name}")
103
+ # Call the transition method if it exists
104
+ getattr(self, to_method)()
105
+ else:
106
+ SDKLogger.warn(f"[Core] gait_name is None, use default `stance`")
107
+ # init arm control mode
108
+ arm_ctrl_mode = self._rb_state.arm_control_mode
109
+ if arm_ctrl_mode is not None:
110
+ self._arm_ctrl_mode = arm_ctrl_mode
111
+ SDKLogger.debug(f"[Core] initialize arm control mode: {arm_ctrl_mode}")
112
+
113
+ # init manipulation mpc
114
+ manipulation_mpc_frame = self._rb_state.manipulation_mpc_frame
115
+ if manipulation_mpc_frame is not None:
116
+ self._manipulation_mpc_frame = manipulation_mpc_frame
117
+ SDKLogger.debug(f"[Core] initialize manipulation mpc frame: {manipulation_mpc_frame}")
118
+ manipulation_mpc_ctrl_mode = self._rb_state.manipulation_mpc_ctrl_mode
119
+ if manipulation_mpc_ctrl_mode is not None:
120
+ self._manipulation_mpc_ctrl_mode = manipulation_mpc_ctrl_mode
121
+ SDKLogger.debug(f"[Core] initialize manipulation mpc ctrl mode: {manipulation_mpc_ctrl_mode}")
122
+ manipulation_mpc_control_flow = self._rb_state.manipulation_mpc_control_flow
123
+ if manipulation_mpc_control_flow is not None:
124
+ self._manipulation_mpc_control_flow = manipulation_mpc_control_flow
125
+ SDKLogger.debug(f"[Core] initialize manipulation mpc control flow: {manipulation_mpc_control_flow}")
126
+
127
+ except Exception as e:
128
+ raise RuntimeError(f"[Core] initialize failed: \n"
129
+ f"{e}, please check the robot is launched, "
130
+ f"e.g. `roslaunch humanoid_controllers load_kuavo_real.launch`")
131
+ rb_info = make_robot_param()
132
+ success, err_msg = self._control.initialize(eef_type=rb_info["end_effector_type"], debug=debug)
133
+ if not success:
134
+ raise RuntimeError(f"[Core] initialize failed: \n{err_msg}, please check the robot is launched, "
135
+ f"e.g. `roslaunch humanoid_controllers load_kuavo_real.launch`")
136
+ return True
137
+
138
+ """ ----------------------- Machine State -----------------------"""
139
+ def _on_enter_stance(self, event):
140
+ previous_state = event.transition.source
141
+ if self.state == previous_state:
142
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in stance state")
143
+ return
144
+
145
+ SDKLogger.debug(f"[Core] [StateMachine] Entering stance state, from {previous_state}")
146
+ if previous_state == 'walk':
147
+ self._control.robot_walk(0.0, 0.0, 0.0) # stop walk state
148
+ start_time = time.time()
149
+ # slow down walk
150
+ try:
151
+ while time.time() - start_time < 1.5:
152
+ self._control.robot_walk(0.0, 0.0, 0.0)
153
+ # linear_x, linear_y, angular_z
154
+ if (abs(self._rb_state.odom_data.linear[0]) < 0.05 and abs(self._rb_state.odom_data.linear[1]) < 0.08
155
+ and abs(self._rb_state.odom_data.angular[2]) < 0.05):
156
+ SDKLogger.debug(f"walk stop, time_cost:{time.time() - start_time}, odom_data:{self._rb_state.odom_data.linear}")
157
+ break
158
+ # SDKLogger.debug(f"kuavo robot linear: {self._rb_state.odom_data.linear}")
159
+ time.sleep(0.1)
160
+ except KeyboardInterrupt:
161
+ pass
162
+ self._control.robot_stance()
163
+ else:
164
+ self._control.robot_stance()
165
+ time.sleep(0.5)
166
+
167
+ def _on_enter_walk(self, event):
168
+ previous_state = event.transition.source
169
+ if self.state == previous_state:
170
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in walk state")
171
+ return
172
+ SDKLogger.debug(f"[Core] [StateMachine] Entering walk state, from {previous_state}")
173
+
174
+ def _on_enter_trot(self, event):
175
+ previous_state = event.transition.source
176
+ if self.state == previous_state:
177
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in trot state")
178
+ return
179
+ SDKLogger.debug(f"[Core] [StateMachine] Entering trot state, from {previous_state}")
180
+ self._control.robot_trot()
181
+
182
+ def _on_enter_custom_gait(self, event):
183
+ previous_state = event.transition.source
184
+ if self.state == previous_state:
185
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in custom_gait state")
186
+ return
187
+ SDKLogger.debug(f"[Core] [StateMachine] Entering custom_gait state, from {previous_state}")
188
+
189
+ def _on_enter_command_pose_world(self, event):
190
+ previous_state = event.transition.source
191
+ if self.state == previous_state:
192
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in command_pose_world state")
193
+ return
194
+ SDKLogger.debug(f"[Core] [StateMachine] Entering command_pose_world state, from {previous_state}")
195
+
196
+ def _on_enter_command_pose(self, event):
197
+ previous_state = event.transition.source
198
+ if self.state == previous_state:
199
+ SDKLogger.debug(f"[Core] [StateMachine] State unchanged: already in command_pose state")
200
+ return
201
+ SDKLogger.debug(f"[Core] [StateMachine] Entering command_pose state, from {previous_state}")
202
+
203
+ """ -------------------------------------------------------------"""
204
+
205
+ """ --------------------------- Control -------------------------"""
206
+ def walk(self, linear_x:float, linear_y:float, angular_z:float)-> bool:
207
+ if self.state != 'walk':
208
+ self.to_walk()
209
+
210
+ # +-0.4, +-0.2, +-0.4 => linear_x, linear_y, angular_z
211
+ limited_linear_x = min(0.4, abs(linear_x)) * (1 if linear_x >= 0 else -1)
212
+ limited_linear_y = min(0.2, abs(linear_y)) * (1 if linear_y >= 0 else -1)
213
+ limited_angular_z = min(0.4, abs(angular_z)) * (1 if angular_z >= 0 else -1)
214
+ return self._control.robot_walk(limited_linear_x, limited_linear_y, limited_angular_z)
215
+
216
+ def squat(self, height:float, pitch:float)->bool:
217
+ if self.state != 'stance':
218
+ SDKLogger.warn(f"[Core] control torso height failed, robot is not in stance state({self.state})!")
219
+ return False
220
+
221
+ MIN_HEIGHT = -0.35
222
+ MAX_HEIGHT = 0.0
223
+ MIN_PITCH = -0.4
224
+ MAX_PITCH = 0.4
225
+
226
+ # Limit height range
227
+ limited_height = min(MAX_HEIGHT, max(MIN_HEIGHT, height))
228
+ if height > MAX_HEIGHT or height < MIN_HEIGHT:
229
+ SDKLogger.warn(f"[Core] height {height} exceeds limit [{MIN_HEIGHT}, {MAX_HEIGHT}], will be limited")
230
+
231
+ # Limit pitch range
232
+ limited_pitch = min(MAX_PITCH, max(MIN_PITCH, pitch))
233
+ if abs(pitch) > MAX_PITCH:
234
+ SDKLogger.warn(f"[Core] pitch {pitch} exceeds limit [{MIN_PITCH}, {MAX_PITCH}], will be limited")
235
+
236
+ return self._control.control_torso_height(limited_height, limited_pitch)
237
+
238
+ def step_control(self, target_pose:list, dt:float=0.4, is_left_first_default:bool=True, collision_check:bool=True)->bool:
239
+ """
240
+ Control the robot's motion by step.
241
+ Raises:
242
+ ValueError: If target_pose length is not 4.
243
+ RuntimeError: If the robot is not in stance state when trying to control step motion.
244
+ """
245
+ if len(target_pose) != 4:
246
+ raise ValueError(f"[Core] target_pose length must be 4, but got {len(target_pose)}")
247
+
248
+ # Wait up to 1.0s for stance state
249
+ wait_time = 0
250
+ while self._rb_state.gait_name() != 'stance' and wait_time < 1.0:
251
+ time.sleep(0.1)
252
+ wait_time += 0.1
253
+
254
+ if self._rb_state.gait_name() != 'stance':
255
+ raise RuntimeError(f"[Core] control robot step failed, robot is not in stance state, {self._rb_state.gait_name()}!")
256
+
257
+ if self.state != 'stance':
258
+ raise RuntimeError(f"[Core] control robot step failed, robot is not in stance state({self.state})!")
259
+
260
+ com_height = self._rb_state.com_height
261
+ # print(f"[Core] Current COM height: {com_height:.2f}m")
262
+ # Check height limits based on current COM height
263
+ MIN_COM_HEIGHT = 0.66 # Minimum allowed COM height in meters
264
+ MAX_COM_HEIGHT = 0.86 # Maximum allowed COM height in meters
265
+
266
+ # Validate COM height constraints
267
+ if target_pose[2] < 0 and com_height < MIN_COM_HEIGHT:
268
+ SDKLogger.warn(f"[Core] Cannot squat lower: COM height {com_height:.2f}m below minimum {MIN_COM_HEIGHT}m")
269
+ return None
270
+
271
+ if target_pose[2] > 0 and com_height > MAX_COM_HEIGHT:
272
+ SDKLogger.warn(f"[Core] Cannot stand higher: COM height {com_height:.2f}m above maximum {MAX_COM_HEIGHT}m")
273
+ return None
274
+
275
+ # Ensure target height is within allowed range if height change requested
276
+ if target_pose[2] != 0:
277
+ target_height = com_height + target_pose[2]
278
+ if target_height < MIN_COM_HEIGHT:
279
+ SDKLogger.warn(f"[Core] Target height {target_height:.2f}m below minimum {MIN_COM_HEIGHT}m, limiting")
280
+ target_pose[2] = MIN_COM_HEIGHT - com_height
281
+ elif target_height > MAX_COM_HEIGHT:
282
+ SDKLogger.warn(f"[Core] Target height {target_height:.2f}m above maximum {MAX_COM_HEIGHT}m, limiting")
283
+ target_pose[2] = MAX_COM_HEIGHT - com_height
284
+
285
+ # TODO(kuavo): 根据实物测试来调整....
286
+ if com_height > 0.82:
287
+ max_x_step = 0.20
288
+ max_y_step = 0.20
289
+ max_yaw_step = 90
290
+ else:
291
+ max_x_step = 0.15
292
+ max_y_step = 0.15
293
+ max_yaw_step = 45
294
+
295
+ body_poses = []
296
+
297
+ # 计算目标点到原点的距离和朝向
298
+ target_dist_x = abs(target_pose[0])
299
+ target_dist_y = abs(target_pose[1])
300
+ target_yaw = target_pose[3] * 180 / math.pi # Convert yaw from radians to degrees
301
+
302
+ # 计算需要的步数(考虑x位移、y位移和转角)
303
+ steps_for_x = int(np.ceil(target_dist_x / max_x_step))
304
+ steps_for_y = int(np.ceil(target_dist_y / max_y_step))
305
+ steps_for_yaw = int(np.ceil(abs(target_yaw) / max_yaw_step))
306
+ steps_needed = max(steps_for_x, steps_for_y, steps_for_yaw)
307
+ # print(f"[Core] Steps needed - X: {steps_for_x}, Y: {steps_for_y}, Yaw: {steps_for_yaw}, Total: {steps_needed}")
308
+
309
+ # 计算每一步的增量
310
+ dx = target_pose[0] / steps_needed
311
+ dy = target_pose[1] / steps_needed
312
+ dyaw = target_yaw / steps_needed
313
+
314
+ # 分解为多个小步,沿着直线路径前进并逐步调整朝向
315
+ for i in range(steps_needed):
316
+ x = dx * (i+1)
317
+ y = dy * (i+1)
318
+ z = target_pose[2]
319
+ yaw = dyaw * (i+1)
320
+ body_poses.append([x, y, 0.0, yaw])
321
+
322
+ # print("target_pose:", target_pose)
323
+ # print("body_poses:", body_poses)
324
+
325
+ if not self._control.step_control(body_poses, dt, is_left_first_default, collision_check):
326
+ return False
327
+
328
+ # Wait for gait to switch to custom_gait
329
+ start_time = time.time()
330
+ while not self._rb_state.is_gait('custom_gait'):
331
+ if time.time() - start_time > 1.0: # 1.0s timeout
332
+ SDKLogger.warn("[Core] Timeout waiting for gait to switch to custom_gait")
333
+ return False
334
+ time.sleep(0.01)
335
+
336
+ return True
337
+
338
+ def control_command_pose(self, target_pose_x:float, target_pose_y:float, target_pose_z:float, target_pose_yaw:float)->bool:
339
+ """
340
+ Control robot pose in base_link frame
341
+
342
+ Arguments:
343
+ - target_pose_x: x position (meters)
344
+ - target_pose_y: y position (meters)
345
+ - target_pose_z: z position (meters)
346
+ - target_pose_yaw: yaw angle (radians)
347
+
348
+ Returns:
349
+ bool: True if command was sent successfully, False otherwise
350
+
351
+ Raises:
352
+ RuntimeError: If robot is not in stance state
353
+ """
354
+ if self.state != 'stance':
355
+ raise RuntimeError(f"[Core] control_command_pose failed: robot must be in stance state, current state: {self.state}")
356
+
357
+ # Add any parameter validation if needed
358
+ # e.g., limit ranges for safety
359
+ self.to_command_pose()
360
+ return self._control.control_command_pose(target_pose_x, target_pose_y, target_pose_z, target_pose_yaw)
361
+
362
+ def control_command_pose_world(self, target_pose_x:float, target_pose_y:float, target_pose_z:float, target_pose_yaw:float)->bool:
363
+ """
364
+ Control robot pose in odom (world) frame
365
+
366
+ Arguments:
367
+ - target_pose_x: x position (meters)
368
+ - target_pose_y: y position (meters)
369
+ - target_pose_z: z position (meters)
370
+ - target_pose_yaw: yaw angle (radians)
371
+
372
+ Returns:
373
+ bool: True if command was sent successfully, False otherwise
374
+
375
+ Raises:
376
+ RuntimeError: If robot is not in stance state
377
+ """
378
+ # if self.state != 'stance':
379
+ # raise RuntimeError(f"[Core] control_command_pose_world failed: robot must be in stance state, current state: {self.state}")
380
+
381
+ # Add any parameter validation if needed
382
+ # e.g., limit ranges for safety
383
+ self.to_command_pose_world()
384
+ return self._control.control_command_pose_world(target_pose_x, target_pose_y, target_pose_z, target_pose_yaw)
385
+
386
+ def execute_gesture(self, gestures:list)->bool:
387
+ return self._control.execute_gesture(gestures)
388
+
389
+ def get_gesture_names(self)->list:
390
+ return self._control.get_gesture_names()
391
+
392
+ def control_robot_dexhand(self, left_position:list, right_position:list)->bool:
393
+ return self._control.control_robot_dexhand(left_position, right_position)
394
+
395
+ def robot_dexhand_command(self, data, ctrl_mode, hand_side):
396
+ return self._control.robot_dexhand_command(data, ctrl_mode, hand_side)
397
+
398
+
399
+ def control_leju_claw(self, postions:list, velocities:list=[90, 90], torques:list=[1.0, 1.0]) ->bool:
400
+ return self._control.control_leju_claw(postions, velocities, torques)
401
+
402
+ def control_robot_head(self, yaw:float, pitch:float)->bool:
403
+ # Convert radians to degrees
404
+ yaw_deg = yaw * 180 / math.pi
405
+ pitch_deg = pitch * 180 / math.pi
406
+ return self._control.control_robot_head(yaw_deg, pitch_deg)
407
+
408
+ def enable_head_tracking(self, target_id: int)->bool:
409
+ return self._control.enable_head_tracking(target_id)
410
+
411
+ def disable_head_tracking(self)->bool:
412
+ return self._control.disable_head_tracking()
413
+
414
+ def control_robot_arm_joint_positions(self, joint_data:list)->bool:
415
+ if self.state != 'stance':
416
+ raise RuntimeError(f"[Core] control_robot_arm_joint_positions failed: robot must be in stance state, current state: {self.state}")
417
+
418
+ # change to external control mode
419
+ if self._arm_ctrl_mode != KuavoArmCtrlMode.ExternalControl:
420
+ SDKLogger.debug("[Core] control_robot_arm_joint_positions, current arm mode != ExternalControl, change it.")
421
+ if not self.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl):
422
+ SDKLogger.warn("[Core] control_robot_arm_joint_positions failed, change robot arm ctrl mode failed!")
423
+ return False
424
+ return self._control.control_robot_arm_joint_positions(joint_data)
425
+
426
+ def control_robot_arm_joint_trajectory(self, times:list, joint_q:list)->bool:
427
+ if self.state != 'stance':
428
+ raise RuntimeError("[Core] control_robot_arm_joint_trajectory failed: robot must be in stance state")
429
+
430
+ if self._arm_ctrl_mode != KuavoArmCtrlMode.ExternalControl:
431
+ SDKLogger.debug("[Core] control_robot_arm_joint_trajectory, current arm mode != ExternalControl, change it.")
432
+ if not self.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl):
433
+ SDKLogger.warn("[Core] control_robot_arm_joint_trajectory failed, change robot arm ctrl mode failed!")
434
+ return False
435
+
436
+ return self._control.control_robot_arm_joint_trajectory(times, joint_q)
437
+
438
+ def control_robot_end_effector_pose(self, left_pose: KuavoPose, right_pose: KuavoPose, frame: KuavoManipulationMpcFrame)->bool:
439
+ if self._arm_ctrl_mode != KuavoArmCtrlMode.ExternalControl:
440
+ SDKLogger.debug("[Core] control_robot_end_effector_pose, current arm mode != ExternalControl, change it.")
441
+ if not self.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl):
442
+ SDKLogger.warn("[Core] control_robot_end_effector_pose failed, change robot arm ctrl mode failed!")
443
+ return False
444
+
445
+ if self._manipulation_mpc_ctrl_mode == KuavoManipulationMpcCtrlMode.NoControl:
446
+ SDKLogger.debug("[Core] control_robot_end_effector_pose, manipulation mpc ctrl mode is NoControl, change it.")
447
+ if not self.change_manipulation_mpc_ctrl_mode(KuavoManipulationMpcCtrlMode.ArmOnly):
448
+ SDKLogger.warn("[Core] control_robot_end_effector_pose failed, change manipulation mpc ctrl mode failed!")
449
+ return False
450
+
451
+ return self._control.control_robot_end_effector_pose(left_pose, right_pose, frame)
452
+
453
+ def change_manipulation_mpc_frame(self, frame: KuavoManipulationMpcFrame)->bool:
454
+ timeout = 1.0
455
+ count = 0
456
+ while self._rb_state.manipulation_mpc_frame != frame:
457
+ SDKLogger.debug(f"[Core] Change manipulation mpc frame from {self._rb_state.manipulation_mpc_frame} to {frame}, retry: {count}")
458
+ self._control.change_manipulation_mpc_frame(frame)
459
+ if self._rb_state.manipulation_mpc_frame == frame:
460
+ break
461
+ if timeout <= 0:
462
+ SDKLogger.warn("[Core] Change manipulation mpc frame timeout!")
463
+ return False
464
+ timeout -= 0.1
465
+ time.sleep(0.1)
466
+ count += 1
467
+ if not hasattr(self, '_manipulation_mpc_frame_lock'):
468
+ self._manipulation_mpc_frame_lock = threading.Lock()
469
+ with self._manipulation_mpc_frame_lock:
470
+ self._manipulation_mpc_frame = frame
471
+ return True
472
+
473
+ def change_manipulation_mpc_ctrl_mode(self, control_mode: KuavoManipulationMpcCtrlMode)->bool:
474
+ timeout = 1.0
475
+ count = 0
476
+ while self._rb_state.manipulation_mpc_ctrl_mode != control_mode:
477
+ SDKLogger.debug(f"[Core] Change manipulation mpc ctrl mode from {self._rb_state.manipulation_mpc_ctrl_mode} to {control_mode}, retry: {count}")
478
+ self._control.change_manipulation_mpc_ctrl_mode(control_mode)
479
+ if self._rb_state.manipulation_mpc_ctrl_mode == control_mode:
480
+ break
481
+ if timeout <= 0:
482
+ SDKLogger.warn("[Core] Change manipulation mpc ctrl mode timeout!")
483
+ return False
484
+ timeout -= 0.1
485
+ time.sleep(0.1)
486
+ count += 1
487
+ if not hasattr(self, '_manipulation_mpc_ctrl_mode_lock'):
488
+ self._manipulation_mpc_ctrl_mode_lock = threading.Lock()
489
+ with self._manipulation_mpc_ctrl_mode_lock:
490
+ self._manipulation_mpc_ctrl_mode = control_mode
491
+ return True
492
+
493
+ def change_manipulation_mpc_control_flow(self, control_flow: KuavoManipulationMpcControlFlow)->bool:
494
+ timeout = 1.0
495
+ count = 0
496
+ while self._rb_state.manipulation_mpc_control_flow != control_flow:
497
+ SDKLogger.debug(f"[Core] Change manipulation mpc control flow from {self._rb_state.manipulation_mpc_control_flow} to {control_flow}, retry: {count}")
498
+ self._control.change_manipulation_mpc_control_flow(control_flow)
499
+ if self._rb_state.manipulation_mpc_control_flow == control_flow:
500
+ break
501
+ if timeout <= 0:
502
+ SDKLogger.warn("[Core] Change manipulation mpc control flow timeout!")
503
+ return False
504
+ timeout -= 0.1
505
+ time.sleep(0.1)
506
+ count += 1
507
+ if not hasattr(self, '_manipulation_mpc_control_flow_lock'):
508
+ self._manipulation_mpc_control_flow_lock = threading.Lock()
509
+ with self._manipulation_mpc_control_flow_lock:
510
+ self._manipulation_mpc_control_flow = control_flow
511
+ return True
512
+
513
+ def change_robot_arm_ctrl_mode(self, mode:KuavoArmCtrlMode)->bool:
514
+ timeout = 1.0
515
+ count = 0
516
+ while self._rb_state.arm_control_mode != mode:
517
+ SDKLogger.debug(f"[Core] Change robot arm control from {self._rb_state.arm_control_mode} to {mode}, retry: {count}")
518
+ self._control.change_robot_arm_ctrl_mode(mode)
519
+ if self._rb_state.arm_control_mode == mode:
520
+ break
521
+ if timeout <= 0:
522
+ SDKLogger.warn("[Core] Change robot arm control mode timeout!")
523
+ return False
524
+ timeout -= 0.1
525
+ time.sleep(0.1)
526
+ count += 1
527
+
528
+ if not hasattr(self, '_arm_ctrl_mode_lock'):
529
+ self._arm_ctrl_mode_lock = threading.Lock()
530
+ with self._arm_ctrl_mode_lock:
531
+ # 手臂控制模式切换成功,更新当前手臂控制模式
532
+ self._arm_ctrl_mode = mode # update arm ctrl mode
533
+
534
+ return True
535
+
536
+ def robot_arm_reset(self)->bool:
537
+ if self.state != 'stance':
538
+ SDKLogger.warn("[Core] robot arm reset failed, robot is not in stance state!")
539
+ return
540
+
541
+ # init_pos = [0.0]*14
542
+ # if not self.control_robot_arm_joint_trajectory([1.5], [init_pos]):
543
+ # SDKLogger.warn("[Core] robot arm reset failed, control robot arm traj failed!")
544
+ # return False
545
+
546
+ return self.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.AutoSwing)
547
+
548
+ def robot_manipulation_mpc_reset(self)->bool:
549
+ if self._manipulation_mpc_ctrl_mode != KuavoManipulationMpcCtrlMode.NoControl:
550
+ SDKLogger.debug("[Core] robot manipulation mpc reset, current manipulation mpc ctrl mode != NoControl, change it.")
551
+ if not self.change_manipulation_mpc_ctrl_mode(KuavoManipulationMpcCtrlMode.NoControl):
552
+ SDKLogger.warn("[Core] robot manipulation mpc reset failed, change manipulation mpc ctrl mode failed!")
553
+ return False
554
+ if self._manipulation_mpc_control_flow != KuavoManipulationMpcControlFlow.ThroughFullBodyMpc:
555
+ SDKLogger.debug("[Core] robot manipulation mpc reset, current manipulation mpc control flow != ThroughFullBodyMpc, change it.")
556
+ if not self.change_manipulation_mpc_control_flow(KuavoManipulationMpcControlFlow.ThroughFullBodyMpc):
557
+ SDKLogger.warn("[Core] robot manipulation mpc reset failed, change manipulation mpc control flow failed!")
558
+ return False
559
+ return True
560
+ """ ------------------------------------------------------------------------"""
561
+ """ 电机参数设置 """
562
+ def change_motor_param(self, motor_param:list)-> Tuple[bool, str]:
563
+ return self._control.change_motor_param(motor_param)
564
+
565
+ def get_motor_param(self)-> Tuple[bool, list]:
566
+ success, param, _ = self._control.get_motor_param()
567
+ return success, param
568
+
569
+ """ ------------------------------------------------------------------------"""
570
+ """ Arm Forward kinematics && Arm Inverse kinematics """
571
+ def arm_ik(self,
572
+ l_eef_pose: KuavoPose,
573
+ r_eef_pose: KuavoPose,
574
+ l_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
575
+ r_elbow_pos_xyz: list = [0.0, 0.0, 0.0],
576
+ arm_q0: list = None,
577
+ params: KuavoIKParams=None) -> list:
578
+ return self._control.arm_ik(l_eef_pose, r_eef_pose, l_elbow_pos_xyz, r_elbow_pos_xyz, arm_q0, params)
579
+
580
+
581
+ def arm_fk(self, q: list) -> Tuple[KuavoPose, KuavoPose]:
582
+ return self._control.arm_fk(q)
583
+
584
+ """ Callbacks """
585
+ def _humanoid_gait_changed(self, current_time: float, gait_name: str):
586
+ if self.state != gait_name:
587
+ # Check if to_$gait_name method exists
588
+ to_method = f'to_{gait_name}'
589
+ if hasattr(self, to_method):
590
+ SDKLogger.debug(f"[Core] Received gait change notification: {gait_name} at time {current_time}")
591
+ # Call the transition method if it exists
592
+ getattr(self, to_method)()
593
+
594
+
595
+ if __name__ == "__main__":
596
+ DEBUG_MODE = 0
597
+ core = KuavoRobotCore()
598
+ core.initialize()
599
+
600
+ if DEBUG_MODE == 0:
601
+ time.sleep(1.0)
602
+ core.change_robot_arm_ctrl_mode(KuavoArmCtrlMode.ExternalControl)
603
+ core.change_manipulation_mpc_frame(KuavoManipulationMpcFrame.VRFrame)
604
+ core.change_manipulation_mpc_ctrl_mode(KuavoManipulationMpcCtrlMode.ArmOnly)
605
+ core.change_manipulation_mpc_control_flow(KuavoManipulationMpcControlFlow.DirectToWbc)
606
+ core.robot_manipulation_mpc_reset()
607
+ elif DEBUG_MODE == 1:
608
+ core.to_stance()
609
+ print("state now is to_stance:", core.state)
610
+ core.control_command_pose_world(0.0, 1.0, 0.0, 1.57)
611
+ print("state now is control_command_pose_world:", core.state)
612
+ elif DEBUG_MODE == 2:
613
+ core.to_trot()
614
+ print("state now is to_trot:", core.state)
615
+ time.sleep(3.0)
616
+ core.to_stance()
617
+ print("state now is to_stance:", core.state)