mink 0.0.1__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.
- mink/.mypy_cache/.gitignore +2 -0
- mink/.mypy_cache/3.12/@plugins_snapshot.json +1 -0
- mink/.mypy_cache/3.12/__future__.data.json +1 -0
- mink/.mypy_cache/3.12/__future__.meta.json +1 -0
- mink/.mypy_cache/3.12/_ast.data.json +1 -0
- mink/.mypy_cache/3.12/_ast.meta.json +1 -0
- mink/.mypy_cache/3.12/_codecs.data.json +1 -0
- mink/.mypy_cache/3.12/_codecs.meta.json +1 -0
- mink/.mypy_cache/3.12/_collections_abc.data.json +1 -0
- mink/.mypy_cache/3.12/_collections_abc.meta.json +1 -0
- mink/.mypy_cache/3.12/_ctypes.data.json +1 -0
- mink/.mypy_cache/3.12/_ctypes.meta.json +1 -0
- mink/.mypy_cache/3.12/_thread.data.json +1 -0
- mink/.mypy_cache/3.12/_thread.meta.json +1 -0
- mink/.mypy_cache/3.12/_typeshed/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/_typeshed/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/_warnings.data.json +1 -0
- mink/.mypy_cache/3.12/_warnings.meta.json +1 -0
- mink/.mypy_cache/3.12/abc.data.json +1 -0
- mink/.mypy_cache/3.12/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/array.data.json +1 -0
- mink/.mypy_cache/3.12/array.meta.json +1 -0
- mink/.mypy_cache/3.12/ast.data.json +1 -0
- mink/.mypy_cache/3.12/ast.meta.json +1 -0
- mink/.mypy_cache/3.12/builtins.data.json +1 -0
- mink/.mypy_cache/3.12/builtins.meta.json +1 -0
- mink/.mypy_cache/3.12/codecs.data.json +1 -0
- mink/.mypy_cache/3.12/codecs.meta.json +1 -0
- mink/.mypy_cache/3.12/collections/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/collections/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/collections/abc.data.json +1 -0
- mink/.mypy_cache/3.12/collections/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/contextlib.data.json +1 -0
- mink/.mypy_cache/3.12/contextlib.meta.json +1 -0
- mink/.mypy_cache/3.12/ctypes/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/ctypes/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/dataclasses.data.json +1 -0
- mink/.mypy_cache/3.12/dataclasses.meta.json +1 -0
- mink/.mypy_cache/3.12/datetime.data.json +1 -0
- mink/.mypy_cache/3.12/datetime.meta.json +1 -0
- mink/.mypy_cache/3.12/email/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/email/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/email/charset.data.json +1 -0
- mink/.mypy_cache/3.12/email/charset.meta.json +1 -0
- mink/.mypy_cache/3.12/email/contentmanager.data.json +1 -0
- mink/.mypy_cache/3.12/email/contentmanager.meta.json +1 -0
- mink/.mypy_cache/3.12/email/errors.data.json +1 -0
- mink/.mypy_cache/3.12/email/errors.meta.json +1 -0
- mink/.mypy_cache/3.12/email/header.data.json +1 -0
- mink/.mypy_cache/3.12/email/header.meta.json +1 -0
- mink/.mypy_cache/3.12/email/message.data.json +1 -0
- mink/.mypy_cache/3.12/email/message.meta.json +1 -0
- mink/.mypy_cache/3.12/email/policy.data.json +1 -0
- mink/.mypy_cache/3.12/email/policy.meta.json +1 -0
- mink/.mypy_cache/3.12/enum.data.json +1 -0
- mink/.mypy_cache/3.12/enum.meta.json +1 -0
- mink/.mypy_cache/3.12/genericpath.data.json +1 -0
- mink/.mypy_cache/3.12/genericpath.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/abc.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/machinery.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/machinery.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/_meta.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/readers.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/readers.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/abc.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/io.data.json +1 -0
- mink/.mypy_cache/3.12/io.meta.json +1 -0
- mink/.mypy_cache/3.12/logging/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/logging/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/math.data.json +1 -0
- mink/.mypy_cache/3.12/math.meta.json +1 -0
- mink/.mypy_cache/3.12/mink/limits/limit.data.json +1 -0
- mink/.mypy_cache/3.12/mink/limits/limit.meta.json +1 -0
- mink/.mypy_cache/3.12/mmap.data.json +1 -0
- mink/.mypy_cache/3.12/mmap.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_pytesttester.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_pytesttester.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_add_docstring.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_add_docstring.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_array_like.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_array_like.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_callable.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_callable.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_char_codes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_char_codes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_dtype_like.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_dtype_like.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_extended_precision.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_extended_precision.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nbit.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nbit.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nested_sequence.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nested_sequence.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_scalars.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_scalars.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_shape.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_shape.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_ufunc.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_ufunc.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/_convertions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/_convertions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_asarray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_asarray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_internal.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_internal.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_type_aliases.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_type_aliases.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_ufunc_config.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_ufunc_config.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/arrayprint.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/arrayprint.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/defchararray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/defchararray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/einsumfunc.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/einsumfunc.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/fromnumeric.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/fromnumeric.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/function_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/function_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/multiarray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/multiarray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numeric.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numeric.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numerictypes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numerictypes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/records.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/records.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/shape_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/shape_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/umath.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/umath.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ctypeslib.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ctypeslib.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/dtypes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/dtypes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/exceptions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/exceptions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/_pocketfft.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/_pocketfft.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/helper.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/helper.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/_version.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/_version.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraypad.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraypad.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraysetops.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraysetops.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arrayterator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arrayterator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/format.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/format.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/function_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/function_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/histograms.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/histograms.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/index_tricks.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/index_tricks.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/mixins.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/mixins.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/nanfunctions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/nanfunctions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/npyio.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/npyio.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/polynomial.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/polynomial.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/scimath.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/scimath.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/shape_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/shape_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/stride_tricks.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/stride_tricks.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/twodim_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/twodim_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/type_check.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/type_check.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/ufunclike.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/ufunclike.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/utils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/utils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/linalg.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/linalg.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/core.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/core.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/extras.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/extras.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/mrecords.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/mrecords.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/defmatrix.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/defmatrix.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/_polybase.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/_polybase.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/chebyshev.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/chebyshev.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite_e.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite_e.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/laguerre.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/laguerre.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/legendre.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/legendre.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polynomial.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polynomial.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polyutils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polyutils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_generator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_generator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_mt19937.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_mt19937.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_pcg64.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_pcg64.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_philox.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_philox.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_sfc64.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_sfc64.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/bit_generator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/bit_generator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/mtrand.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/mtrand.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/utils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/utils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/typing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/typing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/version.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/version.meta.json +1 -0
- mink/.mypy_cache/3.12/os/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/os/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/os/path.data.json +1 -0
- mink/.mypy_cache/3.12/os/path.meta.json +1 -0
- mink/.mypy_cache/3.12/pathlib.data.json +1 -0
- mink/.mypy_cache/3.12/pathlib.meta.json +1 -0
- mink/.mypy_cache/3.12/posixpath.data.json +1 -0
- mink/.mypy_cache/3.12/posixpath.meta.json +1 -0
- mink/.mypy_cache/3.12/re.data.json +1 -0
- mink/.mypy_cache/3.12/re.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_compile.data.json +1 -0
- mink/.mypy_cache/3.12/sre_compile.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_constants.data.json +1 -0
- mink/.mypy_cache/3.12/sre_constants.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_parse.data.json +1 -0
- mink/.mypy_cache/3.12/sre_parse.meta.json +1 -0
- mink/.mypy_cache/3.12/string.data.json +1 -0
- mink/.mypy_cache/3.12/string.meta.json +1 -0
- mink/.mypy_cache/3.12/subprocess.data.json +1 -0
- mink/.mypy_cache/3.12/subprocess.meta.json +1 -0
- mink/.mypy_cache/3.12/sys/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/sys/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/sys/_monitoring.data.json +1 -0
- mink/.mypy_cache/3.12/sys/_monitoring.meta.json +1 -0
- mink/.mypy_cache/3.12/textwrap.data.json +1 -0
- mink/.mypy_cache/3.12/textwrap.meta.json +1 -0
- mink/.mypy_cache/3.12/threading.data.json +1 -0
- mink/.mypy_cache/3.12/threading.meta.json +1 -0
- mink/.mypy_cache/3.12/time.data.json +1 -0
- mink/.mypy_cache/3.12/time.meta.json +1 -0
- mink/.mypy_cache/3.12/types.data.json +1 -0
- mink/.mypy_cache/3.12/types.meta.json +1 -0
- mink/.mypy_cache/3.12/typing.data.json +1 -0
- mink/.mypy_cache/3.12/typing.meta.json +1 -0
- mink/.mypy_cache/3.12/typing_extensions.data.json +1 -0
- mink/.mypy_cache/3.12/typing_extensions.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/_log.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/_log.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/async_case.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/async_case.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/case.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/case.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/loader.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/loader.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/main.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/main.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/result.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/result.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/runner.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/runner.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/signals.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/signals.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/suite.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/suite.meta.json +1 -0
- mink/.mypy_cache/3.12/warnings.data.json +1 -0
- mink/.mypy_cache/3.12/warnings.meta.json +1 -0
- mink/.mypy_cache/3.12/zipfile.data.json +1 -0
- mink/.mypy_cache/3.12/zipfile.meta.json +1 -0
- mink/.mypy_cache/CACHEDIR.TAG +3 -0
- mink/__init__.py +75 -0
- mink/configuration.py +215 -0
- mink/constants.py +34 -0
- mink/exceptions.py +98 -0
- mink/lie/__init__.py +13 -0
- mink/lie/base.py +156 -0
- mink/lie/se3.py +249 -0
- mink/lie/so3.py +224 -0
- mink/lie/tests/__init__.py +0 -0
- mink/lie/tests/test_axioms.py +51 -0
- mink/lie/tests/test_operations.py +77 -0
- mink/lie/tests/utils.py +20 -0
- mink/lie/utils.py +29 -0
- mink/limits/__init__.py +16 -0
- mink/limits/collision_avoidance_limit.py +274 -0
- mink/limits/configuration_limit.py +126 -0
- mink/limits/exceptions.py +7 -0
- mink/limits/limit.py +41 -0
- mink/limits/velocity_limit.py +92 -0
- mink/py.typed +0 -0
- mink/solve_ik.py +105 -0
- mink/tasks/__init__.py +26 -0
- mink/tasks/com_task.py +82 -0
- mink/tasks/exceptions.py +27 -0
- mink/tasks/frame_task.py +114 -0
- mink/tasks/posture_task.py +103 -0
- mink/tasks/task.py +105 -0
- mink/utils.py +128 -0
- mink-0.0.1.dist-info/METADATA +71 -0
- mink-0.0.1.dist-info/RECORD +352 -0
- mink-0.0.1.dist-info/WHEEL +4 -0
mink/tasks/com_task.py
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
"""Center of mass task implementation."""
|
2
|
+
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
import mujoco
|
6
|
+
import numpy as np
|
7
|
+
import numpy.typing as npt
|
8
|
+
|
9
|
+
from ..configuration import Configuration
|
10
|
+
from .exceptions import InvalidTarget, TargetNotSet, TaskDefinitionError
|
11
|
+
from .task import Task
|
12
|
+
|
13
|
+
|
14
|
+
class ComTask(Task):
|
15
|
+
"""Regulate the center of mass (CoM) of a robot.
|
16
|
+
|
17
|
+
Attributes:
|
18
|
+
target_com: Target position of the CoM.
|
19
|
+
"""
|
20
|
+
|
21
|
+
k: int = 3
|
22
|
+
target_com: Optional[np.ndarray]
|
23
|
+
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
cost: npt.ArrayLike,
|
27
|
+
gain: float = 1.0,
|
28
|
+
lm_damping: float = 0.0,
|
29
|
+
):
|
30
|
+
super().__init__(cost=np.zeros((self.k,)), gain=gain, lm_damping=lm_damping)
|
31
|
+
self.target_com = None
|
32
|
+
|
33
|
+
self.set_cost(cost)
|
34
|
+
|
35
|
+
def set_cost(self, cost: npt.ArrayLike) -> None:
|
36
|
+
"""Set a new cost for all CoM coordinates."""
|
37
|
+
cost = np.atleast_1d(cost)
|
38
|
+
if cost.ndim != 1 or cost.shape[0] not in (1, self.k):
|
39
|
+
raise TaskDefinitionError(
|
40
|
+
f"{self.__class__.__name__} cost must be a vector of shape (1,) "
|
41
|
+
f"(aka identical cost for all coordinates) or ({self.k},). "
|
42
|
+
f"Got {cost.shape}"
|
43
|
+
)
|
44
|
+
if not np.all(cost >= 0.0):
|
45
|
+
raise TaskDefinitionError(f"{self.__class__.__name__} cost must be >= 0")
|
46
|
+
self.cost[:] = cost
|
47
|
+
|
48
|
+
def set_target(self, target_com: npt.ArrayLike) -> None:
|
49
|
+
"""Set the target CoM position in the world frame."""
|
50
|
+
target_com = np.atleast_1d(target_com)
|
51
|
+
if target_com.ndim != 1 or target_com.shape[0] != (self.k):
|
52
|
+
raise InvalidTarget(
|
53
|
+
f"Expected target CoM to have shape ({self.k},) but got "
|
54
|
+
f"{target_com.shape}"
|
55
|
+
)
|
56
|
+
self.target_com = target_com.copy()
|
57
|
+
|
58
|
+
def set_target_from_configuration(self, configuration: Configuration) -> None:
|
59
|
+
"""Set the target CoM from a given robot configuration."""
|
60
|
+
self.set_target(configuration.data.subtree_com[1])
|
61
|
+
|
62
|
+
def compute_error(self, configuration: Configuration) -> np.ndarray:
|
63
|
+
"""Compute the CoM task error.
|
64
|
+
|
65
|
+
The error is the difference between the target CoM and current CoM positions,
|
66
|
+
expressed in the world frame.
|
67
|
+
"""
|
68
|
+
if self.target_com is None:
|
69
|
+
raise TargetNotSet(self.__class__.__name__)
|
70
|
+
return configuration.data.subtree_com[1] - self.target_com
|
71
|
+
|
72
|
+
def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
|
73
|
+
"""Compute the CoM task Jacobian.
|
74
|
+
|
75
|
+
The task Jacobian is the derivative of the task error with respect to the
|
76
|
+
current configuration. It has dimension (3, nv).
|
77
|
+
"""
|
78
|
+
if self.target_com is None:
|
79
|
+
raise TargetNotSet(self.__class__.__name__)
|
80
|
+
jac = np.empty((self.k, configuration.nv))
|
81
|
+
mujoco.mj_jacSubtreeCom(configuration.model, configuration.data, jac, 1)
|
82
|
+
return jac
|
mink/tasks/exceptions.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
"""Exceptions raised by tasks."""
|
2
|
+
|
3
|
+
from ..exceptions import MinkError
|
4
|
+
|
5
|
+
|
6
|
+
class TaskDefinitionError(MinkError):
|
7
|
+
"""Exception raised when a task definition is ill-formed."""
|
8
|
+
|
9
|
+
|
10
|
+
class TargetNotSet(MinkError):
|
11
|
+
"""Exception raised when attempting to use a task with an unset target."""
|
12
|
+
|
13
|
+
def __init__(self, cls_name: str):
|
14
|
+
message = f"No target set for {cls_name}"
|
15
|
+
super().__init__(message)
|
16
|
+
|
17
|
+
|
18
|
+
class InvalidTarget(MinkError):
|
19
|
+
"""Exception raised when the target is invalid."""
|
20
|
+
|
21
|
+
|
22
|
+
class InvalidGain(MinkError):
|
23
|
+
"""Exception raised when the gain is outside the valid range."""
|
24
|
+
|
25
|
+
|
26
|
+
class InvalidDamping(MinkError):
|
27
|
+
"""Exception raised when the damping is outside the valid range."""
|
mink/tasks/frame_task.py
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
"""Frame task implementation."""
|
2
|
+
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
import numpy.typing as npt
|
7
|
+
|
8
|
+
from ..configuration import Configuration
|
9
|
+
from ..lie import SE3
|
10
|
+
from .exceptions import TargetNotSet, TaskDefinitionError
|
11
|
+
from .task import Task
|
12
|
+
|
13
|
+
|
14
|
+
class FrameTask(Task):
|
15
|
+
"""Regulate the pose of a robot frame in the world frame.
|
16
|
+
|
17
|
+
Attributes:
|
18
|
+
frame_name: Name of the frame to regulate.
|
19
|
+
frame_type: The frame type: body, geom or site.
|
20
|
+
transform_frame_to_world: Target pose of the frame in the world frame.
|
21
|
+
"""
|
22
|
+
|
23
|
+
k: int = 6
|
24
|
+
transform_target_to_world: Optional[SE3]
|
25
|
+
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
frame_name: str,
|
29
|
+
frame_type: str,
|
30
|
+
position_cost: npt.ArrayLike,
|
31
|
+
orientation_cost: npt.ArrayLike,
|
32
|
+
gain: float = 1.0,
|
33
|
+
lm_damping: float = 0.0,
|
34
|
+
):
|
35
|
+
super().__init__(cost=np.zeros((self.k,)), gain=gain, lm_damping=lm_damping)
|
36
|
+
self.frame_name = frame_name
|
37
|
+
self.frame_type = frame_type
|
38
|
+
self.position_cost = position_cost
|
39
|
+
self.orientation_cost = orientation_cost
|
40
|
+
self.transform_target_to_world = None
|
41
|
+
|
42
|
+
self.set_position_cost(position_cost)
|
43
|
+
self.set_orientation_cost(orientation_cost)
|
44
|
+
|
45
|
+
def set_position_cost(self, position_cost: npt.ArrayLike) -> None:
|
46
|
+
position_cost = np.atleast_1d(position_cost)
|
47
|
+
if position_cost.ndim != 1 or position_cost.shape[0] not in (1, 3):
|
48
|
+
raise TaskDefinitionError(
|
49
|
+
f"{self.__class__.__name__} position cost should be a vector of shape "
|
50
|
+
"1 (aka identical cost for all coordinates) or (3,) but got "
|
51
|
+
f"{position_cost.shape}"
|
52
|
+
)
|
53
|
+
if not np.all(position_cost >= 0.0):
|
54
|
+
raise TaskDefinitionError(
|
55
|
+
f"{self.__class__.__name__} position cost should be >= 0"
|
56
|
+
)
|
57
|
+
self.cost[:3] = position_cost
|
58
|
+
|
59
|
+
def set_orientation_cost(self, orientation_cost: npt.ArrayLike) -> None:
|
60
|
+
orientation_cost = np.atleast_1d(orientation_cost)
|
61
|
+
if orientation_cost.ndim != 1 or orientation_cost.shape[0] not in (1, 3):
|
62
|
+
raise TaskDefinitionError(
|
63
|
+
f"{self.__class__.__name__} orientation cost should be a vector of "
|
64
|
+
"shape 1 (aka identical cost for all coordinates) or (3,) but got "
|
65
|
+
f"{orientation_cost.shape}"
|
66
|
+
)
|
67
|
+
if not np.all(orientation_cost >= 0.0):
|
68
|
+
raise TaskDefinitionError(
|
69
|
+
f"{self.__class__.__name__} position cost should be >= 0"
|
70
|
+
)
|
71
|
+
self.cost[3:] = orientation_cost
|
72
|
+
|
73
|
+
def set_target(self, transform_target_to_world: SE3) -> None:
|
74
|
+
"""Set the target pose in the world frame."""
|
75
|
+
self.transform_target_to_world = transform_target_to_world.copy()
|
76
|
+
|
77
|
+
def set_target_from_configuration(self, configuration: Configuration) -> None:
|
78
|
+
"""Set the target pose from a given robot configuration."""
|
79
|
+
self.set_target(
|
80
|
+
configuration.get_transform_frame_to_world(self.frame_name, self.frame_type)
|
81
|
+
)
|
82
|
+
|
83
|
+
def compute_error(self, configuration: Configuration) -> np.ndarray:
|
84
|
+
"""Compute the frame task error.
|
85
|
+
|
86
|
+
This error is a twist expressed in the local frame, i.e., it is a body twist.
|
87
|
+
It is computed by taking the right minus difference between the target pose
|
88
|
+
and the current frame pose: `e = T_wt ⊖ T_wf`.
|
89
|
+
"""
|
90
|
+
if self.transform_target_to_world is None:
|
91
|
+
raise TargetNotSet(self.__class__.__name__)
|
92
|
+
|
93
|
+
transform_frame_to_world = configuration.get_transform_frame_to_world(
|
94
|
+
self.frame_name, self.frame_type
|
95
|
+
)
|
96
|
+
return self.transform_target_to_world.minus(transform_frame_to_world)
|
97
|
+
|
98
|
+
def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
|
99
|
+
"""Compute the frame task Jacobian.
|
100
|
+
|
101
|
+
The task Jacobian is the derivative of the task error with respect to the
|
102
|
+
current configuration. It has dimension (6, nv).
|
103
|
+
"""
|
104
|
+
if self.transform_target_to_world is None:
|
105
|
+
raise TargetNotSet(self.__class__.__name__)
|
106
|
+
|
107
|
+
jac = configuration.get_frame_jacobian(self.frame_name, self.frame_type)
|
108
|
+
|
109
|
+
transform_frame_to_world = configuration.get_transform_frame_to_world(
|
110
|
+
self.frame_name, self.frame_type
|
111
|
+
)
|
112
|
+
|
113
|
+
T_tb = self.transform_target_to_world.inverse() @ transform_frame_to_world
|
114
|
+
return -T_tb.jlog() @ jac
|
@@ -0,0 +1,103 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
import mujoco
|
4
|
+
import numpy as np
|
5
|
+
import numpy.typing as npt
|
6
|
+
|
7
|
+
from ..configuration import Configuration
|
8
|
+
from ..utils import get_freejoint_dims
|
9
|
+
from .exceptions import InvalidTarget, TargetNotSet, TaskDefinitionError
|
10
|
+
from .task import Task
|
11
|
+
|
12
|
+
|
13
|
+
class PostureTask(Task):
|
14
|
+
"""Regulate joint angles to a desired posture.
|
15
|
+
|
16
|
+
A posture is a vector of actuated joint angles. Floating-base coordinates are not
|
17
|
+
affected by this task.
|
18
|
+
|
19
|
+
Attributes:
|
20
|
+
target_q: Target configuration.
|
21
|
+
"""
|
22
|
+
|
23
|
+
target_q: Optional[np.ndarray]
|
24
|
+
|
25
|
+
def __init__(
|
26
|
+
self,
|
27
|
+
model: mujoco.MjModel,
|
28
|
+
cost: float,
|
29
|
+
gain: float = 1.0,
|
30
|
+
lm_damping: float = 0.0,
|
31
|
+
):
|
32
|
+
if cost < 0.0:
|
33
|
+
raise TaskDefinitionError(f"{self.__class__.__name__} cost must be >= 0")
|
34
|
+
|
35
|
+
super().__init__(
|
36
|
+
cost=np.asarray([cost] * model.nv),
|
37
|
+
gain=gain,
|
38
|
+
lm_damping=lm_damping,
|
39
|
+
)
|
40
|
+
self.target_q = None
|
41
|
+
|
42
|
+
self._v_ids: np.ndarray | None
|
43
|
+
_, v_ids_or_none = get_freejoint_dims(model)
|
44
|
+
if v_ids_or_none:
|
45
|
+
self._v_ids = np.asarray(v_ids_or_none)
|
46
|
+
else:
|
47
|
+
self._v_ids = None
|
48
|
+
|
49
|
+
self.k = model.nv
|
50
|
+
self.nq = model.nq
|
51
|
+
|
52
|
+
def set_target(self, target_q: npt.ArrayLike) -> None:
|
53
|
+
"""Set the target posture."""
|
54
|
+
target_q = np.atleast_1d(target_q)
|
55
|
+
if target_q.ndim != 1 or target_q.shape[0] != (self.nq):
|
56
|
+
raise InvalidTarget(
|
57
|
+
f"Expected target posture to have shape ({self.nq},) but got "
|
58
|
+
f"{target_q.shape}"
|
59
|
+
)
|
60
|
+
self.target_q = target_q.copy()
|
61
|
+
|
62
|
+
def set_target_from_configuration(self, configuration: Configuration) -> None:
|
63
|
+
"""Set the target posture from the current configuration."""
|
64
|
+
self.set_target(configuration.q)
|
65
|
+
|
66
|
+
def compute_error(self, configuration: Configuration) -> np.ndarray:
|
67
|
+
"""Compute the posture task error.
|
68
|
+
|
69
|
+
The error is defined as the right minus error between the target posture and
|
70
|
+
the current posture: `q^* ⊖ q`.
|
71
|
+
"""
|
72
|
+
if self.target_q is None:
|
73
|
+
raise TargetNotSet(self.__class__.__name__)
|
74
|
+
|
75
|
+
# NOTE: mj_differentiatePos calculates qpos2 ⊖ qpos1.
|
76
|
+
qvel = np.empty(configuration.nv)
|
77
|
+
mujoco.mj_differentiatePos(
|
78
|
+
m=configuration.model,
|
79
|
+
qvel=qvel,
|
80
|
+
dt=1.0,
|
81
|
+
qpos1=configuration.q,
|
82
|
+
qpos2=self.target_q,
|
83
|
+
)
|
84
|
+
|
85
|
+
if self._v_ids is not None:
|
86
|
+
qvel[self._v_ids] = 0.0
|
87
|
+
|
88
|
+
return qvel
|
89
|
+
|
90
|
+
def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
|
91
|
+
"""Compute the posture task Jacobian.
|
92
|
+
|
93
|
+
The task Jacobian is the derivative of the task error with respect to the
|
94
|
+
current configuration. It is equal to -I and has dimension (nv, nv).
|
95
|
+
"""
|
96
|
+
if self.target_q is None:
|
97
|
+
raise TargetNotSet(self.__class__.__name__)
|
98
|
+
|
99
|
+
jac = -np.eye(configuration.nv)
|
100
|
+
if self._v_ids is not None:
|
101
|
+
jac[:, self._v_ids] = 0.0
|
102
|
+
|
103
|
+
return jac
|
mink/tasks/task.py
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
import abc
|
2
|
+
from typing import NamedTuple
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
from ..configuration import Configuration
|
7
|
+
from .exceptions import InvalidDamping, InvalidGain
|
8
|
+
|
9
|
+
|
10
|
+
class Objective(NamedTuple):
|
11
|
+
"""Quadratic objective function in the form 0.5 x^T H x + c^T x."""
|
12
|
+
|
13
|
+
H: np.ndarray # (nv, nv)
|
14
|
+
c: np.ndarray # (nv,)
|
15
|
+
|
16
|
+
def value(self, x: np.ndarray) -> float:
|
17
|
+
"""Returns the value of the objective at the input vector."""
|
18
|
+
return x.T @ self.H @ x + self.c @ x
|
19
|
+
|
20
|
+
|
21
|
+
class Task(abc.ABC):
|
22
|
+
"""Abstract base class for kinematic tasks."""
|
23
|
+
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
cost: np.ndarray,
|
27
|
+
gain: float = 1.0,
|
28
|
+
lm_damping: float = 0.0,
|
29
|
+
):
|
30
|
+
"""Constructor.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
cost: Cost vector with the same dimension as the error of the task.
|
34
|
+
gain: Task gain alpha in [0, 1] for additional low-pass filtering. Defaults
|
35
|
+
to 1.0 (no filtering) for dead-beat control.
|
36
|
+
lm_damping: Unitless scale of the Levenberg-Marquardt (only when the error
|
37
|
+
is large) regularization term, which helps when targets are infeasible.
|
38
|
+
Increase this value if the task is too jerky under unfeasible targets, but
|
39
|
+
beware that a larger damping slows down the task.
|
40
|
+
"""
|
41
|
+
if not 0.0 <= gain <= 1.0:
|
42
|
+
raise InvalidGain("`gain` must be in the range [0, 1]")
|
43
|
+
|
44
|
+
if not lm_damping >= 0.0:
|
45
|
+
raise InvalidDamping("`lm_damping` must be >= 0")
|
46
|
+
|
47
|
+
self.cost = cost
|
48
|
+
self.gain = gain
|
49
|
+
self.lm_damping = lm_damping
|
50
|
+
|
51
|
+
@abc.abstractmethod
|
52
|
+
def compute_error(self, configuration: Configuration) -> np.ndarray:
|
53
|
+
"""Compute the task error function at the current configuration.
|
54
|
+
|
55
|
+
The error function e(q), of shape (k,), is the quantity that the task aims to
|
56
|
+
drive to zero. It appears in the first-order task dynamics:
|
57
|
+
|
58
|
+
J(q) Δq = -alpha e(q)
|
59
|
+
|
60
|
+
The Jacobian matrix J(q), of shape (k, nv), is the derivative of the task error
|
61
|
+
with respect to the configuration. This Jacobian is implemented in
|
62
|
+
`compute_jacobian`. Finally, the configuration displacement Δq is the output
|
63
|
+
of inverse kinematics.
|
64
|
+
|
65
|
+
In the first-order task dynamics, the error e(q) is multiplied by the task gain
|
66
|
+
alpha which is between [0, 1]. This gain can be 1.0 for dead-beat control
|
67
|
+
(i.e., converge as fast as possible), but might be unstable as it neglects the
|
68
|
+
first-order approximation. Lower values make the task slower and have a similar
|
69
|
+
effect to low-pass filtering.
|
70
|
+
"""
|
71
|
+
raise NotImplementedError
|
72
|
+
|
73
|
+
@abc.abstractmethod
|
74
|
+
def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
|
75
|
+
"""Compute the task Jacobian at the current configuration.
|
76
|
+
|
77
|
+
The task Jacobian J(q), of shape (k, nv) is the first-order derivative of the
|
78
|
+
error e(q) that defines the task, with k the dimension of the task and
|
79
|
+
nv the dimension of the robot's tangent space.
|
80
|
+
"""
|
81
|
+
raise NotImplementedError
|
82
|
+
|
83
|
+
def compute_qp_objective(self, configuration: Configuration) -> Objective:
|
84
|
+
"""Compute the matrix-vector pair :math:`(H, c)` of the QP objective.
|
85
|
+
|
86
|
+
This pair is such that the contribution of the task to the QP objective
|
87
|
+
of the IK is:
|
88
|
+
|
89
|
+
The weight matrix W, of shape (k, k), weighs and normalizes task coordinates
|
90
|
+
to the same unit. The unit of the overall contribution is [cost]^2.
|
91
|
+
"""
|
92
|
+
jacobian = self.compute_jacobian(configuration) # (k, nv)
|
93
|
+
minus_gain_error = -self.gain * self.compute_error(configuration) # (k,)
|
94
|
+
|
95
|
+
weight = np.diag(self.cost)
|
96
|
+
weighted_jacobian = weight @ jacobian
|
97
|
+
weighted_error = weight @ minus_gain_error
|
98
|
+
|
99
|
+
mu = self.lm_damping * weighted_error @ weighted_error
|
100
|
+
eye_tg = np.eye(configuration.model.nv)
|
101
|
+
|
102
|
+
H = weighted_jacobian.T @ weighted_jacobian + mu * eye_tg # (nv, nv)
|
103
|
+
c = -weighted_error.T @ weighted_jacobian # (nv,)
|
104
|
+
|
105
|
+
return Objective(H, c)
|
mink/utils.py
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
import mujoco
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
from . import constants as consts
|
7
|
+
from .exceptions import InvalidKeyframe, InvalidMocapBody
|
8
|
+
|
9
|
+
|
10
|
+
def move_mocap_to_frame(
|
11
|
+
model: mujoco.MjModel,
|
12
|
+
data: mujoco.MjData,
|
13
|
+
mocap_name: str,
|
14
|
+
frame_name: str,
|
15
|
+
frame_type: str,
|
16
|
+
) -> None:
|
17
|
+
"""Initialize mocap body pose at a desired frame.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
model: An instance of mujoco.MjModel.
|
21
|
+
data: An instance of mujoco.MjData.
|
22
|
+
mocap_name: The name of the mocap body.
|
23
|
+
frame_name: The desired frame name.
|
24
|
+
frame_type: The desired frame type. Can be "body", "geom" or "site".
|
25
|
+
"""
|
26
|
+
mocap_id = model.body(mocap_name).mocapid[0]
|
27
|
+
if mocap_id == -1:
|
28
|
+
raise InvalidMocapBody(mocap_name, model)
|
29
|
+
|
30
|
+
obj_id = mujoco.mj_name2id(model, consts.FRAME_TO_ENUM[frame_type], frame_name)
|
31
|
+
xpos = getattr(data, consts.FRAME_TO_POS_ATTR[frame_type])[obj_id]
|
32
|
+
xmat = getattr(data, consts.FRAME_TO_XMAT_ATTR[frame_type])[obj_id]
|
33
|
+
|
34
|
+
data.mocap_pos[mocap_id] = xpos.copy()
|
35
|
+
mujoco.mju_mat2Quat(data.mocap_quat[mocap_id], xmat)
|
36
|
+
|
37
|
+
|
38
|
+
def get_freejoint_dims(model: mujoco.MjModel) -> tuple[list[int], list[int]]:
|
39
|
+
"""Get all floating joint configuration and tangent indices."""
|
40
|
+
q_ids: list[int] = []
|
41
|
+
v_ids: list[int] = []
|
42
|
+
for j in range(model.njnt):
|
43
|
+
if model.jnt_type[j] == mujoco.mjtJoint.mjJNT_FREE:
|
44
|
+
qadr = model.jnt_qposadr[j]
|
45
|
+
vadr = model.jnt_dofadr[j]
|
46
|
+
q_ids.extend(range(qadr, qadr + 7))
|
47
|
+
v_ids.extend(range(vadr, vadr + 6))
|
48
|
+
return q_ids, v_ids
|
49
|
+
|
50
|
+
|
51
|
+
def custom_configuration_vector(
|
52
|
+
model: mujoco.MjModel,
|
53
|
+
key_name: Optional[str] = None,
|
54
|
+
**kwargs,
|
55
|
+
) -> np.ndarray:
|
56
|
+
"""Generate a configuration vector where named joints have specific values.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
model: An MjModel instance.
|
60
|
+
key_name: Optional keyframe name to initialize the configuration vector from.
|
61
|
+
Otherwise, the default pose qpos0 is used.
|
62
|
+
kwargs: Custom values for joint coordinates.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
Configuration vector where named joints have the values specified in
|
66
|
+
keyword arguments, and other joints have their neutral value or value
|
67
|
+
defined in the keyframe if provided.
|
68
|
+
"""
|
69
|
+
data = mujoco.MjData(model)
|
70
|
+
if key_name is not None:
|
71
|
+
key_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_KEY, key_name)
|
72
|
+
if key_id == -1:
|
73
|
+
raise InvalidKeyframe(key_name, model)
|
74
|
+
mujoco.mj_resetDataKeyframe(model, data, key_id)
|
75
|
+
else:
|
76
|
+
mujoco.mj_resetData(model, data)
|
77
|
+
q = data.qpos.copy()
|
78
|
+
for name, value in kwargs.items():
|
79
|
+
jid = model.joint(name).id
|
80
|
+
jnt_dim = consts.qpos_width(model.jnt_type[jid])
|
81
|
+
qid = model.jnt_qposadr[jid]
|
82
|
+
value = np.atleast_1d(value)
|
83
|
+
if value.shape != (jnt_dim,):
|
84
|
+
raise ValueError(
|
85
|
+
f"Joint {name} should have a qpos value of {jnt_dim,} but "
|
86
|
+
f"got {value.shape}"
|
87
|
+
)
|
88
|
+
q[qid : qid + jnt_dim] = value
|
89
|
+
return q
|
90
|
+
|
91
|
+
|
92
|
+
def get_subtree_geom_ids(model: mujoco.MjModel, body_id: int) -> list[int]:
|
93
|
+
"""Get all geoms belonging to subtree starting at a given body.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
model: An MjModel instance.
|
97
|
+
body_id: ID of body where subtree starts.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
A list containing all subtree geom ids.
|
101
|
+
"""
|
102
|
+
|
103
|
+
def gather_geoms(body_id: int) -> list[int]:
|
104
|
+
geoms: list[int] = []
|
105
|
+
geom_start = model.body_geomadr[body_id]
|
106
|
+
geom_end = geom_start + model.body_geomnum[body_id]
|
107
|
+
geoms.extend(range(geom_start, geom_end))
|
108
|
+
children = [i for i in range(model.nbody) if model.body_parentid[i] == body_id]
|
109
|
+
for child_id in children:
|
110
|
+
geoms.extend(gather_geoms(child_id))
|
111
|
+
return geoms
|
112
|
+
|
113
|
+
return gather_geoms(body_id)
|
114
|
+
|
115
|
+
|
116
|
+
def get_body_geom_ids(model: mujoco.MjModel, body_id: int) -> list[int]:
|
117
|
+
"""Get all geoms belonging to a given body.
|
118
|
+
|
119
|
+
Args:
|
120
|
+
model: An MjModel instance.
|
121
|
+
body_id: ID of body.
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
A list containing all body geom ids.
|
125
|
+
"""
|
126
|
+
geom_start = model.body_geomadr[body_id]
|
127
|
+
geom_end = geom_start + model.body_geomnum[body_id]
|
128
|
+
return list(range(geom_start, geom_end))
|
@@ -0,0 +1,71 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: mink
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: mink: MuJoCo inverse kinematics.
|
5
|
+
Keywords: inverse,kinematics,mujoco
|
6
|
+
Author-email: Kevin Zakka <zakka@berkeley.edu>
|
7
|
+
Requires-Python: >=3.9
|
8
|
+
Description-Content-Type: text/markdown
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
10
|
+
Classifier: Framework :: Robot Framework :: Library
|
11
|
+
Classifier: Intended Audience :: Developers
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
18
|
+
Requires-Dist: mujoco >= 3.1.6
|
19
|
+
Requires-Dist: qpsolvers >= 4.3.1
|
20
|
+
Requires-Dist: quadprog >= 0.1.11
|
21
|
+
Requires-Dist: typing_extensions
|
22
|
+
Requires-Dist: mypy ; extra == "dev"
|
23
|
+
Requires-Dist: ruff ; extra == "dev"
|
24
|
+
Requires-Dist: black ; extra == "dev"
|
25
|
+
Requires-Dist: mink[test] ; extra == "dev"
|
26
|
+
Requires-Dist: loop-rate-limiters >= 0.1.0 ; extra == "examples"
|
27
|
+
Requires-Dist: dm_control >= 1.0.20 ; extra == "examples"
|
28
|
+
Requires-Dist: absl-py ; extra == "test"
|
29
|
+
Requires-Dist: pytest ; extra == "test"
|
30
|
+
Requires-Dist: robot_descriptions >= 1.9.0 ; extra == "test"
|
31
|
+
Project-URL: Changelog, https://github.com/kevinzakka/mink/blob/main/CHANGELOG.md
|
32
|
+
Project-URL: Source, https://github.com/kevinzakka/mink
|
33
|
+
Project-URL: Tracker, https://github.com/kevinzakka/mink/issues
|
34
|
+
Provides-Extra: dev
|
35
|
+
Provides-Extra: examples
|
36
|
+
Provides-Extra: test
|
37
|
+
|
38
|
+
# mink
|
39
|
+
|
40
|
+
[](https://github.com/kevinzakka/mink/actions)
|
41
|
+
|
42
|
+
mink is a library for differential inverse kinematics in Python, based on the [MuJoCo](https://github.com/google-deepmind/mujoco) physics engine.
|
43
|
+
|
44
|
+
## Installation
|
45
|
+
|
46
|
+
```bash
|
47
|
+
pip install -e ".[examples]"
|
48
|
+
```
|
49
|
+
|
50
|
+
## Examples
|
51
|
+
|
52
|
+
* Arms: [UR5e](https://github.com/kevinzakka/mink/blob/main/examples/arm_ur5e_actuators.py), [iiwa14](https://github.com/kevinzakka/mink/blob/main/examples/arm_iiwa.py), [bimanual iiwa14](https://github.com/kevinzakka/mink/blob/main/examples/dual_iiwa.py)
|
53
|
+
* Humanoids: [Unitree G1](https://github.com/kevinzakka/mink/blob/main/examples/humanoid_g1.py)
|
54
|
+
* Quadrupeds: [Unitree Go1](https://github.com/kevinzakka/mink/blob/main/examples/quadruped_go1.py), [Boston Dynamics Spot](https://github.com/kevinzakka/mink/blob/main/examples/quadruped_spot.py)
|
55
|
+
* Hands: [Shadow Hand]()
|
56
|
+
|
57
|
+
Check out the [examples](https://github.com/kevinzakka/mink/blob/main/examples/) directory for more code.
|
58
|
+
|
59
|
+
## How can I help?
|
60
|
+
|
61
|
+
Install the library, use it and report any bugs in the [issue tracker](https://github.com/kevinzakka/mink/issues) if you find any. If you're feeling adventurous, you can also check out the contributing [guidelines](CONTRIBUTING.md) and submit a pull request.
|
62
|
+
|
63
|
+
## Acknowledgements
|
64
|
+
|
65
|
+
mink is a direct port of [pink](https://github.com/stephane-caron/pink) which uses [Pinocchio](https://github.com/stack-of-tasks/pinocchio) under the hood. Stéphane Caron, the original author of pink, is a role model for open-source software in robotics. This library would not have been possible without his work and assistance throughout this project.
|
66
|
+
|
67
|
+
mink also heavily adapts code from the following libraries:
|
68
|
+
|
69
|
+
* The lie algebra library that powers the transforms in mink is adapted from [jaxlie](https://github.com/brentyi/jaxlie).
|
70
|
+
* The collision avoidance constraint is adapted from [dm_robotics](https://github.com/google-deepmind/dm_robotics/tree/main/cpp/controllers)'s LSQP controller.
|
71
|
+
|