Skip to content

Commit

Permalink
Merge pull request #97 from modular-ml/dev_win11
Browse files Browse the repository at this point in the history
Partial beta support for Windows 10 and 11
  • Loading branch information
fabawi committed Feb 15, 2024
2 parents fc789d4 + e9b50dc commit 249a9de
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 46 deletions.
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).<!-- [YARP installation guide](docs/yarp_install_lnk.md). -->
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)
Expand All @@ -79,10 +79,18 @@ 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
* NumPy >= 1.19


* YARP >= v3.3.2
Expand Down Expand Up @@ -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
Expand All @@ -335,33 +345,34 @@ 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*]

## Image

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*]


13 changes: 11 additions & 2 deletions examples/sensors/cam_mic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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")
Expand Down
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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={
Expand Down Expand Up @@ -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",
Expand Down
11 changes: 5 additions & 6 deletions wrapyfi/connect/clients.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
from glob import glob
from pathlib import Path

from wrapyfi.utils import dynamic_module_import

Expand Down Expand Up @@ -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())
Expand Down
22 changes: 16 additions & 6 deletions wrapyfi/connect/listeners.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import os
from glob import glob
from pathlib import Path


from wrapyfi.utils import SingletonOptimized, dynamic_module_import

Expand Down Expand Up @@ -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())
Expand Down
11 changes: 5 additions & 6 deletions wrapyfi/connect/publishers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
from glob import glob
from pathlib import Path

from wrapyfi.utils import SingletonOptimized, dynamic_module_import

Expand Down Expand Up @@ -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())
Expand Down
11 changes: 5 additions & 6 deletions wrapyfi/connect/servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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())
Expand Down
8 changes: 4 additions & 4 deletions wrapyfi/encoders.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""

Expand Down Expand Up @@ -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
"""

Expand Down
7 changes: 7 additions & 0 deletions wrapyfi/listeners/zeromq.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__(
Expand Down
13 changes: 13 additions & 0 deletions wrapyfi/publishers/zeromq.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions wrapyfi/servers/zeromq.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion wrapyfi_extensions/yarp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down

0 comments on commit 249a9de

Please sign in to comment.