如何使用Foxglove WebSocket服务器传输protobuf编码的数据并在工作室中显示模型文件?(python)谢谢在工作室中显示模型文件?
d5vmydt91#
您需要创建一个包含SceneEntity的SceneUpdate消息。在场景实体中包含ModelPrimitive以显示模型。(模型的数据可以嵌入ModelPrimitive中,也可以来自URL。)这里有一个你可以使用的示例脚本。它使用了Protobuf从foxglove_schemas_protobuf生成的类型和示例Flamingo.glb模型from three.js。为了演示如何使用模型发送嵌入的数据,我使用requests.get加载了flamingo模型,但您也可以使用with open(...) as f: model_data = f.read()从文件中加载它。如果您的模型可以通过公共URL访问,您可以简单地设置model.url而不是model.data。为了优化,我加入了一个FoxgloveServerListener,以便仅在客户端订阅SceneUpdate通道时发送模型。这避免了在每一帧上发送大量数据。
Flamingo.glb
requests.get
with open(...) as f: model_data = f.read()
model.url
model.data
pip install requests pyquaternion foxglove-websocket foxglove-schemas-protobuf
import asyncio import math import requests import time from base64 import b64encode from foxglove_websocket import run_cancellable from foxglove_websocket.server import FoxgloveServer, FoxgloveServerListener from foxglove_schemas_protobuf.SceneUpdate_pb2 import SceneUpdate from foxglove_schemas_protobuf.FrameTransform_pb2 import FrameTransform from mcap_protobuf.schema import build_file_descriptor_set from pyquaternion import Quaternion async def main(): flamingo_data = requests.get( "https://github.com/mrdoob/three.js/raw/dev/examples/models/gltf/Flamingo.glb" ).content async with FoxgloveServer("0.0.0.0", 8765, "example server") as server: scene_chan_id = await server.add_channel( { "topic": "scene", "encoding": "protobuf", "schemaName": SceneUpdate.DESCRIPTOR.full_name, "schema": b64encode( build_file_descriptor_set(SceneUpdate).SerializeToString() ).decode("ascii"), } ) tf_chan_id = await server.add_channel( { "topic": "transforms", "encoding": "protobuf", "schemaName": FrameTransform.DESCRIPTOR.full_name, "schema": b64encode( build_file_descriptor_set(FrameTransform).SerializeToString() ).decode("ascii"), } ) class Listener(FoxgloveServerListener): def on_subscribe(self, server, channel_id): # Send the model data only when a client subscribes, to save bandwidth if channel_id == scene_chan_id: scene_update = SceneUpdate() entity = scene_update.entities.add() entity.timestamp.FromNanoseconds(now) entity.id = "model" entity.frame_id = "model" entity.frame_locked = True # allow the entity to move when we update the "model" frame transforms model = entity.models.add() model.pose.position.x = 0 model.pose.position.y = 0 model.pose.position.z = 0 q = Quaternion(axis=[0, 0, 1], angle=0.25 * 2 * math.pi * now / 1e9) model.pose.orientation.x = q.x model.pose.orientation.y = q.y model.pose.orientation.z = q.z model.pose.orientation.w = q.w model.color.r = 0.6 model.color.g = 0.2 model.color.b = 1 model.color.a = 0.8 # Use scale.x/y/z = 1 to use the original scale factor embedded in the model model.scale.x = 0.01 model.scale.y = 0.01 model.scale.z = 0.01 model.data = flamingo_data model.media_type = "model/gltf-binary" asyncio.create_task( server.send_message( scene_chan_id, now, scene_update.SerializeToString() ) ) def on_unsubscribe(self, server, channel_id): pass server.set_listener(Listener()) # Send the FrameTransform every frame to update the model's position while True: await asyncio.sleep(0.02) now = time.time_ns() transform = FrameTransform() transform.parent_frame_id = "root" transform.child_frame_id = "model" transform.timestamp.FromNanoseconds(now) transform.translation.x = 0 transform.translation.y = 0 transform.translation.z = math.sin(now / 1e9 * 0.5) q = Quaternion(axis=[0, 0, 1], angle=-0.1 * 2 * math.pi * now / 1e9) transform.rotation.x = q.x transform.rotation.y = q.y transform.rotation.z = q.z transform.rotation.w = q.w await server.send_message(tf_chan_id, now, transform.SerializeToString()) if __name__ == "__main__": run_cancellable(main())
1条答案
按热度按时间d5vmydt91#
您需要创建一个包含SceneEntity的SceneUpdate消息。在场景实体中包含ModelPrimitive以显示模型。(模型的数据可以嵌入ModelPrimitive中,也可以来自URL。)
这里有一个你可以使用的示例脚本。它使用了Protobuf从foxglove_schemas_protobuf生成的类型和示例
Flamingo.glb
模型from three.js。为了演示如何使用模型发送嵌入的数据,我使用
requests.get
加载了flamingo模型,但您也可以使用with open(...) as f: model_data = f.read()
从文件中加载它。如果您的模型可以通过公共URL访问,您可以简单地设置model.url
而不是model.data
。为了优化,我加入了一个FoxgloveServerListener,以便仅在客户端订阅SceneUpdate通道时发送模型。这避免了在每一帧上发送大量数据。