virtualmodelcontrol 1.0.0__tar.gz → 1.2.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.
Files changed (368) hide show
  1. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/CHANGELOG.md +48 -0
  2. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/PKG-INFO +1 -1
  3. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/index.md +1 -0
  4. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/installation.md +2 -2
  5. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/troubleshooting.md +1 -1
  6. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/build-a-robot.md +3 -1
  7. virtualmodelcontrol-1.2.0/docs/tutorials/friction.md +285 -0
  8. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/real-time.md +23 -0
  9. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/__init__.py +2 -1
  10. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/_version.py +2 -2
  11. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/__init__.py +8 -1
  12. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/output.py +35 -0
  13. virtualmodelcontrol-1.2.0/src/virtualmodelcontrol/identification/efficiency.py +95 -0
  14. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/__init__.py +2 -0
  15. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/efficiency.py +29 -9
  16. virtualmodelcontrol-1.2.0/src/virtualmodelcontrol/models/friction.py +79 -0
  17. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/builder.py +11 -4
  18. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/problem.py +15 -2
  19. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/adapt.py +14 -1
  20. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/rollout.py +6 -1
  21. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/run.py +16 -4
  22. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/runlog.py +11 -0
  23. virtualmodelcontrol-1.2.0/tests/identification/test_fit_friction.py +125 -0
  24. virtualmodelcontrol-1.2.0/tests/models/test_static_friction.py +325 -0
  25. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_runlog.py +28 -0
  26. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_wallclock.py +46 -0
  27. virtualmodelcontrol-1.0.0/src/virtualmodelcontrol/identification/efficiency.py +0 -45
  28. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/.gitignore +0 -0
  29. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/CITATION.cff +0 -0
  30. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/LICENSE +0 -0
  31. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/README.md +0 -0
  32. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/benchmarks/tick.py +0 -0
  33. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_ext/video.py +0 -0
  34. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/create-lab.png +0 -0
  35. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/custom.css +0 -0
  36. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/favicon.svg +0 -0
  37. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/logo-light.svg +0 -0
  38. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/logo.svg +0 -0
  39. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_static/readme-hero.svg +0 -0
  40. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_templates/autosummary/module.rst +0 -0
  41. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/_templates/partials/toc.html +0 -0
  42. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/api/index.md +0 -0
  43. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/conventions.md +0 -0
  44. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/efficiency.md +0 -0
  45. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/finger.md +0 -0
  46. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/library.md +0 -0
  47. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/passivity.md +0 -0
  48. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/pcc.md +0 -0
  49. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/concepts/vmc.md +0 -0
  50. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/conf.py +0 -0
  51. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/development/changelog.md +0 -0
  52. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/development/contributing.md +0 -0
  53. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/development/roadmap.md +0 -0
  54. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/development/support.md +0 -0
  55. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/docs_setup.py +0 -0
  56. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/finger.md +0 -0
  57. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/hand.md +0 -0
  58. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/hanging-arm.md +0 -0
  59. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/soft-arm.md +0 -0
  60. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/turtle.md +0 -0
  61. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/examples/two-arms.md +0 -0
  62. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/__init__.py +0 -0
  63. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/_draw.py +0 -0
  64. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/bimanual.py +0 -0
  65. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/control_loop.py +0 -0
  66. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/energy_flow.py +0 -0
  67. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/finger.py +0 -0
  68. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/four_steps.py +0 -0
  69. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/hand.py +0 -0
  70. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/helyx.py +0 -0
  71. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/library_map.py +0 -0
  72. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/mechanism.py +0 -0
  73. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/params.py +0 -0
  74. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/pcc.py +0 -0
  75. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/turtle.py +0 -0
  76. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/schematics/ur5.py +0 -0
  77. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/scripts/readme_figure.py +0 -0
  78. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/configurations.md +0 -0
  79. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/contact.md +0 -0
  80. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/coordinates-and-components.md +0 -0
  81. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/crawl.md +0 -0
  82. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/energy.md +0 -0
  83. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/estimation.md +0 -0
  84. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/extend.md +0 -0
  85. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/first-controller.md +0 -0
  86. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/fit.md +0 -0
  87. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/force.md +0 -0
  88. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/introduction.md +0 -0
  89. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/kinematics.md +0 -0
  90. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/mpc.md +0 -0
  91. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/optimize.md +0 -0
  92. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/outside.md +0 -0
  93. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/parameters.md +0 -0
  94. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/reach.yaml +0 -0
  95. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/run-logs.md +0 -0
  96. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/run-settings.yaml +0 -0
  97. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/stiffness.md +0 -0
  98. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/swaps.md +0 -0
  99. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/tuning.md +0 -0
  100. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/docs/tutorials/underactuated.md +0 -0
  101. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/pyproject.toml +0 -0
  102. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/__init__.py +0 -0
  103. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/force.py +0 -0
  104. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/limits.py +0 -0
  105. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/position.py +0 -0
  106. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/scalar.py +0 -0
  107. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/seeking.py +0 -0
  108. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/adaptation/stiffness.py +0 -0
  109. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/compiler.py +0 -0
  110. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/__init__.py +0 -0
  111. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/controllers.py +0 -0
  112. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/coordinates.py +0 -0
  113. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/experiment.py +0 -0
  114. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/files.py +0 -0
  115. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/config/spec.py +0 -0
  116. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/blending.py +0 -0
  117. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/controller.py +0 -0
  118. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/projection.py +0 -0
  119. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/schedule.py +0 -0
  120. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/state.py +0 -0
  121. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/tank.py +0 -0
  122. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/control/underactuated.py +0 -0
  123. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/__init__.py +0 -0
  124. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/backends.py +0 -0
  125. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/params.py +0 -0
  126. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/registry.py +0 -0
  127. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/signals.py +0 -0
  128. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/space.py +0 -0
  129. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/symbolic.py +0 -0
  130. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/core/units.py +0 -0
  131. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/dynamics.py +0 -0
  132. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/__init__.py +0 -0
  133. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/balance.py +0 -0
  134. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/compliance.py +0 -0
  135. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/contact.py +0 -0
  136. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/imu.py +0 -0
  137. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/inversion.py +0 -0
  138. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/kalman.py +0 -0
  139. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/measurement.py +0 -0
  140. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/momentum.py +0 -0
  141. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/sensors.py +0 -0
  142. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/stiffness.py +0 -0
  143. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/estimation/velocity.py +0 -0
  144. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/hardware/__init__.py +0 -0
  145. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/hardware/profile.py +0 -0
  146. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/__init__.py +0 -0
  147. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/params.py +0 -0
  148. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/plateaus.py +0 -0
  149. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/steps.py +0 -0
  150. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/stiffness.py +0 -0
  151. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/identification/transmission.py +0 -0
  152. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/math.py +0 -0
  153. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/__init__.py +0 -0
  154. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/__init__.py +0 -0
  155. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/base.py +0 -0
  156. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/constrained.py +0 -0
  157. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/dissipation.py +0 -0
  158. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/gated.py +0 -0
  159. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/inertance.py +0 -0
  160. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/locomotion.py +0 -0
  161. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/sources.py +0 -0
  162. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/components/storage.py +0 -0
  163. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/__init__.py +0 -0
  164. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/base.py +0 -0
  165. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/frames.py +0 -0
  166. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/geometry.py +0 -0
  167. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/joints.py +0 -0
  168. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/ops.py +0 -0
  169. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/references.py +0 -0
  170. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/mechanisms/mechanism.py +0 -0
  171. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/actuation.py +0 -0
  172. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/assembly.py +0 -0
  173. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/continuum/__init__.py +0 -0
  174. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/continuum/pcc.py +0 -0
  175. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/equations.py +0 -0
  176. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/function.py +0 -0
  177. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/joint_space.py +0 -0
  178. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/kinematic.py +0 -0
  179. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/kinematics.py +0 -0
  180. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/rigid/__init__.py +0 -0
  181. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/rigid/couplings.py +0 -0
  182. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/rigid/poe.py +0 -0
  183. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/models/rigid/spline.py +0 -0
  184. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/__init__.py +0 -0
  185. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/asktell.py +0 -0
  186. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/collocation.py +0 -0
  187. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/equilibrium.py +0 -0
  188. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/horizon.py +0 -0
  189. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/mpc.py +0 -0
  190. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/nlp.py +0 -0
  191. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/result.py +0 -0
  192. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/search.py +0 -0
  193. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/shooting.py +0 -0
  194. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/solver.py +0 -0
  195. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/tank.py +0 -0
  196. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/terms.py +0 -0
  197. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/trajectory.py +0 -0
  198. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/variables.py +0 -0
  199. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/optimization/virtual.py +0 -0
  200. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/py.typed +0 -0
  201. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/__init__.py +0 -0
  202. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/bimanual.py +0 -0
  203. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/helyx.py +0 -0
  204. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/planar.py +0 -0
  205. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/turtle.py +0 -0
  206. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/robots/ur5.py +0 -0
  207. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/__init__.py +0 -0
  208. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/balance.py +0 -0
  209. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/model_plant.py +0 -0
  210. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/plant.py +0 -0
  211. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/sim/replay.py +0 -0
  212. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/system.py +0 -0
  213. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/testing.py +0 -0
  214. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/viz/__init__.py +0 -0
  215. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/viz/animation.py +0 -0
  216. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/viz/draw.py +0 -0
  217. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/src/virtualmodelcontrol/viz/style.py +0 -0
  218. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_fingertip.py +0 -0
  219. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_force.py +0 -0
  220. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_grasp.py +0 -0
  221. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_holding.py +0 -0
  222. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_loop.py +0 -0
  223. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_position.py +0 -0
  224. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_scalar.py +0 -0
  225. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_seeking.py +0 -0
  226. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_stiffness_tracking.py +0 -0
  227. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/adaptation/test_virtual_state.py +0 -0
  228. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/backend_helpers.py +0 -0
  229. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/config/test_config.py +0 -0
  230. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/conftest.py +0 -0
  231. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_blending.py +0 -0
  232. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_honesty.py +0 -0
  233. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_inputs.py +0 -0
  234. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_output.py +0 -0
  235. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_projection.py +0 -0
  236. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_schedule.py +0 -0
  237. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_state_layout.py +0 -0
  238. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_tank.py +0 -0
  239. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_underactuated.py +0 -0
  240. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_underactuated_golden.py +0 -0
  241. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/control/test_vmc_golden.py +0 -0
  242. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_backends.py +0 -0
  243. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_backends_torch.py +0 -0
  244. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_params.py +0 -0
  245. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_registry.py +0 -0
  246. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_signals.py +0 -0
  247. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_space.py +0 -0
  248. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/core/test_symbolic.py +0 -0
  249. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/adaptation.npz +0 -0
  250. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/compliance.npz +0 -0
  251. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/components.npz +0 -0
  252. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/finger.yaml +0 -0
  253. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/hand.yaml +0 -0
  254. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/soft-arm.yaml +0 -0
  255. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/turtle.yaml +0 -0
  256. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/two-arms.yaml +0 -0
  257. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/configs/ur5-hand.yaml +0 -0
  258. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/derivatives.npz +0 -0
  259. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/dynamics.npz +0 -0
  260. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/efficiency.npz +0 -0
  261. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/estimation.npz +0 -0
  262. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/finger.npz +0 -0
  263. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/fingertip.npz +0 -0
  264. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/hand.npz +0 -0
  265. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/heuristics.npz +0 -0
  266. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/imu.npz +0 -0
  267. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/kalman.npz +0 -0
  268. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/mocap.npz +0 -0
  269. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/optimization.json +0 -0
  270. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/optimization.npz +0 -0
  271. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/pcc.npz +0 -0
  272. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/transmission.npz +0 -0
  273. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/turtle.npz +0 -0
  274. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/underactuated.npz +0 -0
  275. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/data/vmc.npz +0 -0
  276. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_compliance_golden.py +0 -0
  277. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_contact.py +0 -0
  278. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_imu.py +0 -0
  279. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_inversion.py +0 -0
  280. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_kalman.py +0 -0
  281. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_kalman_golden.py +0 -0
  282. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_kalman_unscented.py +0 -0
  283. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_mocap_golden.py +0 -0
  284. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_momentum.py +0 -0
  285. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_sensors.py +0 -0
  286. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_unmeasured.py +0 -0
  287. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/estimation/test_velocity.py +0 -0
  288. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/hardware/test_profile.py +0 -0
  289. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/hardware/test_templates.py +0 -0
  290. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/helpers.py +0 -0
  291. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_efficiency_fit.py +0 -0
  292. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_fit_params.py +0 -0
  293. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_friction.py +0 -0
  294. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_steps.py +0 -0
  295. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_stiffness_fit.py +0 -0
  296. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/identification/test_transmission.py +0 -0
  297. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/lab_optimization.py +0 -0
  298. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_components.py +0 -0
  299. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_components_golden.py +0 -0
  300. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_contact.py +0 -0
  301. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_coordinates.py +0 -0
  302. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_distances.py +0 -0
  303. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_frames.py +0 -0
  304. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_friction.py +0 -0
  305. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_gated.py +0 -0
  306. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_mechanism.py +0 -0
  307. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_more_components.py +0 -0
  308. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_pair_contact.py +0 -0
  309. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_phase_spring.py +0 -0
  310. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/mechanisms/test_virtual_model.py +0 -0
  311. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_actuation.py +0 -0
  312. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_assembly.py +0 -0
  313. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_contact_map.py +0 -0
  314. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_efficiency.py +0 -0
  315. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_equations.py +0 -0
  316. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_floating.py +0 -0
  317. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_floating_base.py +0 -0
  318. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_function.py +0 -0
  319. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_kinematics.py +0 -0
  320. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_pcc.py +0 -0
  321. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_poe.py +0 -0
  322. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_rail.py +0 -0
  323. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/models/test_underactuated.py +0 -0
  324. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_asktell.py +0 -0
  325. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_collocation.py +0 -0
  326. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_equilibrium.py +0 -0
  327. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_horizon.py +0 -0
  328. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_lab.py +0 -0
  329. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_mpc.py +0 -0
  330. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_periodic.py +0 -0
  331. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_plant.py +0 -0
  332. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_problem.py +0 -0
  333. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_search.py +0 -0
  334. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_shooting.py +0 -0
  335. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_solvers.py +0 -0
  336. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_structure.py +0 -0
  337. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_swap.py +0 -0
  338. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_tank.py +0 -0
  339. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_terms.py +0 -0
  340. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_variables.py +0 -0
  341. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/optimization/test_virtual.py +0 -0
  342. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_adapt.py +0 -0
  343. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_bimanual.py +0 -0
  344. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_crawler.py +0 -0
  345. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_hand.py +0 -0
  346. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_helyx.py +0 -0
  347. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_parametric.py +0 -0
  348. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_planar.py +0 -0
  349. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_turtle.py +0 -0
  350. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/robots/test_ur5.py +0 -0
  351. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_balance.py +0 -0
  352. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_record.py +0 -0
  353. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_replay.py +0 -0
  354. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_rollout.py +0 -0
  355. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/sim/test_run.py +0 -0
  356. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/small_plan.py +0 -0
  357. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/soft_arm_plan.py +0 -0
  358. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_benchmark.py +0 -0
  359. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_compiler.py +0 -0
  360. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_docs.py +0 -0
  361. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_dynamics.py +0 -0
  362. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_import.py +0 -0
  363. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_math.py +0 -0
  364. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_readme.py +0 -0
  365. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/test_testing.py +0 -0
  366. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/underactuated_lab.py +0 -0
  367. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/viz/test_animate.py +0 -0
  368. {virtualmodelcontrol-1.0.0 → virtualmodelcontrol-1.2.0}/tests/viz/test_viz.py +0 -0
@@ -4,6 +4,54 @@ 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.2.0] - 2026-10-09
8
+
9
+ A robot that runs for hours: the log of a real-time run can keep only its last seconds. Nothing that
10
+ worked before changes.
11
+
12
+ ### Added
13
+
14
+ - `sim.run(..., window=)`: on real time, a run that goes on for hours keeps only the last `window`
15
+ seconds of its log (up to a quarter more, until the next trim) instead of every step in memory;
16
+ `info["steps"]` still counts them all, and a Ctrl-C keeps only whole steps.
17
+ - `RunLog.crop(t_min, t_max)`: the steps of a time window as a new log, with the same `info` and
18
+ `meta`; an end left out is open.
19
+
20
+ ## [1.1.0] - 2026-10-09
21
+
22
+ Static friction of the motors: a model of it, a compensation for it, its identification and a
23
+ tutorial, all off unless asked for. Nothing that worked before changes.
24
+
25
+ ### Added
26
+
27
+ - Static friction of the motors, off by default. `StaticFriction(breakaway, kinetic, width)`
28
+ [N·m] is the torque that friction takes from a motor as a smooth function of the torque applied
29
+ to it: all of it below the breakaway torque F (the motor is stuck), the kinetic torque Fc with
30
+ the sign of the command past it (Fc = 0: static friction gone once it moves; Fc = F: it stays),
31
+ smooth (C^∞) over `width`, so solvers differentiate it. It depends on the torque only, not on
32
+ the speed. `Efficiency(c1, ..., friction=StaticFriction(...))` takes it before the polynomial, so
33
+ every transmission carries it (`Direct`, `Underactuated`, `TendonTransmission`, stacked ones, and
34
+ configuration files), and the simulator, `compile_dynamics`, `Collocation`, `Shooting`, `MPC`, the
35
+ Kalman filter and the force law all have it. Its Params are `friction.breakaway`,
36
+ `friction.kinetic` and `friction.width`; with F = Fc = 0, the default, nothing changes. Not passive
37
+ by construction: when a command brakes the motion it can create up to F |θ̇| of power, which the
38
+ tutorial states and measures.
39
+ - `control.StaticFrictionCompensation(kinetic, width, fraction)` (and `.of(friction, fraction)`), an
40
+ output stage that adds the kinetic friction torque in the direction of the command, smooth in the
41
+ command. Against a `StaticFriction(F, Fc)` it delivers the command once the motor moves and
42
+ narrows the dead band from F to F − Fc. Nothing turns it on but you: no template or controller
43
+ has it by default. It has a `symbolic` form, so `Problem(system, output=[...])` and
44
+ `sim.rollout(..., output=[...])` apply it in a plan as `VMCController(output=)` does in a run
45
+ (`Problem` now raises for an output stage that has no `symbolic` form).
46
+ - Identification of the friction: its Params are the robot's, so `identification.fit_params` fits
47
+ them, with the stiffness and damping, to a run in which the command rises slowly from rest;
48
+ `fit_efficiency(commanded, delivered, friction=True, width=)` fits the efficiency and the friction
49
+ to static torques (per motor or `shared`), by a grid and a refinement over the breakaway and the
50
+ kinetic torque.
51
+ - `robots.adapt.finger_friction()` and `hand_friction()`: the lab's friction values of the finger
52
+ (0.20 N·m) and the hand (0.10 N·m) as a `StaticFriction`, to ask for.
53
+ - Docs: the tutorial "Static friction of the motors".
54
+
7
55
  ## [1.0.0] - 2026-10-07
8
56
 
9
57
  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.0.0
3
+ Version: 1.2.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/
@@ -108,6 +108,7 @@ tutorials/parameters
108
108
  tutorials/configurations
109
109
  tutorials/kinematics
110
110
  tutorials/build-a-robot
111
+ tutorials/friction
111
112
  tutorials/extend
112
113
  tutorials/outside
113
114
  ```
@@ -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.0.0"
123
+ pip install "virtualmodelcontrol==1.2.0"
124
124
  ```
125
125
 
126
- In a `requirements.txt` file, write `virtualmodelcontrol==1.0.0`. In a conda `environment.yml`,
126
+ In a `requirements.txt` file, write `virtualmodelcontrol==1.2.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
 
@@ -32,7 +32,7 @@ sudo apt install python3-venv
32
32
  pip installs CasADi from a prebuilt wheel. If pip starts building CasADi from source, or
33
33
  `import casadi` fails, there is no wheel for your Python version or platform. Create the
34
34
  environment with a Python version listed among the files on CasADi's
35
- [PyPI page](https://pypi.org/project/casadi/#files).
35
+ [PyPI page](https://pypi.org/project/casadi/).
36
36
 
37
37
  ## Compiling takes long
38
38
 
@@ -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.
@@ -132,6 +132,29 @@ length of each step. `log.info` counts the `overruns` (steps longer than the per
132
132
  `stale` readings the loop refused as too old and the `guard_trips` (readings missing or not
133
133
  numbers). A refused reading means zero torque for that step.
134
134
 
135
+ A run that goes on for hours would keep every step in memory. With `window` [s], `run` keeps
136
+ only the last seconds of the log (up to a quarter more, until it trims), and `log.info["steps"]`
137
+ still counts every step. `log.crop(t_min, t_max)` takes a part of any log:
138
+
139
+ ```{code-cell} python
140
+ driver = Driver()
141
+ clock = vmc.sim.WallClock(1 / 330, 0.05, now=driver.time,
142
+ sleep=driver.sim.advance)
143
+ long = vmc.sim.run(Plant(driver), controller, clock, T=3.0, window=1.0)
144
+ kept = long.arrays()["t"].ravel()
145
+ last = long.crop(t_min=kept[-1] - 0.5) # the last half second
146
+ len(kept), len(last.arrays()["t"])
147
+ ```
148
+
149
+ ```{code-cell} python
150
+ :tags: [remove-cell]
151
+ assert long.info["steps"] == 990 and 330 <= len(kept) <= 413
152
+ assert abs(kept[-1] - 989 / 330) < 1e-9 and 160 <= len(last.arrays()["t"]) <= 167
153
+ glue("kept", len(kept), display=False)
154
+ ```
155
+
156
+ The log holds {glue:text}`kept` of the 990 steps, the last second or so, and nothing older.
157
+
135
158
  `run` does not close the plant: do it yourself, with `try` and `finally`:
136
159
 
137
160
  ```python
@@ -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.0.0'
22
- __version_tuple__ = version_tuple = (1, 0, 0)
21
+ __version__ = version = '1.2.0'
22
+ __version_tuple__ = version_tuple = (1, 2, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -2,7 +2,13 @@
2
2
 
3
3
  from .blending import SwapController, blend_weight
4
4
  from .controller import VMCController
5
- from .output import FrictionCompensation, Pretension, TorqueLimit, TorqueOffset
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",
@@ -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)
@@ -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",