From b5f4a26d03de9e9bdb2a719f0a41181b3b832cb5 Mon Sep 17 00:00:00 2001 From: fabawi Date: Wed, 14 Feb 2024 00:21:11 +0100 Subject: [PATCH 1/4] Windows 11 experimental support --- examples/sensors/cam_mic.py | 13 +++++++++++-- wrapyfi/connect/clients.py | 11 +++++------ wrapyfi/connect/listeners.py | 22 ++++++++++++++++------ wrapyfi/connect/publishers.py | 11 +++++------ wrapyfi/connect/servers.py | 11 +++++------ wrapyfi/listeners/zeromq.py | 7 +++++++ wrapyfi/publishers/zeromq.py | 13 +++++++++++++ wrapyfi/servers/zeromq.py | 7 +++++++ 8 files changed, 69 insertions(+), 26 deletions(-) diff --git a/examples/sensors/cam_mic.py b/examples/sensors/cam_mic.py index 34ad2ff..644509c 100755 --- a/examples/sensors/cam_mic.py +++ b/examples/sensors/cam_mic.py @@ -175,7 +175,7 @@ def capture_cam_mic(self): pass elif self.enable_video: while True: - self.collect_cam(mware=self.mware) + self.collect_cam(mware=self.mware, img_width=self.img_width, img_height=self.img_height) def _mic_callback(self, audio, frames, time, status): """ @@ -291,7 +291,16 @@ def main(args): print(sd.query_devices()) return - cam_mic = CamMic(stream=args.stream, mic_source=args.mic_source, mware=args.mware) + cam_mic = CamMic(stream=args.stream, + mic_source=args.mic_source, + mic_rate=args.mic_rate, + mic_chunk=args.mic_chunk, + mic_channels=args.mic_channels, + img_source=args.img_source, + img_width=args.img_width, + img_height=args.img_height, + mware=args.mware, + ) if args.mode == "publish": cam_mic.activate_communication(CamMic.collect_cam, mode="publish") diff --git a/wrapyfi/connect/clients.py b/wrapyfi/connect/clients.py index 45666f2..a8e44f4 100755 --- a/wrapyfi/connect/clients.py +++ b/wrapyfi/connect/clients.py @@ -1,6 +1,7 @@ import logging import os from glob import glob +from pathlib import Path from wrapyfi.utils import dynamic_module_import @@ -34,13 +35,11 @@ def scan(): """ Scan for clients and add them to the registry. """ - modules = glob( - os.path.join(os.path.dirname(__file__), "..", "clients", "*.py"), - recursive=True, - ) + base_dir = Path(__file__).parent.parent / "clients" + modules = glob(str(base_dir / "*.py"), recursive=True) + modules = [ - "wrapyfi.clients." - + module.replace(os.path.dirname(__file__) + "/../clients/", "") + "wrapyfi.clients." + Path(module).relative_to(base_dir).as_posix() for module in modules ] dynamic_module_import(modules, globals()) diff --git a/wrapyfi/connect/listeners.py b/wrapyfi/connect/listeners.py index 54fcdfe..6247c75 100755 --- a/wrapyfi/connect/listeners.py +++ b/wrapyfi/connect/listeners.py @@ -1,6 +1,8 @@ import logging import os from glob import glob +from pathlib import Path + from wrapyfi.utils import SingletonOptimized, dynamic_module_import @@ -79,13 +81,21 @@ def scan(): """ Scan for listeners and add them to the registry. """ - modules = glob( - os.path.join(os.path.dirname(__file__), "..", "listeners", "*.py"), - recursive=True, - ) + # modules = glob( + # os.path.join(os.path.dirname(__file__), "..", "listeners", "*.py"), + # recursive=True, + # ) + # modules = [ + # "wrapyfi.listeners." + # + module.replace(os.path.dirname(__file__) + "/../listeners/", "") + # for module in modules + # ] + # dynamic_module_import(modules, globals()) + base_dir = Path(__file__).parent.parent / "listeners" + modules = glob(str(base_dir / "*.py"), recursive=True) + modules = [ - "wrapyfi.listeners." - + module.replace(os.path.dirname(__file__) + "/../listeners/", "") + "wrapyfi.listeners." + Path(module).relative_to(base_dir).as_posix() for module in modules ] dynamic_module_import(modules, globals()) diff --git a/wrapyfi/connect/publishers.py b/wrapyfi/connect/publishers.py index de92df1..0151c87 100755 --- a/wrapyfi/connect/publishers.py +++ b/wrapyfi/connect/publishers.py @@ -1,6 +1,7 @@ import logging import os from glob import glob +from pathlib import Path from wrapyfi.utils import SingletonOptimized, dynamic_module_import @@ -80,13 +81,11 @@ def scan(): """ Scan for publishers and add them to the registry. """ - modules = glob( - os.path.join(os.path.dirname(__file__), "..", "publishers", "*.py"), - recursive=True, - ) + base_dir = Path(__file__).parent.parent / "publishers" + modules = glob(str(base_dir / "*.py"), recursive=True) + modules = [ - "wrapyfi.publishers." - + module.replace(os.path.dirname(__file__) + "/../publishers/", "") + "wrapyfi.publishers." + Path(module).relative_to(base_dir).as_posix() for module in modules ] dynamic_module_import(modules, globals()) diff --git a/wrapyfi/connect/servers.py b/wrapyfi/connect/servers.py index 831a924..efb0091 100755 --- a/wrapyfi/connect/servers.py +++ b/wrapyfi/connect/servers.py @@ -2,6 +2,7 @@ import os from glob import glob from typing import Optional +from pathlib import Path from wrapyfi.utils import dynamic_module_import @@ -36,13 +37,11 @@ def scan(): """ Scan for servers and add them to the registry. """ - modules = glob( - os.path.join(os.path.dirname(__file__), "..", "servers", "*.py"), - recursive=True, - ) + base_dir = Path(__file__).parent.parent / "servers" + modules = glob(str(base_dir / "*.py"), recursive=True) + modules = [ - "wrapyfi.servers." - + module.replace(os.path.dirname(__file__) + "/../servers/", "") + "wrapyfi.servers." + Path(module).relative_to(base_dir).as_posix() for module in modules ] dynamic_module_import(modules, globals()) diff --git a/wrapyfi/listeners/zeromq.py b/wrapyfi/listeners/zeromq.py index 961ee8e..ac6448a 100755 --- a/wrapyfi/listeners/zeromq.py +++ b/wrapyfi/listeners/zeromq.py @@ -24,6 +24,13 @@ WATCHDOG_POLL_REPEAT = None +if os.name == "nt" and ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN == "process": + ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN = "thread" + logging.warning("[ZeroMQ] Wrapyfi does not support multiprocessing on Windows. Please set " + "the environment variable WRAPYFI_ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN='thread'. " + "Switching automatically to 'thread' mode. ") + + class ZeroMQListener(Listener): def __init__( diff --git a/wrapyfi/publishers/zeromq.py b/wrapyfi/publishers/zeromq.py index d531b16..2585391 100644 --- a/wrapyfi/publishers/zeromq.py +++ b/wrapyfi/publishers/zeromq.py @@ -35,6 +35,19 @@ WATCHDOG_POLL_REPEAT = None +if os.name == "nt" and PROXY_BROKER_SPAWN == "process" and START_PROXY_BROKER: + PROXY_BROKER_SPAWN = "thread" + logging.warning("[ZeroMQ] Wrapyfi does not support multiprocessing on Windows. Please set " + "the environment variable WRAPYFI_ZEROMQ_PROXY_BROKER_SPAWN='thread'. " + "Switching automatically to 'thread' mode. ") + +if os.name == "nt" and ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN == "process": + ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN = "thread" + logging.warning("[ZeroMQ] Wrapyfi does not support multiprocessing on Windows. Please set " + "the environment variable WRAPYFI_ZEROMQ_PUBSUB_MONITOR_LISTENER_SPAWN='thread'. " + "Switching automatically to 'thread' mode. ") + + class ZeroMQPublisher(Publisher): def __init__( self, diff --git a/wrapyfi/servers/zeromq.py b/wrapyfi/servers/zeromq.py index 4c21eb8..9a218ad 100644 --- a/wrapyfi/servers/zeromq.py +++ b/wrapyfi/servers/zeromq.py @@ -23,6 +23,13 @@ WATCHDOG_POLL_REPEAT = None +if os.name == "nt" and PROXY_BROKER_SPAWN == "process" and START_PROXY_BROKER: + PROXY_BROKER_SPAWN = "thread" + logging.warning("[ZeroMQ] Wrapyfi does not support multiprocessing on Windows. Please set " + "the environment variable WRAPYFI_ZEROMQ_PROXY_BROKER_SPAWN='thread'. " + "Switching automatically to 'thread' mode. ") + + class ZeroMQServer(Server): def __init__( self, From 7e448b46c8488570669f760dc1fc30101f2145f8 Mon Sep 17 00:00:00 2001 From: abawi Date: Wed, 14 Feb 2024 20:04:34 +0100 Subject: [PATCH 2/4] Update ReadME for Windows 11 support indication --- README.md | 19 +++++++++++++++---- setup.py | 2 ++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8646dee..ffa564b 100755 --- a/README.md +++ b/README.md @@ -62,12 +62,12 @@ Before using Wrapyfi, YARP, ROS, or ZeroMQ must be installed. * Follow the [YARP installation guide](https://github.com/fabawi/wrapyfi/tree/main/wrapyfi_extensions/yarp/README.md?rank=0). Note that the iCub package is not needed for Wrapyfi to work and does not have to be installed if you do not intend on using the iCub robot. -* For installing ROS, follow the [ROS installation guide](http://wiki.ros.org/noetic/Installation/Ubuntu). +* For installing ROS, follow the ROS installation guide [\[Ubuntu\]](http://wiki.ros.org/noetic/Installation/Ubuntu)[\[Windows\]](https://wiki.ros.org/noetic/Installation/Windows). We recommend installing ROS on Conda using the [RoboStack](https://github.com/RoboStack/ros-noetic) environment. Additionally, the [Wrapyfi ROS interfaces](https://github.com/modular-ml/wrapyfi_ros_interfaces/blob/master/README.md?rank=0) must be built to support messages needed for audio transmission [![ROS Package Index](https://img.shields.io/ros/v/noetic/wrapyfi_ros_interfaces)](https://index.ros.org/r/wrapyfi_ros_interfaces/#noetic) -* For installing ROS 2, follow the [ROS 2 installation guide](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html). +* For installing ROS 2, follow the ROS 2 installation guide [\[Ubuntu\]](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html)[\[Windows\]](https://docs.ros.org/en/humble/Installation/Windows-Install-Binary.html). We recommend installing ROS 2 on Conda using the [RoboStack](https://github.com/RoboStack/ros-humble) environment. Additionally, the [Wrapyfi ROS 2 interfaces](https://github.com/modular-ml/wrapyfi_ros2_interfaces/blob/master/README.md?rank=0) must be built to support messages and services needed for audio transmission and the REQ/REP pattern support [![ROS Package Index](https://img.shields.io/ros/v/humble/wrapyfi_ros2_interfaces)](https://index.ros.org/p/wrapyfi_ros2_interfaces/#humble) @@ -79,7 +79,15 @@ A standalone broker can be found [here](https://github.com/fabawi/wrapyfi/tree/m #### Compatibility -* Ubuntu >= 18.04 (Not tested with earlier versions of Ubuntu or other OS) +* Operating System + * [X] Ubuntu >= 18.04 (Not tested with earlier versions of Ubuntu or other Linux distributions) + * [X] Windows >= 10 [*beta support*]: + * Multiprocessing is disabled. ZeroMQ brokers spawn as threads only + * Not tested with YARP and ROS 2 + * ROS only tested within mamba/micromamba environment installed using [RoboStack](https://github.com/RoboStack/ros-noetic) + * ROS and ROS 2 interfaces not tested + * Installation instructions across Wrapyfi guides and tutorials are not guaranteed to be compatible with Windows 11 + * [ ] MacOS 10.14 Mojave [*planned for Wrapyfi v0.5*] * Python >= 3.6 * OpenCV >= 4.2 * Numpy >= 1.19 @@ -323,7 +331,9 @@ For more examples of usage, refer to the [user guide](docs/usage.md). Run script * [x] **YARP** * [x] **ROS** * [x] **ROS 2** -* [x] **ZeroMQ** (beta feature: `should_wait` trigger introduced with event monitoring) +* [x] **ZeroMQ** [*beta feature*]: + * `should_wait` trigger introduced with event monitoring + * Event monitoring currently cannot be disabled [*planned for Wrapyfi v0.5*] ## Serializers @@ -351,6 +361,7 @@ Supported Objects by the `NativeObject` type include: * [x] [**Pint Quantity**](https://pint.readthedocs.io/en/stable/) * [ ] [**pandas 2.0 DataFrame|Series**](https://pandas.pydata.org/docs/) * [ ] [**Gmpy 2 MPZ**](https://gmpy2.readthedocs.io/en/latest/) +* [ ] [**MLX**](https://ml-explore.github.io/mlx/build/html/index.html) [*planned for Wrapyfi v0.5*] ## Image diff --git a/setup.py b/setup.py index 62b5eea..b8d71df 100755 --- a/setup.py +++ b/setup.py @@ -79,6 +79,8 @@ def check_cv2(default_python="opencv-python"): "Topic :: System :: Distributed Computing", "License :: OSI Approved :: MIT License", "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows :: Windows 10", + "Operating System :: Microsoft :: Windows :: Windows 11", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", From faf403553dbc761f4e163524664ce29d5221a9af Mon Sep 17 00:00:00 2001 From: abawi Date: Thu, 15 Feb 2024 19:20:48 +0100 Subject: [PATCH 3/4] Minor fixes to README.md --- README.md | 20 ++++++++++---------- wrapyfi/encoders.py | 8 ++++---- wrapyfi_extensions/yarp/README.md | 8 +++++++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ffa564b..1cc0601 100755 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ A standalone broker can be found [here](https://github.com/fabawi/wrapyfi/tree/m * [ ] MacOS 10.14 Mojave [*planned for Wrapyfi v0.5*] * Python >= 3.6 * OpenCV >= 4.2 -* Numpy >= 1.19 +* NumPy >= 1.19 * YARP >= v3.3.2 @@ -345,21 +345,21 @@ For more examples of usage, refer to the [user guide](docs/usage.md). Run script Supported Objects by the `NativeObject` type include: -* [x] [**Numpy Array|Generic**](https://numpy.org/doc/1.23/) -* [x] [**Pytorch Tensor**](https://pytorch.org/docs/stable/index.html) +* [x] [**NumPy Array | Generic**](https://numpy.org/doc/1.23/) +* [x] [**PyTorch Tensor**](https://pytorch.org/docs/stable/index.html) * [x] [**Tensorflow 2 Tensor**](https://www.tensorflow.org/api_docs/python/tf) * [x] [**JAX Tensor**](https://jax.readthedocs.io/en/latest/) * [x] [**MXNet Tensor**](https://mxnet.apache.org/versions/1.9.1/api/python.html) * [x] [**Paddlepaddle Tensor**](https://www.paddlepaddle.org.cn/documentation/docs/en/guides/index_en.html) -* [x] [**pandas DataFrame|Series**](https://pandas.pydata.org/docs/) +* [x] [**pandas DataFrame | Series**](https://pandas.pydata.org/docs/) * [x] [**Pillow Image**](https://pillow.readthedocs.io/en/stable/reference/Image.html) * [x] [**PyArrow Array**](https://arrow.apache.org/docs/python/index.html) * [x] [**CuPy Array**](https://docs.cupy.dev/en/stable/index.html) -* [x] [**Xarray DataArray|Dataset**](http://xarray.pydata.org/en/stable/) -* [x] [**Dask Array|DataFrame**](https://www.dask.org/get-started) -* [x] [**Zarr Array|Group**](https://zarr.readthedocs.io/en/stable/) +* [x] [**Xarray DataArray | Dataset**](http://xarray.pydata.org/en/stable/) +* [x] [**Dask Array | DataFrame**](https://www.dask.org/get-started) +* [x] [**Zarr Array | Group**](https://zarr.readthedocs.io/en/stable/) * [x] [**Pint Quantity**](https://pint.readthedocs.io/en/stable/) -* [ ] [**pandas 2.0 DataFrame|Series**](https://pandas.pydata.org/docs/) +* [ ] [**pandas 2.0 DataFrame | Series**](https://pandas.pydata.org/docs/) * [ ] [**Gmpy 2 MPZ**](https://gmpy2.readthedocs.io/en/latest/) * [ ] [**MLX**](https://ml-explore.github.io/mlx/build/html/index.html) [*planned for Wrapyfi v0.5*] @@ -367,12 +367,12 @@ Supported Objects by the `NativeObject` type include: Supported Objects by the `Image` type include: -* [x] **Numpy Array** (supports many libraries including [scikit-image](https://scikit-image.org/), [imageio](https://imageio.readthedocs.io/en/stable/), [Open CV](https://opencv.org/), [imutils](https://github.com/PyImageSearch/imutils), [matplotlib.image](https://matplotlib.org/stable/api/image_api.html), and [Mahotas](https://mahotas.readthedocs.io/en/latest/)) +* [x] **NumPy Array** [*supports many libraries including [scikit-image](https://scikit-image.org/), [imageio](https://imageio.readthedocs.io/en/stable/), [Open CV](https://opencv.org/), [imutils](https://github.com/PyImageSearch/imutils), [matplotlib.image](https://matplotlib.org/stable/api/image_api.html), and [Mahotas](https://mahotas.readthedocs.io/en/latest/)*] ## Sound Supported Objects by the `AudioChunk` type include: -* [x] **Numpy Array**,int (supports the [sounddevice](https://python-sounddevice.readthedocs.io/en/0.4.5/) format) +* [x] Tuple(**NumPy Array**, int) [*supports the [sounddevice](https://python-sounddevice.readthedocs.io/en/0.4.5/) format*] diff --git a/wrapyfi/encoders.py b/wrapyfi/encoders.py index d4bd2f6..d014228 100644 --- a/wrapyfi/encoders.py +++ b/wrapyfi/encoders.py @@ -14,8 +14,8 @@ class JsonEncoder(json.JSONEncoder): A custom JSON encoder that can encode: - Sets - Datetime objects - - Numpy datetime64 objects - - Numpy ndarray objects + - NumPy datetime64 objects + - NumPy ndarray objects - Objects registered with the PluginRegistrar """ @@ -104,8 +104,8 @@ class JsonDecodeHook(object): - Tuples - Sets - Datetime objects - - Numpy datetime64 objects - - Numpy ndarray objects + - NumPy datetime64 objects + - NumPy ndarray objects - Objects registered with the PluginRegistrar """ diff --git a/wrapyfi_extensions/yarp/README.md b/wrapyfi_extensions/yarp/README.md index 9725fd1..7b205de 100644 --- a/wrapyfi_extensions/yarp/README.md +++ b/wrapyfi_extensions/yarp/README.md @@ -3,8 +3,14 @@ To run the iCub simulator, the YARP framework as well as the iCub simulator need For this guide, we install YARP v3.3.2 and iCub (icub-main) v1.16.0. ## Installing YARP + +```warning +For installing YARP on **Windows** [follow these instructions](https://www.yarp.it/latest/install_yarp_windows.html) +or install it within a [conda or conda-like (mamba/micromamba) environment](https://github.com/conda-forge/yarp-feedstock) +``` + Several instructional tutorials are available for installing YARP and its python bindings. -The installation process described here works on Ubuntu 20.04 and Python 3.8. +The installation process described here targets Ubuntu 20.04 and Python 3.8. Download the YARP source and install following the [official installation documentation](https://www.yarp.it/install_yarp_linux.html) (do not use the precompiled binaries). Set the environment variable ```YARP_ROOT``` to the YARP source location: From e9b50dca11f30a6b081d36256a01dbbff44647e7 Mon Sep 17 00:00:00 2001 From: Fares Abawi Date: Thu, 15 Feb 2024 19:21:43 +0100 Subject: [PATCH 4/4] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b8d71df..932becb 100755 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ def check_cv2(default_python="opencv-python"): setuptools.setup( name="wrapyfi", - version="0.4.40", + version="0.4.41", description="Wrapyfi is a wrapper for simplifying Middleware communication", url="https://github.com/fabawi/wrapyfi/blob/main/", project_urls={