virtualmodelcontrol 1.0.0__tar.gz → 1.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.
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/CHANGELOG.md +35 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/PKG-INFO +1 -1
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/index.md +1 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/installation.md +2 -2
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/build-a-robot.md +3 -1
- virtualmodelcontrol-1.1.0/docs/tutorials/friction.md +285 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/__init__.py +2 -1
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/_version.py +2 -2
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/__init__.py +8 -1
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/output.py +35 -0
- virtualmodelcontrol-1.1.0/src/virtualmodelcontrol/identification/efficiency.py +95 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/__init__.py +2 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/efficiency.py +29 -9
- virtualmodelcontrol-1.1.0/src/virtualmodelcontrol/models/friction.py +79 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/builder.py +11 -4
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/problem.py +15 -2
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/adapt.py +14 -1
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/rollout.py +6 -1
- virtualmodelcontrol-1.1.0/tests/identification/test_fit_friction.py +125 -0
- virtualmodelcontrol-1.1.0/tests/models/test_static_friction.py +325 -0
- virtualmodelcontrol-1.0.0/src/virtualmodelcontrol/identification/efficiency.py +0 -45
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/.gitignore +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/CITATION.cff +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/LICENSE +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/README.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/benchmarks/tick.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_ext/video.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/create-lab.png +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/custom.css +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/favicon.svg +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/logo-light.svg +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/logo.svg +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_static/readme-hero.svg +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_templates/autosummary/module.rst +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/_templates/partials/toc.html +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/api/index.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/conventions.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/efficiency.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/finger.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/library.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/passivity.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/pcc.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/concepts/vmc.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/conf.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/development/changelog.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/development/contributing.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/development/roadmap.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/development/support.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/docs_setup.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/finger.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/hand.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/hanging-arm.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/soft-arm.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/turtle.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/examples/two-arms.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/_draw.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/bimanual.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/control_loop.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/energy_flow.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/finger.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/four_steps.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/hand.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/helyx.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/library_map.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/mechanism.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/params.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/pcc.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/turtle.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/schematics/ur5.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/scripts/readme_figure.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/troubleshooting.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/configurations.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/contact.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/coordinates-and-components.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/crawl.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/energy.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/estimation.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/extend.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/first-controller.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/fit.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/force.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/introduction.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/kinematics.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/mpc.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/optimize.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/outside.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/parameters.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/reach.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/real-time.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/run-logs.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/run-settings.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/stiffness.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/swaps.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/tuning.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/docs/tutorials/underactuated.md +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/pyproject.toml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/force.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/limits.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/position.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/scalar.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/seeking.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/adaptation/stiffness.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/compiler.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/controllers.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/coordinates.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/experiment.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/files.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/config/spec.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/blending.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/controller.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/projection.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/schedule.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/state.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/tank.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/underactuated.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/backends.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/params.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/registry.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/signals.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/space.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/symbolic.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/core/units.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/dynamics.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/balance.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/compliance.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/contact.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/imu.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/inversion.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/kalman.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/measurement.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/momentum.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/sensors.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/stiffness.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/estimation/velocity.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/hardware/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/hardware/profile.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/params.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/plateaus.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/steps.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/stiffness.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/identification/transmission.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/math.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/base.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/constrained.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/dissipation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/gated.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/inertance.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/locomotion.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/sources.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/components/storage.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/base.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/frames.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/geometry.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/joints.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/ops.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/coordinates/references.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/mechanisms/mechanism.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/actuation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/assembly.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/continuum/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/continuum/pcc.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/equations.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/function.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/joint_space.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/kinematic.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/kinematics.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/rigid/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/rigid/couplings.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/rigid/poe.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/rigid/spline.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/asktell.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/collocation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/equilibrium.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/horizon.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/mpc.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/nlp.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/result.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/search.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/shooting.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/solver.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/tank.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/terms.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/trajectory.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/variables.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/optimization/virtual.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/py.typed +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/bimanual.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/helyx.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/planar.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/turtle.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/robots/ur5.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/balance.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/model_plant.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/plant.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/replay.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/run.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/sim/runlog.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/system.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/testing.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/viz/__init__.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/viz/animation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/viz/draw.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/viz/style.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_fingertip.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_force.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_grasp.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_holding.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_loop.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_position.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_scalar.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_seeking.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_stiffness_tracking.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/adaptation/test_virtual_state.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/backend_helpers.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/config/test_config.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/conftest.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_blending.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_honesty.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_inputs.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_output.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_projection.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_schedule.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_state_layout.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_tank.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_underactuated.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_underactuated_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/control/test_vmc_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_backends.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_backends_torch.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_params.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_registry.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_signals.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_space.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/core/test_symbolic.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/adaptation.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/compliance.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/components.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/finger.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/hand.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/soft-arm.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/turtle.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/two-arms.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/configs/ur5-hand.yaml +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/derivatives.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/dynamics.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/efficiency.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/estimation.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/finger.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/fingertip.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/hand.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/heuristics.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/imu.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/kalman.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/mocap.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/optimization.json +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/optimization.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/pcc.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/transmission.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/turtle.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/underactuated.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/data/vmc.npz +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_compliance_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_contact.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_imu.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_inversion.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_kalman.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_kalman_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_kalman_unscented.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_mocap_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_momentum.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_sensors.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_unmeasured.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/estimation/test_velocity.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/hardware/test_profile.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/hardware/test_templates.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/helpers.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_efficiency_fit.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_fit_params.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_friction.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_steps.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_stiffness_fit.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/identification/test_transmission.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/lab_optimization.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_components.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_components_golden.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_contact.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_coordinates.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_distances.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_frames.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_friction.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_gated.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_mechanism.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_more_components.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_pair_contact.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_phase_spring.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/mechanisms/test_virtual_model.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_actuation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_assembly.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_contact_map.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_efficiency.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_equations.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_floating.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_floating_base.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_function.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_kinematics.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_pcc.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_poe.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_rail.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/models/test_underactuated.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_asktell.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_collocation.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_equilibrium.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_horizon.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_lab.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_mpc.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_periodic.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_plant.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_problem.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_search.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_shooting.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_solvers.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_structure.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_swap.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_tank.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_terms.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_variables.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/optimization/test_virtual.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_adapt.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_bimanual.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_crawler.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_hand.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_helyx.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_parametric.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_planar.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_turtle.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/robots/test_ur5.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_balance.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_record.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_replay.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_rollout.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_run.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_runlog.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/sim/test_wallclock.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/small_plan.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/soft_arm_plan.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_benchmark.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_compiler.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_docs.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_dynamics.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_import.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_math.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_readme.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/test_testing.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/underactuated_lab.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/viz/test_animate.py +0 -0
- {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/tests/viz/test_viz.py +0 -0
|
@@ -4,6 +4,41 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
5
|
[Semantic Versioning](https://semver.org/) (0.x: the API may change between minor versions).
|
|
6
6
|
|
|
7
|
+
## [1.1.0] - 2026-10-09
|
|
8
|
+
|
|
9
|
+
Static friction of the motors: a model of it, a compensation for it, its identification and a
|
|
10
|
+
tutorial, all off unless asked for. Nothing that worked before changes.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Static friction of the motors, off by default. `StaticFriction(breakaway, kinetic, width)`
|
|
15
|
+
[N·m] is the torque that friction takes from a motor as a smooth function of the torque applied
|
|
16
|
+
to it: all of it below the breakaway torque F (the motor is stuck), the kinetic torque Fc with
|
|
17
|
+
the sign of the command past it (Fc = 0: static friction gone once it moves; Fc = F: it stays),
|
|
18
|
+
smooth (C^∞) over `width`, so solvers differentiate it. It depends on the torque only, not on
|
|
19
|
+
the speed. `Efficiency(c1, ..., friction=StaticFriction(...))` takes it before the polynomial, so
|
|
20
|
+
every transmission carries it (`Direct`, `Underactuated`, `TendonTransmission`, stacked ones, and
|
|
21
|
+
configuration files), and the simulator, `compile_dynamics`, `Collocation`, `Shooting`, `MPC`, the
|
|
22
|
+
Kalman filter and the force law all have it. Its Params are `friction.breakaway`,
|
|
23
|
+
`friction.kinetic` and `friction.width`; with F = Fc = 0, the default, nothing changes. Not passive
|
|
24
|
+
by construction: when a command brakes the motion it can create up to F |θ̇| of power, which the
|
|
25
|
+
tutorial states and measures.
|
|
26
|
+
- `control.StaticFrictionCompensation(kinetic, width, fraction)` (and `.of(friction, fraction)`), an
|
|
27
|
+
output stage that adds the kinetic friction torque in the direction of the command, smooth in the
|
|
28
|
+
command. Against a `StaticFriction(F, Fc)` it delivers the command once the motor moves and
|
|
29
|
+
narrows the dead band from F to F − Fc. Nothing turns it on but you: no template or controller
|
|
30
|
+
has it by default. It has a `symbolic` form, so `Problem(system, output=[...])` and
|
|
31
|
+
`sim.rollout(..., output=[...])` apply it in a plan as `VMCController(output=)` does in a run
|
|
32
|
+
(`Problem` now raises for an output stage that has no `symbolic` form).
|
|
33
|
+
- Identification of the friction: its Params are the robot's, so `identification.fit_params` fits
|
|
34
|
+
them, with the stiffness and damping, to a run in which the command rises slowly from rest;
|
|
35
|
+
`fit_efficiency(commanded, delivered, friction=True, width=)` fits the efficiency and the friction
|
|
36
|
+
to static torques (per motor or `shared`), by a grid and a refinement over the breakaway and the
|
|
37
|
+
kinetic torque.
|
|
38
|
+
- `robots.adapt.finger_friction()` and `hand_friction()`: the lab's friction values of the finger
|
|
39
|
+
(0.20 N·m) and the hand (0.10 N·m) as a `StaticFriction`, to ask for.
|
|
40
|
+
- Docs: the tutorial "Static friction of the motors".
|
|
41
|
+
|
|
7
42
|
## [1.0.0] - 2026-10-07
|
|
8
43
|
|
|
9
44
|
The first stable release. It also carries the work meant for 0.6.0 (planning with virtual states,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: virtualmodelcontrol
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Virtual Model Control: robots and controllers as mechanisms of springs, dampers and inertances, compiled with CasADi.
|
|
5
5
|
Project-URL: Repository, https://github.com/vigno0405/VirtualModelControl
|
|
6
6
|
Project-URL: Documentation, https://vigno0405.github.io/VirtualModelControl/
|
|
@@ -120,10 +120,10 @@ pip install -e .
|
|
|
120
120
|
An experiment should always run the same code. Pin the version, and move the pin on purpose:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
pip install "virtualmodelcontrol==1.
|
|
123
|
+
pip install "virtualmodelcontrol==1.1.0"
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
In a `requirements.txt` file, write `virtualmodelcontrol==1.
|
|
126
|
+
In a `requirements.txt` file, write `virtualmodelcontrol==1.1.0`. In a conda `environment.yml`,
|
|
127
127
|
list it under `pip:`. `pip show virtualmodelcontrol` tells you which version you have, and the
|
|
128
128
|
[changelog](development/changelog.md) what changed between versions.
|
|
129
129
|
|
|
@@ -54,7 +54,9 @@ np.abs(a - b).max() # [m], the two descriptions agree
|
|
|
54
54
|
|
|
55
55
|
A robot is a mechanism around its model. Its physical components are point masses at sites,
|
|
56
56
|
gravity, and here a little viscous friction in the joints. The simulator needs all of them; the
|
|
57
|
-
controller needs only the point masses, for `GravityCompensation`.
|
|
57
|
+
controller needs only the point masses, for `GravityCompensation`. The static friction of the
|
|
58
|
+
motors, which holds a joint until the command passes a breakaway torque, is a part of the
|
|
59
|
+
transmission: see [static friction of the motors](friction.md).
|
|
58
60
|
|
|
59
61
|
```{code-cell} python
|
|
60
62
|
arm = vmc.Mechanism("arm", model=chain)
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
---
|
|
2
|
+
file_format: mystnb
|
|
3
|
+
kernelspec:
|
|
4
|
+
name: python3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Static friction of the motors
|
|
8
|
+
|
|
9
|
+
A motor does not deliver a small torque: friction holds it until the command passes a
|
|
10
|
+
breakaway value. A virtual spring that pulls with less than that does not move the joint, and
|
|
11
|
+
the robot stops short of its goal. In this tutorial we model that friction as a function of
|
|
12
|
+
the torque we apply, see what it does to a controller, compensate it, identify it from data,
|
|
13
|
+
and plan with it. Everything here is off unless we ask for it.
|
|
14
|
+
|
|
15
|
+
```{code-cell} python
|
|
16
|
+
:tags: [remove-cell]
|
|
17
|
+
import docs_setup
|
|
18
|
+
from myst_nb import glue
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## The model
|
|
22
|
+
|
|
23
|
+
`StaticFriction(breakaway, kinetic, width)` is the torque $\tau_f$ that friction takes from a
|
|
24
|
+
motor, as a function of the torque $u$ we apply to it, in N·m. Below the breakaway torque $F$
|
|
25
|
+
the motor is stuck: friction takes all of $u$. Past it the motor moves, and friction takes the
|
|
26
|
+
kinetic torque $F_c$, with the sign of $u$. With $F_c = 0$ the static friction is gone once the
|
|
27
|
+
motor moves, and with $F_c = F$ it stays. Around $|u| = F$ the change is smooth over `width`,
|
|
28
|
+
and the whole map is smooth, so a solver can differentiate it. It depends on the torque only,
|
|
29
|
+
not on the speed.
|
|
30
|
+
|
|
31
|
+
```{code-cell} python
|
|
32
|
+
import numpy as np
|
|
33
|
+
import matplotlib.pyplot as plt
|
|
34
|
+
import virtualmodelcontrol as vmc
|
|
35
|
+
|
|
36
|
+
F = 0.2 # breakaway torque [N·m]
|
|
37
|
+
u = np.linspace(-0.6, 0.6, 601) # commanded torque [N·m]
|
|
38
|
+
|
|
39
|
+
fig, (top, bottom) = plt.subplots(2, 1, sharex=True)
|
|
40
|
+
for Fc, style in ((0.0, "-"), (F, "--")):
|
|
41
|
+
friction = vmc.StaticFriction(F, Fc, 0.01)
|
|
42
|
+
top.plot(u, friction(u), style, label=f"$F_c$ = {Fc}")
|
|
43
|
+
bottom.plot(u, u - friction(u), style)
|
|
44
|
+
top.set_ylabel(r"friction $\tau_f$")
|
|
45
|
+
top.set_ylim(-0.3, 0.6) # room for the legend
|
|
46
|
+
bottom.set_ylabel(r"delivered $u - \tau_f$")
|
|
47
|
+
bottom.set_xlabel(r"commanded torque $u$ [N$\cdot$m]")
|
|
48
|
+
top.legend(loc="upper left", fontsize=18);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```{code-cell} python
|
|
52
|
+
:tags: [remove-cell]
|
|
53
|
+
gone, stays = vmc.StaticFriction(F, 0.0, 0.01), vmc.StaticFriction(F, F, 0.01)
|
|
54
|
+
delivered = u - gone(u)
|
|
55
|
+
assert abs(delivered[abs(u) < 0.15]).max() < 2e-3 # a dead band
|
|
56
|
+
assert abs(delivered[abs(u) > 0.4] - u[abs(u) > 0.4]).max() < 2e-3
|
|
57
|
+
assert abs((u - stays(u))[u > 0.4] - (u[u > 0.4] - F)).max() < 2e-3
|
|
58
|
+
assert not vmc.StaticFriction()(u).any() # no friction by default
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The motor delivers nothing in the dead band, and then the command less $F_c$. The default is
|
|
62
|
+
$F = F_c = 0$, which is no friction at all. The three numbers are `design` Params, to tune or to
|
|
63
|
+
identify.
|
|
64
|
+
|
|
65
|
+
## In a robot
|
|
66
|
+
|
|
67
|
+
Friction belongs to the motor, so it goes with the robot's transmission: its `Efficiency` takes
|
|
68
|
+
a `friction`. Here is a joint with an inertia and a damper, and a virtual spring of
|
|
69
|
+
1 N·m/rad that pulls it to 1 rad:
|
|
70
|
+
|
|
71
|
+
```{code-cell} python
|
|
72
|
+
from virtualmodelcontrol.models import Direct, Efficiency, JointSpace
|
|
73
|
+
|
|
74
|
+
def system_of(friction=None, stiffness=1.0):
|
|
75
|
+
efficiency = Efficiency(1.0, friction=friction)
|
|
76
|
+
robot = vmc.Mechanism("robot", model=JointSpace(1, unit="rad"),
|
|
77
|
+
actuation=Direct(efficiency))
|
|
78
|
+
q = robot.joint(0)
|
|
79
|
+
robot.add("inertia", vmc.Inertance(q, 1.0)) # [kg·m²]
|
|
80
|
+
robot.add("damper", vmc.LinearDamper(q, 1.5)) # [N·m·s/rad]
|
|
81
|
+
ctrl = vmc.Mechanism("ctrl")
|
|
82
|
+
goal = vmc.Ref("goal", 1, [1.0]) # [rad]
|
|
83
|
+
ctrl.add("spring", vmc.LinearSpring(q - goal, stiffness))
|
|
84
|
+
ctrl.add("damper", vmc.LinearDamper(q, 1.0))
|
|
85
|
+
return vmc.VirtualMechanismSystem(robot, ctrl)
|
|
86
|
+
|
|
87
|
+
def run(system, output=(), T=30.0):
|
|
88
|
+
plant = vmc.sim.ModelPlant(system.robot)
|
|
89
|
+
controller = vmc.VMCController(vmc.compile(system), output=list(output))
|
|
90
|
+
clock = vmc.sim.SimClock(dt=1 / 100)
|
|
91
|
+
return vmc.sim.run(plant, controller, clock, T=T).arrays()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
We run it without friction, and with friction that stays at 0.3 N·m once the motor moves:
|
|
95
|
+
|
|
96
|
+
```{code-cell} python
|
|
97
|
+
kept = vmc.StaticFriction(0.3, 0.3, 0.005)
|
|
98
|
+
free, held = run(system_of()), run(system_of(kept))
|
|
99
|
+
|
|
100
|
+
fig, ax = plt.subplots()
|
|
101
|
+
ax.plot(free["t"], free["q"][:, 0], label="no friction")
|
|
102
|
+
ax.plot(held["t"], held["q"][:, 0], "--", label=r"friction 0.3 N$\cdot$m")
|
|
103
|
+
ax.set_xlabel("time [s]")
|
|
104
|
+
ax.set_ylabel("angle [rad]")
|
|
105
|
+
ax.legend(loc="lower right", fontsize=18);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```{code-cell} python
|
|
109
|
+
:tags: [remove-cell]
|
|
110
|
+
short = 1.0 - held["q"][-1, 0]
|
|
111
|
+
assert abs(1.0 - free["q"][-1, 0]) < 1e-3
|
|
112
|
+
assert abs(short - 0.3) < 0.015
|
|
113
|
+
glue("short", float(short), display=False)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The joint without friction arrives. With it, the joint stops {glue:text}`short:.2f` rad short:
|
|
117
|
+
the spring pulls with $K e$, and the motor is stuck while that is below the breakaway torque, so
|
|
118
|
+
it stops at $e = F / K$. A stiffer spring narrows the gap, and a spring that is too soft for the
|
|
119
|
+
friction does not move the joint at all.
|
|
120
|
+
|
|
121
|
+
## Compensation
|
|
122
|
+
|
|
123
|
+
The compensation adds the friction to the command, in the direction of the command:
|
|
124
|
+
$u + F_c u / \sqrt{u^2 + w^2}$, smooth in $u$. `StaticFrictionCompensation.of(friction)` takes
|
|
125
|
+
$F_c$ and the width from a `StaticFriction`, and an optional `fraction` of it. It is an output
|
|
126
|
+
stage, applied after the controller's law like the other ones, and nothing turns it on but us:
|
|
127
|
+
|
|
128
|
+
```{code-cell} python
|
|
129
|
+
from virtualmodelcontrol.control import StaticFrictionCompensation
|
|
130
|
+
|
|
131
|
+
full = StaticFrictionCompensation.of(kept)
|
|
132
|
+
half = StaticFrictionCompensation.of(kept, fraction=0.5)
|
|
133
|
+
stages = {"none": [], "half": [half], "full": [full]}
|
|
134
|
+
errors = {name: 1.0 - run(system_of(kept), stage)["q"][-1, 0]
|
|
135
|
+
for name, stage in stages.items()}
|
|
136
|
+
errors
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```{code-cell} python
|
|
140
|
+
:tags: [remove-cell]
|
|
141
|
+
assert abs(errors["none"] - 0.3) < 0.015
|
|
142
|
+
assert abs(errors["half"] - 0.15) < 0.02
|
|
143
|
+
assert abs(errors["full"]) < 0.02
|
|
144
|
+
glue("full", float(errors["full"]), display=False)
|
|
145
|
+
glue("half", float(errors["half"]), display=False)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Compensating all of the friction leaves {glue:text}`full:.3f` rad, and half of it leaves
|
|
149
|
+
{glue:text}`half:.2f` rad. The compensation is exact only for the kinetic torque: if the
|
|
150
|
+
breakaway torque $F$ is larger than $F_c$, a band of $F - F_c$ is left, because a command that
|
|
151
|
+
is not enough to break away is not enough with the compensation either.
|
|
152
|
+
|
|
153
|
+
The compensation adds energy: it pushes with $F_c$ in the direction of the command, which is
|
|
154
|
+
up to $F_c |\dot\theta|$ of power. The friction map has its own limit. It depends on the torque
|
|
155
|
+
alone, so it does not know which way the motor moves. When a command brakes the motion, the map
|
|
156
|
+
takes from the braking torque and can create power, up to $F |\dot\theta|$:
|
|
157
|
+
|
|
158
|
+
```{code-cell} python
|
|
159
|
+
friction = vmc.StaticFriction(F, 0.0, 0.01)
|
|
160
|
+
rate = np.linspace(-3, 3, 61) # [rad/s]
|
|
161
|
+
power = friction(u)[:, None] * rate[None, :] # friction torque times rate
|
|
162
|
+
created = -power.min() # [W]
|
|
163
|
+
created, F * abs(rate).max()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```{code-cell} python
|
|
167
|
+
:tags: [remove-cell]
|
|
168
|
+
assert 0 < created <= F * abs(rate).max()
|
|
169
|
+
agree = (u[:, None] * rate[None, :]) >= 0
|
|
170
|
+
assert (power[agree] >= -1e-15).all() # and it only dissipates when they agree
|
|
171
|
+
glue("created", float(created), display=False)
|
|
172
|
+
glue("bound", float(F * abs(rate).max()), display=False)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
So the friction is dissipative when the command and the motion agree, and otherwise creates at
|
|
176
|
+
most {glue:text}`created:.2f` W here, at 3 rad/s, under the bound $F |\dot\theta|$ of
|
|
177
|
+
{glue:text}`bound:.1f` W. A passivity argument that counts on the motors' friction can count
|
|
178
|
+
on no more than that.
|
|
179
|
+
|
|
180
|
+
## Identification
|
|
181
|
+
|
|
182
|
+
The three numbers are Params of the robot, so `fit_params` finds them from a run, with the
|
|
183
|
+
stiffness and damping. The command has to rise slowly from rest, a ramp, or the breakaway torque
|
|
184
|
+
does not show: after a step the motor has broken away at the first sample. We simulate a robot
|
|
185
|
+
with friction under a ramp of torque, up and down, and fit from a rough guess:
|
|
186
|
+
|
|
187
|
+
```{code-cell} python
|
|
188
|
+
from virtualmodelcontrol.identification import fit_params
|
|
189
|
+
|
|
190
|
+
dt = 1 / 330
|
|
191
|
+
rise = np.arange(0.0, 0.8, 0.5 * dt) # [N·m], 0.5 N·m/s
|
|
192
|
+
command = np.concatenate([np.zeros(150), rise, rise[::-1], np.zeros(150)])
|
|
193
|
+
|
|
194
|
+
truth = vmc.StaticFriction(0.3, 0.1, 0.002)
|
|
195
|
+
robot = system_of(truth).robot
|
|
196
|
+
robot.add("spring", vmc.LinearSpring(robot.joint(0), 40.0))
|
|
197
|
+
none = vmc.VirtualMechanismSystem(robot, vmc.Mechanism("none"))
|
|
198
|
+
log = vmc.sim.rollout(none, [0.0], len(command) * dt, dt, max_step=dt,
|
|
199
|
+
u=command[:, None])
|
|
200
|
+
|
|
201
|
+
guess = system_of(vmc.StaticFriction(0.2, 0.05, 0.002)).robot
|
|
202
|
+
guess.add("spring", vmc.LinearSpring(guess.joint(0), 30.0))
|
|
203
|
+
names = ["efficiency.friction.breakaway", "efficiency.friction.kinetic",
|
|
204
|
+
"spring.stiffness"]
|
|
205
|
+
fit = fit_params(guess, names, [log], smoothing=11)
|
|
206
|
+
for name in names:
|
|
207
|
+
print(name, fit.values[name].ravel().round(3))
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```{code-cell} python
|
|
211
|
+
:tags: [remove-cell]
|
|
212
|
+
found = {name: float(fit.values[name].ravel()[0]) for name in names}
|
|
213
|
+
assert abs(found[names[0]] - 0.3) < 0.01 and abs(found[names[1]] - 0.1) < 0.01
|
|
214
|
+
assert abs(found[names[2]] - 40.0) < 0.5
|
|
215
|
+
glue("breakaway", float(found[names[0]]), display=False)
|
|
216
|
+
glue("kinetic", float(found[names[1]]), display=False)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The fit gives {glue:text}`breakaway:.2f` N·m for the breakaway and {glue:text}`kinetic:.2f` N·m
|
|
220
|
+
for the kinetic torque, against 0.30 and 0.10 in the simulated robot. The fit is local: it
|
|
221
|
+
starts from the robot's values, and a start far from the truth can end in a wrong one, so the
|
|
222
|
+
first command at which the motor moved is a good guess for the breakaway torque. If we have the delivered torque of each motor at static commands, from a load cell,
|
|
223
|
+
`fit_efficiency(commanded, delivered, friction=True)` fits the efficiency and the friction
|
|
224
|
+
together; the points must cover the dead band, on both sides.
|
|
225
|
+
|
|
226
|
+
```{code-cell} python
|
|
227
|
+
from virtualmodelcontrol.identification import fit_efficiency
|
|
228
|
+
|
|
229
|
+
commanded = np.linspace(-1.0, 1.0, 81)[:, None] * np.ones((1, 2)) # [N·m]
|
|
230
|
+
dead = vmc.StaticFriction([0.25, 0.15], 0.05) # breakaway of each motor
|
|
231
|
+
motors = Efficiency((0.8, 0.6), friction=dead)
|
|
232
|
+
efficiency = fit_efficiency(commanded, motors(commanded), friction=True,
|
|
233
|
+
width=0.01)
|
|
234
|
+
efficiency.friction.params["breakaway"].value.round(2)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```{code-cell} python
|
|
238
|
+
:tags: [remove-cell]
|
|
239
|
+
assert abs(efficiency.friction.params["breakaway"].value - [0.25, 0.15]).max() < 0.01
|
|
240
|
+
assert abs(efficiency.params["c1"].value - [0.8, 0.6]).max() < 0.01
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Planning with it
|
|
244
|
+
|
|
245
|
+
The friction is in the robot's dynamics, so a plan, an optimization and an MPC see it. A
|
|
246
|
+
compensation joins them through `Problem(output=...)`, which applies the stage to the
|
|
247
|
+
controller's command as `VMCController(output=...)` does in a simulation:
|
|
248
|
+
|
|
249
|
+
```{code-cell} python
|
|
250
|
+
from virtualmodelcontrol import optimization as opt
|
|
251
|
+
|
|
252
|
+
kept = vmc.StaticFriction(0.3, 0.3, 0.02)
|
|
253
|
+
stage = StaticFrictionCompensation.of(kept, fraction=0.7)
|
|
254
|
+
system = system_of(kept)
|
|
255
|
+
|
|
256
|
+
problem = opt.Problem(system, output=[stage])
|
|
257
|
+
problem.add(opt.Shooting([0.0], 3.0, 11, v0=[0.0], substeps=5))
|
|
258
|
+
plan = problem.solve()
|
|
259
|
+
sim = vmc.sim.rollout(system, [0.0], 3.0, 0.06, v0=[0.0], max_step=0.06,
|
|
260
|
+
output=[stage])
|
|
261
|
+
gap = abs(plan.q[:-1] - sim["q"][::5]).max()
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```{code-cell} python
|
|
265
|
+
:tags: [remove-cell]
|
|
266
|
+
assert plan.converged and gap < 1e-8
|
|
267
|
+
glue("gap", float(gap), display=False)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The plan follows the simulation within {glue:text}`gap:.0e` rad, as without friction: it is the
|
|
271
|
+
same closed loop, with the motor's friction and the compensation in it. `MPC(problem)` takes the
|
|
272
|
+
same problem, so it plans with friction too.
|
|
273
|
+
|
|
274
|
+
## Good to know
|
|
275
|
+
|
|
276
|
+
- **Off by default.** `Efficiency(friction=None)` and `StaticFriction()` with no torques are the
|
|
277
|
+
robots as they were, and no template turns the compensation on. The finger's and the hand's
|
|
278
|
+
lab values, `adapt.finger_friction()` and `adapt.hand_friction()`, are there to ask for.
|
|
279
|
+
- **The width** is the smoothing of the corner at the breakaway torque, in N·m. A smaller one
|
|
280
|
+
is closer to a real motor and harder for a solver: a plan from rest may need a warm start.
|
|
281
|
+
- **No memory.** The map depends on the torque we apply and not on how the motor got there, so
|
|
282
|
+
it has no hysteresis: a real motor that has stopped holds up to $F$ against the net torque,
|
|
283
|
+
load included.
|
|
284
|
+
- **Where it acts.** The friction takes its torque from the command before the efficiency
|
|
285
|
+
polynomial, in the units of the command.
|
|
@@ -55,7 +55,7 @@ from .mechanisms import (
|
|
|
55
55
|
TanhSpring,
|
|
56
56
|
Time,
|
|
57
57
|
)
|
|
58
|
-
from .models import Efficiency, Kinematics
|
|
58
|
+
from .models import Efficiency, Kinematics, StaticFriction
|
|
59
59
|
from .system import VirtualMechanismSystem
|
|
60
60
|
|
|
61
61
|
try:
|
|
@@ -128,6 +128,7 @@ __all__ = [
|
|
|
128
128
|
"SpeedRegulator",
|
|
129
129
|
"SphereDistance",
|
|
130
130
|
"Stack",
|
|
131
|
+
"StaticFriction",
|
|
131
132
|
"Sum",
|
|
132
133
|
"TanhDamper",
|
|
133
134
|
"TanhSpring",
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.
|
|
22
|
-
__version_tuple__ = version_tuple = (1,
|
|
21
|
+
__version__ = version = '1.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 1, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
{virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/__init__.py
RENAMED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from .blending import SwapController, blend_weight
|
|
4
4
|
from .controller import VMCController
|
|
5
|
-
from .output import
|
|
5
|
+
from .output import (
|
|
6
|
+
FrictionCompensation,
|
|
7
|
+
Pretension,
|
|
8
|
+
StaticFrictionCompensation,
|
|
9
|
+
TorqueLimit,
|
|
10
|
+
TorqueOffset,
|
|
11
|
+
)
|
|
6
12
|
from .projection import project_psd
|
|
7
13
|
from .schedule import Schedule, ScheduledController
|
|
8
14
|
from .state import StateController
|
|
@@ -14,6 +20,7 @@ __all__ = [
|
|
|
14
20
|
"Schedule",
|
|
15
21
|
"ScheduledController",
|
|
16
22
|
"StateController",
|
|
23
|
+
"StaticFrictionCompensation",
|
|
17
24
|
"SwapController",
|
|
18
25
|
"Tank",
|
|
19
26
|
"TorqueLimit",
|
{virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/control/output.py
RENAMED
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
import casadi as ca
|
|
12
13
|
import numpy as np
|
|
13
14
|
from numpy.typing import ArrayLike
|
|
14
15
|
|
|
@@ -33,6 +34,40 @@ class FrictionCompensation:
|
|
|
33
34
|
return u + np.asarray(self.max_torque) * np.exp(-((v / self.velocity) ** 2)) * np.sign(u)
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
@register("output", "static_friction_compensation")
|
|
38
|
+
@dataclass
|
|
39
|
+
class StaticFrictionCompensation:
|
|
40
|
+
"""The kinetic friction torque added in the direction of the command, smooth in the command:
|
|
41
|
+
u + fraction · Fc · u / √(u² + w²).
|
|
42
|
+
|
|
43
|
+
``kinetic`` Fc [N·m] (scalar or per motor), ``width`` w [N·m], ``fraction`` of Fc that is
|
|
44
|
+
compensated. Against an actuator with ``StaticFriction(F, Fc)`` it delivers the command once
|
|
45
|
+
the actuator moves and narrows the dead band from F to F − Fc. It adds energy (up to Fc |θ̇|),
|
|
46
|
+
so nothing turns it on but you. ``symbolic`` is the same map for a plan (``Problem(output=)``).
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
kinetic: ArrayLike
|
|
50
|
+
width: float = 0.01
|
|
51
|
+
fraction: float = 1.0
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def of(cls, friction: Any, fraction: float = 1.0) -> StaticFrictionCompensation:
|
|
55
|
+
"""The compensation of a ``StaticFriction``, at its current kinetic torque and width."""
|
|
56
|
+
return cls(
|
|
57
|
+
friction.params["kinetic"].value, float(friction.params["width"].value), fraction
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def __call__(self, u: np.ndarray, meas: Signals) -> np.ndarray:
|
|
61
|
+
"""Add the compensation."""
|
|
62
|
+
a = np.sqrt(u * u + self.width**2)
|
|
63
|
+
return u + self.fraction * np.asarray(self.kinetic) * u / a
|
|
64
|
+
|
|
65
|
+
def symbolic(self, u: Any) -> Any:
|
|
66
|
+
"""The same map for CasADi expressions."""
|
|
67
|
+
a = ca.sqrt(u * u + self.width**2)
|
|
68
|
+
return u + self.fraction * ca.DM(np.asarray(self.kinetic, dtype=float)) * u / a
|
|
69
|
+
|
|
70
|
+
|
|
36
71
|
@register("output", "pretension")
|
|
37
72
|
@dataclass
|
|
38
73
|
class Pretension:
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""A transmission efficiency fitted to static measurements, by least squares through the origin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import ArrayLike
|
|
7
|
+
|
|
8
|
+
from ..models.efficiency import Efficiency
|
|
9
|
+
from ..models.friction import StaticFriction, friction_torque
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def fit_efficiency(
|
|
13
|
+
commanded: ArrayLike,
|
|
14
|
+
measured: ArrayLike,
|
|
15
|
+
degree: int = 1,
|
|
16
|
+
*,
|
|
17
|
+
weights: ArrayLike | None = None,
|
|
18
|
+
shared: bool = False,
|
|
19
|
+
friction: bool = False,
|
|
20
|
+
width: float = 0.01,
|
|
21
|
+
) -> Efficiency:
|
|
22
|
+
"""The polynomial efficiency, of ``degree``, that best explains static measurements.
|
|
23
|
+
|
|
24
|
+
``commanded`` [N·m] has one row per static point and one column per motor. Without
|
|
25
|
+
``weights``, ``measured`` holds each motor's delivered torque, laid out the same way. With
|
|
26
|
+
``weights`` (same layout), it holds one value per point, Σⱼ wⱼ τⱼ: a force along a direction,
|
|
27
|
+
say, with wⱼ from the Jacobian. Each motor gets its own coefficients, or one set for all with
|
|
28
|
+
``shared``. No constant term: no command, no torque.
|
|
29
|
+
|
|
30
|
+
With ``friction``, the actuator's static friction is fitted too, the breakaway and the kinetic
|
|
31
|
+
torque of a ``StaticFriction`` (``width`` [N·m] is its smoothing, which static points do not
|
|
32
|
+
determine): the points must then span the dead band, commands from well below to well above
|
|
33
|
+
the breakaway torque, in both directions. It needs each motor's delivered torque: no
|
|
34
|
+
``weights``.
|
|
35
|
+
"""
|
|
36
|
+
u = np.asarray(commanded, dtype=float)
|
|
37
|
+
u = u.reshape(len(u), -1)
|
|
38
|
+
if friction:
|
|
39
|
+
if weights is not None:
|
|
40
|
+
raise ValueError("friction needs the delivered torque of each motor: leave out weights")
|
|
41
|
+
return _with_friction(
|
|
42
|
+
u, np.asarray(measured, dtype=float).reshape(u.shape), degree, shared, width
|
|
43
|
+
)
|
|
44
|
+
powers = np.stack([u**k for k in range(1, degree + 1)], axis=-1) # point, motor, power
|
|
45
|
+
if weights is None:
|
|
46
|
+
tau = np.asarray(measured, dtype=float).reshape(u.shape)
|
|
47
|
+
if shared:
|
|
48
|
+
return Efficiency(*_least_squares(powers.reshape(-1, degree), tau.ravel()))
|
|
49
|
+
c = np.array([_least_squares(powers[:, j], tau[:, j]) for j in range(u.shape[1])])
|
|
50
|
+
return Efficiency(*c.T)
|
|
51
|
+
w = np.asarray(weights, dtype=float).reshape(u.shape)
|
|
52
|
+
y = np.asarray(measured, dtype=float).ravel()
|
|
53
|
+
phi = w[:, :, None] * powers
|
|
54
|
+
if shared:
|
|
55
|
+
return Efficiency(*_least_squares(phi.sum(axis=1), y))
|
|
56
|
+
return Efficiency(*_least_squares(phi.reshape(len(u), -1), y).reshape(u.shape[1], degree).T)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _least_squares(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
60
|
+
return np.linalg.lstsq(a, b, rcond=None)[0]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _with_friction(
|
|
64
|
+
u: np.ndarray, tau: np.ndarray, degree: int, shared: bool, width: float
|
|
65
|
+
) -> Efficiency:
|
|
66
|
+
"""The polynomial and the friction that best explain delivered torques, motor by motor or one
|
|
67
|
+
set for all. For given friction the polynomial is linear, so only the breakaway and the
|
|
68
|
+
kinetic torque are searched: on a grid, then refined."""
|
|
69
|
+
from scipy.optimize import minimize
|
|
70
|
+
|
|
71
|
+
def fit(x: np.ndarray, y: np.ndarray) -> tuple[np.ndarray, float, float]:
|
|
72
|
+
def residual(f: np.ndarray) -> tuple[float, np.ndarray]:
|
|
73
|
+
net = x - friction_torque(x, abs(f[0]), abs(f[1]), width)
|
|
74
|
+
powers = np.stack([net**k for k in range(1, degree + 1)], axis=1)
|
|
75
|
+
c = _least_squares(powers, y)
|
|
76
|
+
return float(((powers @ c - y) ** 2).sum()), c
|
|
77
|
+
|
|
78
|
+
top = np.abs(x).max()
|
|
79
|
+
grid = [(F, Fc) for F in np.linspace(0.0, 0.95 * top, 40) for Fc in np.linspace(0.0, F, 6)]
|
|
80
|
+
best = min(grid, key=lambda f: residual(np.array(f))[0])
|
|
81
|
+
f = minimize(
|
|
82
|
+
lambda f: residual(f)[0],
|
|
83
|
+
np.array(best),
|
|
84
|
+
method="Nelder-Mead",
|
|
85
|
+
options={"xatol": 1e-7, "fatol": 1e-14},
|
|
86
|
+
).x
|
|
87
|
+
return residual(f)[1], abs(float(f[0])), abs(float(f[1]))
|
|
88
|
+
|
|
89
|
+
if shared:
|
|
90
|
+
c, F, Fc = fit(u.T.ravel(), tau.T.ravel()) # the points of every motor, one after another
|
|
91
|
+
return Efficiency(*c, friction=StaticFriction(F, Fc, width))
|
|
92
|
+
fits = [fit(u[:, j], tau[:, j]) for j in range(u.shape[1])]
|
|
93
|
+
c = np.array([f[0] for f in fits])
|
|
94
|
+
friction = StaticFriction([f[1] for f in fits], [f[2] for f in fits], width)
|
|
95
|
+
return Efficiency(*c.T, friction=friction)
|
{virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/__init__.py
RENAMED
|
@@ -5,6 +5,7 @@ from .assembly import Assembly, StackedActuation
|
|
|
5
5
|
from .continuum import PCC, segment_frame
|
|
6
6
|
from .efficiency import Efficiency
|
|
7
7
|
from .equations import Equations
|
|
8
|
+
from .friction import StaticFriction
|
|
8
9
|
from .function import FunctionModel
|
|
9
10
|
from .joint_space import JointSpace
|
|
10
11
|
from .kinematic import KinematicModel, evaluate_frame, from_dict
|
|
@@ -26,6 +27,7 @@ __all__ = [
|
|
|
26
27
|
"Passive",
|
|
27
28
|
"SerialChain",
|
|
28
29
|
"StackedActuation",
|
|
30
|
+
"StaticFriction",
|
|
29
31
|
"TendonTransmission",
|
|
30
32
|
"Underactuated",
|
|
31
33
|
"evaluate_frame",
|
{virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.1.0}/src/virtualmodelcontrol/models/efficiency.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"""Transmission efficiency: the motor torque a robot receives, a polynomial of the commanded one
|
|
1
|
+
"""Transmission efficiency: the motor torque a robot receives, a polynomial of the commanded one,
|
|
2
|
+
after the friction of the actuator."""
|
|
2
3
|
|
|
3
4
|
from __future__ import annotations
|
|
4
5
|
|
|
@@ -10,6 +11,7 @@ from numpy.typing import ArrayLike
|
|
|
10
11
|
from ..core.params import ParamSet, as_param
|
|
11
12
|
from ..core.registry import register
|
|
12
13
|
from ..core.units import NM
|
|
14
|
+
from .friction import StaticFriction, as_friction
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
@register("efficiency", "polynomial")
|
|
@@ -20,39 +22,57 @@ class Efficiency:
|
|
|
20
22
|
``Efficiency(c1, c2, ...)``: each coefficient is one value for every motor or one per motor.
|
|
21
23
|
``Efficiency(1.0)``, the default of every transmission, delivers the commanded torque. The
|
|
22
24
|
coefficients are ``design`` Params ``c1`` … ``cn``, to tune or to identify.
|
|
25
|
+
|
|
26
|
+
``friction`` (a ``StaticFriction``, none by default) is the actuator's static friction: the
|
|
27
|
+
polynomial then takes the torque that friction leaves, with u − τ_f(u) in place of u. Its
|
|
28
|
+
Params are ``friction.breakaway``, ``friction.kinetic`` and ``friction.width``.
|
|
23
29
|
"""
|
|
24
30
|
|
|
25
|
-
def __init__(self, *coefficients: Any) -> None:
|
|
31
|
+
def __init__(self, *coefficients: Any, friction: Any = None) -> None:
|
|
26
32
|
if not coefficients:
|
|
27
33
|
raise ValueError("an efficiency needs at least its linear coefficient c1")
|
|
28
34
|
self.params = ParamSet()
|
|
29
35
|
for k, c in enumerate(coefficients, start=1):
|
|
30
36
|
unit, bounds = ("", (0.0, 1.0)) if k == 1 else (f"({NM})^{1 - k}", (-np.inf, np.inf))
|
|
31
37
|
self.params.add(as_param(c, f"c{k}", unit=unit, bounds=bounds, scope="design"), f"c{k}")
|
|
38
|
+
self._degree = len(coefficients)
|
|
39
|
+
self.friction: StaticFriction | None = as_friction(friction)
|
|
40
|
+
if self.friction is not None:
|
|
41
|
+
self.params.merge(self.friction.params, "friction")
|
|
32
42
|
|
|
33
43
|
@property
|
|
34
44
|
def degree(self) -> int:
|
|
35
45
|
"""The highest power of the commanded torque."""
|
|
36
|
-
return
|
|
46
|
+
return self._degree
|
|
37
47
|
|
|
38
48
|
def delivered(self, u: Any, p: dict[str, Any]) -> Any:
|
|
39
49
|
"""Delivered torques for commanded ones ``u``, with the coefficients ``p`` by name."""
|
|
50
|
+
if self.friction is not None:
|
|
51
|
+
own = {k[len("friction.") :]: v for k, v in p.items() if k.startswith("friction.")}
|
|
52
|
+
u = u - self.friction.torque(u, own)
|
|
40
53
|
return sum(p[f"c{k}"] * u**k for k in range(1, self.degree + 1))
|
|
41
54
|
|
|
42
55
|
def __call__(self, u: ArrayLike) -> np.ndarray:
|
|
43
56
|
"""Delivered torques [N·m] at the current coefficients; motors along the last axis."""
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
net = np.asarray(u, dtype=float)
|
|
58
|
+
if self.friction is not None:
|
|
59
|
+
net = net - self.friction(net)
|
|
60
|
+
return np.asarray(
|
|
61
|
+
sum(self.params[f"c{k}"].value * net**k for k in range(1, self.degree + 1))
|
|
62
|
+
)
|
|
46
63
|
|
|
47
64
|
def to_dict(self) -> dict[str, Any]:
|
|
48
|
-
"""The coefficients at their current values."""
|
|
49
|
-
values = [
|
|
50
|
-
|
|
65
|
+
"""The coefficients (and the friction) at their current values."""
|
|
66
|
+
values = [self.params[f"c{k}"].value.tolist() for k in range(1, self.degree + 1)]
|
|
67
|
+
out: dict[str, Any] = {"type": "polynomial", "coefficients": values}
|
|
68
|
+
if self.friction is not None:
|
|
69
|
+
out["friction"] = self.friction.to_dict()
|
|
70
|
+
return out
|
|
51
71
|
|
|
52
72
|
@classmethod
|
|
53
73
|
def from_dict(cls, data: dict[str, Any]) -> Efficiency:
|
|
54
74
|
"""Inverse of ``to_dict``."""
|
|
55
|
-
return cls(*data["coefficients"])
|
|
75
|
+
return cls(*data["coefficients"], friction=data.get("friction"))
|
|
56
76
|
|
|
57
77
|
|
|
58
78
|
def as_efficiency(value: Any) -> Efficiency:
|