kuavo-humanoid-sdk 1.2.1b3295__20250916004502-py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kuavo-humanoid-sdk might be problematic. Click here for more details.
- kuavo_humanoid_sdk/__init__.py +6 -0
- kuavo_humanoid_sdk/common/logger.py +45 -0
- kuavo_humanoid_sdk/interfaces/__init__.py +4 -0
- kuavo_humanoid_sdk/interfaces/data_types.py +288 -0
- kuavo_humanoid_sdk/interfaces/end_effector.py +62 -0
- kuavo_humanoid_sdk/interfaces/robot.py +22 -0
- kuavo_humanoid_sdk/interfaces/robot_info.py +56 -0
- kuavo_humanoid_sdk/kuavo/__init__.py +16 -0
- kuavo_humanoid_sdk/kuavo/core/audio.py +32 -0
- kuavo_humanoid_sdk/kuavo/core/core.py +666 -0
- kuavo_humanoid_sdk/kuavo/core/dex_hand_control.py +114 -0
- kuavo_humanoid_sdk/kuavo/core/leju_claw_control.py +67 -0
- kuavo_humanoid_sdk/kuavo/core/llm_doubao.py +608 -0
- kuavo_humanoid_sdk/kuavo/core/microphone.py +192 -0
- kuavo_humanoid_sdk/kuavo/core/navigation.py +70 -0
- kuavo_humanoid_sdk/kuavo/core/ros/audio.py +110 -0
- kuavo_humanoid_sdk/kuavo/core/ros/camera.py +105 -0
- kuavo_humanoid_sdk/kuavo/core/ros/control.py +1524 -0
- kuavo_humanoid_sdk/kuavo/core/ros/microphone.py +38 -0
- kuavo_humanoid_sdk/kuavo/core/ros/navigation.py +217 -0
- kuavo_humanoid_sdk/kuavo/core/ros/observation.py +94 -0
- kuavo_humanoid_sdk/kuavo/core/ros/param.py +201 -0
- kuavo_humanoid_sdk/kuavo/core/ros/sat_utils.py +103 -0
- kuavo_humanoid_sdk/kuavo/core/ros/state.py +652 -0
- kuavo_humanoid_sdk/kuavo/core/ros/tools.py +220 -0
- kuavo_humanoid_sdk/kuavo/core/ros/vision.py +234 -0
- kuavo_humanoid_sdk/kuavo/core/ros_env.py +238 -0
- kuavo_humanoid_sdk/kuavo/core/sdk_deprecated.py +41 -0
- kuavo_humanoid_sdk/kuavo/demo_climbstair.py +249 -0
- kuavo_humanoid_sdk/kuavo/dexterous_hand.py +238 -0
- kuavo_humanoid_sdk/kuavo/leju_claw.py +235 -0
- kuavo_humanoid_sdk/kuavo/logger_client.py +80 -0
- kuavo_humanoid_sdk/kuavo/robot.py +561 -0
- kuavo_humanoid_sdk/kuavo/robot_arm.py +411 -0
- kuavo_humanoid_sdk/kuavo/robot_audio.py +39 -0
- kuavo_humanoid_sdk/kuavo/robot_blockly.py +1154 -0
- kuavo_humanoid_sdk/kuavo/robot_climbstair.py +1607 -0
- kuavo_humanoid_sdk/kuavo/robot_head.py +95 -0
- kuavo_humanoid_sdk/kuavo/robot_info.py +134 -0
- kuavo_humanoid_sdk/kuavo/robot_microphone.py +19 -0
- kuavo_humanoid_sdk/kuavo/robot_navigation.py +135 -0
- kuavo_humanoid_sdk/kuavo/robot_observation.py +64 -0
- kuavo_humanoid_sdk/kuavo/robot_speech.py +24 -0
- kuavo_humanoid_sdk/kuavo/robot_state.py +310 -0
- kuavo_humanoid_sdk/kuavo/robot_tool.py +109 -0
- kuavo_humanoid_sdk/kuavo/robot_vision.py +81 -0
- kuavo_humanoid_sdk/kuavo_strategy/__init__.py +2 -0
- kuavo_humanoid_sdk/kuavo_strategy/grasp_box/grasp_box_strategy.py +1325 -0
- kuavo_humanoid_sdk/kuavo_strategy/kuavo_strategy.py +106 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/common/data_type.py +340 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/common/events/base_event.py +215 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/common/robot_sdk.py +25 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/pick_place_box/case.py +331 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/pick_place_box/strategy.py +504 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/utils/logger_setup.py +40 -0
- kuavo_humanoid_sdk/kuavo_strategy_v2/utils/utils.py +88 -0
- kuavo_humanoid_sdk/msg/__init__.py +4 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/__init__.py +7 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetection.py +306 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AprilTagDetectionArray.py +437 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_AudioReceiverData.py +122 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_FTsensorData.py +260 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_JoySticks.py +191 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_Metadata.py +199 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_MmDetectionMsg.py +264 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_RobotActionState.py +112 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_TFArray.py +323 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_TaskPoint.py +175 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/__init__.py +62 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armCollisionCheckInfo.py +160 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armHandPose.py +161 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armHandPoseFree.py +171 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armPoseWithTimeStamp.py +168 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_armTargetPoses.py +171 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_bezierCurveCubicPoint.py +178 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandCommand.py +229 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_dexhandTouchState.py +256 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_endEffectorData.py +227 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPose.py +123 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPose6D.py +123 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPose6DTargetTrajectories.py +320 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoseTargetTrajectories.py +301 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoseWithVision.py +136 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoseWithVisionArray.py +231 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoses.py +149 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_footPoses6D.py +149 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_fullBodyTargetTrajectories.py +258 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gaitTimeName.py +147 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureInfo.py +218 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_gestureTask.py +149 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_handPose.py +136 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_headBodyPose.py +145 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveError.py +171 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_ikSolveParam.py +140 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_imuData.py +165 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointBezierTrajectory.py +201 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointCmd.py +390 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_jointData.py +205 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_kuavoModeSchedule.py +224 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawCommand.py +320 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_lejuClawState.py +341 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_motorParam.py +122 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_picoPoseInfo.py +143 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_picoPoseInfoList.py +220 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_planArmState.py +120 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_qv.py +121 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotArmQVVD.py +177 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotBodyMatrices.py +332 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHandPosition.py +225 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotHeadMotionData.py +128 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_robotState.py +222 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_sensorsData.py +655 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_switchGaitByName.py +200 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_tagDataArray.py +216 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_touchSensorStatus.py +162 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPose.py +273 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmd.py +316 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseCmdFree.py +338 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_twoArmHandPoseFree.py +299 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloDetection.py +251 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/msg/_yoloOutputData.py +168 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_CreatePath.py +581 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_ExecuteArmAction.py +281 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_GetAllMaps.py +241 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_GetCurrentMap.py +225 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_GetTargetPartPoseInCamera.py +298 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_InitialPoseWithTaskPoint.py +281 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_LoadMap.py +281 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_NavigateToTaskPoint.py +281 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_RepublishTFs.py +373 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetInitialPose.py +394 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetJoyTopic.py +282 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetLEDMode.py +468 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SetLEDMode_free.py +289 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_SpeechSynthesis.py +270 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_TaskPointOperation.py +536 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/__init__.py +43 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_adjustZeroPoint.py +277 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlMode.py +275 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeArmCtrlModeKuavo.py +236 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeMotorParam.py +299 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_changeTorsoCtrlMode.py +274 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_controlLejuClaw.py +408 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_enableHandTouchSensor.py +304 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_fkSrv.py +395 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_footPose6DTargetTrajectoriesSrv.py +426 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_footPoseTargetTrajectoriesSrv.py +409 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecute.py +339 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureExecuteState.py +257 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_gestureList.py +418 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getCurrentGaitName.py +253 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getMotorParam.py +299 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_getMotorZeroPoints.py +286 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_handForceLevel.py +330 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_jointMoveTo.py +302 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryBezierCurve.py +422 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_planArmTrajectoryCubicSpline.py +490 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_playmusic.py +268 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setHwIntialState.py +304 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMmCtrlFrame.py +273 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setMotorEncoderRoundService.py +283 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_setTagId.py +275 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_singleStepControl.py +444 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdFreeSrv.py +716 -0
- kuavo_humanoid_sdk/msg/kuavo_msgs/srv/_twoArmHandPoseCmdSrv.py +664 -0
- kuavo_humanoid_sdk/msg/motion_capture_ik/__init__.py +7 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/__init__.py +7 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/__init__.py +12 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_constraint.py +142 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_controller_data.py +121 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_lagrangian_metrics.py +148 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mode_schedule.py +150 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_flattened_controller.py +666 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_input.py +122 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_observation.py +209 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_performance_indices.py +140 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_solver_data.py +886 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_state.py +122 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_mpc_target_trajectories.py +239 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/msg/_multiplier.py +148 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/srv/__init__.py +1 -0
- kuavo_humanoid_sdk/msg/ocs2_msgs/srv/_reset.py +376 -0
- kuavo_humanoid_sdk-1.2.1b3295.dist-info/METADATA +296 -0
- kuavo_humanoid_sdk-1.2.1b3295.dist-info/RECORD +186 -0
- kuavo_humanoid_sdk-1.2.1b3295.dist-info/WHEEL +6 -0
- kuavo_humanoid_sdk-1.2.1b3295.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
import rospy
|
|
4
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.microphone import Microphone
|
|
5
|
+
import contextlib, sys
|
|
6
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
7
|
+
|
|
8
|
+
from funasr import AutoModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RobotMicrophoneCore:
|
|
13
|
+
"""
|
|
14
|
+
The core logic for handling wake-up word detection using audio data provided by ROS nodes.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, subscribe_topic="/micphone_data"):
|
|
17
|
+
self.microphone = Microphone(subscribe_topic)
|
|
18
|
+
|
|
19
|
+
# 创建VAD和ASR两个模型
|
|
20
|
+
self.vad_model = AutoModel(model="fsmn-vad", model_revision="v2.0.4", disable_update=True)
|
|
21
|
+
self.asr_model = AutoModel(model="paraformer-zh-streaming", model_revision="v2.0.4",disable_update=True)
|
|
22
|
+
|
|
23
|
+
# 配置参数
|
|
24
|
+
self.CHUNK = 1024 # 每个缓冲区的帧数
|
|
25
|
+
self.target_sample_rate = 16000 # ASR模型的目标采样率
|
|
26
|
+
self.target_mic_keywords = ['夸父', '鲁班',] # 识别麦克风设备的关键词
|
|
27
|
+
|
|
28
|
+
# 流式识别相关参数
|
|
29
|
+
self.audio_buffer = [] # 音频缓冲区
|
|
30
|
+
self.vad_cache = {} # VAD模型缓存
|
|
31
|
+
self.asr_cache = {} # ASR模型缓存
|
|
32
|
+
self.silence_frames = 0 # 静音帧计数
|
|
33
|
+
self.max_silence_frames = int(1.0 * self.target_sample_rate / self.CHUNK) # 最大静音帧数(1秒)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# 语音段状态管理
|
|
37
|
+
self.speech_segment_buffer = [] # 语音段缓冲区
|
|
38
|
+
self.is_in_speech = False # 是否在语音段中
|
|
39
|
+
self.speech_start_time = 0 # 语音开始时间
|
|
40
|
+
self.consecutive_speech_frames = 0 # 连续语音帧计数
|
|
41
|
+
self.min_speech_frames = 3 # 最小连续语音帧数,防止误触发
|
|
42
|
+
|
|
43
|
+
# VAD配置
|
|
44
|
+
self.vad_chunk_size = 300 # 毫秒,VAD模型的块大小
|
|
45
|
+
self.vad_chunk_stride = int(self.vad_chunk_size * self.target_sample_rate / 1000) # 3200 采样点
|
|
46
|
+
|
|
47
|
+
# ASR配置
|
|
48
|
+
self.asr_chunk_size = [0, 10, 5] # [0, 10, 5] 表示600ms实时出字粒度
|
|
49
|
+
self.asr_encoder_chunk_look_back = 4 # 编码器回看的块数
|
|
50
|
+
self.asr_decoder_chunk_look_back = 1 # 解码器回看的块数
|
|
51
|
+
self.asr_chunk_stride = self.asr_chunk_size[1] * 960 # 9600 采样点 (600ms * 16kHz)
|
|
52
|
+
|
|
53
|
+
SDKLogger.debug("The audio processor node is ready.")
|
|
54
|
+
|
|
55
|
+
def wait_for_wake_word(self, timeout_sec=60, wake_word='鲁班鲁班'):
|
|
56
|
+
"""
|
|
57
|
+
Actively pull audio data, process it and wait for wake-up word detection.
|
|
58
|
+
Returns True if a wake-up word is detected within the timeout period, otherwise returns False.
|
|
59
|
+
"""
|
|
60
|
+
hot_word = [wake_word] + self.target_mic_keywords
|
|
61
|
+
start_time = rospy.get_time()
|
|
62
|
+
|
|
63
|
+
# 重置所有状态
|
|
64
|
+
self.audio_buffer = []
|
|
65
|
+
self.vad_cache = {}
|
|
66
|
+
self.asr_cache = {}
|
|
67
|
+
self.speech_segment_buffer = []
|
|
68
|
+
self.is_in_speech = False
|
|
69
|
+
self.silence_frames = 0
|
|
70
|
+
|
|
71
|
+
while not rospy.is_shutdown():
|
|
72
|
+
if rospy.get_time() - start_time > timeout_sec:
|
|
73
|
+
SDKLogger.debug("Timeout has been reached. No wake-up word was detected.")
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
new_data = self.microphone.get_data()
|
|
77
|
+
if new_data:
|
|
78
|
+
|
|
79
|
+
audio_np = np.frombuffer(new_data, dtype=np.int16).astype(np.float32) / 32768.0
|
|
80
|
+
|
|
81
|
+
self.audio_buffer.extend(audio_np)
|
|
82
|
+
# 检测是否有声音(简单的音量检测)
|
|
83
|
+
current_volume = np.sqrt(np.mean(audio_np**2))
|
|
84
|
+
|
|
85
|
+
# 调试:打印音量信息
|
|
86
|
+
# print(f"current_volume: {current_volume:.6f}")
|
|
87
|
+
|
|
88
|
+
# 调整音量阈值 - 对于归一化到[-1,1]的数据,静音应该在0.01以下
|
|
89
|
+
is_speaking = current_volume > 0.01
|
|
90
|
+
|
|
91
|
+
if is_speaking:
|
|
92
|
+
self.silence_frames = 0
|
|
93
|
+
else:
|
|
94
|
+
self.silence_frames += 1
|
|
95
|
+
|
|
96
|
+
# print(f"is_speaking: {is_speaking}")
|
|
97
|
+
# 当缓冲区有足够的数据时进行VAD检测
|
|
98
|
+
if len(self.audio_buffer) >= self.vad_chunk_stride:
|
|
99
|
+
|
|
100
|
+
# 提取一个VAD块的数据
|
|
101
|
+
vad_chunk = np.array(self.audio_buffer[:self.vad_chunk_stride], dtype=np.float64)
|
|
102
|
+
|
|
103
|
+
# 判断是否为最后一个块(静音超过阈值)
|
|
104
|
+
is_final = self.silence_frames >= self.max_silence_frames
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
# 使用VAD检测语音活动
|
|
108
|
+
with self.suppress_output():
|
|
109
|
+
vad_res = self.vad_model.generate(input=vad_chunk, cache=self.vad_cache, is_final=is_final, chunk_size=self.vad_chunk_size)
|
|
110
|
+
|
|
111
|
+
# print(vad_res)
|
|
112
|
+
# 检查VAD结果
|
|
113
|
+
has_speech = False
|
|
114
|
+
if len(vad_res) > 0 and "value" in vad_res[0] and vad_res[0]["value"]:
|
|
115
|
+
has_speech = True
|
|
116
|
+
|
|
117
|
+
# 语音段管理
|
|
118
|
+
if has_speech and not self.is_in_speech:
|
|
119
|
+
# 开始新的语音段
|
|
120
|
+
self.is_in_speech = True
|
|
121
|
+
self.speech_segment_buffer = []
|
|
122
|
+
SDKLogger.debug("🎤 检测到语音开始")
|
|
123
|
+
|
|
124
|
+
if self.is_in_speech:
|
|
125
|
+
# 在语音段中,累积音频数据
|
|
126
|
+
self.speech_segment_buffer.extend(vad_chunk)
|
|
127
|
+
|
|
128
|
+
if is_final and self.is_in_speech:
|
|
129
|
+
# 语音段结束,进行ASR识别
|
|
130
|
+
SDKLogger.debug("🔍 语音段结束,开始识别...")
|
|
131
|
+
|
|
132
|
+
if len(self.speech_segment_buffer) > 0:
|
|
133
|
+
# 将语音段数据转换为ASR格式
|
|
134
|
+
speech_segment = np.array(self.speech_segment_buffer, dtype=np.float64)
|
|
135
|
+
|
|
136
|
+
# 使用ASR进行识别
|
|
137
|
+
with self.suppress_output():
|
|
138
|
+
asr_res = self.asr_model.generate(input=speech_segment, cache=self.asr_cache, is_final=True,
|
|
139
|
+
chunk_size=self.asr_chunk_size,
|
|
140
|
+
encoder_chunk_look_back=self.asr_encoder_chunk_look_back,
|
|
141
|
+
decoder_chunk_look_back=self.asr_decoder_chunk_look_back, hotword=hot_word)
|
|
142
|
+
|
|
143
|
+
# 检查ASR结果
|
|
144
|
+
if len(asr_res) > 0:
|
|
145
|
+
# 检查不同的结果字段
|
|
146
|
+
recognized_text = ""
|
|
147
|
+
if "value" in asr_res[0] and asr_res[0]["value"]:
|
|
148
|
+
recognized_text = " ".join(asr_res[0]["value"])
|
|
149
|
+
elif "text" in asr_res[0] and asr_res[0]["text"]:
|
|
150
|
+
recognized_text = asr_res[0]["text"]
|
|
151
|
+
|
|
152
|
+
if recognized_text:
|
|
153
|
+
SDKLogger.debug(f"📝 识别结果: {recognized_text}")
|
|
154
|
+
if wake_word in recognized_text:
|
|
155
|
+
return True
|
|
156
|
+
else:
|
|
157
|
+
SDKLogger.debug("❌ 未能识别出内容")
|
|
158
|
+
else:
|
|
159
|
+
SDKLogger.debug("❌ ASR识别失败")
|
|
160
|
+
|
|
161
|
+
# 重置语音段状态
|
|
162
|
+
self.is_in_speech = False
|
|
163
|
+
self.speech_segment_buffer = []
|
|
164
|
+
self.vad_cache = {}
|
|
165
|
+
self.asr_cache = {}
|
|
166
|
+
SDKLogger.debug("--- 语音段处理完成 ---")
|
|
167
|
+
|
|
168
|
+
# 移除已处理的数据,保留一些重叠
|
|
169
|
+
# overlap = self.vad_chunk_stride // 2 # 50% 重叠
|
|
170
|
+
self.audio_buffer = self.audio_buffer[self.vad_chunk_stride:]
|
|
171
|
+
|
|
172
|
+
except Exception as e:
|
|
173
|
+
SDKLogger.debug(f"处理错误: {e}")
|
|
174
|
+
rospy.sleep(0.01) # 减少睡眠时间以提高响应性
|
|
175
|
+
|
|
176
|
+
# 创建输出抑制上下文管理器
|
|
177
|
+
@contextlib.contextmanager
|
|
178
|
+
def suppress_output(self):
|
|
179
|
+
"""临时抑制所有标准输出和错误输出"""
|
|
180
|
+
# 保存原始的标准输出和错误输出
|
|
181
|
+
old_stdout = sys.stdout
|
|
182
|
+
old_stderr = sys.stderr
|
|
183
|
+
# 重定向到空设备
|
|
184
|
+
with open(os.devnull, 'w') as devnull:
|
|
185
|
+
sys.stdout = devnull
|
|
186
|
+
sys.stderr = devnull
|
|
187
|
+
try:
|
|
188
|
+
yield
|
|
189
|
+
finally:
|
|
190
|
+
# 恢复原始输出
|
|
191
|
+
sys.stdout = old_stdout
|
|
192
|
+
sys.stderr = old_stderr
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import math
|
|
3
|
+
import rospy
|
|
4
|
+
import threading
|
|
5
|
+
import numpy as np
|
|
6
|
+
from typing import Tuple
|
|
7
|
+
from transitions import Machine, State
|
|
8
|
+
from geometry_msgs.msg import Pose
|
|
9
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
10
|
+
from kuavo_humanoid_sdk.kuavo.core.ros.navigation import Navigation, NavigationStatus
|
|
11
|
+
|
|
12
|
+
class KuavoRobotNavigationCore:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.robot_navigation = Navigation()
|
|
15
|
+
|
|
16
|
+
def stop_navigation(self) -> bool:
|
|
17
|
+
"""
|
|
18
|
+
stop navigation
|
|
19
|
+
"""
|
|
20
|
+
return self.robot_navigation.pub_stop_navigation()
|
|
21
|
+
|
|
22
|
+
def get_current_status(self) -> NavigationStatus:
|
|
23
|
+
"""
|
|
24
|
+
get current status
|
|
25
|
+
"""
|
|
26
|
+
return self.robot_navigation.get_current_status()
|
|
27
|
+
|
|
28
|
+
def load_map(self, map_name: str) -> bool:
|
|
29
|
+
"""
|
|
30
|
+
load map
|
|
31
|
+
"""
|
|
32
|
+
return self.robot_navigation.srv_load_map(map_name)
|
|
33
|
+
|
|
34
|
+
def get_current_map(self) -> str:
|
|
35
|
+
"""
|
|
36
|
+
get current map
|
|
37
|
+
"""
|
|
38
|
+
return self.robot_navigation.srv_get_current_map()
|
|
39
|
+
|
|
40
|
+
def get_all_maps(self) -> list:
|
|
41
|
+
"""
|
|
42
|
+
get all maps
|
|
43
|
+
"""
|
|
44
|
+
return self.robot_navigation.srv_get_all_maps()
|
|
45
|
+
|
|
46
|
+
def navigate_to_task_point(self, task_point_name: str) -> bool:
|
|
47
|
+
"""
|
|
48
|
+
navigate to task point
|
|
49
|
+
"""
|
|
50
|
+
return self.robot_navigation.srv_navigate_to_task_point(task_point_name)
|
|
51
|
+
|
|
52
|
+
def init_localization_by_pose(self, pose: Pose) -> bool:
|
|
53
|
+
"""
|
|
54
|
+
initialize localization by pose
|
|
55
|
+
"""
|
|
56
|
+
return self.robot_navigation.pub_init_localization_by_pose(pose)
|
|
57
|
+
|
|
58
|
+
def init_localization_by_task_point(self, task_point_name: str) -> bool:
|
|
59
|
+
"""
|
|
60
|
+
initialize localization by task point
|
|
61
|
+
"""
|
|
62
|
+
return self.robot_navigation.srv_init_localization_by_task_point(task_point_name)
|
|
63
|
+
|
|
64
|
+
def navigate_to_goal(self, goal: Pose) -> bool:
|
|
65
|
+
"""
|
|
66
|
+
navigate to goal
|
|
67
|
+
"""
|
|
68
|
+
return self.robot_navigation.pub_navigate_to_goal(goal)
|
|
69
|
+
|
|
70
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import rospy
|
|
4
|
+
from std_msgs.msg import Bool, Int16MultiArray
|
|
5
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
6
|
+
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
7
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import playmusic, playmusicRequest
|
|
8
|
+
from kuavo_humanoid_sdk.msg.kuavo_msgs.srv import SpeechSynthesis, SpeechSynthesisRequest
|
|
9
|
+
class Audio:
|
|
10
|
+
"""Audio system interface for controlling audio playback functionality of Kuavo humanoid robot.
|
|
11
|
+
|
|
12
|
+
Provides functionality to play music files.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
"""Initialize the audio system."""
|
|
17
|
+
self._audio_stop_publisher = rospy.Publisher('stop_music', Bool, queue_size=10)
|
|
18
|
+
self.audio_data_publisher = rospy.Publisher('audio_data', Int16MultiArray, queue_size=10)
|
|
19
|
+
rospy.sleep(0.5) # Wait for publisher initialization
|
|
20
|
+
def play_audio(self, file_name: str, volume: int = 100, speed: float = 1.0) -> bool:
|
|
21
|
+
"""Play the specified audio file.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
file_name (str): Name of the audio file to play
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
bool: True if the play request was successfully sent, False otherwise
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
# Wait for service availability
|
|
31
|
+
rospy.wait_for_service('play_music', timeout=2.0)
|
|
32
|
+
# Create service client
|
|
33
|
+
play_music_service = rospy.ServiceProxy('play_music', playmusic)
|
|
34
|
+
# Call service
|
|
35
|
+
request = playmusicRequest()
|
|
36
|
+
request.music_number = file_name
|
|
37
|
+
volume = min(max(volume , 0), 100)
|
|
38
|
+
request.volume = volume
|
|
39
|
+
response = play_music_service(request)
|
|
40
|
+
SDKLogger.info(f"[Robot Audio] Requested to play audio file: {file_name}")
|
|
41
|
+
return True
|
|
42
|
+
except rospy.ROSException as e:
|
|
43
|
+
SDKLogger.error(f"[Robot Audio] Audio playback service unavailable: {str(e)}")
|
|
44
|
+
return False
|
|
45
|
+
except Exception as e:
|
|
46
|
+
SDKLogger.error(f"[Robot Audio] Failed to play audio file: {str(e)}")
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
def stop_audio(self):
|
|
50
|
+
"""Stop the currently playing audio."""
|
|
51
|
+
try:
|
|
52
|
+
msg = Bool()
|
|
53
|
+
msg.data = True
|
|
54
|
+
self._audio_stop_publisher.publish(msg)
|
|
55
|
+
SDKLogger.info("[Robot Audio] Requested to stop audio playback")
|
|
56
|
+
return True
|
|
57
|
+
except Exception as e:
|
|
58
|
+
SDKLogger.error(f"[Robot Audio] Failed to stop audio playback: {str(e)}")
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def text_to_speech(self, text: str,volume: float = 0.5) -> bool:
|
|
62
|
+
"""Synthesize and play the specified text.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
text (str): Text to be played
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
bool: True if the play request was successfully sent, False otherwise
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
# Wait for service availability
|
|
72
|
+
rospy.wait_for_service('play_music', timeout=2.0)
|
|
73
|
+
# Create service client
|
|
74
|
+
play_music_service = rospy.ServiceProxy('speech_synthesis', SpeechSynthesis)
|
|
75
|
+
# Call service
|
|
76
|
+
request = SpeechSynthesisRequest()
|
|
77
|
+
request.data = text
|
|
78
|
+
request.volume = volume
|
|
79
|
+
response = play_music_service(request)
|
|
80
|
+
SDKLogger.info(f"[Robot Audio] Requested to play audio text: {text}")
|
|
81
|
+
return True
|
|
82
|
+
except rospy.ROSException as e:
|
|
83
|
+
SDKLogger.error(f"[Robot Audio] Audio playback service unavailable: {str(e)}")
|
|
84
|
+
return False
|
|
85
|
+
except Exception as e:
|
|
86
|
+
SDKLogger.error(f"[Robot Audio] Failed to play audio text: {str(e)}")
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
def publish_audio_chunk(self, audio_chunk, gain: int = 1):
|
|
90
|
+
"""Publish a single audio chunk to the topic, for real-time audio streaming"""
|
|
91
|
+
try:
|
|
92
|
+
if not audio_chunk:
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
# 应用增益
|
|
96
|
+
amplified_chunk = [int(sample * gain) for sample in audio_chunk]
|
|
97
|
+
|
|
98
|
+
# 创建并发布消息
|
|
99
|
+
msg = Int16MultiArray()
|
|
100
|
+
msg.data = amplified_chunk
|
|
101
|
+
|
|
102
|
+
self.audio_data_publisher.publish(msg)
|
|
103
|
+
# SDKLogger.debug(f"[Robot Audio] 发布音频块,大小: {len(amplified_chunk)}")
|
|
104
|
+
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
SDKLogger.error(f"[Robot Audio] 发布音频块时出错: {e}")
|
|
109
|
+
return False
|
|
110
|
+
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import rospy
|
|
4
|
+
from std_msgs.msg import Bool, Int16MultiArray
|
|
5
|
+
from kuavo_humanoid_sdk.common.logger import SDKLogger
|
|
6
|
+
from kuavo_humanoid_sdk.kuavo.core.core import KuavoRobotCore
|
|
7
|
+
from sensor_msgs.msg import Image
|
|
8
|
+
from cv_bridge import CvBridge, CvBridgeError
|
|
9
|
+
from kuavo_msgs.msg import yoloOutputData, yoloDetection
|
|
10
|
+
import threading
|
|
11
|
+
|
|
12
|
+
class CameraROSInterface:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.bridge = CvBridge()
|
|
15
|
+
|
|
16
|
+
self.cameras = {
|
|
17
|
+
'head': {
|
|
18
|
+
'topic': '/camera/color/image_raw',
|
|
19
|
+
'pub_topic': '/model_output_data',
|
|
20
|
+
'publisher': None
|
|
21
|
+
},
|
|
22
|
+
'chest': {
|
|
23
|
+
'topic': '/chest_cam',
|
|
24
|
+
'pub_topic': '/chest_detection_data',
|
|
25
|
+
'publisher': None
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
self.cv_image_shape = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def init_ros_node(self):
|
|
33
|
+
if not rospy.get_node_uri():
|
|
34
|
+
rospy.init_node('YOLO_detection', anonymous=True)
|
|
35
|
+
|
|
36
|
+
for camera in self.cameras.values():
|
|
37
|
+
camera['publisher'] = rospy.Publisher(
|
|
38
|
+
camera['pub_topic'],
|
|
39
|
+
yoloDetection,
|
|
40
|
+
queue_size=1,
|
|
41
|
+
tcp_nodelay=True
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def get_camera_image(self, camera):
|
|
45
|
+
if camera not in self.cameras:
|
|
46
|
+
rospy.logerr(f"Unknown camera: {camera}")
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# 使用rospy.wait_for_message()获取一帧图像
|
|
51
|
+
msg = rospy.wait_for_message(self.cameras[camera]['topic'], Image, timeout=1.0)
|
|
52
|
+
cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")
|
|
53
|
+
self.cv_image_shape = cv_image.shape
|
|
54
|
+
return cv_image
|
|
55
|
+
except rospy.ROSException as e:
|
|
56
|
+
print(f"Timeout waiting for {camera} camera image: {e}")
|
|
57
|
+
return None
|
|
58
|
+
except CvBridgeError as e:
|
|
59
|
+
rospy.logerr(f"{camera.capitalize()} Camera CvBridge Error: {e}")
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def node_spin(self):
|
|
63
|
+
rospy.spin()
|
|
64
|
+
|
|
65
|
+
def node_is_shutdown(self):
|
|
66
|
+
return rospy.is_shutdown()
|
|
67
|
+
|
|
68
|
+
def tensor_to_msg(self, results):
|
|
69
|
+
if not results:
|
|
70
|
+
return None
|
|
71
|
+
else:
|
|
72
|
+
yolo_detections = yoloDetection()
|
|
73
|
+
for result in results:
|
|
74
|
+
boxes = result.boxes.cpu().numpy()
|
|
75
|
+
|
|
76
|
+
xywh = boxes.xywh # center-x(i,0), center-y(i,1), width(i,2), height(i,3)
|
|
77
|
+
class_ids = result.boxes.cls.int().cpu().numpy()
|
|
78
|
+
class_names = [result.names[cls.item()] for cls in result.boxes.cls.int()]
|
|
79
|
+
confs = boxes.conf
|
|
80
|
+
|
|
81
|
+
for i in range(len(xywh)):
|
|
82
|
+
yolo_output_data = yoloOutputData(
|
|
83
|
+
class_name=class_names[i],
|
|
84
|
+
class_id=int(class_ids[i]),
|
|
85
|
+
confidence=confs[i],
|
|
86
|
+
x_pos=xywh[i][0],
|
|
87
|
+
y_pos=xywh[i][1],
|
|
88
|
+
height=xywh[i][2],
|
|
89
|
+
width=xywh[i][3]
|
|
90
|
+
)
|
|
91
|
+
yolo_detections.data.append(yolo_output_data)
|
|
92
|
+
return yolo_detections
|
|
93
|
+
|
|
94
|
+
def publish_results(self, results, camera):
|
|
95
|
+
if not results:
|
|
96
|
+
rospy.loginfo(f"No results to publish for {camera} camera.")
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if camera not in self.cameras:
|
|
100
|
+
rospy.logerr(f"Unknown camera: {camera}")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
yolo_detections = self.tensor_to_msg(results)
|
|
104
|
+
if yolo_detections:
|
|
105
|
+
self.cameras[camera]['publisher'].publish(yolo_detections)
|