Source code for smarts.core.utils.pybullet

# Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from multiprocessing import Pipe, Process
from multiprocessing.connection import Connection

from smarts.core.utils.core_logging import suppress_output

# XXX: Importing pybullet logs an annoying build version tag. There's no "friendly"
#      way to fix this since they simply use print(...). Disabling logging at the
#      time of import is our hack.
with suppress_output():
    import pybullet
    from pybullet import *
    from pybullet_utils import bullet_client


[docs]class SafeBulletClient(bullet_client.BulletClient): """A wrapper for pybullet to manage different clients.""" def __init__(self, connection_mode=None): """Creates a Bullet client and connects to a simulation. Args: connection_mode: `None` connects to an existing simulation or, if fails, creates a new headless simulation, `pybullet.GUI` creates a new simulation with a GUI, `pybullet.DIRECT` creates a headless simulation, `pybullet.SHARED_MEMORY` connects to an existing simulation. """ with suppress_output(stderr=False): super().__init__(connection_mode=connection_mode) def __del__(self): """Clean up connection if not already done.""" try: super().__del__() except TypeError as error: # Pybullet 3.2.6 currently attempts to catch an error type that does not exist. if not error.args[0].contains("BaseException"): raise def __getattr__(self, name): """Inject the client id into Bullet functions.""" if name in {"__deepcopy__", "__getstate__", "__setstate__"}: raise RuntimeError(f"{self.__class__} does not allow `{name}`") return super().__getattr__(name)
[docs]class BulletClientMACOS: """This wrapper class is a hack for `macOS` where running PyBullet in GUI mode, alongside Panda3D segfaults. It seems due to running two OpenGL applications in the same process. Here we spawn a process to run PyBullet and forward all calls to it over unix pipes. N.B. This class can be directly subbed-in for pybullet_utils's BulletClient but your application must start from a, if __name__ == "__main__:": # https://turtlemonvh.github.io/python-multiprocessing-and-corefoundation-libraries.html import multiprocessing as mp mp.set_start_method('spawn', force=True) """ def __init__(self, bullet_connect_mode=pybullet.GUI): self._parent_conn, self._child_conn = Pipe() self.process = Process( target=BulletClientMACOS.consume, args=( bullet_connect_mode, self._child_conn, ), ) self.process.start() def __getattr__(self, name): def wrapper(*args, **kwargs): self._parent_conn.send((name, args, kwargs)) return self._parent_conn.recv() return wrapper
[docs] @staticmethod def consume(bullet_connect_mode, connection: Connection): """Builds a child pybullet process. Args: bullet_connect_mode: The type of bullet process. connection: The child end of a pipe. """ # runs in sep. process client = SafeBulletClient(bullet_connect_mode) while True: method, args, kwargs = connection.recv() result = getattr(client, method)(*args, **kwargs) connection.send(result)