diff --git a/docs/examples/example.ipynb b/docs/examples/example.ipynb index 9367bd021..94c38e2ef 100644 --- a/docs/examples/example.ipynb +++ b/docs/examples/example.ipynb @@ -296,7 +296,7 @@ "from typing_extensions import Self\n", "\n", "from viam.proto.app.robot import ComponentConfig\n", - "from viam.proto.common import ResourceName\n", + "from viam.proto.common import Mesh, ResourceName\n", "from viam.resource.base import ResourceBase\n", "from viam.resource.types import Model, ModelFamily\n", "\n", @@ -543,14 +543,14 @@ "# modular-arm/src/my_modular_arm.py\n", "import asyncio\n", "import os\n", - "from typing import Any, ClassVar, Dict, Mapping, Optional, Tuple\n", + "from typing import Any, ClassVar, Dict, Mapping, Optional, Tuple, Union\n", "from typing_extensions import Self\n", "\n", "from viam.components.arm import Arm, JointPositions, KinematicsFileFormat, Pose\n", "from viam.module.module import Module\n", "from viam.operations import run_with_operation\n", "from viam.proto.app.robot import ComponentConfig\n", - "from viam.proto.common import ResourceName\n", + "from viam.proto.common import Mesh, ResourceName\n", "from viam.resource.base import ResourceBase\n", "from viam.resource.registry import Registry, ResourceCreatorRegistration\n", "from viam.resource.types import Model, ModelFamily\n", @@ -615,7 +615,7 @@ " async def is_moving(self) -> bool:\n", " return not self.is_stopped\n", "\n", - " async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]:\n", + " async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Union[Tuple[KinematicsFileFormat.ValueType, bytes], Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]]:\n", " return KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, self.kinematics\n", "\n", "async def main():\n", @@ -672,176 +672,7 @@ { "data": { "text/html": [ - "
# my-python-robot/my_cool_arm.py\n",
-       "\n",
-       "import asyncio\n",
-       "import json\n",
-       "from typing import Any, Dict, Optional, Tuple\n",
-       "\n",
-       "from viam.components.arm import Arm, JointPositions, KinematicsFileFormat, Pose\n",
-       "from viam.operations import run_with_operation\n",
-       "\n",
-       "\n",
-       "class MyCoolArm(Arm):\n",
-       "    # Subclass the Viam Arm component and implement the required functions\n",
-       "\n",
-       "    def __init__(self, name: str):\n",
-       "        # Starting position\n",
-       "        self.position = Pose(\n",
-       "            x=0,\n",
-       "            y=0,\n",
-       "            z=0,\n",
-       "            o_x=0,\n",
-       "            o_y=0,\n",
-       "            o_z=0,\n",
-       "            theta=0,\n",
-       "        )\n",
-       "\n",
-       "        # Starting joint positions\n",
-       "        self.joint_positions = JointPositions(values=[0, 0, 0, 0, 0, 0])\n",
-       "        self.is_stopped = True\n",
-       "\n",
-       "        # Minimal working kinematics model\n",
-       "        self.kinematics = json.dumps(\n",
-       "            {\n",
-       "                "name": "MyArm",\n",
-       "                "links": [{"id": "base", "parent": "world", "translation": {"x": 0, "y": 0, "z": 0}}],\n",
-       "                "joints": [\n",
-       "                    {"id": "waist", "type": "revolute", "parent": "base", "axis": {"x": 0, "y": 0, "z": 1}, "max": 359, "min": -359}\n",
-       "                ],\n",
-       "            }\n",
-       "        ).encode("utf-8")\n",
-       "        super().__init__(name)\n",
-       "\n",
-       "    async def get_end_position(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Pose:\n",
-       "        return self.position\n",
-       "\n",
-       "    @run_with_operation\n",
-       "    async def move_to_position(\n",
-       "        self,\n",
-       "        pose: Pose,\n",
-       "        extra: Optional[Dict[str, Any]] = None,\n",
-       "        **kwargs,\n",
-       "    ):\n",
-       "        operation = self.get_operation(kwargs)\n",
-       "\n",
-       "        self.is_stopped = False\n",
-       "        self.position = pose\n",
-       "\n",
-       "        # Simulate the length of time it takes for the arm to move to its new position\n",
-       "        for x in range(10):\n",
-       "            await asyncio.sleep(1)\n",
-       "\n",
-       "            # Check if the operation is cancelled and, if it is, stop the arm's motion\n",
-       "            if await operation.is_cancelled():\n",
-       "                await self.stop()\n",
-       "                break\n",
-       "\n",
-       "        self.is_stopped = True\n",
-       "\n",
-       "    async def get_joint_positions(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> JointPositions:\n",
-       "        return self.joint_positions\n",
-       "\n",
-       "    @run_with_operation\n",
-       "    async def move_to_joint_positions(self, positions: JointPositions, extra: Optional[Dict[str, Any]] = None, **kwargs):\n",
-       "        operation = self.get_operation(kwargs)\n",
-       "\n",
-       "        self.is_stopped = False\n",
-       "        self.joint_positions = positions\n",
-       "\n",
-       "        # Simulate the length of time it takes for the arm to move to its new joint position\n",
-       "        for x in range(10):\n",
-       "            await asyncio.sleep(1)\n",
-       "\n",
-       "            # Check if the operation is cancelled and, if it is, stop the arm's motion\n",
-       "            if await operation.is_cancelled():\n",
-       "                await self.stop()\n",
-       "                break\n",
-       "\n",
-       "        self.is_stopped = True\n",
-       "\n",
-       "    async def stop(self, extra: Optional[Dict[str, Any]] = None, **kwargs):\n",
-       "        self.is_stopped = True\n",
-       "\n",
-       "    async def is_moving(self) -> bool:\n",
-       "        return not self.is_stopped\n",
-       "\n",
-       "    async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]:\n",
-       "        return KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, self.kinematics\n",
-       "
\n" + "
# my-python-robot/my_cool_arm.py\n\nimport asyncio\nimport json\nfrom typing import Any, Dict, Optional, Tuple\n\nfrom viam.components.arm import Arm, JointPositions, KinematicsFileFormat, Pose\nfrom viam.operations import run_with_operation\n\n\nclass MyCoolArm(Arm):\n    # Subclass the Viam Arm component and implement the required functions\n\n    def __init__(self, name: str):\n        # Starting position\n        self.position = Pose(\n            x=0,\n            y=0,\n            z=0,\n            o_x=0,\n            o_y=0,\n            o_z=0,\n            theta=0,\n        )\n\n        # Starting joint positions\n        self.joint_positions = JointPositions(values=[0, 0, 0, 0, 0, 0])\n        self.is_stopped = True\n\n        # Minimal working kinematics model\n        self.kinematics = json.dumps(\n            {\n                "name": "MyArm",\n                "links": [{"id": "base", "parent": "world", "translation": {"x": 0, "y": 0, "z": 0}}],\n                "joints": [\n                    {"id": "waist", "type": "revolute", "parent": "base", "axis": {"x": 0, "y": 0, "z": 1}, "max": 359, "min": -359}\n                ],\n            }\n        ).encode("utf-8")\n        super().__init__(name)\n\n    async def get_end_position(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Pose:\n        return self.position\n\n    @run_with_operation\n    async def move_to_position(\n        self,\n        pose: Pose,\n        extra: Optional[Dict[str, Any]] = None,\n        **kwargs,\n    ):\n        operation = self.get_operation(kwargs)\n\n        self.is_stopped = False\n        self.position = pose\n\n        # Simulate the length of time it takes for the arm to move to its new position\n        for x in range(10):\n            await asyncio.sleep(1)\n\n            # Check if the operation is cancelled and, if it is, stop the arm's motion\n            if await operation.is_cancelled():\n                await self.stop()\n                break\n\n        self.is_stopped = True\n\n    async def get_joint_positions(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> JointPositions:\n        return self.joint_positions\n\n    @run_with_operation\n    async def move_to_joint_positions(self, positions: JointPositions, extra: Optional[Dict[str, Any]] = None, **kwargs):\n        operation = self.get_operation(kwargs)\n\n        self.is_stopped = False\n        self.joint_positions = positions\n\n        # Simulate the length of time it takes for the arm to move to its new joint position\n        for x in range(10):\n            await asyncio.sleep(1)\n\n            # Check if the operation is cancelled and, if it is, stop the arm's motion\n            if await operation.is_cancelled():\n                await self.stop()\n                break\n\n        self.is_stopped = True\n\n    async def stop(self, extra: Optional[Dict[str, Any]] = None, **kwargs):\n        self.is_stopped = True\n\n    async def is_moving(self) -> bool:\n        return not self.is_stopped\n\n    async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Union[Tuple[KinematicsFileFormat.ValueType, bytes], Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]]:\n        return KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, self.kinematics\n
\n" ], "text/plain": [ "" @@ -1037,7 +868,7 @@ "from typing_extensions import Self\n", "\n", "from viam.proto.app.robot import ComponentConfig\n", - "from viam.proto.common import ResourceName\n", + "from viam.proto.common import Mesh, ResourceName\n", "from viam.resource.base import ResourceBase\n", "from viam.resource.types import Model, ModelFamily\n", "\n", diff --git a/docs/examples/my_cool_arm.py b/docs/examples/my_cool_arm.py index 1fcdb11e9..889b3cb66 100644 --- a/docs/examples/my_cool_arm.py +++ b/docs/examples/my_cool_arm.py @@ -2,11 +2,11 @@ import asyncio import json -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Mapping, Optional, Tuple, Union from viam.components.arm import Arm, JointPositions, KinematicsFileFormat, Pose from viam.operations import run_with_operation -from viam.proto.common import Capsule, Geometry, Sphere +from viam.proto.common import Capsule, Geometry, Mesh, Sphere class MyCoolArm(Arm): @@ -100,7 +100,9 @@ async def is_moving(self) -> bool: async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> List[Geometry]: return self.geometries - async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + async def get_kinematics( + self, extra: Optional[Dict[str, Any]] = None, **kwargs + ) -> Union[Tuple[KinematicsFileFormat.ValueType, bytes], Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]]: return KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, self.kinematics async def close(self): diff --git a/examples/server/v1/components.py b/examples/server/v1/components.py index 1f1c18ee9..4bc0de836 100644 --- a/examples/server/v1/components.py +++ b/examples/server/v1/components.py @@ -19,7 +19,6 @@ from PIL import Image from viam.components.arm import Arm -from viam.components.audio_in import AudioIn, AudioResponse from viam.components.audio_out import AudioOut from viam.components.base import Base from viam.components.board import Board, TickStream @@ -48,6 +47,7 @@ ResponseMetadata, Sphere, Vector3, + Mesh, ) from viam.proto.component.arm import JointPositions from viam.proto.component.encoder import PositionType @@ -73,7 +73,7 @@ def __init__(self, name: str): ) self.joint_positions = JointPositions(values=[0, 0, 0, 0, 0, 0]) self.is_stopped = True - self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) super().__init__(name) async def get_end_position(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Pose: @@ -101,71 +101,12 @@ async def stop(self, extra: Optional[Dict[str, Any]] = None, **kwargs): async def is_moving(self): return not self.is_stopped - async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: return self.kinematics async def get_geometries(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> List[Geometry]: return GEOMETRIES -class ExampleAudioIn(AudioIn): - def __init__(self, name: str): - super().__init__(name) - self.sample_rate = 44100 - self.num_channels = 2 - self.supported_codecs = ["pcm16"] - self.chunk_count = 0 - self.latency = timedelta(milliseconds=20) - self.volume_scale = 0.2 - self.frequency_hz = 440 - - async def get_audio( - self, codec: str, duration_seconds: float, previous_timestamp_ns: int, *, timeout: Optional[float] = None, **kwargs - ) -> AudioIn.AudioStream: - async def read() -> AsyncIterator[AudioIn.AudioResponse]: - # Generate chunks based on duration - chunk_duration_ms = 100 # 100ms per chunk - chunks_to_generate = max(1, int((duration_seconds * 1000) / chunk_duration_ms)) - - for i in range(chunks_to_generate): - # Generate audio data (sine wave pattern) - chunk_data = b"" - samples_per_chunk = int(self.sample_rate * (chunk_duration_ms / 1000)) - - for sample in range(samples_per_chunk): - # Calculate the timing in seconds of this audio sample - time_offset = (i * chunk_duration_ms / 1000) + (sample / self.sample_rate) - # Generate one 16-bit PCM audio sample for a sine wave - # 32767 scales the value from (-1,1) to full 16 bit signed range (-32768,32767) - amplitude = int(32767 * self.volume_scale * math.sin(2 * math.pi * self.frequency_hz * time_offset)) - - # Convert to 16-bit PCM stereo - sample_bytes = amplitude.to_bytes(2, byteorder="little", signed=True) - chunk_data += sample_bytes * self.num_channels - - chunk_start_time = previous_timestamp_ns + (i * chunk_duration_ms * 1000000) # Convert ms to ns - chunk_end_time = chunk_start_time + (chunk_duration_ms * 1000000) - - audio_chunk = AudioInChunk( - audio_data=bytes(chunk_data), - audio_info=AudioInfo(codec=codec, sample_rate_hz=int(self.sample_rate), num_channels=self.num_channels), - sequence=i, - start_timestamp_nanoseconds=chunk_start_time, - end_timestamp_nanoseconds=chunk_end_time, - ) - audio_response = AudioResponse(audio=audio_chunk) - yield audio_response - - await asyncio.sleep(self.latency.total_seconds()) - - return StreamWithIterator(read()) - - async def get_properties(self, *, timeout: Optional[float] = None, **kwargs) -> AudioIn.Properties: - """Return the audio input device properties.""" - return AudioIn.Properties(supported_codecs=self.supported_codecs, sample_rate_hz=self.sample_rate, num_channels=self.num_channels) - - async def get_geometries(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> List[Geometry]: - return GEOMETRIES - class ExampleAudioOut(AudioOut): def __init__(self, name: str): @@ -546,8 +487,8 @@ async def is_moving(self): async def get_geometries(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> List[Geometry]: return GEOMETRIES - async def get_kinematics(self, *, extra=None, timeout=None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]: - return (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_UNSPECIFIED, b"abc") + async def get_kinematics(self, *, extra=None, timeout=None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: + return (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_UNSPECIFIED, b"abc", {}) class ExampleGripper(Gripper): @@ -555,7 +496,7 @@ def __init__(self, name: str): self.opened = False self.is_stopped = True self.holding_something = False - self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) super().__init__(name) async def open(self, extra: Optional[Dict[str, Any]] = None, **kwargs): @@ -581,7 +522,7 @@ async def is_moving(self): async def get_geometries(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> List[Geometry]: return GEOMETRIES - async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + async def get_kinematics(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: return self.kinematics diff --git a/examples/server/v1/server.py b/examples/server/v1/server.py index 188bfe904..4a31c5137 100644 --- a/examples/server/v1/server.py +++ b/examples/server/v1/server.py @@ -8,7 +8,6 @@ from .components import ( ExampleAnalog, ExampleArm, - ExampleAudioIn, ExampleAudioOut, ExampleBase, ExampleBoard, @@ -30,7 +29,6 @@ async def run(host: str, port: int, log_level: int): my_arm = ExampleArm("arm0") - my_audio_in = ExampleAudioIn("audio_in0") my_audio_out = ExampleAudioOut("audio_out0") my_base = ExampleBase("base0") my_board = ExampleBoard( @@ -77,7 +75,6 @@ async def run(host: str, port: int, log_level: int): server = Server( resources=[ my_arm, - my_audio_in, my_audio_out, my_base, my_board, diff --git a/src/viam/app/app_client.py b/src/viam/app/app_client.py index 1f2dfc231..d2d2674c5 100644 --- a/src/viam/app/app_client.py +++ b/src/viam/app/app_client.py @@ -165,6 +165,8 @@ UpdateRobotResponse, UploadModuleFileRequest, Visibility, + FragmentImport, + FragmentImportList, ) from viam.proto.app import Fragment as FragmentPB from viam.proto.app import FragmentHistoryEntry as FragmentHistoryEntryPB @@ -736,6 +738,7 @@ async def update_organization( public_namespace: Optional[str] = None, region: Optional[str] = None, cid: Optional[str] = None, + default_fragments: Optional[List[FragmentImport]] = None, ) -> Organization: """Updates organization details. @@ -768,6 +771,11 @@ async def update_organization( region=region, cid=cid, name=name, + default_fragments=( + FragmentImportList(fragments=default_fragments) + if default_fragments is not None + else None + ), ) response: UpdateOrganizationResponse = await self._app_client.UpdateOrganization(request, metadata=self._metadata) return response.organization diff --git a/src/viam/app/data_client.py b/src/viam/app/data_client.py index 8cc2d9aa8..d255995e9 100644 --- a/src/viam/app/data_client.py +++ b/src/viam/app/data_client.py @@ -1535,6 +1535,7 @@ async def binary_data_capture_upload( tags: Optional[List[str]] = None, dataset_ids: Optional[List[str]] = None, data_request_times: Optional[Tuple[datetime, datetime]] = None, + mime_type: Optional[str] = None, ) -> str: """Upload binary sensor data. @@ -1573,6 +1574,7 @@ async def binary_data_capture_upload( dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to. data_request_times (Optional[Tuple[datetime.datetime, datetime.datetime]]): Optional tuple containing datetime objects denoting the times this data was requested ``[0]`` by the robot and received ``[1]`` from the appropriate sensor. + mime_type (Optional[str]): Optional mime type of the data. Raises: GRPCError: If an invalid part ID is passed. @@ -1603,6 +1605,7 @@ async def binary_data_capture_upload( method_parameters=method_parameters, tags=tags, dataset_ids=dataset_ids, + mime_type=mime_type or "", ) if file_extension: metadata.file_extension = file_extension if file_extension[0] == "." else f".{file_extension}" @@ -1721,6 +1724,7 @@ async def streaming_data_capture_upload( data_request_times: Optional[Tuple[datetime, datetime]] = None, tags: Optional[List[str]] = None, dataset_ids: Optional[List[str]] = None, + mime_type: Optional[str] = None, ) -> str: """Uploads the metadata and contents of streaming binary data. @@ -1753,6 +1757,7 @@ async def streaming_data_capture_upload( denoting the times this data was requested ``[0]`` by the robot and received ``[1]`` from the appropriate sensor. tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data. dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to. + mime_type (Optional[str]): Optional mime type of the data. Raises: GRPCError: If an invalid part ID is passed. @@ -1773,6 +1778,7 @@ async def streaming_data_capture_upload( file_extension=file_ext if file_ext[0] == "." else f".{file_ext}", tags=tags, dataset_ids=dataset_ids, + mime_type=mime_type or "", ) sensor_metadata = SensorMetadata( time_requested=datetime_to_timestamp(data_request_times[0]) if data_request_times else None, @@ -1802,6 +1808,7 @@ async def file_upload( file_extension: Optional[str] = None, tags: Optional[List[str]] = None, dataset_ids: Optional[List[str]] = None, + mime_type: Optional[str] = None, ) -> str: """Upload arbitrary file data. @@ -1832,6 +1839,7 @@ async def file_upload( isn't provided. Files with a ``.jpeg``, ``.jpg``, or ``.png`` extension will be saved to the **Images** tab. tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data. dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to. + mime_type (Optional[str]): Optional mime type of the data. Raises: GRPCError: If an invalid part ID is passed. @@ -1866,6 +1874,7 @@ async def file_upload_from_path( method_parameters: Optional[Mapping[str, Any]] = None, tags: Optional[List[str]] = None, dataset_ids: Optional[List[str]] = None, + mime_type: Optional[str] = None, ) -> str: """Upload arbitrary file data. @@ -1890,6 +1899,7 @@ async def file_upload_from_path( method_parameters (Optional[str]): Optional dictionary of the method parameters. No longer in active use. tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data. dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to. + mime_type (Optional[str]): Optional mime type of the data. Raises: GRPCError: If an invalid part ID is passed. @@ -1917,6 +1927,7 @@ async def file_upload_from_path( file_extension=file_extension if file_extension else "", tags=tags, dataset_ids=dataset_ids, + mime_type=mime_type or "", ) response: FileUploadResponse = await self._file_upload(metadata=metadata, file_contents=FileData(data=data if data else bytes())) return response.binary_data_id diff --git a/src/viam/components/__init__.py b/src/viam/components/__init__.py index e69de29bb..8a1abd54a 100644 --- a/src/viam/components/__init__.py +++ b/src/viam/components/__init__.py @@ -0,0 +1,12 @@ +from typing import Mapping, Tuple, Union + +from viam.proto.common import KinematicsFileFormat, Mesh + +KinematicsReturn = Union[ + Tuple[KinematicsFileFormat.ValueType, bytes], + Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]], +] + +__all__ = [ + "KinematicsReturn", +] diff --git a/src/viam/components/arm/__init__.py b/src/viam/components/arm/__init__.py index 60278e410..fcc9ce871 100644 --- a/src/viam/components/arm/__init__.py +++ b/src/viam/components/arm/__init__.py @@ -1,3 +1,4 @@ +from viam.components import KinematicsReturn from viam.proto.common import KinematicsFileFormat, Pose from viam.proto.component.arm import JointPositions from viam.resource.registry import Registry, ResourceRegistration @@ -10,6 +11,7 @@ "Arm", "JointPositions", "KinematicsFileFormat", + "KinematicsReturn", "Pose", ] diff --git a/src/viam/components/arm/arm.py b/src/viam/components/arm/arm.py index 5569bfafb..0c262f7ff 100644 --- a/src/viam/components/arm/arm.py +++ b/src/viam/components/arm/arm.py @@ -1,10 +1,11 @@ import abc -from typing import Any, Dict, Final, Optional, Tuple +from typing import Any, Dict, Final, Optional from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT +from .. import KinematicsReturn from ..component_base import ComponentBase -from . import JointPositions, KinematicsFileFormat, Pose +from . import JointPositions, Pose class Arm(ComponentBase): @@ -195,7 +196,7 @@ async def is_moving(self) -> bool: @abc.abstractmethod async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: """ Get the kinematics information associated with the arm. @@ -217,6 +218,7 @@ async def get_kinematics( file, either in URDF format (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_URDF``) or Viam's kinematic parameter format (spatial vector algebra) (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA``), and the second [1] value represents the byte contents of the file. + If available, a third [2] value provides meshes keyed by URDF filepath. For more information, see `Arm component `_. """ diff --git a/src/viam/components/arm/client.py b/src/viam/components/arm/client.py index 37ad25e08..523eb8b31 100644 --- a/src/viam/components/arm/client.py +++ b/src/viam/components/arm/client.py @@ -1,7 +1,8 @@ -from typing import Any, Dict, List, Mapping, Optional, Tuple +from typing import Any, Dict, List, Mapping, Optional from grpclib.client import Channel +from viam.components import KinematicsReturn from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, GetKinematicsRequest, GetKinematicsResponse from viam.proto.component.arm import ( ArmServiceStub, @@ -19,7 +20,7 @@ from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict -from . import Arm, KinematicsFileFormat, Pose +from . import Arm, Pose class ArmClient(Arm, ReconfigurableResourceRPCClientBase): @@ -113,11 +114,11 @@ async def do_command( async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: md = kwargs.get("metadata", self.Metadata()).proto request = GetKinematicsRequest(name=self.name, extra=dict_to_struct(extra)) response: GetKinematicsResponse = await self.client.GetKinematics(request, timeout=timeout, metadata=md) - return (response.format, response.kinematics_data) + return (response.format, response.kinematics_data, response.meshes_by_urdf_filepath) async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> List[Geometry]: md = kwargs.get("metadata", self.Metadata()) diff --git a/src/viam/components/arm/service.py b/src/viam/components/arm/service.py index 56e903daf..b4d3d7f5f 100644 --- a/src/viam/components/arm/service.py +++ b/src/viam/components/arm/service.py @@ -109,8 +109,13 @@ async def GetKinematics(self, stream: Stream[GetKinematicsRequest, GetKinematics assert request is not None arm = self.get_resource(request.name) timeout = stream.deadline.time_remaining() if stream.deadline else None - format, kinematics_data = await arm.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata) - response = GetKinematicsResponse(format=format, kinematics_data=kinematics_data) + kinematics = await arm.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata) + if len(kinematics) == 2: + format, kinematics_data = kinematics + meshes = {} + else: + format, kinematics_data, meshes = kinematics + response = GetKinematicsResponse(format=format, kinematics_data=kinematics_data, meshes_by_urdf_filepath=meshes) await stream.send_message(response) async def GetGeometries(self, stream: Stream[GetGeometriesRequest, GetGeometriesResponse]) -> None: diff --git a/src/viam/components/gantry/client.py b/src/viam/components/gantry/client.py index 1d300bbf9..8a3fe2bf0 100644 --- a/src/viam/components/gantry/client.py +++ b/src/viam/components/gantry/client.py @@ -1,14 +1,14 @@ -from typing import Any, Dict, List, Mapping, Optional, Tuple +from typing import Any, Dict, List, Mapping, Optional from grpclib.client import Channel +from viam.components import KinematicsReturn from viam.proto.common import ( DoCommandRequest, DoCommandResponse, Geometry, GetKinematicsRequest, GetKinematicsResponse, - KinematicsFileFormat, ) from viam.proto.component.gantry import ( GantryServiceStub, @@ -119,11 +119,11 @@ async def do_command( async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: md = kwargs.get("metadata", self.Metadata()).proto request = GetKinematicsRequest(name=self.name, extra=dict_to_struct(extra)) response: GetKinematicsResponse = await self.client.GetKinematics(request, timeout=timeout, metadata=md) - return (response.format, response.kinematics_data) + return (response.format, response.kinematics_data, response.meshes_by_urdf_filepath) async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> List[Geometry]: md = kwargs.get("metadata", self.Metadata()) diff --git a/src/viam/components/gantry/gantry.py b/src/viam/components/gantry/gantry.py index 6d552fbe5..59a07d293 100644 --- a/src/viam/components/gantry/gantry.py +++ b/src/viam/components/gantry/gantry.py @@ -1,9 +1,9 @@ import abc -from typing import Any, Dict, Final, List, Optional, Tuple +from typing import Any, Dict, Final, List, Optional -from viam.components.arm import KinematicsFileFormat from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT +from .. import KinematicsReturn from ..component_base import ComponentBase @@ -159,7 +159,7 @@ async def is_moving(self) -> bool: @abc.abstractmethod async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: """ Get the kinematics information associated with the gantry. @@ -181,6 +181,7 @@ async def get_kinematics( file, either in URDF format (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_URDF``) or Viam's kinematic parameter format (spatial vector algebra) (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA``), and the second [1] value represents the byte contents of the file. + If available, a third [2] value provides meshes keyed by URDF filepath. For more information, see `Arm component `_. """ diff --git a/src/viam/components/gantry/service.py b/src/viam/components/gantry/service.py index 7036a0517..70f99a01d 100644 --- a/src/viam/components/gantry/service.py +++ b/src/viam/components/gantry/service.py @@ -115,8 +115,13 @@ async def GetKinematics(self, stream: Stream[GetKinematicsRequest, GetKinematics assert request is not None gantry = self.get_resource(request.name) timeout = stream.deadline.time_remaining() if stream.deadline else None - format, data = await gantry.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata) - response = GetKinematicsResponse(format=format, kinematics_data=data) + kinematics = await gantry.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata) + if len(kinematics) == 2: + format, data = kinematics + meshes = {} + else: + format, data, meshes = kinematics + response = GetKinematicsResponse(format=format, kinematics_data=data, meshes_by_urdf_filepath=meshes) await stream.send_message(response) async def GetGeometries(self, stream: Stream[GetGeometriesRequest, GetGeometriesResponse]) -> None: diff --git a/src/viam/components/gripper/client.py b/src/viam/components/gripper/client.py index 359a862b3..2b8319b05 100644 --- a/src/viam/components/gripper/client.py +++ b/src/viam/components/gripper/client.py @@ -1,7 +1,8 @@ -from typing import Any, Dict, List, Mapping, Optional, Tuple +from typing import Any, Dict, List, Mapping, Optional from grpclib.client import Channel +from viam.components import KinematicsReturn from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, GetKinematicsRequest, GetKinematicsResponse from viam.proto.component.gripper import ( GrabRequest, @@ -17,7 +18,6 @@ from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict -from . import KinematicsFileFormat from .gripper import Gripper @@ -101,8 +101,8 @@ async def get_kinematics( extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs, - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: md = kwargs.get("metadata", self.Metadata()).proto request = GetKinematicsRequest(name=self.name, extra=dict_to_struct(extra)) response: GetKinematicsResponse = await self.client.GetKinematics(request, timeout=timeout, metadata=md) - return (response.format, response.kinematics_data) + return (response.format, response.kinematics_data, response.meshes_by_urdf_filepath) diff --git a/src/viam/components/gripper/gripper.py b/src/viam/components/gripper/gripper.py index 60883bbac..b49b4aa60 100644 --- a/src/viam/components/gripper/gripper.py +++ b/src/viam/components/gripper/gripper.py @@ -1,11 +1,11 @@ import abc from dataclasses import dataclass -from typing import Any, Dict, Final, Optional, Tuple +from typing import Any, Dict, Final, Optional from viam.components.component_base import ComponentBase from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT -from . import KinematicsFileFormat +from .. import KinematicsReturn class Gripper(ComponentBase): @@ -161,7 +161,7 @@ async def get_kinematics( extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs, - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> KinematicsReturn: """ Get the kinematics information associated with the gripper. @@ -183,6 +183,7 @@ async def get_kinematics( file, either in URDF format (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_URDF``) or Viam's kinematic parameter format (spatial vector algebra) (``KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA``), and the second [1] value represents the byte contents of the file. + If available, a third [2] value provides meshes keyed by URDF filepath. For more information, see `Gripper component `_. """ diff --git a/src/viam/components/gripper/service.py b/src/viam/components/gripper/service.py index 571992b0d..f40b02df3 100644 --- a/src/viam/components/gripper/service.py +++ b/src/viam/components/gripper/service.py @@ -105,6 +105,11 @@ async def GetKinematics(self, stream: Stream[GetKinematicsRequest, GetKinematics assert request is not None gripper = self.get_resource(request.name) timeout = stream.deadline.time_remaining() if stream.deadline else None - format, kinematics_data = await gripper.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout) - response = GetKinematicsResponse(format=format, kinematics_data=kinematics_data) + kinematics = await gripper.get_kinematics(extra=struct_to_dict(request.extra), timeout=timeout) + if len(kinematics) == 2: + format, kinematics_data = kinematics + meshes = {} + else: + format, kinematics_data, meshes = kinematics + response = GetKinematicsResponse(format=format, kinematics_data=kinematics_data, meshes_by_urdf_filepath=meshes) await stream.send_message(response) diff --git a/src/viam/gen/app/v1/app_pb2.py b/src/viam/gen/app/v1/app_pb2.py index cd137c5de..e54d0f293 100644 --- a/src/viam/gen/app/v1/app_pb2.py +++ b/src/viam/gen/app/v1/app_pb2.py @@ -704,4 +704,4 @@ _globals['_MACHINEPICKERCUSTOMIZATIONS']._serialized_start = 36026 _globals['_MACHINEPICKERCUSTOMIZATIONS']._serialized_end = 36150 _globals['_APPSERVICE']._serialized_start = 38142 - _globals['_APPSERVICE']._serialized_end = 49144 \ No newline at end of file + _globals['_APPSERVICE']._serialized_end = 49144 diff --git a/tests/mocks/components.py b/tests/mocks/components.py index e435db614..7e658f095 100644 --- a/tests/mocks/components.py +++ b/tests/mocks/components.py @@ -13,7 +13,7 @@ from google.protobuf.timestamp_pb2 import Timestamp from viam.components.arm import Arm, JointPositions, KinematicsFileFormat -from viam.components.audio_in import AudioIn, AudioResponse +from viam.components.audio_in import AudioIn from viam.components.audio_out import AudioOut from viam.components.base import Base from viam.components.board import Board, Tick @@ -33,8 +33,8 @@ from viam.components.switch import Switch from viam.errors import ResourceNotFoundError from viam.media.video import CameraMimeType, NamedImage, ViamImage -from viam.proto.common import AudioInfo, Capsule, Geometry, GeoPoint, Orientation, Pose, PoseInFrame, ResponseMetadata, Sphere, Vector3 -from viam.proto.component.audioin import AudioChunk as Chunk +from viam.proto.common import AudioInfo, Capsule, Geometry, GeoPoint, Orientation, Pose, PoseInFrame, ResponseMetadata, Sphere, Vector3, Mesh +from viam.proto.component.audioin import AudioChunk, GetAudioResponse from viam.proto.component.board import PowerMode from viam.proto.component.encoder import PositionType from viam.streams import StreamWithIterator @@ -51,7 +51,7 @@ def __init__(self, name: str): self.position = Pose(x=1, y=2, z=3, o_x=2, o_y=3, o_z=4, theta=20) self.joint_positions = JointPositions(values=[0, 0, 0, 0, 0, 0]) self.is_stopped = True - self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) self.geometries = GEOMETRIES self.extra = None self.timeout: Optional[float] = None @@ -100,7 +100,7 @@ async def is_moving(self) -> bool: async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: self.extra = extra self.timeout = timeout return self.kinematics @@ -117,60 +117,48 @@ async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Option class MockAudioIn(AudioIn): def __init__(self, name: str, properties: AudioIn.Properties): super().__init__(name) - self.geometries = GEOMETRIES self.properties = properties + self.geometries = GEOMETRIES self.timeout: Optional[float] = None self.extra: Optional[Dict[str, Any]] = None async def get_audio( - self, - codec: str, - duration_seconds: float, - previous_timestamp_ns: int, - *, - extra: Optional[Dict[str, Any]] = None, - timeout: Optional[float] = None, - **kwargs, - ): - async def read() -> AsyncIterator[AudioResponse]: - # Generate mock audio chunks - for i in range(2): - chunk_data = f"audio_chunk_{i}".encode("utf-8") - timestamp_start = previous_timestamp_ns + i * 1000000000 # 1 second intervals in nanoseconds - timestamp_end = timestamp_start + 1000000000 - - audio_chunk = Chunk( - audio_data=chunk_data, - audio_info=AudioInfo( - codec=codec, sample_rate_hz=self.properties.sample_rate_hz, num_channels=self.properties.num_channels - ), - sequence=i, - start_timestamp_nanoseconds=timestamp_start, - end_timestamp_nanoseconds=timestamp_end, + self, codec: str, duration_seconds: float, previous_timestamp_ns: int, *, timeout: Optional[float] = None, **kwargs + ) -> StreamWithIterator[GetAudioResponse]: + self.timeout = timeout + + async def read() -> AsyncIterator[GetAudioResponse]: + for sequence in range(2): + start_ts = previous_timestamp_ns + (sequence + 1) * 1_000_000_000 + end_ts = start_ts + 1_000_000_000 + yield GetAudioResponse( + audio=AudioChunk( + audio_data=b"mock-audio-data", + audio_info=AudioInfo( + codec=codec, + sample_rate_hz=self.properties.sample_rate_hz, + num_channels=self.properties.num_channels, + ), + start_timestamp_nanoseconds=start_ts, + end_timestamp_nanoseconds=end_ts, + sequence=sequence, + ) ) - audio_response = AudioResponse(audio=audio_chunk, request_id="mock_request") - yield audio_response - - self.extra = extra - self.timeout = timeout return StreamWithIterator(read()) - async def get_properties( - self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> AudioIn.Properties: - self.extra = extra + async def get_properties(self, *, timeout: Optional[float] = None, **kwargs) -> AudioIn.Properties: self.timeout = timeout return self.properties - async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> List[Geometry]: + async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Optional[float] = None, **kwargs) -> Mapping[str, ValueTypes]: + return {"command": command} + + async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs): self.extra = extra self.timeout = timeout return self.geometries - async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Optional[float] = None, **kwargs) -> Mapping[str, ValueTypes]: - return {"command": command} - class MockAudioOut(AudioOut): def __init__(self, name: str, properties: AudioOut.Properties): @@ -518,7 +506,7 @@ def __init__(self, name: str, position: List[float], lengths: List[float]): self.position = position self.lengths = lengths self.is_stopped = True - self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) self.extra = None self.homed = True self.speeds = Optional[List[float]] @@ -567,7 +555,7 @@ async def is_moving(self) -> bool: async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: self.extra = extra self.timeout = timeout return self.kinematics @@ -599,7 +587,7 @@ class MockGripper(Gripper): def __init__(self, name: str): self.opened = False self.geometries = GEOMETRIES - self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + self.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) self.holding_something = False self.extra = None self.is_stopped = True @@ -642,7 +630,7 @@ async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeou async def get_kinematics( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs - ) -> Tuple[KinematicsFileFormat.ValueType, bytes]: + ) -> Tuple[KinematicsFileFormat.ValueType, bytes, Mapping[str, Mesh]]: self.extra = extra self.timeout = timeout return self.kinematics diff --git a/tests/test_arm.py b/tests/test_arm.py index 9a2bfd07c..ac57357ec 100644 --- a/tests/test_arm.py +++ b/tests/test_arm.py @@ -35,7 +35,7 @@ class TestArm: arm = MockArm(name="arm") pose = Pose(x=5, y=5, z=5, o_x=5, o_y=5, o_z=5, theta=20) joint_pos = JointPositions(values=[1, 8, 2]) - kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) async def test_move_to_position(self): await self.arm.move_to_position(self.pose) @@ -92,7 +92,7 @@ def setup_class(cls): cls.service = ArmRPCService(cls.manager) cls.pose = Pose(x=5, y=5, z=5, o_x=5, o_y=5, o_z=5, theta=20) cls.joint_pos = JointPositions(values=[1, 8, 2]) - cls.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + cls.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) async def test_move_to_position(self): async with ChannelFor([self.service]) as channel: @@ -155,7 +155,7 @@ async def test_get_kinematics(self): client = ArmServiceStub(channel) request = GetKinematicsRequest(name=self.name) response: GetKinematicsResponse = await client.GetKinematics(request) - assert (response.format, response.kinematics_data) == self.kinematics + assert (response.format, response.kinematics_data, response.meshes_by_urdf_filepath) == self.kinematics async def test_get_geometries(self): async with ChannelFor([self.service]) as channel: @@ -182,7 +182,7 @@ def setup_class(cls): cls.service = ArmRPCService(cls.manager) cls.pose = Pose(x=5, y=5, z=5, o_x=5, o_y=5, o_z=5, theta=20) cls.joint_pos = JointPositions(values=[1, 8, 2]) - cls.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + cls.kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) async def test_move_to_position(self): async with ChannelFor([self.service]) as channel: diff --git a/tests/test_gantry.py b/tests/test_gantry.py index 728f1926a..e22501df1 100644 --- a/tests/test_gantry.py +++ b/tests/test_gantry.py @@ -72,9 +72,10 @@ async def test_extra(self): assert self.gantry.extra == extra async def test_get_kinematics(self): - format, data = await self.gantry.get_kinematics() + format, data, meshes = await self.gantry.get_kinematics() assert format == self.gantry.kinematics[0] assert data == self.gantry.kinematics[1] + assert meshes == self.gantry.kinematics[2] async def test_timeout(self): assert self.gantry.timeout is None @@ -258,9 +259,10 @@ async def test_extra(self): async def test_get_kinematics(self): async with ChannelFor([self.service]) as channel: client = GantryClient(self.gantry.name, channel) - format, data = await client.get_kinematics(timeout=1.1) + format, data, meshes = await client.get_kinematics(timeout=1.1) assert format == self.gantry.kinematics[0] assert data == self.gantry.kinematics[1] + assert meshes == self.gantry.kinematics[2] assert self.gantry.timeout == loose_approx(1.1) async def test_get_geometries(self): diff --git a/tests/test_gripper.py b/tests/test_gripper.py index 38499b724..22b88ea2e 100644 --- a/tests/test_gripper.py +++ b/tests/test_gripper.py @@ -87,7 +87,7 @@ async def test_get_geometries(self, gripper: MockGripper): assert geometries == GEOMETRIES async def test_get_kinematics(self, gripper: MockGripper): - kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) kd = await gripper.get_kinematics(extra={"1": "2"}) assert kd == kinematics assert gripper.extra == {"1": "2"} @@ -162,10 +162,10 @@ async def test_get_geometries(self, gripper: MockGripper, service: GripperRPCSer async def test_get_kinematics(self, gripper: MockGripper, service: GripperRPCService): async with ChannelFor([service]) as channel: client = GripperServiceStub(channel) - kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) request = GetKinematicsRequest(name=gripper.name) response: GetKinematicsResponse = await client.GetKinematics(request) - assert (response.format, response.kinematics_data) == kinematics + assert (response.format, response.kinematics_data, response.meshes_by_urdf_filepath) == kinematics class TestClient: @@ -226,7 +226,7 @@ async def test_get_geometries(self, gripper: MockGripper, service: GripperRPCSer async def test_get_kinematics(self, gripper: MockGripper, service: GripperRPCService): async with ChannelFor([service]) as channel: client = GripperClient(gripper.name, channel) - kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02") + kinematics = (KinematicsFileFormat.KINEMATICS_FILE_FORMAT_SVA, b"\x00\x01\x02", {}) kd = await client.get_kinematics(extra={"1": "2"}) assert kd == kinematics assert gripper.extra == {"1": "2"} diff --git a/tests/test_registry.py b/tests/test_registry.py index ad1b70583..72ed8223f 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -24,7 +24,6 @@ def __init__(self, name: str, channel: Channel): def test_components_register_themselves_correctly(): assert API(RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "arm") in Registry.REGISTERED_APIS() - assert API(RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "audio_in") in Registry.REGISTERED_APIS() assert API(RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "audio_out") in Registry.REGISTERED_APIS() assert API(RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "base") in Registry.REGISTERED_APIS() assert API(RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "board") in Registry.REGISTERED_APIS()