imt-ring 1.6.39__py3-none-any.whl → 1.6.45__py3-none-any.whl
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.
- {imt_ring-1.6.39.dist-info → imt_ring-1.6.45.dist-info}/METADATA +18 -14
- {imt_ring-1.6.39.dist-info → imt_ring-1.6.45.dist-info}/RECORD +8 -7
- {imt_ring-1.6.39.dist-info → imt_ring-1.6.45.dist-info}/WHEEL +1 -1
- imt_ring-1.6.45.dist-info/entry_points.txt +2 -0
- ring/algorithms/generator/base.py +8 -0
- ring/ml/base.py +6 -2
- ring/sim2real/sim2real.py +29 -5
- {imt_ring-1.6.39.dist-info → imt_ring-1.6.45.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: imt-ring
|
3
|
-
Version: 1.6.
|
3
|
+
Version: 1.6.45
|
4
4
|
Summary: RING: Recurrent Inertial Graph-based Estimator
|
5
5
|
Author-email: Simon Bachhuber <simon.bachhuber@fau.de>
|
6
6
|
Project-URL: Homepage, https://github.com/SimiPixel/ring
|
@@ -32,12 +32,15 @@ Requires-Dist: pytest-xdist; extra == "dev"
|
|
32
32
|
Requires-Dist: nbmake; extra == "dev"
|
33
33
|
|
34
34
|
<p align="center">
|
35
|
-
<img src="https://raw.githubusercontent.com/simon-bachhuber/ring/main/docs/img/
|
35
|
+
<img src="https://raw.githubusercontent.com/simon-bachhuber/ring/main/docs/img/concept_v4.png" height="200" />
|
36
36
|
</p>
|
37
37
|
|
38
|
+
|
38
39
|
# Recurrent Inertial Graph-based Estimator (RING)
|
39
40
|
<img src="https://raw.githubusercontent.com/simon-bachhuber/ring/main/docs/img/coverage_badge.svg" height="20" />
|
40
41
|
|
42
|
+
RING provides a pluripotent, problem-unspecific plug-and-play IMT solution that, in contrast to conventional IMT solutions, eliminates the need for expert knowledge to identify, select, and parameterize the appropriate method. RING's pluripotency is enabled by a novel online-capable neural network architecture that uses a decentralized network of message-passing, parameter-sharing recurrent neural networks, which map local IMU measurements and nearest-neighbour messages to local orientations. This architecture enables RING to address a broad range of IMT problems that vary greatly in aspects such as the number of attached sensors, or the number of segments in the kinematic chain, and even generalize to previously unsolved IMT problems, including the challenging combination of magnetometer-free and sparse sensing with unknown sensor-to-segment parameters. Remarkably, RING is trained solely on simulated data, yet evaluated on experimental data, which indicates its exceptional ability to zero-shot generalize from simulation to experiment, while outperforming several state-of-the-art problem-specific solutions. For example, RING can, for the first time, accurately track a four-segment kinematic chain (which requires estimating four orientations) using only two magnetometer-free inertial measurement units.
|
43
|
+
|
41
44
|
> **ℹ️ Tip:**
|
42
45
|
>
|
43
46
|
> Check out my new plug-and-play interface for inertial motion tracking (RING included) [here](https://github.com/simon-bachhuber/imt.git).
|
@@ -50,26 +53,23 @@ Install with `pip` using
|
|
50
53
|
|
51
54
|
`pip install imt-ring`
|
52
55
|
|
53
|
-
Typically, this will install `jax` as cpu-only version.
|
54
|
-
```bash
|
55
|
-
pip install --upgrade "jax[cuda12_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html
|
56
|
-
```
|
56
|
+
Typically, this will install `jax` as cpu-only version. For GPU install instructions for `jax` see https://github.com/jax-ml/jax?tab=readme-ov-file#instructions.
|
57
57
|
|
58
58
|
## Documentation
|
59
59
|
|
60
|
-
Available [here](https://
|
60
|
+
Available [here](https://simon-bachhuber.github.io/ring/).
|
61
61
|
|
62
62
|
## Quickstart Example
|
63
63
|
```python
|
64
64
|
import ring
|
65
65
|
import numpy as np
|
66
66
|
|
67
|
-
T : int = 30
|
68
|
-
Ts : float = 0.01
|
69
|
-
B : int = 1
|
70
|
-
lam: list[int] = [0, 1
|
71
|
-
N : int = len(lam)
|
72
|
-
T_i: int = int(T/Ts)
|
67
|
+
T : int = 30 # sequence length [s]
|
68
|
+
Ts : float = 0.01 # sampling interval [s]
|
69
|
+
B : int = 1 # batch size
|
70
|
+
lam: list[int] = [-1, 0, 1] # parent array
|
71
|
+
N : int = len(lam) # number of bodies
|
72
|
+
T_i: int = int(T/Ts) # number of timesteps
|
73
73
|
|
74
74
|
X = np.zeros((B, T_i, N, 9))
|
75
75
|
# where X is structured as follows:
|
@@ -112,7 +112,11 @@ Solution:
|
|
112
112
|
|
113
113
|
## Publications
|
114
114
|
|
115
|
-
The
|
115
|
+
The main publication is:
|
116
|
+
|
117
|
+
- [*Recurrent Inertial Graph-Based Estimator (RING): A Single Pluripotent Inertial Motion Tracking Solution*](https://openreview.net/pdf?id=h2C3rkn0zR)
|
118
|
+
|
119
|
+
The following publications also utilize this software library, and refer to it as the *Random Chain Motion Generator (RCMG)* (more specifically the function `ring.RCMG`):
|
116
120
|
|
117
121
|
- [*RNN-based Observability Analysis for Magnetometer-Free Sparse Inertial Motion Tracking*](https://ieeexplore.ieee.org/document/9841375)
|
118
122
|
- [*Plug-and-Play Sparse Inertial Motion Tracking With Sim-to-Real Transfer*](https://ieeexplore.ieee.org/document/10225275)
|
@@ -15,7 +15,7 @@ ring/algorithms/custom_joints/rr_joint.py,sha256=jnRtjtOCALMaq2_0bcu2d7qgfQ6etXp
|
|
15
15
|
ring/algorithms/custom_joints/rsaddle_joint.py,sha256=QoMo6NXdYgA9JygSzBvr0eCdd3qKhUgCrGPNO2Qdxko,1200
|
16
16
|
ring/algorithms/custom_joints/suntay.py,sha256=TZG307NqdMiXnNY63xEx8AkAjbQBQ4eO6DQ7R4j4D08,16726
|
17
17
|
ring/algorithms/generator/__init__.py,sha256=bF-CW3x2x-o6KWESKy-DuxzZPh3UNSjJb_MaAcSHGsQ,277
|
18
|
-
ring/algorithms/generator/base.py,sha256=
|
18
|
+
ring/algorithms/generator/base.py,sha256=yPH_RIQPU_nlq58HyZ6T3RUm1S5chA3-Ro__-ArYTq0,22669
|
19
19
|
ring/algorithms/generator/batch.py,sha256=xp1X8oYtwI6l2cH4GRu9zw-P8dnh-X1FWTSyixEfgr8,2652
|
20
20
|
ring/algorithms/generator/finalize_fns.py,sha256=ty1NaU-Mghx1RL-voivDjS0TWSKNtjTmbdmBnShhn7k,10398
|
21
21
|
ring/algorithms/generator/motion_artifacts.py,sha256=2VJbldVDbI3PSyboshIbtYvSAKzBBwGV7cQfYjqvluM,9167
|
@@ -52,7 +52,7 @@ ring/io/xml/test_from_xml.py,sha256=bckVrVVmEhCwujd_OF9FGYnX3zU3BgztpqGxxmd0htM,
|
|
52
52
|
ring/io/xml/test_to_xml.py,sha256=NGn4VSiFdwhYN5YTBduWMiY9B5dwtxZhCQAR_PXeqKU,946
|
53
53
|
ring/io/xml/to_xml.py,sha256=Wo4iySLw9nM-iVW42AGvMRqjtU2qRc2FD_Zlc7w1IrE,3438
|
54
54
|
ring/ml/__init__.py,sha256=nbh48gaswWeY4S4vT1sply_3ROj2DQ7agjoLR4Ho3T8,1517
|
55
|
-
ring/ml/base.py,sha256=
|
55
|
+
ring/ml/base.py,sha256=HAAM6ehXiyV53cvh1bLvPHIrlM7S4pgN-xcGTI8Mvsw,10238
|
56
56
|
ring/ml/callbacks.py,sha256=oCPXl4_Zcw3g0KRgyyUDmdiGxV0phnDVc_t8rEG4Lls,13737
|
57
57
|
ring/ml/ml_utils.py,sha256=hu189AnHcmkhkpEPZZ19O0gWz3T-YKpWQW9buqDTMow,10915
|
58
58
|
ring/ml/optimizer.py,sha256=TZF0_LmnewzmGVso-zIQJtpWguUW0fW3HeRpIdG_qoI,4763
|
@@ -68,7 +68,7 @@ ring/rendering/mujoco_render.py,sha256=HMvZc04I0-lXPBL3hcnBzV2bNiXQAQM7QcHlG_Obm
|
|
68
68
|
ring/rendering/vispy_render.py,sha256=6Z6S5LNZ7iy9BN1GVb9EDe-Tix5N_SQ1s7ZsfiTSDEA,10261
|
69
69
|
ring/rendering/vispy_visuals.py,sha256=ooBZqppnebeL0ANe6V6zUgnNTtDcdkOsa4vZuM4sx-I,7873
|
70
70
|
ring/sim2real/__init__.py,sha256=gCLYg8IoMdzUagzhCFcfjZ5GavtIU772L7HR0G5hUtM,251
|
71
|
-
ring/sim2real/sim2real.py,sha256=
|
71
|
+
ring/sim2real/sim2real.py,sha256=4MtxsyQmfnSi9llzL0ZB5wmJ5zfAXBv705RbSpI26gY,10373
|
72
72
|
ring/sys_composer/__init__.py,sha256=5J_JJJIHfTPcpxh0v4FqiOs81V1REPUd7pgiw2nAN5E,193
|
73
73
|
ring/sys_composer/delete_sys.py,sha256=cIM9KbyLfg7B9121g7yjzuFbjeNu9cil1dPavAYEgzk,3408
|
74
74
|
ring/sys_composer/inject_sys.py,sha256=PLuxLbXU7hPtAsqvpsEim9hkoVE26ddrg3OipZNvnhU,3504
|
@@ -86,7 +86,8 @@ ring/utils/randomize_sys.py,sha256=G_vBIo0OwQkXL2u0djwbaoaeb02C4LQCTNNloOYIU2M,3
|
|
86
86
|
ring/utils/utils.py,sha256=gKwOXLxWraeZfX6EbBcg3hkq30DcXN0mcRUeOSTNiMo,7336
|
87
87
|
ring/utils/register_gym_envs/__init__.py,sha256=PtPIRBQJ16339xZ9G9VpvqrvcGbQ_Pk_SUz4tQPa9nQ,94
|
88
88
|
ring/utils/register_gym_envs/saddle.py,sha256=tA5CyW_akSXyDm0xJ83CtOrUMVElH0f9vZtEDDJQalI,4422
|
89
|
-
imt_ring-1.6.
|
90
|
-
imt_ring-1.6.
|
91
|
-
imt_ring-1.6.
|
92
|
-
imt_ring-1.6.
|
89
|
+
imt_ring-1.6.45.dist-info/METADATA,sha256=gjZdACsiCHmMA8kB0eRzjI2QIKoP6BgUVzYaVznaNTc,5708
|
90
|
+
imt_ring-1.6.45.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
91
|
+
imt_ring-1.6.45.dist-info/entry_points.txt,sha256=npNqSOvNiBR0BNa_GL3J66q8Gky3h0G_PHzHzk8oyE0,66
|
92
|
+
imt_ring-1.6.45.dist-info/top_level.txt,sha256=EiT790-lAyi8iwTzJArH3f2k77rwhDn00q-4PlmvDQo,5
|
93
|
+
imt_ring-1.6.45.dist-info/RECORD,,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from dataclasses import replace
|
2
2
|
from functools import partial
|
3
|
+
import logging
|
3
4
|
import random
|
4
5
|
from typing import Callable, Optional
|
5
6
|
import warnings
|
@@ -20,6 +21,8 @@ from ring.algorithms.generator import motion_artifacts
|
|
20
21
|
from ring.algorithms.generator import setup_fns
|
21
22
|
from ring.algorithms.generator import types
|
22
23
|
|
24
|
+
logger = logging.getLogger(__name__)
|
25
|
+
|
23
26
|
|
24
27
|
class RCMG:
|
25
28
|
def __init__(
|
@@ -237,7 +240,9 @@ class RCMG:
|
|
237
240
|
def _generators_ncalls(self, sizes: int | list[int] = 1):
|
238
241
|
"Returns list of unbatched sequences as numpy arrays."
|
239
242
|
repeats = self._compute_repeats(sizes)
|
243
|
+
logger.info(f"`repeats` = {repeats}")
|
240
244
|
sizes = list(jnp.array(repeats) * jnp.array(self._size_of_generators))
|
245
|
+
logger.info(f"`sizes` = {sizes}")
|
241
246
|
|
242
247
|
reduced_repeats = []
|
243
248
|
n_calls = []
|
@@ -246,6 +251,9 @@ class RCMG:
|
|
246
251
|
gcd = utils.gcd(n_call, repeat)
|
247
252
|
n_calls.append(gcd)
|
248
253
|
reduced_repeats.append(repeat // gcd)
|
254
|
+
logger.info(f"`reduced_repeats` = {reduced_repeats}")
|
255
|
+
logger.info(f"`n_calls` = {n_calls}")
|
256
|
+
|
249
257
|
jits = [N > 1 for N in n_calls]
|
250
258
|
|
251
259
|
gens = []
|
ring/ml/base.py
CHANGED
@@ -297,8 +297,12 @@ class NoGraph_FilterWrapper(AbstractFilterWrapper):
|
|
297
297
|
|
298
298
|
if self._quat_normalize:
|
299
299
|
assert yhat.shape[-1] == 4, f"yhat.shape={yhat.shape}"
|
300
|
-
|
301
|
-
|
300
|
+
|
301
|
+
# for exporting neural networks to ONNX format, you will have to use
|
302
|
+
# the first version, but for neural network training the second version
|
303
|
+
# is required
|
304
|
+
# yhat = yhat / jnp.linalg.norm(yhat, axis=-1, keepdims=True)
|
305
|
+
yhat = ring.maths.safe_normalize(yhat)
|
302
306
|
|
303
307
|
return yhat, state
|
304
308
|
|
ring/sim2real/sim2real.py
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
from typing import Optional, Tuple
|
2
2
|
|
3
3
|
import jax
|
4
|
+
import tree_utils
|
5
|
+
|
4
6
|
from ring import algebra
|
5
7
|
from ring import base
|
6
8
|
from ring import io
|
7
9
|
from ring import maths
|
8
10
|
from ring.algorithms import generator
|
9
11
|
from ring.algorithms import jcalc
|
10
|
-
import tree_utils
|
11
12
|
|
12
13
|
|
13
14
|
def xs_from_raw(
|
@@ -189,7 +190,14 @@ def delete_to_world_pos_rot(sys: base.System, xs: base.Transform) -> base.Transf
|
|
189
190
|
|
190
191
|
|
191
192
|
def randomize_to_world_pos_rot(
|
192
|
-
key: jax.Array,
|
193
|
+
key: jax.Array,
|
194
|
+
sys: base.System,
|
195
|
+
xs: base.Transform,
|
196
|
+
config: jcalc.MotionConfig,
|
197
|
+
world_joint: str = "free",
|
198
|
+
cor: bool = False,
|
199
|
+
overwrite_q_ref: jax.Array = None,
|
200
|
+
damping=None,
|
193
201
|
) -> base.Transform:
|
194
202
|
"""Replace the transforms of all links that connect to the worldbody
|
195
203
|
by randomize transforms.
|
@@ -210,14 +218,30 @@ def randomize_to_world_pos_rot(
|
|
210
218
|
<x_xy>
|
211
219
|
<options dt="0.01"/>
|
212
220
|
<worldbody>
|
213
|
-
<body name="free" joint="free"
|
221
|
+
<body name="free" joint="free" damping="15.0 15.0 15.0 25.0 25.0 25.0">
|
222
|
+
<geom type="box" mass="1" dim="0.1 0.1 0.1"/>
|
223
|
+
</body>
|
214
224
|
</worldbody>
|
215
225
|
</x_xy>
|
216
226
|
"""
|
217
|
-
|
218
227
|
free_sys = io.load_sys_from_str(free_sys_str)
|
228
|
+
|
229
|
+
dynamic_simulation = True if overwrite_q_ref is not None else False
|
230
|
+
|
231
|
+
if world_joint != "free":
|
232
|
+
if dynamic_simulation:
|
233
|
+
assert damping is not None
|
234
|
+
free_sys = free_sys.change_joint_type("free", world_joint, new_damp=damping)
|
235
|
+
|
219
236
|
_, xs_free = generator.RCMG(
|
220
|
-
free_sys,
|
237
|
+
free_sys,
|
238
|
+
config,
|
239
|
+
finalize_fn=lambda key, q, x, sys: (q, x),
|
240
|
+
cor=cor,
|
241
|
+
dynamic_simulation=dynamic_simulation,
|
242
|
+
dynamic_simulation_kwargs=dict(
|
243
|
+
overwrite_q_ref=(overwrite_q_ref, free_sys.idx_map("q"))
|
244
|
+
),
|
221
245
|
).to_lazy_gen()(key)
|
222
246
|
xs_free = xs_free.take(0, axis=0)
|
223
247
|
xs_free = xs_free.take(free_sys.name_to_idx("free"), axis=1)
|
File without changes
|