From 5735d899fb1bc3559f2fb147d7d16a9e23cd44a1 Mon Sep 17 00:00:00 2001 From: linbo <1034003879@qq.com> Date: Tue, 26 Aug 2025 17:19:45 +0800 Subject: [PATCH] update --- cmvr/camera_client.py | 59 ++++++++++++- cmvr/client.py | 34 ++++++- cmvr/dexhand_client.py | 15 ---- example_usage.py | 196 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 285 insertions(+), 19 deletions(-) diff --git a/cmvr/camera_client.py b/cmvr/camera_client.py index a05def3..66d01fa 100644 --- a/cmvr/camera_client.py +++ b/cmvr/camera_client.py @@ -159,4 +159,61 @@ class CameraClient: except grpc.RpcError as e: print(f"停止录像失败: {e}") - return CMVRErrorCode.CMVR_RPC_FAILED \ No newline at end of file + 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) \ No newline at end of file diff --git a/cmvr/client.py b/cmvr/client.py index 237e391..26c6015 100644 --- a/cmvr/client.py +++ b/cmvr/client.py @@ -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): """关闭所有连接""" # 关闭所有流式连接 diff --git a/cmvr/dexhand_client.py b/cmvr/dexhand_client.py index 3a12ba1..a0de0b0 100644 --- a/cmvr/dexhand_client.py +++ b/cmvr/dexhand_client.py @@ -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() diff --git a/example_usage.py b/example_usage.py index 4bc1cc0..267adf8 100644 --- a/example_usage.py +++ b/example_usage.py @@ -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()