pysio-hermes 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pysio_hermes-0.1.0/LICENSE +20 -0
- pysio_hermes-0.1.0/PKG-INFO +178 -0
- pysio_hermes-0.1.0/README.md +131 -0
- pysio_hermes-0.1.0/examples/main.py +223 -0
- pysio_hermes-0.1.0/pyproject.toml +64 -0
- pysio_hermes-0.1.0/pysio_hermes.egg-info/PKG-INFO +178 -0
- pysio_hermes-0.1.0/pysio_hermes.egg-info/SOURCES.txt +55 -0
- pysio_hermes-0.1.0/pysio_hermes.egg-info/dependency_links.txt +1 -0
- pysio_hermes-0.1.0/pysio_hermes.egg-info/requires.txt +20 -0
- pysio_hermes-0.1.0/pysio_hermes.egg-info/top_level.txt +3 -0
- pysio_hermes-0.1.0/setup.cfg +4 -0
- pysio_hermes-0.1.0/src/hermes/__init__.py +0 -0
- pysio_hermes-0.1.0/src/hermes/base/__init__.py +0 -0
- pysio_hermes-0.1.0/src/hermes/base/broker/__init__.py +1 -0
- pysio_hermes-0.1.0/src/hermes/base/broker/broker.py +362 -0
- pysio_hermes-0.1.0/src/hermes/base/broker/broker_interface.py +152 -0
- pysio_hermes-0.1.0/src/hermes/base/broker/broker_states.py +350 -0
- pysio_hermes-0.1.0/src/hermes/base/delay_estimator.py +53 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/__init__.py +11 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/consumer.py +163 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/consumer_interface.py +32 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/node.py +150 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/node_interface.py +86 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/node_states.py +103 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/pipeline.py +208 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/pipeline_interface.py +52 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/producer.py +168 -0
- pysio_hermes-0.1.0/src/hermes/base/nodes/producer_interface.py +69 -0
- pysio_hermes-0.1.0/src/hermes/base/state_interface.py +42 -0
- pysio_hermes-0.1.0/src/hermes/base/storage/__init__.py +1 -0
- pysio_hermes-0.1.0/src/hermes/base/storage/storage.py +837 -0
- pysio_hermes-0.1.0/src/hermes/base/storage/storage_interface.py +73 -0
- pysio_hermes-0.1.0/src/hermes/base/storage/storage_states.py +93 -0
- pysio_hermes-0.1.0/src/hermes/base/stream.py +393 -0
- pysio_hermes-0.1.0/src/hermes/datastructures/__init__.py +0 -0
- pysio_hermes-0.1.0/src/hermes/datastructures/cache.py +121 -0
- pysio_hermes-0.1.0/src/hermes/datastructures/fifo.py +241 -0
- pysio_hermes-0.1.0/src/hermes/dummy/__init__.py +4 -0
- pysio_hermes-0.1.0/src/hermes/dummy/consumer.py +59 -0
- pysio_hermes-0.1.0/src/hermes/dummy/pipeline.py +83 -0
- pysio_hermes-0.1.0/src/hermes/dummy/producer.py +99 -0
- pysio_hermes-0.1.0/src/hermes/dummy/stream.py +53 -0
- pysio_hermes-0.1.0/src/hermes/logger/__init__.py +0 -0
- pysio_hermes-0.1.0/src/hermes/logger/consumer.py +66 -0
- pysio_hermes-0.1.0/src/hermes/utils/__init__.py +0 -0
- pysio_hermes-0.1.0/src/hermes/utils/angle_utils.py +59 -0
- pysio_hermes-0.1.0/src/hermes/utils/argparse_utils.py +110 -0
- pysio_hermes-0.1.0/src/hermes/utils/dict_utils.py +102 -0
- pysio_hermes-0.1.0/src/hermes/utils/mp_utils.py +31 -0
- pysio_hermes-0.1.0/src/hermes/utils/msgpack_utils.py +65 -0
- pysio_hermes-0.1.0/src/hermes/utils/node_utils.py +62 -0
- pysio_hermes-0.1.0/src/hermes/utils/numpy_utils.py +56 -0
- pysio_hermes-0.1.0/src/hermes/utils/print_utils.py +186 -0
- pysio_hermes-0.1.0/src/hermes/utils/sensor_utils.py +45 -0
- pysio_hermes-0.1.0/src/hermes/utils/time_utils.py +139 -0
- pysio_hermes-0.1.0/src/hermes/utils/types.py +52 -0
- pysio_hermes-0.1.0/src/hermes/utils/zmq_utils.py +66 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Maxim Yudayev [https://yudayev.com] and KU Leuven eMedia Lab.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pysio-hermes
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A realtime physiological sensing and edge AI processing framework
|
|
5
|
+
Author: e-Media Research Lab @ KU Leuven
|
|
6
|
+
Author-email: Maxim Yudayev <maxim.yudayev@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://maximyudayev.github.io/hermes
|
|
9
|
+
Project-URL: Documentation, https://maximyudayev.github.io/hermes
|
|
10
|
+
Project-URL: Repository, https://github.com/maximyudayev/hermes.git
|
|
11
|
+
Project-URL: Issues, https://github.com/maximyudayev/hermes/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/maximyudayev/hermes/blob/main/CHANGELOG.md
|
|
13
|
+
Keywords: embedded ai,wearables,sensors,streaming,realtime processing,physiology
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Development Status :: 4 - Beta
|
|
17
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
18
|
+
Classifier: Intended Audience :: Education
|
|
19
|
+
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Intended Audience :: Science/Research
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
24
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
25
|
+
Requires-Python: >=3.7
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: pyzmq
|
|
29
|
+
Requires-Dist: msgpack
|
|
30
|
+
Requires-Dist: ffmpeg-python
|
|
31
|
+
Requires-Dist: h5py
|
|
32
|
+
Requires-Dist: numpy
|
|
33
|
+
Requires-Dist: pandas
|
|
34
|
+
Requires-Dist: pyyaml
|
|
35
|
+
Requires-Dist: pyusb
|
|
36
|
+
Requires-Dist: pyserial
|
|
37
|
+
Requires-Dist: pyperclip
|
|
38
|
+
Requires-Dist: openpyxl
|
|
39
|
+
Requires-Dist: orjson
|
|
40
|
+
Provides-Extra: build
|
|
41
|
+
Requires-Dist: build; extra == "build"
|
|
42
|
+
Requires-Dist: twine; extra == "build"
|
|
43
|
+
Provides-Extra: docs
|
|
44
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
45
|
+
Requires-Dist: mkdocstrings-python; extra == "docs"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
<h1 align="center">
|
|
49
|
+
<img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/logo.png" alt="HERMES: Heterogeneous Edge Realtime Measurement and Execution System" width="60%">
|
|
50
|
+
|
|
51
|
+
<br>
|
|
52
|
+
Heterogeneous Edge Realtime Measurement and Execution System
|
|
53
|
+
</h1>
|
|
54
|
+
|
|
55
|
+
<h4 align="center">A Unified Open-Source Framework for Realtime Multimodal Physiological Sensing, Edge AI, and Intervention in Closed-Loop Smart Healthcare Applications
|
|
56
|
+
</h4>
|
|
57
|
+
|
|
58
|
+
<div align="center">
|
|
59
|
+
|
|
60
|
+

|
|
61
|
+

|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<a href="#installation">Quickstart</a> •
|
|
68
|
+
<a href="https://maximyudayev.github.io/hermes">Docs</a> •
|
|
69
|
+
<a href="#data-annotation">GUI</a> •
|
|
70
|
+
<a href="#showcase">Showcase</a> •
|
|
71
|
+
<a href="#citation">Cite</a> •
|
|
72
|
+
<a href="#contact">Contact</a>
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
HERMES for the Greek mythology analogy of the god of communication and speed, protector of information, the gods' herald. He embodies the nature of smooth and reliable communication. His role accurately resonates with the vision of this framework: facilitate reliable and fast exchange of continuously generated multimodal physiological and external data across distributed wireless and wired multi-sensor hosts for synchronized realtime data collection, in-the-loop AI stream processing, and analysis, in intelligent med- and health-tech (wearable) applications.
|
|
76
|
+
|
|
77
|
+
<div align="center"><img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/overview.png" alt="Overview of the system architecture on one of the distributed hosts" width="80%"></div>
|
|
78
|
+
<br>
|
|
79
|
+
|
|
80
|
+
HERMES offers out-of-the-box streaming integrations to a number of commercial sensor devices and systems, high resolution cameras, templates for extension with custom user devices, and a ready-made wrapper for easy PyTorch AI model insertion. It reliably and synchronously captures heterogeneous data across distributed interconnected devices on a local network in a continuous manner, and enables realtime AI processing at the edge toward personalized intelligent closed-loop interventions of the user. All continuously acquired data is periodically flushed to disk for as long as the system has disk space, as MKV/MP4 and HDF5 files, for video and sensor data, respectively.
|
|
81
|
+
|
|
82
|
+
# Quickstart
|
|
83
|
+
## Core
|
|
84
|
+
Create a Python 3 virtual environment `python -m venv .venv` (python >= 3.7).
|
|
85
|
+
|
|
86
|
+
Activate it with `.venv/bin/activate` for Linux or `.venv\Scripts\activate` for Windows.
|
|
87
|
+
|
|
88
|
+
Single-command install HERMES into your project along other dependendices.
|
|
89
|
+
```bash
|
|
90
|
+
pip install pysio-hermes
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Extra
|
|
94
|
+
All the integrated, validated and supported sensor devices are separately installable as `pysio-hermes-<subpackage_name>`, like:
|
|
95
|
+
```bash
|
|
96
|
+
pip install pysio-hermes-torch
|
|
97
|
+
```
|
|
98
|
+
Will install the AI processing subpackage to wrap user-specified PyTorch models.
|
|
99
|
+
|
|
100
|
+
<details>
|
|
101
|
+
<summary>List of supported devices <i>(continuously updated)</i></summary>
|
|
102
|
+
Some subpackages require OEM software installation, check each below for detailed prerequisites.
|
|
103
|
+
|
|
104
|
+
- `torch` [Wrapper for PyTorch AI models](https://github.com/maximyudayev/hermes-torch)
|
|
105
|
+
- `pupillabs` [Pupil Labs Core smartglasses](https://github.com/maximyudayev/hermes-pupillabs)
|
|
106
|
+
- `basler` [Basler cameras](https://github.com/maximyudayev/hermes-basler)
|
|
107
|
+
- `dots` [Movella DOTs IMUs](https://github.com/maximyudayev/hermes-dots)
|
|
108
|
+
- `mvn` [Xsens MVN Analyze MoCap suit](https://github.com/maximyudayev/hermes-mvn)
|
|
109
|
+
- `awinda` [Xsens Awinda IMUs](https://github.com/maximyudayev/hermes-awinda)
|
|
110
|
+
- `cometa` [Cometa WavePlus sEMG](https://github.com/maximyudayev/hermes-cometa)
|
|
111
|
+
- `moticon` [Moticon OpenGo pressure insoles](https://github.com/maximyudayev/hermes-moticon)
|
|
112
|
+
- `tmsi` [TMSi SAGA physiological signals](https://github.com/maximyudayev/hermes-tmsi)
|
|
113
|
+
- `vicon` [Vicon Nexus capture system](https://github.com/maximyudayev/hermes-vicon)
|
|
114
|
+
- `moxy` [Moxy muscle oxygenation monitor](https://github.com/maximyudayev/hermes-moxy)
|
|
115
|
+
|
|
116
|
+
The following subpackages are in development.
|
|
117
|
+
- `gui` [Live monitoring dashboard](https://github.com/maximyudayev/hermes-gui)
|
|
118
|
+
- `mic` [PC-attached generic microphone](https://github.com/maximyudayev/hermes-mic)
|
|
119
|
+
|
|
120
|
+
</details>
|
|
121
|
+
<br>
|
|
122
|
+
|
|
123
|
+
# Documentation
|
|
124
|
+
Check out the [full documentation site](https://maximyudayev.github.io/hermes) for more usage examples, architecture overview, detailed extension guide, and FAQs.
|
|
125
|
+
|
|
126
|
+
# Data Annotation
|
|
127
|
+
<div align="center"><img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/gui.png" alt="Pysioviz: A dashboard for visualization and annotation of collected multimodal data for AI workflows" width="80%"></div>
|
|
128
|
+
<br>
|
|
129
|
+
|
|
130
|
+
We developed [PysioViz](https://github.com/maximyudayev/pysioviz) a complementary dashboard based on [Dash Plotly](https://dash.plotly.com/) for analysis and annotation of the collected multimodal data. We use it ourselves to generate ground truth labels for the AI training workflows. Check it out and leave feedback!
|
|
131
|
+
|
|
132
|
+
# Showcase
|
|
133
|
+
These are some of our own projects enabled by HERMES to excite you to adopt it in your smart closed-looop healthtech usecases.
|
|
134
|
+
|
|
135
|
+
<details>
|
|
136
|
+
<summary>AI-enabled intent prediction for high-level locomotion mode selection in a smart leg prosthesis</summary>
|
|
137
|
+
</details>
|
|
138
|
+
<br>
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary>Realtime automated cueing for freezing-of-gait Parkinson's patients in free-living conditions</summary>
|
|
142
|
+
</details>
|
|
143
|
+
<br>
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary>Personalized level of assistance in prolong use rehabilitation and support exoskeletons</summary>
|
|
147
|
+
</details>
|
|
148
|
+
<br>
|
|
149
|
+
|
|
150
|
+
# License
|
|
151
|
+
This project is licensed under the MIT license - see the [LICENSE](/LICENSE) file for details.
|
|
152
|
+
|
|
153
|
+
# Citation
|
|
154
|
+
When using in your project, research, or product, please cite the following and notify us so we can update the index of success stories enabled by HERMES.
|
|
155
|
+
|
|
156
|
+
<!-- <a href="https://arxiv.org/abs/..." style="display:inline-block;">
|
|
157
|
+
<img src="http://img.shields.io/badge/paper-arxiv.x-B31B1B.svg" height="20" >
|
|
158
|
+
</a>
|
|
159
|
+
```bibtex
|
|
160
|
+
@inproceedings{yudayev2025hermes,
|
|
161
|
+
title={HERMES: A Unified Open-Source Framework for Realtime Multimodal Physiological Sensing, Edge AI, and Intervention in Closed-Loop Smart Healthcare Applications},
|
|
162
|
+
author={Yudayev, Maxim and Carlon, Juha and Lamsal, Diwas and Vanrumste, Bart, and Filtjens, Benjamin},
|
|
163
|
+
booktitle={},
|
|
164
|
+
year={2025}
|
|
165
|
+
}
|
|
166
|
+
``` -->
|
|
167
|
+
|
|
168
|
+
# Acknowledgement
|
|
169
|
+
This project was primarily written by Maxim Yudayev while at the Department of Electrical Engineering, KU Leuven.
|
|
170
|
+
|
|
171
|
+
This study was funded, in part, by the AidWear project funded by the Federal Public Service for Policy and Support,
|
|
172
|
+
the AID-FOG project by the Michael J. Fox Foundation for Parkinson’s Research under Grant No.: MJFF-024628,
|
|
173
|
+
and the Flemish Government under the Flanders AI Research Program (FAIR).
|
|
174
|
+
|
|
175
|
+
HERMES is a "Ship of Theseus"[[1](https://en.wikipedia.org/wiki/Ship_of_Theseus)] of [ActionSense](https://github.com/delpreto/ActionNet) that started as a fork and became a complete architectural rewrite of the system from the ground up to bridge the fundamental gaps in the state-of-the-art, and to match our research group's needs in realtime deployments and reliable data acquisition.
|
|
176
|
+
Although there is no part of ActionSense in HERMES, we believe that its authors deserve recognition as inspiration for our system.
|
|
177
|
+
|
|
178
|
+
Special thanks for contributions, usage, bug reports, good times, and feature requests to Juha Carlon (KU Leuven), Stefano Nuzzo (VUB), Diwas Lamsal (KU Leuven), Vayalet Stefanova (KU Leuven), Léonore Foguenne (ULiège).
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/logo.png" alt="HERMES: Heterogeneous Edge Realtime Measurement and Execution System" width="60%">
|
|
3
|
+
|
|
4
|
+
<br>
|
|
5
|
+
Heterogeneous Edge Realtime Measurement and Execution System
|
|
6
|
+
</h1>
|
|
7
|
+
|
|
8
|
+
<h4 align="center">A Unified Open-Source Framework for Realtime Multimodal Physiological Sensing, Edge AI, and Intervention in Closed-Loop Smart Healthcare Applications
|
|
9
|
+
</h4>
|
|
10
|
+
|
|
11
|
+
<div align="center">
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+

|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="#installation">Quickstart</a> •
|
|
21
|
+
<a href="https://maximyudayev.github.io/hermes">Docs</a> •
|
|
22
|
+
<a href="#data-annotation">GUI</a> •
|
|
23
|
+
<a href="#showcase">Showcase</a> •
|
|
24
|
+
<a href="#citation">Cite</a> •
|
|
25
|
+
<a href="#contact">Contact</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
HERMES for the Greek mythology analogy of the god of communication and speed, protector of information, the gods' herald. He embodies the nature of smooth and reliable communication. His role accurately resonates with the vision of this framework: facilitate reliable and fast exchange of continuously generated multimodal physiological and external data across distributed wireless and wired multi-sensor hosts for synchronized realtime data collection, in-the-loop AI stream processing, and analysis, in intelligent med- and health-tech (wearable) applications.
|
|
29
|
+
|
|
30
|
+
<div align="center"><img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/overview.png" alt="Overview of the system architecture on one of the distributed hosts" width="80%"></div>
|
|
31
|
+
<br>
|
|
32
|
+
|
|
33
|
+
HERMES offers out-of-the-box streaming integrations to a number of commercial sensor devices and systems, high resolution cameras, templates for extension with custom user devices, and a ready-made wrapper for easy PyTorch AI model insertion. It reliably and synchronously captures heterogeneous data across distributed interconnected devices on a local network in a continuous manner, and enables realtime AI processing at the edge toward personalized intelligent closed-loop interventions of the user. All continuously acquired data is periodically flushed to disk for as long as the system has disk space, as MKV/MP4 and HDF5 files, for video and sensor data, respectively.
|
|
34
|
+
|
|
35
|
+
# Quickstart
|
|
36
|
+
## Core
|
|
37
|
+
Create a Python 3 virtual environment `python -m venv .venv` (python >= 3.7).
|
|
38
|
+
|
|
39
|
+
Activate it with `.venv/bin/activate` for Linux or `.venv\Scripts\activate` for Windows.
|
|
40
|
+
|
|
41
|
+
Single-command install HERMES into your project along other dependendices.
|
|
42
|
+
```bash
|
|
43
|
+
pip install pysio-hermes
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Extra
|
|
47
|
+
All the integrated, validated and supported sensor devices are separately installable as `pysio-hermes-<subpackage_name>`, like:
|
|
48
|
+
```bash
|
|
49
|
+
pip install pysio-hermes-torch
|
|
50
|
+
```
|
|
51
|
+
Will install the AI processing subpackage to wrap user-specified PyTorch models.
|
|
52
|
+
|
|
53
|
+
<details>
|
|
54
|
+
<summary>List of supported devices <i>(continuously updated)</i></summary>
|
|
55
|
+
Some subpackages require OEM software installation, check each below for detailed prerequisites.
|
|
56
|
+
|
|
57
|
+
- `torch` [Wrapper for PyTorch AI models](https://github.com/maximyudayev/hermes-torch)
|
|
58
|
+
- `pupillabs` [Pupil Labs Core smartglasses](https://github.com/maximyudayev/hermes-pupillabs)
|
|
59
|
+
- `basler` [Basler cameras](https://github.com/maximyudayev/hermes-basler)
|
|
60
|
+
- `dots` [Movella DOTs IMUs](https://github.com/maximyudayev/hermes-dots)
|
|
61
|
+
- `mvn` [Xsens MVN Analyze MoCap suit](https://github.com/maximyudayev/hermes-mvn)
|
|
62
|
+
- `awinda` [Xsens Awinda IMUs](https://github.com/maximyudayev/hermes-awinda)
|
|
63
|
+
- `cometa` [Cometa WavePlus sEMG](https://github.com/maximyudayev/hermes-cometa)
|
|
64
|
+
- `moticon` [Moticon OpenGo pressure insoles](https://github.com/maximyudayev/hermes-moticon)
|
|
65
|
+
- `tmsi` [TMSi SAGA physiological signals](https://github.com/maximyudayev/hermes-tmsi)
|
|
66
|
+
- `vicon` [Vicon Nexus capture system](https://github.com/maximyudayev/hermes-vicon)
|
|
67
|
+
- `moxy` [Moxy muscle oxygenation monitor](https://github.com/maximyudayev/hermes-moxy)
|
|
68
|
+
|
|
69
|
+
The following subpackages are in development.
|
|
70
|
+
- `gui` [Live monitoring dashboard](https://github.com/maximyudayev/hermes-gui)
|
|
71
|
+
- `mic` [PC-attached generic microphone](https://github.com/maximyudayev/hermes-mic)
|
|
72
|
+
|
|
73
|
+
</details>
|
|
74
|
+
<br>
|
|
75
|
+
|
|
76
|
+
# Documentation
|
|
77
|
+
Check out the [full documentation site](https://maximyudayev.github.io/hermes) for more usage examples, architecture overview, detailed extension guide, and FAQs.
|
|
78
|
+
|
|
79
|
+
# Data Annotation
|
|
80
|
+
<div align="center"><img src="https://raw.githubusercontent.com/maximyudayev/hermes/refs/heads/main/images/gui.png" alt="Pysioviz: A dashboard for visualization and annotation of collected multimodal data for AI workflows" width="80%"></div>
|
|
81
|
+
<br>
|
|
82
|
+
|
|
83
|
+
We developed [PysioViz](https://github.com/maximyudayev/pysioviz) a complementary dashboard based on [Dash Plotly](https://dash.plotly.com/) for analysis and annotation of the collected multimodal data. We use it ourselves to generate ground truth labels for the AI training workflows. Check it out and leave feedback!
|
|
84
|
+
|
|
85
|
+
# Showcase
|
|
86
|
+
These are some of our own projects enabled by HERMES to excite you to adopt it in your smart closed-looop healthtech usecases.
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary>AI-enabled intent prediction for high-level locomotion mode selection in a smart leg prosthesis</summary>
|
|
90
|
+
</details>
|
|
91
|
+
<br>
|
|
92
|
+
|
|
93
|
+
<details>
|
|
94
|
+
<summary>Realtime automated cueing for freezing-of-gait Parkinson's patients in free-living conditions</summary>
|
|
95
|
+
</details>
|
|
96
|
+
<br>
|
|
97
|
+
|
|
98
|
+
<details>
|
|
99
|
+
<summary>Personalized level of assistance in prolong use rehabilitation and support exoskeletons</summary>
|
|
100
|
+
</details>
|
|
101
|
+
<br>
|
|
102
|
+
|
|
103
|
+
# License
|
|
104
|
+
This project is licensed under the MIT license - see the [LICENSE](/LICENSE) file for details.
|
|
105
|
+
|
|
106
|
+
# Citation
|
|
107
|
+
When using in your project, research, or product, please cite the following and notify us so we can update the index of success stories enabled by HERMES.
|
|
108
|
+
|
|
109
|
+
<!-- <a href="https://arxiv.org/abs/..." style="display:inline-block;">
|
|
110
|
+
<img src="http://img.shields.io/badge/paper-arxiv.x-B31B1B.svg" height="20" >
|
|
111
|
+
</a>
|
|
112
|
+
```bibtex
|
|
113
|
+
@inproceedings{yudayev2025hermes,
|
|
114
|
+
title={HERMES: A Unified Open-Source Framework for Realtime Multimodal Physiological Sensing, Edge AI, and Intervention in Closed-Loop Smart Healthcare Applications},
|
|
115
|
+
author={Yudayev, Maxim and Carlon, Juha and Lamsal, Diwas and Vanrumste, Bart, and Filtjens, Benjamin},
|
|
116
|
+
booktitle={},
|
|
117
|
+
year={2025}
|
|
118
|
+
}
|
|
119
|
+
``` -->
|
|
120
|
+
|
|
121
|
+
# Acknowledgement
|
|
122
|
+
This project was primarily written by Maxim Yudayev while at the Department of Electrical Engineering, KU Leuven.
|
|
123
|
+
|
|
124
|
+
This study was funded, in part, by the AidWear project funded by the Federal Public Service for Policy and Support,
|
|
125
|
+
the AID-FOG project by the Michael J. Fox Foundation for Parkinson’s Research under Grant No.: MJFF-024628,
|
|
126
|
+
and the Flemish Government under the Flanders AI Research Program (FAIR).
|
|
127
|
+
|
|
128
|
+
HERMES is a "Ship of Theseus"[[1](https://en.wikipedia.org/wiki/Ship_of_Theseus)] of [ActionSense](https://github.com/delpreto/ActionNet) that started as a fork and became a complete architectural rewrite of the system from the ground up to bridge the fundamental gaps in the state-of-the-art, and to match our research group's needs in realtime deployments and reliable data acquisition.
|
|
129
|
+
Although there is no part of ActionSense in HERMES, we believe that its authors deserve recognition as inspiration for our system.
|
|
130
|
+
|
|
131
|
+
Special thanks for contributions, usage, bug reports, good times, and feature requests to Juha Carlon (KU Leuven), Stefano Nuzzo (VUB), Diwas Lamsal (KU Leuven), Vayalet Stefanova (KU Leuven), Léonore Foguenne (ULiège).
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
############
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2024 Maxim Yudayev and KU Leuven eMedia Lab
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
# Created 2024-2025 for the KU Leuven AidWear, AidFOG, and RevalExo projects
|
|
24
|
+
# by Maxim Yudayev [https://yudayev.com].
|
|
25
|
+
#
|
|
26
|
+
# ############
|
|
27
|
+
|
|
28
|
+
import threading
|
|
29
|
+
import os
|
|
30
|
+
import yaml
|
|
31
|
+
import argparse
|
|
32
|
+
import sys
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
sys.path.append("./src")
|
|
36
|
+
|
|
37
|
+
from hermes.base.nodes import Node
|
|
38
|
+
from hermes.base.broker import Broker
|
|
39
|
+
from hermes.utils.mp_utils import launch_callable
|
|
40
|
+
from hermes.utils.node_utils import search_node_class
|
|
41
|
+
from hermes.utils.time_utils import *
|
|
42
|
+
from hermes.utils.zmq_utils import *
|
|
43
|
+
from hermes.utils.argparse_utils import *
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__version = 'v0.1.0'
|
|
47
|
+
|
|
48
|
+
HERMES = r"""
|
|
49
|
+
______ ________________________ ___________________
|
|
50
|
+
___ / / /__ ____/__ __ \__ |/ /__ ____/_ ___/
|
|
51
|
+
__ /_/ /__ __/ __ /_/ /_ /|_/ /__ __/ _____ \
|
|
52
|
+
_ __ / _ /___ _ _, _/_ / / / _ /___ ____/ /
|
|
53
|
+
/_/ /_/ /_____/ /_/ |_| /_/ /_/ /_____/ /____/
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
if __name__ == '__main__':
|
|
58
|
+
parser = argparse.ArgumentParser(prog='HERMES',
|
|
59
|
+
description='Heterogeneous edge realtime measurement and execution system '
|
|
60
|
+
'for continual multimodal data acquisition and processing.',
|
|
61
|
+
epilog='Copyright (c) 2024 Maxim Yudayev and KU Leuven eMedia Lab.\n'
|
|
62
|
+
'Created 2024-2025 at KU Leuven for the AidWear, AID-FOG, and RevalExo '
|
|
63
|
+
'projects of prof. Bart Vanrumste, by Maxim Yudayev [https://yudayev.com].',
|
|
64
|
+
formatter_class=argparse.RawTextHelpFormatter)
|
|
65
|
+
parser.add_argument('--verbose', '-v',
|
|
66
|
+
action='count',
|
|
67
|
+
default=0,
|
|
68
|
+
help='increase level of logging verbosity [0,3]')
|
|
69
|
+
parser.add_argument('--version',
|
|
70
|
+
action='version',
|
|
71
|
+
version='%(prog)s ' + __version)
|
|
72
|
+
|
|
73
|
+
parser.add_argument('--experiment',
|
|
74
|
+
nargs='*',
|
|
75
|
+
action=ParseExperimentKwargs,
|
|
76
|
+
help='key-value pair tags detailing the experiment, used for '
|
|
77
|
+
'directory creation and metadata on files')
|
|
78
|
+
parser.add_argument('--time', '-t',
|
|
79
|
+
type=float,
|
|
80
|
+
dest='log_time_s',
|
|
81
|
+
default=get_time(),
|
|
82
|
+
help='master start time of the system')
|
|
83
|
+
parser.add_argument('--duration', '-d',
|
|
84
|
+
type=int,
|
|
85
|
+
dest='duration_s',
|
|
86
|
+
default=None,
|
|
87
|
+
help='duration in seconds, if using for recording only (to be used only by master)')
|
|
88
|
+
parser.add_argument('--config_file',
|
|
89
|
+
type=validate_path,
|
|
90
|
+
default=None,
|
|
91
|
+
help='path to the configuration file for the current host device, '
|
|
92
|
+
'instead of the CLI arguments')
|
|
93
|
+
|
|
94
|
+
# parser.add_argument('--host_ip',
|
|
95
|
+
# type=validate_ip,
|
|
96
|
+
# help='LAN IPv4 address of the host device')
|
|
97
|
+
# parser.add_argument('--is_master',
|
|
98
|
+
# dest='is_master_broker',
|
|
99
|
+
# action='store_true',
|
|
100
|
+
# help='flag to set host as Master Broker that others connect to')
|
|
101
|
+
# parser.add_argument('--subscriber_ips',
|
|
102
|
+
# nargs='*',
|
|
103
|
+
# dest='remote_subscriber_ips',
|
|
104
|
+
# type=validate_ip,
|
|
105
|
+
# default=list(),
|
|
106
|
+
# help='list of IPv4 devices listening to data of the host')
|
|
107
|
+
# parser.add_argument('--publisher_ips',
|
|
108
|
+
# nargs='*',
|
|
109
|
+
# dest='remote_publisher_ips',
|
|
110
|
+
# type=validate_ip,
|
|
111
|
+
# default=list(),
|
|
112
|
+
# help='list of IPv4 devices to listen to for their data')
|
|
113
|
+
# parser.add_argument('--kill',
|
|
114
|
+
# dest='is_remote_kill',
|
|
115
|
+
# action='store_true',
|
|
116
|
+
# help='flag to set host to listen to remote KILLSIG (only for slave devices)')
|
|
117
|
+
# parser.add_argument('--kill_ip',
|
|
118
|
+
# dest='remote_kill_ip',
|
|
119
|
+
# type=validate_ip,
|
|
120
|
+
# help='LAN IPv4 address of device delegating KILLSIG (only for slave devices)')
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# parser.add_argument('--logging_spec',
|
|
124
|
+
# nargs='*',
|
|
125
|
+
# action=ParseLoggingKwargs,
|
|
126
|
+
# help='key-value pair tags configuring logging modules of each Node')
|
|
127
|
+
|
|
128
|
+
# parser.add_argument('--producer_specs',
|
|
129
|
+
# nargs='*',
|
|
130
|
+
# action=ParseNodeKwargs,
|
|
131
|
+
# default=list(),
|
|
132
|
+
# help='key-value pair tags detailing local producer Nodes of the host')
|
|
133
|
+
# parser.add_argument('--consumer_specs',
|
|
134
|
+
# nargs='*',
|
|
135
|
+
# action=ParseNodeKwargs,
|
|
136
|
+
# default=list(),
|
|
137
|
+
# help='key-value pair tags detailing local consumer Nodes of the host')
|
|
138
|
+
# parser.add_argument('--pipeline_specs',
|
|
139
|
+
# nargs='*',
|
|
140
|
+
# action=ParseNodeKwargs,
|
|
141
|
+
# default=list(),
|
|
142
|
+
# help='key-value pair tags detailing local pipeline Nodes of the host')
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Parse launch arguments.
|
|
146
|
+
args = parser.parse_args()
|
|
147
|
+
|
|
148
|
+
# Override CLI arguments with a config file.
|
|
149
|
+
if args.config_file is not None:
|
|
150
|
+
with open(args.config_file, "r") as f:
|
|
151
|
+
try:
|
|
152
|
+
config: dict = yaml.safe_load(f)
|
|
153
|
+
parser.set_defaults(**config)
|
|
154
|
+
except yaml.YAMLError as e:
|
|
155
|
+
print(e)
|
|
156
|
+
exit('Error parsing CLI inputs.')
|
|
157
|
+
args = parser.parse_args()
|
|
158
|
+
|
|
159
|
+
# Load video codec spec.
|
|
160
|
+
if 'stream_video' in args.logging_spec and args.logging_spec['stream_video']:
|
|
161
|
+
with open(args.logging_spec['video_codec_config_filepath'], "r") as f:
|
|
162
|
+
try:
|
|
163
|
+
args.logging_spec['video_codec'] = yaml.safe_load(f)
|
|
164
|
+
except yaml.YAMLError as e:
|
|
165
|
+
print(e)
|
|
166
|
+
|
|
167
|
+
# Initialize folders and other chore data, and share programmatically across Node specs.
|
|
168
|
+
script_dir: str = os.path.dirname(os.path.realpath(__file__))
|
|
169
|
+
(log_time_str, log_time_s) = get_time_str(time_s=args.log_time_s, return_time_s=True)
|
|
170
|
+
log_dir: str = os.path.join(script_dir,
|
|
171
|
+
'data',
|
|
172
|
+
*map(lambda tup: '_'.join(tup), args.experiment.items()))
|
|
173
|
+
# Initialize a file for writing the log history of all printouts/messages.
|
|
174
|
+
log_history_filepath: str = os.path.join(log_dir, '%s.log'%args.host_ip)
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
os.makedirs(log_dir)
|
|
178
|
+
except OSError:
|
|
179
|
+
exit("'%s' already exists. Update experiment YML file with correct data for this subject."%log_dir)
|
|
180
|
+
|
|
181
|
+
args.logging_spec['log_dir'] = log_dir
|
|
182
|
+
args.logging_spec['experiment'] = args.experiment
|
|
183
|
+
args.logging_spec['log_time_s'] = log_time_s
|
|
184
|
+
|
|
185
|
+
node_specs: list[dict] = args.producer_specs + args.consumer_specs + args.pipeline_specs
|
|
186
|
+
for spec in node_specs:
|
|
187
|
+
spec['settings']['logging_spec'] = args.logging_spec
|
|
188
|
+
spec['settings']['log_history_filepath'] = log_history_filepath
|
|
189
|
+
spec['settings']['host_ip'] = args.host_ip
|
|
190
|
+
spec['settings']['port_pub'] = PORT_BACKEND
|
|
191
|
+
spec['settings']['port_sub'] = PORT_FRONTEND
|
|
192
|
+
spec['settings']['port_sync'] = PORT_SYNC_HOST
|
|
193
|
+
spec['settings']['port_killsig'] = PORT_KILL
|
|
194
|
+
|
|
195
|
+
# Create the broker and manage all the components of the experiment.
|
|
196
|
+
local_broker: Broker = Broker(host_ip=args.host_ip,
|
|
197
|
+
node_specs=node_specs,
|
|
198
|
+
is_master_broker=args.is_master_broker)
|
|
199
|
+
|
|
200
|
+
# Connect broker to remote publishers at the wearable PC to get data from the wearable sensors.
|
|
201
|
+
for ip in args.remote_publisher_ips:
|
|
202
|
+
local_broker.connect_to_remote_broker(addr=ip)
|
|
203
|
+
|
|
204
|
+
# Expose local wearable data to remote subscribers (e.g. lab PC in AidFOG project).
|
|
205
|
+
if args.remote_subscriber_ips:
|
|
206
|
+
local_broker.expose_to_remote_broker(args.remote_subscriber_ips)
|
|
207
|
+
|
|
208
|
+
# Subscribe to the KILL signal of a remote machine.
|
|
209
|
+
if args.is_remote_kill:
|
|
210
|
+
local_broker.subscribe_to_killsig(addr=args.remote_kill_ip)
|
|
211
|
+
|
|
212
|
+
# Only the master broker can terminate the experiment via the terminal command.
|
|
213
|
+
if args.is_master_broker:
|
|
214
|
+
is_quit = False
|
|
215
|
+
# Run broker's main until user exits in GUI or 'q' in terminal.
|
|
216
|
+
t = threading.Thread(target=launch_callable, args=(local_broker, args.duration_s))
|
|
217
|
+
t.start()
|
|
218
|
+
while not is_quit:
|
|
219
|
+
is_quit = input("Enter 'q' to exit: ") == 'q'
|
|
220
|
+
local_broker.set_is_quit()
|
|
221
|
+
t.join()
|
|
222
|
+
else:
|
|
223
|
+
local_broker()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pysio-hermes"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
requires-python = ">=3.7"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name="Maxim Yudayev", email="maxim.yudayev@gmail.com" },
|
|
11
|
+
{ name="e-Media Research Lab @ KU Leuven" },
|
|
12
|
+
]
|
|
13
|
+
description = "A realtime physiological sensing and edge AI processing framework"
|
|
14
|
+
keywords = ["embedded ai", "wearables", "sensors", "streaming", "realtime processing", "physiology"]
|
|
15
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
16
|
+
license = "MIT"
|
|
17
|
+
license-files = ["LICEN[CS]E*", "AUTHORS.md"]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Healthcare Industry",
|
|
23
|
+
"Intended Audience :: Education",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"Topic :: Scientific/Engineering",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
28
|
+
"Topic :: Scientific/Engineering :: Medical Science Apps.",
|
|
29
|
+
"Topic :: System :: Distributed Computing"
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"pyzmq",
|
|
33
|
+
"msgpack",
|
|
34
|
+
"ffmpeg-python",
|
|
35
|
+
"h5py",
|
|
36
|
+
"numpy",
|
|
37
|
+
"pandas",
|
|
38
|
+
"pyyaml",
|
|
39
|
+
"pyusb",
|
|
40
|
+
"pyserial",
|
|
41
|
+
"pyperclip",
|
|
42
|
+
"openpyxl",
|
|
43
|
+
"orjson",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
build = [
|
|
48
|
+
"build",
|
|
49
|
+
"twine"
|
|
50
|
+
]
|
|
51
|
+
docs = [
|
|
52
|
+
"mkdocs-material",
|
|
53
|
+
"mkdocstrings-python"
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
exclude = ["docs*", ".vscode*", ".venv*", "images*"]
|
|
58
|
+
|
|
59
|
+
[project.urls]
|
|
60
|
+
Homepage = "https://maximyudayev.github.io/hermes"
|
|
61
|
+
Documentation = "https://maximyudayev.github.io/hermes"
|
|
62
|
+
Repository = "https://github.com/maximyudayev/hermes.git"
|
|
63
|
+
Issues = "https://github.com/maximyudayev/hermes/issues"
|
|
64
|
+
Changelog = "https://github.com/maximyudayev/hermes/blob/main/CHANGELOG.md"
|