This commit is contained in:
linbo 2025-08-26 17:19:45 +08:00
parent bd79b8fbd1
commit 5735d899fb
4 changed files with 285 additions and 19 deletions

View File

@ -160,3 +160,60 @@ class CameraClient:
except grpc.RpcError as e:
print(f"停止录像失败: {e}")
return CMVRErrorCode.CMVR_RPC_FAILED
def create_rgb_stream_request(self):
"""创建流请求(无参数)"""
generated = self._import_generated()
request = generated.camera_command_pb2.GetRGBImageStreamCommand.Request()
request.header.CopyFrom(self._create_command_header())
# 不需要设置其他参数
return request
def get_rgb_stream(self, request_generator):
"""
双向流获取传感器数据
参数:
request_generator: 请求生成器
返回:
传感器数据流迭代器
"""
generated = self._import_generated()
return self.stub.GetRGBImageStream(request_generator)
def create_depth_stream_request(self):
"""创建流请求(无参数)"""
generated = self._import_generated()
request = generated.camera_command_pb2.GetDepthImageStreamCommand.Request()
request.header.CopyFrom(self._create_command_header())
# 不需要设置其他参数
return request
def get_depth_stream(self, request_generator):
"""
双向流获取传感器数据
参数:
request_generator: 请求生成器
返回:
传感器数据流迭代器
"""
generated = self._import_generated()
return self.stub.GetDepthImageStream(request_generator)
def create_rgbd_stream_request(self):
"""创建流请求(无参数)"""
generated = self._import_generated()
request = generated.camera_command_pb2.GetRGBDImageStreamCommand.Request()
request.header.CopyFrom(self._create_command_header())
# 不需要设置其他参数
return request
def get_rgbd_stream(self, request_generator):
"""
双向流获取传感器数据
参数:
request_generator: 请求生成器
返回:
传感器数据流迭代器
"""
generated = self._import_generated()
return self.stub.GetRGBDImageStream(request_generator)

View File

@ -5,7 +5,8 @@ from .enums import CMVRErrorCode
from .biohead_client import BioHeadClient
from .camera_client import CameraClient
from .dexhand_client import DexHandClient
from .micphone_client import MicphoneClient
from .speaker_client import SpeakerClient
class CMVRGrpcClient:
"""CMVR gRPC 主客户端"""
@ -27,6 +28,12 @@ class CMVRGrpcClient:
self.dexhand_stub = None
self.dexhand_map: Dict[str, DexHandClient] = {}
self.micphone_stub = None
self.micphone_map: Dict[str, MicphoneClient] = {}
self.speaker_stub = None
self.speaker_map: Dict[str, SpeakerClient] = {}
# 检查连接状态
try:
grpc.channel_ready_future(self.channel).result(timeout=5)
@ -38,6 +45,10 @@ class CMVRGrpcClient:
self.dexhand_stub = self.generated.dexhand_service_pb2_grpc.DexHandServiceStub(self.channel)
self.speaker_stub = self.generated.speaker_service_pb2_grpc.SpeakerServiceStub(self.channel)
self.micphone_stub = self.generated.microphone_service_pb2_grpc.MicPhoneServiceStub(self.channel)
except grpc.FutureTimeoutError:
print(f"连接服务器超时: {server_address}")
self.connected = False
@ -53,6 +64,11 @@ class CMVRGrpcClient:
from generated.cmvr.api import camera_command_pb2
from generated.cmvr.api import dexhand_command_pb2
from generated.cmvr.api import dexhand_service_pb2_grpc
from generated.cmvr.api import speaker_command_pb2
from generated.cmvr.api import speaker_service_pb2_grpc
from generated.cmvr.api import microphone_command_pb2
from generated.cmvr.api import microphone_service_pb2_grpc
self.generated = type('GeneratedModules', (), {
'biohead_service_pb2_grpc': biohead_service_pb2_grpc,
'common_pb2': common_pb2,
@ -60,7 +76,11 @@ class CMVRGrpcClient:
'camera_service_pb2_grpc': camera_service_pb2_grpc,
'camera_command_pb2': camera_command_pb2,
'dexhand_service_pb2_grpc': dexhand_service_pb2_grpc,
'dexhand_command_pb2': dexhand_command_pb2
'dexhand_command_pb2': dexhand_command_pb2,
'speaker_service_pb2_grpc': speaker_service_pb2_grpc,
'speaker_command_pb2': speaker_command_pb2,
'microphone_service_pb2_grpc': microphone_service_pb2_grpc,
'microphone_command_pb2': microphone_command_pb2
})
except ImportError as e:
@ -89,6 +109,16 @@ class CMVRGrpcClient:
self.dexhand_map[device_id] = DexHandClient(device_id, self.dexhand_stub)
return self.dexhand_map[device_id]
def get_speaker(self, device_id: str) -> SpeakerClient:
if device_id not in self.speaker_map:
self.speaker_map[device_id] = SpeakerClient(device_id, self.speaker_stub)
return self.speaker_map[device_id]
def get_micphone(self, device_id: str) -> MicphoneClient:
if device_id not in self.micphone_map:
self.micphone_map[device_id] = MicphoneClient(device_id, self.micphone_stub)
return self.micphone_map[device_id]
def close(self):
"""关闭所有连接"""
# 关闭所有流式连接

View File

@ -231,21 +231,6 @@ class DexHandClient:
print(f"获取灵巧手传感器数据失败: {e}")
return CMVRErrorCode.CMVR_RPC_FAILED, HandTactileSensors()
def sensor_data_stream(self):
try:
generated = self._import_generated()
# 创建传感器数据请求
request = generated.dexhand_command_pb2.GetSensorDataCommand.Request()
request.header.CopyFrom(self._create_command_header())
# 调用RPC接口获取数据
response = self.stub.GetSensorData(request)
if not response.header.success:
return CMVRErrorCode.CMVR_RPC_FAILED, HandTactileSensors()
except grpc.RpcError as e:
print(f"获取灵巧手传感器数据失败: {e}")
def create_stream_request(self):
"""创建流请求(无参数)"""
generated = self._import_generated()

View File

@ -231,6 +231,82 @@ def test_camera():
client.close()
def test_rgb_image_stream():
"""测试双向流视频帧数据接口"""
print("=== 测试双向流视频帧数据接口 ===")
# 初始化GRPC客户端
client = CMVRGrpcClient("192.168.1.222:50060")
if not client.is_connected():
print("连接服务器失败")
return
# 获取camera客户端
camera = client.get_camera("cam4")
if not camera:
print("获取camera客户端失败")
client.close()
return
# 启动相机
start_result = camera.start_camera()
if start_result == CMVRErrorCode.CMVR_SUCCESS:
print("相机启动成功")
else:
print(f"相机启动失败,错误码: {start_result}")
client.close()
return
# 等待相机启动
time.sleep(1)
try:
# 1. 启动传感器数据流
print("\n--- 启动rgb数据流 ---")
# 创建请求生成器(双向流不需要参数,发送空请求)
def request_generator() -> Generator:
# 发送初始请求启动流
yield camera.create_rgb_stream_request()
# 保持流连接每5秒发送一次心跳可选
try:
while True:
time.sleep(5)
# 发送空请求保持连接
yield camera.create_rgb_stream_request()
except GeneratorExit:
print("请求生成器已关闭")
return
# 2. 接收并处理流数据
print("开始接收rgb流数据5秒后自动停止...")
start_time = time.time()
stream_duration = 15 # 接收15秒数据
keyframe_count = 0 # 关键帧计数器
total_frame_count = 0 # 总帧数计数器
# 存储流迭代器的变量
stream_iterator = camera.get_rgb_stream(request_generator())
# 调用双向流接口
for feedback in stream_iterator:
# 检查是否超时
if time.time() - start_time > stream_duration:
print("\n达到预设接收时间,停止接收")
break
total_frame_count += 1 # 累加总帧数
# 检查是否为关键帧并计数
if feedback.color_frame.is_key_frame:
keyframe_count += 1
print(f"[关键帧 #{keyframe_count}] 收到关键帧 (总帧数: {total_frame_count})")
stream_iterator.cancel()
print(f"\n流接收结束 - 总帧数: {total_frame_count}, 关键帧数: {keyframe_count}, 关键帧占比: {keyframe_count/total_frame_count:.2%}")
except grpc.RpcError as e:
print(f"双向流通信错误: {e}")
except Exception as e:
print(f"处理流数据时发生错误: {e}")
finally:
# 关闭连接
client.close()
print("\n=== 双向流传感器数据测试完成 ===")
def test_dexhand():
"""测试DexHand功能获取状态、设置角度和传感器数据"""
print("=== 测试DexHand功能 ===")
@ -466,8 +542,126 @@ def test_sensor_data_stream():
# 关闭连接
client.close()
print("\n=== 双向流传感器数据测试完成 ===")
def test_speaker():
"""测试扬声器功能"""
print("\n=== 测试扬声器功能 ===")
# 初始化GRPC客户端
client = CMVRGrpcClient("192.168.1.222:50060")
if not client.is_connected():
print("连接服务器失败")
return
speaker = client.get_speaker("spk1")
if speaker is None:
print("获取扬声器失败")
return
# 获取状态
result, status = speaker.get_status()
if result == CMVRErrorCode.CMVR_SUCCESS:
print(f"扬声器状态: 初始化={status.is_initialized}, 运行中={status.is_running}")
else:
print(f"获取扬声器状态失败,错误码: {result}")
# 设置音量
result = speaker.set_volume(80) # 80%音量
if result == CMVRErrorCode.CMVR_SUCCESS:
print("设置音量成功")
else:
print(f"设置音量失败,错误码: {result}")
# 获取音量
result, volume = speaker.get_volume()
if result == CMVRErrorCode.CMVR_SUCCESS:
print(f"当前音量: {volume}%")
else:
print(f"获取音量失败,错误码: {result}")
# 播放音频 (需要替换为实际存在的音频文件路径)
audio_path = "/home/share/assets/upload/员工女_车内温度有点低是否需要调高空调.wav"
print(f"尝试播放音频: {audio_path}")
result = speaker.play_audio(audio_path)
if result == CMVRErrorCode.CMVR_SUCCESS:
print("开始播放音频")
# 等待3秒
time.sleep(3)
# 暂停播放
result = speaker.pause_audio()
if result == CMVRErrorCode.CMVR_SUCCESS:
print("暂停播放")
# 等待1秒
time.sleep(1)
# 继续播放
result = speaker.resume_audio()
if result == CMVRErrorCode.CMVR_SUCCESS:
print("继续播放")
# 等待2秒
time.sleep(2)
# 停止播放
result = speaker.stop_audio()
if result == CMVRErrorCode.CMVR_SUCCESS:
print("停止播放")
else:
print(f"停止播放失败,错误码: {result}")
else:
print(f"继续播放失败,错误码: {result}")
else:
print(f"暂停播放失败,错误码: {result}")
else:
print(f"播放音频失败,错误码: {result}")
def test_microphone():
"""测试麦克风功能"""
print("\n=== 测试麦克风功能 ===")
# 初始化GRPC客户端
client = CMVRGrpcClient("192.168.1.222:50060")
if not client.is_connected():
print("连接服务器失败")
return
microphone = client.get_micphone("mic2")
if microphone is None:
print("获取麦克风失败")
return
# 获取状态
result, status = microphone.get_status()
if result == CMVRErrorCode.CMVR_SUCCESS:
print(f"麦克风状态: 初始化={status.is_initialized}, 录音中={status.is_recording}")
else:
print(f"获取麦克风状态失败,错误码: {result}")
# 开始录音
audio_path = "/home/linbo/Data/Audio/recorded_audio.mp3"
result = microphone.start_record(audio_path)
if result == CMVRErrorCode.CMVR_SUCCESS:
print(f"开始录音,保存到: {audio_path}")
# 录音5秒
time.sleep(5)
# 停止录音
result = microphone.stop_record()
if result == CMVRErrorCode.CMVR_SUCCESS:
print("停止录音")
else:
print(f"停止录音失败,错误码: {result}")
else:
print(f"开始录音失败,错误码: {result}")
if __name__ == "__main__":
test_biohead()
# test_biohead()
# test_camera()
# test_rgb_image_stream()
# test_dexhand()
# test_sensor_data_stream()
# test_speaker()
test_microphone()