virtualmodelcontrol 0.3.0__tar.gz → 0.5.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 (385) hide show
  1. virtualmodelcontrol-0.5.0/CHANGELOG.md +630 -0
  2. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/PKG-INFO +1 -7
  3. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/README.md +0 -2
  4. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/api/index.md +4 -1
  5. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/conventions.md +7 -6
  6. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/efficiency.md +10 -10
  7. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/finger.md +11 -9
  8. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/library.md +8 -7
  9. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/passivity.md +8 -7
  10. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/pcc.md +8 -7
  11. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/concepts/vmc.md +11 -10
  12. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/development/contributing.md +9 -7
  13. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/examples/finger.md +130 -7
  14. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/examples/hand.md +20 -19
  15. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/examples/hanging-arm.md +110 -58
  16. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/examples/soft-arm.md +29 -28
  17. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/examples/turtle.md +12 -8
  18. virtualmodelcontrol-0.5.0/docs/examples/two-arms.md +307 -0
  19. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/index.md +35 -8
  20. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/installation.md +15 -15
  21. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/library_map.py +13 -3
  22. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/troubleshooting.md +4 -4
  23. virtualmodelcontrol-0.5.0/docs/tutorials/build-a-robot.md +464 -0
  24. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/configurations.md +26 -24
  25. virtualmodelcontrol-0.5.0/docs/tutorials/contact.md +432 -0
  26. virtualmodelcontrol-0.5.0/docs/tutorials/coordinates-and-components.md +291 -0
  27. virtualmodelcontrol-0.5.0/docs/tutorials/crawl.md +362 -0
  28. virtualmodelcontrol-0.5.0/docs/tutorials/energy.md +305 -0
  29. virtualmodelcontrol-0.5.0/docs/tutorials/estimation.md +357 -0
  30. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/extend.md +40 -17
  31. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/first-controller.md +7 -7
  32. virtualmodelcontrol-0.5.0/docs/tutorials/fit.md +93 -0
  33. virtualmodelcontrol-0.5.0/docs/tutorials/force.md +541 -0
  34. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/introduction.md +8 -9
  35. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/kinematics.md +96 -7
  36. virtualmodelcontrol-0.5.0/docs/tutorials/optimize.md +739 -0
  37. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/parameters.md +6 -6
  38. virtualmodelcontrol-0.5.0/docs/tutorials/real-time.md +352 -0
  39. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/run-logs.md +24 -20
  40. virtualmodelcontrol-0.5.0/docs/tutorials/stiffness.md +294 -0
  41. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/swaps.md +19 -21
  42. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/tuning.md +75 -16
  43. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/pyproject.toml +10 -24
  44. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/__init__.py +40 -9
  45. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/_version.py +2 -2
  46. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/__init__.py +17 -0
  47. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/force.py +107 -0
  48. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/limits.py +39 -0
  49. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/position.py +94 -0
  50. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/scalar.py +94 -0
  51. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/seeking.py +90 -0
  52. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/adaptation/stiffness.py +71 -0
  53. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/coordinates.py +110 -0
  54. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/control/__init__.py +4 -0
  55. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/control/controller.py +30 -9
  56. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/control/projection.py +14 -0
  57. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/control/tank.py +70 -0
  58. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/__init__.py +2 -1
  59. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/space.py +83 -0
  60. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/symbolic.py +1 -25
  61. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/dynamics.py +25 -5
  62. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/__init__.py +28 -0
  63. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/balance.py +34 -0
  64. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/compliance.py +29 -0
  65. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/contact.py +35 -0
  66. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/imu.py +131 -0
  67. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/inversion.py +99 -0
  68. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/kalman.py +218 -0
  69. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/measurement.py +80 -0
  70. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/momentum.py +74 -0
  71. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/sensors.py +122 -0
  72. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/stiffness.py +45 -0
  73. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/estimation/velocity.py +37 -0
  74. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/hardware/__init__.py +5 -0
  75. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/hardware/profile.py +114 -0
  76. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/identification/__init__.py +19 -0
  77. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/identification/params.py +120 -0
  78. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/identification/steps.py +55 -0
  79. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/identification/stiffness.py +126 -0
  80. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/identification/transmission.py +18 -0
  81. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/math.py +188 -0
  82. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/__init__.py +28 -0
  83. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/__init__.py +9 -2
  84. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/base.py +6 -2
  85. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/mechanisms/components/dissipation.py +152 -0
  86. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/mechanisms/components/gated.py +40 -0
  87. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/inertance.py +29 -1
  88. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/mechanisms/components/locomotion.py +59 -0
  89. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/sources.py +27 -4
  90. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/coordinates/__init__.py +21 -4
  91. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/coordinates/base.py +10 -0
  92. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/mechanisms/coordinates/frames.py +189 -0
  93. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/mechanisms/coordinates/geometry.py +187 -0
  94. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/coordinates/ops.py +18 -0
  95. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/coordinates/references.py +13 -0
  96. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/mechanism.py +20 -3
  97. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/__init__.py +4 -1
  98. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/actuation.py +51 -0
  99. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/assembly.py +2 -2
  100. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/models/function.py +70 -0
  101. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/kinematics.py +14 -0
  102. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/models/rigid/poe.py +238 -0
  103. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/models/rigid/spline.py +41 -0
  104. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/__init__.py +41 -0
  105. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/asktell.py +258 -0
  106. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/builder.py +185 -0
  107. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/collocation.py +235 -0
  108. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/equilibrium.py +64 -0
  109. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/horizon.py +224 -0
  110. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/nlp.py +66 -0
  111. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/problem.py +270 -0
  112. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/result.py +63 -0
  113. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/search.py +125 -0
  114. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/solver.py +80 -0
  115. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/terms.py +217 -0
  116. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/trajectory.py +54 -0
  117. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/optimization/variables.py +67 -0
  118. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/robots/adapt.py +9 -16
  119. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/robots/bimanual.py +4 -13
  120. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/robots/helyx.py +4 -10
  121. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/robots/turtle.py +213 -0
  122. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/__init__.py +5 -0
  123. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/sim/balance.py +50 -0
  124. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/model_plant.py +12 -0
  125. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/sim/rollout.py +158 -0
  126. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/run.py +35 -51
  127. virtualmodelcontrol-0.5.0/src/virtualmodelcontrol/testing.py +183 -0
  128. virtualmodelcontrol-0.5.0/tests/adaptation/test_fingertip.py +139 -0
  129. virtualmodelcontrol-0.5.0/tests/adaptation/test_force.py +219 -0
  130. virtualmodelcontrol-0.5.0/tests/adaptation/test_grasp.py +99 -0
  131. virtualmodelcontrol-0.5.0/tests/adaptation/test_holding.py +154 -0
  132. virtualmodelcontrol-0.5.0/tests/adaptation/test_loop.py +58 -0
  133. virtualmodelcontrol-0.5.0/tests/adaptation/test_position.py +71 -0
  134. virtualmodelcontrol-0.5.0/tests/adaptation/test_scalar.py +155 -0
  135. virtualmodelcontrol-0.5.0/tests/adaptation/test_seeking.py +139 -0
  136. virtualmodelcontrol-0.5.0/tests/adaptation/test_stiffness_tracking.py +136 -0
  137. virtualmodelcontrol-0.5.0/tests/adaptation/test_virtual_state.py +67 -0
  138. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/config/test_config.py +76 -0
  139. virtualmodelcontrol-0.5.0/tests/control/test_inputs.py +32 -0
  140. virtualmodelcontrol-0.5.0/tests/control/test_projection.py +45 -0
  141. virtualmodelcontrol-0.5.0/tests/control/test_tank.py +152 -0
  142. virtualmodelcontrol-0.5.0/tests/core/test_space.py +113 -0
  143. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/core/test_symbolic.py +1 -10
  144. virtualmodelcontrol-0.5.0/tests/data/adaptation.npz +0 -0
  145. virtualmodelcontrol-0.5.0/tests/data/compliance.npz +0 -0
  146. virtualmodelcontrol-0.5.0/tests/data/estimation.npz +0 -0
  147. virtualmodelcontrol-0.5.0/tests/data/fingertip.npz +0 -0
  148. virtualmodelcontrol-0.5.0/tests/data/heuristics.npz +0 -0
  149. virtualmodelcontrol-0.5.0/tests/data/imu.npz +0 -0
  150. virtualmodelcontrol-0.5.0/tests/data/kalman.npz +0 -0
  151. virtualmodelcontrol-0.5.0/tests/data/mocap.npz +0 -0
  152. virtualmodelcontrol-0.5.0/tests/data/optimization.json +326 -0
  153. virtualmodelcontrol-0.5.0/tests/data/optimization.npz +0 -0
  154. virtualmodelcontrol-0.5.0/tests/data/transmission.npz +0 -0
  155. virtualmodelcontrol-0.5.0/tests/estimation/test_compliance_golden.py +63 -0
  156. virtualmodelcontrol-0.5.0/tests/estimation/test_contact.py +201 -0
  157. virtualmodelcontrol-0.5.0/tests/estimation/test_imu.py +236 -0
  158. virtualmodelcontrol-0.5.0/tests/estimation/test_inversion.py +264 -0
  159. virtualmodelcontrol-0.5.0/tests/estimation/test_kalman.py +261 -0
  160. virtualmodelcontrol-0.5.0/tests/estimation/test_kalman_golden.py +149 -0
  161. virtualmodelcontrol-0.5.0/tests/estimation/test_kalman_unscented.py +184 -0
  162. virtualmodelcontrol-0.5.0/tests/estimation/test_mocap_golden.py +109 -0
  163. virtualmodelcontrol-0.5.0/tests/estimation/test_momentum.py +176 -0
  164. virtualmodelcontrol-0.5.0/tests/estimation/test_sensors.py +115 -0
  165. virtualmodelcontrol-0.5.0/tests/estimation/test_velocity.py +67 -0
  166. virtualmodelcontrol-0.5.0/tests/hardware/test_profile.py +37 -0
  167. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/helpers.py +23 -3
  168. virtualmodelcontrol-0.5.0/tests/identification/test_fit_params.py +168 -0
  169. virtualmodelcontrol-0.5.0/tests/identification/test_friction.py +98 -0
  170. virtualmodelcontrol-0.5.0/tests/identification/test_steps.py +174 -0
  171. virtualmodelcontrol-0.5.0/tests/identification/test_transmission.py +59 -0
  172. virtualmodelcontrol-0.5.0/tests/lab_optimization.py +137 -0
  173. virtualmodelcontrol-0.5.0/tests/mechanisms/test_distances.py +140 -0
  174. virtualmodelcontrol-0.5.0/tests/mechanisms/test_frames.py +182 -0
  175. virtualmodelcontrol-0.5.0/tests/mechanisms/test_friction.py +163 -0
  176. virtualmodelcontrol-0.5.0/tests/mechanisms/test_gated.py +68 -0
  177. virtualmodelcontrol-0.5.0/tests/mechanisms/test_more_components.py +208 -0
  178. virtualmodelcontrol-0.5.0/tests/mechanisms/test_pair_contact.py +124 -0
  179. virtualmodelcontrol-0.5.0/tests/mechanisms/test_phase_spring.py +346 -0
  180. virtualmodelcontrol-0.5.0/tests/mechanisms/test_virtual_model.py +175 -0
  181. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/models/test_actuation.py +67 -4
  182. virtualmodelcontrol-0.5.0/tests/models/test_contact_map.py +38 -0
  183. virtualmodelcontrol-0.5.0/tests/models/test_floating.py +165 -0
  184. virtualmodelcontrol-0.5.0/tests/models/test_floating_base.py +46 -0
  185. virtualmodelcontrol-0.5.0/tests/models/test_function.py +86 -0
  186. virtualmodelcontrol-0.5.0/tests/models/test_poe.py +165 -0
  187. virtualmodelcontrol-0.5.0/tests/models/test_rail.py +196 -0
  188. virtualmodelcontrol-0.5.0/tests/optimization/test_asktell.py +259 -0
  189. virtualmodelcontrol-0.5.0/tests/optimization/test_collocation.py +223 -0
  190. virtualmodelcontrol-0.5.0/tests/optimization/test_equilibrium.py +151 -0
  191. virtualmodelcontrol-0.5.0/tests/optimization/test_horizon.py +263 -0
  192. virtualmodelcontrol-0.5.0/tests/optimization/test_lab.py +128 -0
  193. virtualmodelcontrol-0.5.0/tests/optimization/test_periodic.py +583 -0
  194. virtualmodelcontrol-0.5.0/tests/optimization/test_problem.py +424 -0
  195. virtualmodelcontrol-0.5.0/tests/optimization/test_search.py +146 -0
  196. virtualmodelcontrol-0.5.0/tests/optimization/test_structure.py +120 -0
  197. virtualmodelcontrol-0.5.0/tests/optimization/test_swap.py +51 -0
  198. virtualmodelcontrol-0.5.0/tests/optimization/test_terms.py +226 -0
  199. virtualmodelcontrol-0.5.0/tests/optimization/test_variables.py +43 -0
  200. virtualmodelcontrol-0.5.0/tests/robots/test_crawler.py +333 -0
  201. virtualmodelcontrol-0.5.0/tests/robots/test_turtle.py +113 -0
  202. virtualmodelcontrol-0.5.0/tests/sim/test_balance.py +110 -0
  203. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/sim/test_record.py +22 -0
  204. virtualmodelcontrol-0.5.0/tests/sim/test_rollout.py +193 -0
  205. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/sim/test_wallclock.py +13 -9
  206. virtualmodelcontrol-0.5.0/tests/small_plan.py +62 -0
  207. virtualmodelcontrol-0.5.0/tests/soft_arm_plan.py +30 -0
  208. virtualmodelcontrol-0.5.0/tests/test_benchmark.py +54 -0
  209. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/test_dynamics.py +18 -0
  210. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/test_import.py +1 -10
  211. virtualmodelcontrol-0.5.0/tests/test_math.py +152 -0
  212. virtualmodelcontrol-0.5.0/tests/test_testing.py +191 -0
  213. virtualmodelcontrol-0.3.0/CHANGELOG.md +0 -291
  214. virtualmodelcontrol-0.3.0/docs/examples/two-arms.md +0 -180
  215. virtualmodelcontrol-0.3.0/docs/tutorials/build-a-robot.md +0 -181
  216. virtualmodelcontrol-0.3.0/docs/tutorials/contact.md +0 -199
  217. virtualmodelcontrol-0.3.0/docs/tutorials/coordinates-and-components.md +0 -161
  218. virtualmodelcontrol-0.3.0/docs/tutorials/energy.md +0 -193
  219. virtualmodelcontrol-0.3.0/docs/tutorials/interactive.md +0 -221
  220. virtualmodelcontrol-0.3.0/docs/tutorials/real-time.md +0 -232
  221. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/__init__.py +0 -38
  222. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/bus.py +0 -203
  223. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/check.py +0 -41
  224. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/dynamixel.py +0 -162
  225. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/homing.py +0 -70
  226. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/hardware/profile.py +0 -194
  227. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/identification/__init__.py +0 -7
  228. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/identification/stiffness.py +0 -70
  229. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/__init__.py +0 -25
  230. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/controls.py +0 -82
  231. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/interactive.py +0 -111
  232. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/joystick.py +0 -101
  233. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/keyboard.py +0 -64
  234. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/recorder.py +0 -87
  235. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/session.py +0 -96
  236. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/interactive/window.py +0 -205
  237. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/mechanisms/components/dissipation.py +0 -72
  238. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/mechanisms/coordinates/frames.py +0 -62
  239. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/mechanisms/coordinates/geometry.py +0 -74
  240. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/models/rigid/poe.py +0 -158
  241. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/robots/turtle.py +0 -99
  242. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/__init__.py +0 -41
  243. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/joint_io.py +0 -52
  244. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/node.py +0 -53
  245. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/params.py +0 -43
  246. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/plant.py +0 -121
  247. virtualmodelcontrol-0.3.0/src/virtualmodelcontrol/ros/twin.py +0 -82
  248. virtualmodelcontrol-0.3.0/tests/core/test_space.py +0 -52
  249. virtualmodelcontrol-0.3.0/tests/hardware/test_dynamixel.py +0 -164
  250. virtualmodelcontrol-0.3.0/tests/hardware/test_profile.py +0 -85
  251. virtualmodelcontrol-0.3.0/tests/interactive/conftest.py +0 -58
  252. virtualmodelcontrol-0.3.0/tests/interactive/test_controls.py +0 -83
  253. virtualmodelcontrol-0.3.0/tests/interactive/test_interactive.py +0 -261
  254. virtualmodelcontrol-0.3.0/tests/interactive/test_joystick.py +0 -74
  255. virtualmodelcontrol-0.3.0/tests/interactive/test_keyboard.py +0 -62
  256. virtualmodelcontrol-0.3.0/tests/interactive/test_session.py +0 -127
  257. virtualmodelcontrol-0.3.0/tests/interactive/test_window.py +0 -191
  258. virtualmodelcontrol-0.3.0/tests/models/test_poe.py +0 -75
  259. virtualmodelcontrol-0.3.0/tests/robots/test_turtle.py +0 -50
  260. virtualmodelcontrol-0.3.0/tests/ros/conftest.py +0 -9
  261. virtualmodelcontrol-0.3.0/tests/ros/test_joint_io.py +0 -29
  262. virtualmodelcontrol-0.3.0/tests/ros/test_ros.py +0 -136
  263. virtualmodelcontrol-0.3.0/tests/sim/test_paced.py +0 -108
  264. virtualmodelcontrol-0.3.0/tests/test_benchmark.py +0 -27
  265. virtualmodelcontrol-0.3.0/tests/test_deprecations.py +0 -106
  266. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/.gitignore +0 -0
  267. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/CITATION.cff +0 -0
  268. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/LICENSE +0 -0
  269. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/benchmarks/tick.py +0 -0
  270. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_ext/video.py +0 -0
  271. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/create-lab.png +0 -0
  272. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/custom.css +0 -0
  273. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/favicon.svg +0 -0
  274. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/logo-light.svg +0 -0
  275. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/logo.svg +0 -0
  276. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_static/readme-hero.svg +0 -0
  277. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_templates/autosummary/module.rst +0 -0
  278. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/_templates/partials/toc.html +0 -0
  279. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/conf.py +0 -0
  280. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/development/changelog.md +0 -0
  281. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/development/roadmap.md +0 -0
  282. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/docs_setup.py +0 -0
  283. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/__init__.py +0 -0
  284. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/_draw.py +0 -0
  285. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/bimanual.py +0 -0
  286. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/control_loop.py +0 -0
  287. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/energy_flow.py +0 -0
  288. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/finger.py +0 -0
  289. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/four_steps.py +0 -0
  290. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/hand.py +0 -0
  291. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/helyx.py +0 -0
  292. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/mechanism.py +0 -0
  293. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/params.py +0 -0
  294. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/pcc.py +0 -0
  295. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/turtle.py +0 -0
  296. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/schematics/ur5.py +0 -0
  297. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/scripts/readme_figure.py +0 -0
  298. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/reach.yaml +0 -0
  299. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/docs/tutorials/run-settings.yaml +0 -0
  300. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/compiler.py +0 -0
  301. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/__init__.py +0 -0
  302. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/controllers.py +0 -0
  303. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/experiment.py +0 -0
  304. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/files.py +0 -0
  305. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/config/spec.py +0 -0
  306. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/control/blending.py +0 -0
  307. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/control/output.py +0 -0
  308. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/control/schedule.py +0 -0
  309. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/params.py +0 -0
  310. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/registry.py +0 -0
  311. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/signals.py +0 -0
  312. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/core/units.py +0 -0
  313. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/identification/efficiency.py +0 -0
  314. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/identification/plateaus.py +0 -0
  315. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/constrained.py +0 -0
  316. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/components/storage.py +0 -0
  317. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/mechanisms/coordinates/joints.py +0 -0
  318. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/continuum/__init__.py +0 -0
  319. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/continuum/pcc.py +0 -0
  320. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/efficiency.py +0 -0
  321. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/joint_space.py +0 -0
  322. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/kinematic.py +0 -0
  323. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/rigid/__init__.py +0 -0
  324. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/models/rigid/couplings.py +0 -0
  325. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/py.typed +0 -0
  326. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/robots/__init__.py +0 -0
  327. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/robots/ur5.py +0 -0
  328. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/plant.py +0 -0
  329. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/replay.py +0 -0
  330. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/sim/runlog.py +0 -0
  331. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/system.py +0 -0
  332. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/viz/__init__.py +0 -0
  333. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/viz/animation.py +0 -0
  334. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/viz/draw.py +0 -0
  335. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/src/virtualmodelcontrol/viz/style.py +0 -0
  336. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/conftest.py +0 -0
  337. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/control/test_blending.py +0 -0
  338. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/control/test_honesty.py +0 -0
  339. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/control/test_output.py +0 -0
  340. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/control/test_schedule.py +0 -0
  341. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/control/test_vmc_golden.py +0 -0
  342. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/core/test_params.py +0 -0
  343. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/core/test_registry.py +0 -0
  344. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/core/test_signals.py +0 -0
  345. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/components.npz +0 -0
  346. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/finger.yaml +0 -0
  347. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/hand.yaml +0 -0
  348. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/soft-arm.yaml +0 -0
  349. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/turtle.yaml +0 -0
  350. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/two-arms.yaml +0 -0
  351. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/configs/ur5-hand.yaml +0 -0
  352. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/derivatives.npz +0 -0
  353. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/dynamics.npz +0 -0
  354. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/efficiency.npz +0 -0
  355. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/finger.npz +0 -0
  356. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/hand.npz +0 -0
  357. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/pcc.npz +0 -0
  358. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/turtle.npz +0 -0
  359. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/data/vmc.npz +0 -0
  360. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/hardware/test_templates.py +0 -0
  361. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/identification/test_efficiency_fit.py +0 -0
  362. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/identification/test_stiffness_fit.py +0 -0
  363. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/mechanisms/test_components.py +0 -0
  364. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/mechanisms/test_components_golden.py +0 -0
  365. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/mechanisms/test_contact.py +0 -0
  366. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/mechanisms/test_coordinates.py +0 -0
  367. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/mechanisms/test_mechanism.py +0 -0
  368. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/models/test_assembly.py +0 -0
  369. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/models/test_efficiency.py +0 -0
  370. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/models/test_kinematics.py +0 -0
  371. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/models/test_pcc.py +0 -0
  372. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_adapt.py +0 -0
  373. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_bimanual.py +0 -0
  374. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_hand.py +0 -0
  375. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_helyx.py +0 -0
  376. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_parametric.py +0 -0
  377. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/robots/test_ur5.py +0 -0
  378. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/sim/test_replay.py +0 -0
  379. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/sim/test_run.py +0 -0
  380. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/sim/test_runlog.py +0 -0
  381. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/test_compiler.py +0 -0
  382. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/test_docs.py +0 -0
  383. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/test_readme.py +0 -0
  384. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/viz/test_animate.py +0 -0
  385. {virtualmodelcontrol-0.3.0 → virtualmodelcontrol-0.5.0}/tests/viz/test_viz.py +0 -0
@@ -0,0 +1,630 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
+ [Semantic Versioning](https://semver.org/) (0.x: the API may change between minor versions).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.5.0] - 2026-10-06
10
+
11
+ This release also carries the work meant for 0.4.0 (optimization of virtual mechanisms, the energy
12
+ tank, tuning and the calibrations), which was never released on its own.
13
+
14
+ ### Added
15
+
16
+ - `vmc.optimization`: plan the motion of a controller on a robot and optimize its Params.
17
+ `Problem(system)` is built once and solved many times. `free` chooses the Params to optimize
18
+ and `parameter` the ones set at every solve (references, say), by name or glob; bounds and
19
+ scale come from the Param. `Collocation(q0, horizon, nodes, initial=, transition=, scales=)` is
20
+ trapezoidal collocation of the closed loop on the robot's full dynamics, without inverting the
21
+ mass matrix. With an `initial` controller, its torques fade out as the new ones fade in with the
22
+ blend of `SwapController`, so the plan is what the swap executes, and the model starts at rest
23
+ where the robot is whatever it gets wrong there. `Effort`, `Cost` (a library coordinate brought
24
+ to zero from a time on) and `Bound` (a coordinate kept within limits) are the terms, `Term`
25
+ the base to write your own. `Result` holds the motion, the Params found, the cost by term and
26
+ the solver's status, and `apply` puts the values into a running controller (returning the exact
27
+ energy jump) or into a system. `search_references` searches a reference on a grid, one at a
28
+ time, keeping the best converged plan. `Problem.build` returns the `NLP` for any other solver.
29
+ `Collocation(scheme="hermite-simpson")` integrates to fourth order instead of second: it adds the
30
+ acceleration at the middle of every interval to the unknowns, and needs far fewer nodes for the
31
+ same agreement with a simulation.
32
+ The program agrees with the lab's own optimization code to rounding error, and its solved plans
33
+ to solver tolerance. Controllers with virtual states and non-flat configuration spaces are not
34
+ supported yet.
35
+ - `optimization.Equilibrium(q0)`: the closed loop at rest, as a static problem. It takes the place of
36
+ `Collocation`: the unknown is a configuration where the controller's torques balance the
37
+ robot's own forces, found with the free Params, and the terms see it as their one node.
38
+ `Cost` and `Effort` count it once, and a `Bound` holds there. The tutorial finds where the
39
+ soft arm rests, in milliseconds.
40
+ - `Collocation(periodic=True)` plans an orbit that repeats: the last node equals the first (q and
41
+ v), the first node is free (`q0` and `v0` are only the solver's starting guess), and `Bound`
42
+ reaches it. `Collocation(free_time=(lower, upper))` makes the horizon an unknown within these
43
+ bounds, starting at `horizon`: the node spacing, the controller's time and the coordinates of
44
+ `vmc.Time()` are expressions of it, and `Effort` and `Cost` integrate with the horizon found.
45
+ The windows of the terms still read the nodes' times at the starting horizon. `Result.horizon`
46
+ is the horizon found (the given one for a fixed horizon, 0 for an `Equilibrium`) and
47
+ `Result.t` uses it; `warm_start` takes a `horizon`. `Trajectory.dt` is a number or an
48
+ expression of the free horizon, and `Trajectory.times` and `Trajectory.horizon` are the same,
49
+ for terms of your own. `optimization.Period(param)` holds the horizon equal to a Param, so that
50
+ a controller whose reference is a function of `vmc.Time()` and that Param (a period, free or a
51
+ parameter) repeats with the orbit. Neither option goes with an `initial` controller. Both
52
+ schemes work.
53
+ - Docs: tutorial "Optimizing a virtual mechanism".
54
+ - Docs: the optimization tutorial finds the period of a mass on a spring, and the least-effort
55
+ period of a pulled one with a controller that keeps time, against their closed forms.
56
+ - Docs: the optimization tutorial plans the soft arm around a sphere (`Bound` on `SphereDistance`),
57
+ checks the clearance in simulation, and shows that two sets of scales give the same plan.
58
+ - `vmc.sim.rollout(system, q0, T, dt)`: the closed loop simulated in one compiled call
59
+ (`mapaccum`), differentiable with respect to the controller's live Params, with the robot
60
+ integrated by `"implicit"` (the default, as `ModelPlant`), `"rk4"` or `"cvodes"`;
61
+ it reproduces `vmc.sim.run` to rounding error. `vmc.sim.ode(system)` is the closed loop in
62
+ continuous time, f(t, x) for SciPy's `solve_ivp`.
63
+ - `vmc.control.Tank(controller, level, capacity)`: an energy budget for changing a running
64
+ controller. `tank.set(values)` applies a change of live Params as far as the tank can pay for
65
+ the exact jump it gives the controller's energy (the largest fraction of the step that fits);
66
+ a step that releases energy is applied whole, even with an empty tank, and refills it.
67
+ `result.apply(tank)` passes an optimizer's result through it. `VMCController.jump(values)`
68
+ gives the jump `set` would give, without applying it.
69
+ Run in place of the controller (`vmc.sim.run(plant, tank, ...)`), the tank also refills itself
70
+ with what the controller's own dampers take at every step.
71
+ - `identification.fit_stiffness_damping` takes a run log (`RunLog`) as it is, or a mapping whose motor
72
+ torques are `motor_torque` or `u`.
73
+ - `identification.Steps(baseline, pulls, held_out, hold, rest)`: the step experiment as a controller
74
+ that runs on any plant. Every motor gets the baseline torque, and each pull adds a torque to some
75
+ motors for `hold` seconds, with `rest` seconds at the baseline between them. Its log marks the
76
+ training steps (`train`), which the fit uses as they are; the held-out ones are for validation.
77
+ - `fit_stiffness_damping(..., friction=True)` adds a static friction torque per motor, F sign(θ̇),
78
+ to the fit and returns it after K and D (`K, D, F`). Friction that is not in the fit passes for
79
+ damping. A motor that stands still has none in the model, so a run that stops at the end of every
80
+ step hardly shows it: use one that keeps the motors moving.
81
+ - `identification.validate(model, run)`: simulates a robot with its stiffness and damping under the
82
+ logged torques of the held-out steps of a run, from the state the run is in at the first of them,
83
+ and returns the root-mean-square error and the variance accounted for of each coordinate.
84
+ `vmc.sim.rollout` takes `u`, motor torques with a row per step, to simulate open loop.
85
+ - Docs: the hanging arm's page identifies its stiffness and damping with `Steps`, checks them on
86
+ held-out steps and shows the friction option.
87
+ - `identification.fit_transmission(motor, joint)`: the joint angle per motor angle of a cable drive,
88
+ from a sweep of the joint, by least squares through the origin. It reproduces the finger's and
89
+ the hand's transmission constants from their recorded sweeps. The finger's page shows it.
90
+ - `vmc.adaptation`: laws that change a running controller's live Params, a step at a time. Every
91
+ `step` returns the jump of the controller's energy [J] that was applied, and a `Tank` passed in
92
+ place of the controller applies only the part it pays for. A new value stays within the Param's
93
+ bounds (a stiffness stops at zero), and a square matrix stays symmetric and positive
94
+ semidefinite (`control.project_psd`).
95
+ - `ForceTracking(controller, site, params, normal=None, max_force_step=0.01, max_step=None,
96
+ rate=None)` descends the error of a contact force: `params` are glob patterns of live Params
97
+ (a spring's goal or its stiffness), `normal` keeps the force along it. The gradient is exact,
98
+ by automatic differentiation of the delivered torque, and agrees with the lab's hand-derived
99
+ one to 1e-8 for the goal and the stiffness, at the tip and mid-arm, along a normal and in 3D,
100
+ also where the point's Jacobian has rank below 3 (the two-motor finger). A step is the largest
101
+ that changes the force by `max_force_step` [N] (the lab finds it by a finite-difference probe
102
+ and agrees to 1e-5), or `rate`, a fixed learning rate as in the finger's experiments, where
103
+ it agrees with the lab's joint-space stiffness and reference descent at the lab's rates.
104
+ `direction` gives the descent direction without applying it.
105
+ - `ForceRatio(controller, params, max_change=0.05)` and `Stiffening(controller, params, low,
106
+ high, alpha)`: the laws of the lab's hand and finger that need no model. The first scales
107
+ stiffnesses by 1 plus or minus `max_change` times the relative error of the force (the hand's
108
+ multiplicative law); the second sets k(F) = low + (high - low)(1 - exp(-alpha F)) from the
109
+ measured force (the finger's law). Both equal the lab's. K(d) is the `SigmoidSpring` and the
110
+ `PolynomialSpring`.
111
+ - `StiffnessTracking(controller, site, params, normal=None, robot=None, fraction=1.0)`: direct
112
+ stiffness tracking. The stiffness at the site is affine in the springs' stiffness, so `target`
113
+ solves a linear system for the Params that give a wanted matrix, the solution of smallest
114
+ norm as in the lab's inversion, and `step` goes `fraction` of the way. Where no spring pulls
115
+ it agrees with the lab's inversion to 1e-6; where they do, it counts the geometric terms
116
+ that the lab's leaves out.
117
+ - `PositionRegulation(controller, sites, gain=0.05)`: integral pose regulation. A step adds
118
+ `gain` times the error of a point of the robot to the goal of the spring that pulls it.
119
+ - `HoldingGoals(controller, sites, robot=None)`: the open-loop counterpart, the lab's position
120
+ feedforward. It puts the goals at wanted positions (default: where the points are) plus the
121
+ smallest offset that lets the springs carry the robot's own stiffness and weight at the pose
122
+ now, one Newton step on the static balance. It agrees with the lab's to 1e-9; with as many
123
+ springs as motors the arm then stays where it is.
124
+ - `vmc.estimation`: quantities of a running robot that no sensor measures. Both take the
125
+ controller, a site (a name, an arc parameter or `(part, s)`) and a `normal`, and a `robot`:
126
+ the model that holds the arm at rest, without the surroundings the plant may have. They use the
127
+ controller's law before the output stages, the system's transmission and efficiency, and leave
128
+ velocities out.
129
+ - `ContactForce(controller, site, normal=None, robot=None)`: the force a robot exerts at a site
130
+ at rest. What the delivered motor torques and the robot's own stiffness and weight do not
131
+ balance goes through the site's Jacobian by the pseudo-inverse. It agrees with the lab's
132
+ contact force from the virtual springs and the structural stiffness (the efficiency on the
133
+ springs' term only) to 1e-9, with its torque-based variant, and with the finger's. A fingertip
134
+ at rest on a simulated table reads the table's force to 2 %.
135
+ - `TaskStiffness(controller, site, normal=None, robot=None)`: the stiffness [N/m] at the site, a
136
+ 3 by 3 matrix. It is the stiffness of the static balance, by automatic differentiation, with
137
+ the geometric terms (the Hessians of the site and of the springs) counted, and agrees with
138
+ the lab's exact apparent stiffness to 1e-8. The lab's first-order version leaves the
139
+ geometric terms out and is not provided.
140
+ - `KalmanFilter(system, dt, Q=None, P0=None, gate=40.0, robot=None)` and `Measurement(q, v, Rq,
141
+ Rv, observed, name)`: a Kalman filter of the robot's state (q, v). Its process model is the
142
+ robot's own dynamics, linearised at the estimate at rest and held over the step (the lab's
143
+ frozen mass matrix, in general form), with the command going through the system's
144
+ transmission. It fuses encoders (`kf.encoder`) and any sensor that sees part of the state,
145
+ gates each measurement on its innovation, and reports the sensors it rejected (`rejected`,
146
+ `rejected_total`) and the expected ones that offered nothing (`missing`). Over a run with
147
+ dropouts and an outlier of each sensor it agrees with the lab's filter in its state to 1e-9,
148
+ its covariance, its innovation distances and the sensors it rejects.
149
+ - `Inversion(robot, at, damping, tol, max_iter)`: the configuration that puts the robot's points
150
+ `at` where a position sensor saw them (motion-capture markers), by damped Gauss-Newton from the
151
+ last result, for any robot. It agrees with the lab's closed form for the three-section arm
152
+ to 1e-8, and finds the soft arm from its neutral configuration up to 0.6 rad of bend in each
153
+ section (give `q0` beyond). `VelocityFilter(dt, alpha=0.3)`: the low-passed difference of
154
+ consecutive samples, the lab's velocity of the markers, with `dt` the sensor's own period.
155
+ - `ImuFilter(arm, mounts, kp, acc_tol, gravity)`: the curvature (Dx, Dy) of each section of a
156
+ soft arm and its rate from an IMU on its base and on each section end, by a complementary
157
+ filter of each section's relative rotation (the gyros turn it, the gravity both accelerometers
158
+ see corrects it, and it is kept on the rotations the arm can make). `calibrate` takes the
159
+ gyro bias and the starting pose from the arm held still. Its `observed` coordinates go to
160
+ `Measurement`. It agrees with the lab's filter to 1e-10 over a run with accelerometers that
161
+ cannot be trusted.
162
+ - `VMCController.inputs()`: the vector the law reads, with the live Params as they are now.
163
+ A Param that acts only through a virtual state does not change the force at once, and the
164
+ laws leave it.
165
+ - Docs: the tutorials "Track a contact force" (the laws, the estimate without a sensor, the tank)
166
+ and "Shape the stiffness of the tip"; the finger's page presses between two force levels; the
167
+ two arms' page holds an object with a chosen force, with estimates alone, with a sensor on the
168
+ object, and through a tank (the object feels the wanted force to 0.2 % from the estimates).
169
+ - `vmc.Gated(component, gate)`: an element whose force and energy are multiplied by a live Param
170
+ `gate` between 0 and 1. `optimization.Sparsity(weight, *patterns)` adds the sum of the free Params
171
+ that match (each at least 0) to the cost. With the gates free, the optimizer keeps the elements
172
+ that earn their place: structure optimization, tested on a mass with three springs and on the
173
+ soft arm with five repulsive fields, and shown in the optimization tutorial ("Which fields to
174
+ keep").
175
+ - `vmc.models.FunctionModel(frame, space, params, sites, q_unit)`: a kinematic model from a function
176
+ `frame(q, at, p)` that returns the rotation and the position of a site, as CasADi values or as
177
+ lists and arrays. It works in `Kinematics`, mechanisms and `check_model`; a function cannot be
178
+ written to a file, so it has no `to_dict`.
179
+ - `vmc.testing.check_model(model)`: the model contract in one call, for a kinematic model or a
180
+ robot's mechanism: everything finite (also with each Param a tenth of its default and ten times
181
+ it), orthonormal rotations, Jacobians, angular Jacobians and Hessians against finite
182
+ differences, no jump along the arc parameter `s`, `to_dict` and `from_dict` giving the model
183
+ back, and, for a robot with masses and no dampers, an energy drift that falls with the step. It
184
+ raises an `AssertionError` that lists the failed checks and returns the worst error of each. The
185
+ tutorials "Build your own robot" and "Extend the library" use it.
186
+ - `vmc.BoxDistance`, `CapsuleDistance` and `CylinderDistance`: signed distances from a point to a
187
+ box with its sides along the axes, a capsule and a cylinder, for contacts and obstacles, with the
188
+ same Params as `SphereDistance` (and the kinds `box_distance`, `capsule_distance` and
189
+ `cylinder_distance` in configuration files). The contact tutorial uses the cylinder.
190
+ - `vmc.ContactFriction(distance, stiffness, friction)`: Coulomb friction at a contact, smoothed. It
191
+ pushes a point against its sliding speed along the surface, with the size of the friction
192
+ coefficient times the contact spring's force (give it the spring's stiffness `Param`), and falls
193
+ linearly below the small speed `speed`, so a point at rest creeps. It works on every signed
194
+ distance, which now share the base class `SurfaceDistance` with a `unit_normal`; the type is
195
+ `contact_friction` in configuration files. The contact tutorial drags a fingertip along a table.
196
+ - `vmc.sim.run(..., record="robot")` logs what a simulated robot feels, component by component:
197
+ `robot/<name>/y`, `ydot`, `force` and `torque` of each spring, damper and contact, from
198
+ `ModelPlant.elements()` (and `Dynamics.elements`). A real robot reports no forces, so recording
199
+ it raises an error.
200
+ - `vmc.estimation.Encoders`, `Markers`, `Imus` and `LoadCell`: simulated sensors, the true state in
201
+ and a noisy reading out, as the estimators take it. The encoders read the motors through the
202
+ transmission, with noise and a constant slack per motor; the markers, the positions of points of
203
+ the arm; the IMUs, the angular velocity and gravity in each frame's own axes, with a constant gyro
204
+ bias; the load cell, a force with a bias and noise. Every one has a seed. The estimation tutorial
205
+ uses them in place of the lines it wrote by hand.
206
+ - `vmc.adaptation.DitherSeeking(controller, params, amplitude, frequency, gain, window)`: extremum
207
+ seeking from the cost alone, the two-tone law of the turtle paper. Each scalar live Param is held
208
+ at an estimate plus a sinusoidal dither at its own frequency (2π n / `window`, a whole n each, so
209
+ that the tones are orthogonal); the cost's correlation with a tone over the window is the slope
210
+ with respect to that Param, and the estimate moves downhill at `gain` times it, at most
211
+ `max_rate`, within the Param's bounds. On a `Tank`, the changes are paid from its energy, which is
212
+ the paper's passivity cap. The crawl tutorial lets the crawler find its best `peak` this way.
213
+ - `turtle.controller(robot, depth=, peak=, steer=, limit=)`: with any of them the cranks' springs
214
+ are `PhaseSpring`s (the paper's phase-modulated, saturating potential); without, they are the
215
+ plain ones of the lab's controller, as before.
216
+ - `vmc.optimization.MovingHorizon(system, dt, window=10, Q=, P=)`: moving-horizon estimation of a
217
+ robot's state (q, v). Every step finds the states of the last `window` steps that best agree
218
+ with the sensors' readings (the same `Measurement`s as the Kalman filter's), with the robot's own
219
+ dynamics up to the process noise `Q`, and with the state before the window, which goes one step of
220
+ an extended Kalman filter whenever the window slides. It is solved by Gauss-Newton with a trust
221
+ region. With a linear robot it is the Kalman filter, to rounding error, however short the window;
222
+ it also gives `cost` and the covariance `P`. The estimation tutorial runs it on the soft arm.
223
+ - `vmc.identification.fit_params(robot, names, runs)`: any Params of a robot, by name or glob,
224
+ fitted to logged runs by least squares on the residual of its own dynamics, within the Params'
225
+ bounds. A residual linear in the Params (masses, stiffnesses, dampings, efficiencies) is solved
226
+ in a step, and any other, such as the saturating damper's, by Gauss-Newton. It returns the values
227
+ in each Param's shape, their standard errors and the residual's root mean square. A run with
228
+ an `a` uses it, and otherwise the acceleration is the smoothed velocity's difference against the
229
+ torques averaged over the step they were held. It agrees with ordinary least squares, values and
230
+ covariance, on a mass, spring and damper. The tutorial "Fit Params to a run" uses it.
231
+ - `KalmanFilter(..., unscented=True, substeps=10)`: the prediction sends sigma points of the
232
+ estimate (the scaled unscented transform, a root of three standard deviations out) through the
233
+ robot's own integrator, in `substeps` steps, instead of linearising at the estimate; the sensors
234
+ stay linear, so the update is the same. On a double pendulum it follows the mean of a Monte
235
+ Carlo to 0.003 where the linearised prediction is off by 2; on a linear robot the two agree.
236
+ - `vmc.estimation.MomentumObserver(system, dt, gain, robot=None)`: the external force on a robot
237
+ from its motion, without accelerations. From the momentum and what the model says would change
238
+ it, it gives the generalized force the model does not explain, as a low-pass filter of bandwidth
239
+ `gain` of the true one, and `force(site, normal)` carries it to a site, as `ContactForce` does.
240
+ It works while the robot moves, where `ContactForce` assumes rest. The force tutorial shows a
241
+ finger landing on a table. Its velocity must be the rate of its configuration (no floating
242
+ bodies yet).
243
+ - `vmc.estimation.object_compliance(position, force, baseline_position, baseline_force)`: the
244
+ compliance in m/N of an object a tip presses, the distance over the force that stiffer settings
245
+ of the controller add to a gentle one, from the median of each setting's samples. It is the
246
+ lab's probe of the hand, and it agrees with the lab's code to rounding error. The force tutorial
247
+ shows it on three objects, with the force from `ContactForce`.
248
+ - Docs: the contact tutorial also shows two points of a robot touching (a self-contact, the two
249
+ arms), friction between two points and a soft object between two tips, from the pieces above.
250
+ - `vmc.control.project_psd(K)`: the symmetric positive semidefinite matrix nearest to a stiffness,
251
+ for an update that an adaptation law proposes, before it goes through `set` or a tank.
252
+ - `vmc.sim.energy_balance(log)`: the controller's energy over a run recorded with
253
+ `record=["energy"]`: its energy, the work given through its port, what its dampers took and its
254
+ sources gave, `injected` (what changes of live Params put in, plus the error of the steps) and
255
+ the `margin` it can still give, which stays above 0 while the controller is passive.
256
+ - `vmc.optimization.Grid`, `Random`, `CMAES`, `ExtremumSeeking` and `Bayes`: gradient-free tuning by ask and tell
257
+ (`ask()` gives candidates, `tell(candidates, costs)` takes their costs), `tune` to run it, and
258
+ `bounds_of` for the bounds and values of named Params. `Bayes` fits a Gaussian process to the
259
+ costs seen so far and asks for the candidate with the highest expected improvement: it suits
260
+ slow episodes, tens of them. The episodes are yours, in simulation or on a robot in your own loop.
261
+ - `compile_dynamics(robot, runtime, actuation)` takes the actuation of a robot that has none, so a
262
+ system's efficiency Params (`robot.efficiency.c1`) are the ones the dynamics read.
263
+ - `vmc.math`: rotations and rigid transforms that run on numpy arrays and CasADi symbols alike
264
+ (`rot_x`, `rot_y`, `rot_z`, `rot`, `skew`, `vee`, `exp_so3`, `log_so3`, `transform`, `invert`,
265
+ `exp_se3`, `log_se3`, `adjoint`), for writing the `frame` of a `FunctionModel`. Every function
266
+ is smooth at the identity, also in its second derivatives (the exact forms lose them there).
267
+ They replace the three rotation helpers of `core.symbolic`.
268
+ - `SerialChain` joints: `"helical"` (a turn that slides by a pitch, given as `("helical", pitch)`),
269
+ `"spherical"` (three coordinates, a rotation vector about the joint's point) and `"free"` (six:
270
+ a translation and a rotation vector, a floating base). A chain on a free base, a brick of point
271
+ masses thrown with a spin and its momenta and energy are tested; a branch of a tree is a part
272
+ mounted on a site of another part by `Assembly`.
273
+ - `SerialChain` joint `("rail", waypoints)`: a slide along the natural cubic spline through the
274
+ waypoints, which are a `design` Param (an array of rows of three) in the frame of the joint
275
+ before it. Its coordinate is the spline parameter, 0 at the first waypoint and 1 at the last. It
276
+ agrees with SciPy's natural spline, and a bead on a circular wire swings as a pendulum.
277
+ - `SerialChain` joint `"floating"`: a floating base whose rotation is a unit quaternion, with
278
+ seven coordinates and six velocities (the translation's and the body's angular velocity in its
279
+ own axes). `vmc.Quaternion` is its space, and `Space.coadjoint` gives the term that
280
+ velocities that do not commute add to the dynamics (the Euler-Poincare term), which
281
+ `compile_dynamics` now includes. A body tumbles about its intermediate axis through several
282
+ full turns by Euler's equations, and a base with an arm keeps its momenta and energy.
283
+ - `vmc.FramePoint(model, site, q=coordinate)`: a point of a virtual model, at the configuration
284
+ that `coordinate` gives: a virtual state (a cart on a rail with a mass of its own), a
285
+ reference, or a function of time. `vmc.Time()` is the time of the run, to build functions of
286
+ time with `Custom`; a damper on the difference to such a goal feels its velocity.
287
+ - More coordinates: `vmc.Sum` (and the plus sign: `tip + [0, 0, 0.05]`), `vmc.FrameRotation` (a
288
+ frame's rotation matrix, row by row), `vmc.OrientationError(model, site, goal=)` (the rotation
289
+ vector from a goal orientation to a frame's, in the goal's axes, with `goal` a live Param; a
290
+ spring on it is a rotational spring whose torque is exact at any error, where the one from the
291
+ angular Jacobian is 8 % off at 0.4 rad), `vmc.InFrame` and `vmc.FromFrame` (a vector along the
292
+ axes of a frame, and back: a stiffness along the tool's axes turns with the tool). They take a
293
+ site or an arc parameter, and a virtual model through `q=`. Configuration files build them as
294
+ `sum`, `rotation`, `orientation_error`, `in_frame` and `from_frame`.
295
+ - More components: `vmc.RotationalInertia(rotation, inertia)`, the inertia of a rigid body about
296
+ its frame (a matrix, or three principal moments) on the frame's rotation matrix, next to a
297
+ `PointMass` for its mass: it follows Euler's equations, moves like the same body made of point
298
+ masses to rounding error, and a rotational spring on it oscillates at the square root of K over
299
+ I. `vmc.DiodeDamper(y, D, sign, smoothing)` damps one direction of motion only.
300
+ `ForceSource(y, f, max_force=, max_power=)` bounds the force smoothly, and the power it
301
+ delivers. `Mechanism.add_mass_along(name, mass, s0, s1, n)` spreads a mass along a model as
302
+ point masses at the nodes of Gauss-Legendre quadrature. An `Inertance` on a difference is an
303
+ inerter, tested.
304
+ - Docs: "A spring on the tool's orientation" and "A spring along the tool's axes" in "Kinematics on
305
+ the UR5"; "A damper that works one way" in "Coordinates and components"; a rigid body and the
306
+ mass along an arm in "Build your own robot".
307
+ - Docs: the tutorial "Estimate the state of a soft arm" (encoders with slack, markers and IMUs
308
+ fused by the filter, an outlier and lost frames); "A rail along a path" and the floating joint
309
+ in "Build your own robot"; "A cart on a rail" in "Coordinates and components".
310
+ - `vmc.PhaseSpring(coord, stiffness, depth, peak, steer, side, limit)`: a spring on a deflection e
311
+ whose stiffness follows a phase, on the coordinate `Stack(e, phase)`: K (1 + side steer) (1 +
312
+ depth cos(phase - peak)). Its force is minus the gradient of its energy, so the phase feels the
313
+ reaction that keeps a flywheel loop passive. With `limit` the potential saturates, and the torque
314
+ never goes above K (1 + |steer|) times the limit. With no depth, no steer and no limit it is a
315
+ `LinearSpring`. The type is `phase_spring` in configuration files.
316
+ - `vmc.models.Passive(nv)`: an actuation with no motors, for a part that nothing drives, such as a
317
+ floating body. Stacked with the other parts' motors (`Assembly.stacked_actuation`), the motor
318
+ vector holds only theirs, so a simulated robot can have more coordinates than motors. The motors
319
+ do not give a passive part's configuration, so a controller is compiled against a robot without
320
+ it, and the simulator runs the one with it.
321
+ - `robots.turtle.crawler(**CRAWLER)`: a simple crawler for the simulator, with placeholder
322
+ constants, not the lab's turtle: a floating body on the ground with gravity, two cranks about its
323
+ lateral axis with a foot each, and a contact spring, damper and friction at each foot and at the
324
+ four corners of the underside. Its motors are the two cranks, in the gait convention of
325
+ `turtle.robot()`, which is what the controller is compiled against. Under the flywheel controller
326
+ it crawls forward, further the faster the flywheel is driven, and does not advance without
327
+ friction; a positive steer of `PhaseSpring` turns it left. Docs: the tutorial "Crawl with a
328
+ flywheel".
329
+
330
+ ### Removed
331
+
332
+ - `vmc.ros` (`RosPlant`, `control`, `serve`, `LiveParams`, `JointIO`, `TOPICS`) and the direct
333
+ Dynamixel path (`hardware.DynamixelPlant`, `home`, `present_ticks`, `scan`, `latency_timer`,
334
+ `Bus`, `SdkBus`, `FakeBus`), deprecated in 0.3.0. The library is communication-agnostic: it
335
+ turns measurements into torques, and how they reach the robot stays outside it. The Dynamixel
336
+ SDK and pyserial are no longer dependencies, and CI no longer runs the ROS tests. Hardware
337
+ profiles (`HardwareProfile`, `Motor`, `KT`, `MODES` and each robot's `hardware` template) stay.
338
+ A project that still uses a removed name keeps `virtualmodelcontrol==0.3.0`.
339
+ - `vmc.interactive` (the window, the keyboard, the joystick, the session, the mailbox, the wrapper
340
+ and the recorder), the `joystick` extra and `SimClock`'s `speed`, `now` and `sleep`: the library
341
+ is for control, not for interfaces. A running controller still changes through
342
+ `controller.set`, schedules and swaps. A project that uses them keeps `virtualmodelcontrol==0.3.0`.
343
+ - From the hardware profiles, the raw Dynamixel units (encoder ticks, velocity units, goal
344
+ currents, motor constants `kt` and the `KT` table, baud rate, serial port, velocity filter, home
345
+ ticks, per-motor torque limits and operating modes). A `Motor` is now `Motor(id, sign, hold)`
346
+ and a `HardwareProfile` `(motors, rate, bus_order)`, with the conversions between a driver's
347
+ degrees, bus order and signs and the library's SI units.
348
+
349
+ ## [0.3.0] - 2026-10-05
350
+
351
+ ### Added
352
+
353
+ - `vmc.config`: experiments in YAML files. `vmc.config.load` reads the robot (a template and its
354
+ arguments), named coordinates, the controller's elements (a registered component `type`, the
355
+ `coordinate` it acts on, its gains), controllers to swap to, and how to run them: a simulation
356
+ (with the robot's dynamics and simulated elements such as contacts), the rate, the duration,
357
+ output stages, schedules and the initial virtual state.
358
+ `Experiment.run` runs it, `save` writes it back with the Params' current values. Robot
359
+ templates, output stages and coordinate kinds are registry entries, so a project adds its own.
360
+ An experiment from a file gives the same run as the same experiment written in Python.
361
+ - `vmc.control.Schedule` and `ScheduledController`: live Params that follow values over time
362
+ (in straight lines or steps) and swaps at given times; a new run starts afresh. The lab's
363
+ linear ramps are two-point schedules.
364
+ - `vmc.sim.run(..., z0=...)` also takes a function of the first reading, such as
365
+ `turtle.initial_state`.
366
+ - Docs: tutorial "Experiments in files".
367
+ - Run logs. `vmc.sim.RunLog` saves a run whole or not at all (`save`: a compressed `.npz` with a
368
+ schema version and what the run was, in `meta`: the library's version, the start time, the
369
+ Params at the start, the plant's hardware profile and, from a configuration, the
370
+ configuration; written through a temporary file, and a name already taken is refused unless
371
+ `overwrite=True`), loads it back (`load`) and exports CSV (`to_csv`, one column per entry).
372
+ `step` adds one step and keeps every signal at one row per step, with NaN for what a step
373
+ did not compute.
374
+ - `vmc.sim.replay` sends a log's motor torques again to a simulated robot, each held for as long
375
+ as it was in the run, from the log's `q` and `v` or, for a real robot's log, from its first
376
+ motor reading (`ModelPlant.state_from_motors`); `vmc.sim.compare` gives the largest and the
377
+ root-mean-square difference of each signal of two runs. A replay on the true model gives the
378
+ run back.
379
+ - A run's log holds `law_torque`, the controller's torque before the output stages.
380
+ `vmc.sim.run(..., record=...)` adds the live Params (`"params"`), each element's coordinate,
381
+ rate, force and share of the motor torques (`"elements"`), and the controller's energies and
382
+ powers (`"energy"`), from `VMCController.elements()` and `balance()`.
383
+ - Configurations: `experiment.run` settings (`name`, `folder`, `overwrite`, `record`) save each
384
+ run beside the file and refuse a name already taken before the run starts.
385
+ - Docs: tutorial "Run logs".
386
+ - `vmc.interactive`: change a running controller by hand. `Controls` is a thread-safe mailbox
387
+ for new values of live Params and for swaps. `Interactive` wraps any controller and applies
388
+ what the mailbox holds just before each step, in a simulation or inside a robot's own node;
389
+ the changes act exactly as `controller.set` before the step, and it counts the energy they give
390
+ the running controller (`injected`). `Recorder` turns what was applied into `schedule` entries
391
+ with `step` interpolation and saves them into a configuration, which repeats the session
392
+ exactly. `Window` (matplotlib, no new dependency) draws the robot live, with goals to drag,
393
+ sliders, buttons to swap controllers, record and pause; `Keyboard` and `Joystick` (pygame, the
394
+ extra `virtualmodelcontrol[joystick]`) move a goal; `Session` runs a simulation in real time
395
+ in a worker thread with its window.
396
+ - `vmc.sim.SimClock(dt, speed=...)` paces a simulation to the computer's clock: with `speed`,
397
+ `run(T=None)` runs until stopped and Ctrl-C ends it with the log so far. Other simulations are
398
+ unchanged. `VMCController.live_params()` and `Experiment.z0()`.
399
+ - Docs: tutorial "Interactive control".
400
+ - Docs: tutorials "Real-time runs" (the loop on the computer's clock: measured steps, late steps
401
+ never caught up in a burst, old and missing readings, Ctrl-C, and a checklist for the first run
402
+ on a robot) and "Swaps and schedules" (the quintic blend and its continuity, a swap on the soft
403
+ arm, the schedules' interpolation).
404
+ - `vmc.ros.control`: the controller node. It runs a controller at the profile's rate on the
405
+ robot behind the driver's topics, with its live Params as ROS parameters, for a duration or
406
+ until Ctrl-C, and ends with zero torque.
407
+ - On real time (`WallClock`), `vmc.sim.run(..., T=None)` runs until Ctrl-C, and Ctrl-C ends
408
+ a real-time run with the log so far.
409
+ - CI runs the ROS tests in ROS 2 Humble and Jazzy containers, on a private domain.
410
+ - `vmc.control.SwapController` and `blend_weight`: one set of virtual elements replaces another
411
+ with a quintic blend of the two controllers' torques (continuous torque and first two
412
+ derivatives), the blend the lab's controller uses; a swap asked for during a blend waits for
413
+ it. `vmc.ros.control(..., swaps={name: controller})` swaps on a `String` message.
414
+ - `vmc.Efficiency`: the motor torque a transmission delivers, as a polynomial of the commanded
415
+ one, τ = c₁u + c₂u² + … + cₙuⁿ, each coefficient one value for every motor or one per motor.
416
+ The coefficients are `design` Params, to change, tune, keep live in a simulator or identify.
417
+ `Direct` and `TendonTransmission` take one, or a number for its linear coefficient.
418
+ - `vmc.identification`: `plateaus`, the settled end of every hold of a command in a log, and
419
+ `fit_efficiency`, a least-squares fit through the origin, motor by motor or shared, from
420
+ delivered torques or from one measured quantity with a weight per motor (a fingertip force,
421
+ say). Both agree with the lab's calibration code, and the fit gives the finger's
422
+ `adapt.MOTOR_EFFICIENCY` back from its recorded data.
423
+ - Docs: concepts pages "Transmission efficiency", "Virtual Model Control" (coordinates, forces,
424
+ the torques that realize them, virtual states), "Passivity" (the energy balances, stability,
425
+ what weakens it) and "Finger and hand kinematics" (motors to joints, joints to the
426
+ fingertip, the hand's couplings).
427
+ - The constrained elements as components of their own: `ConstrainedLinearSpring`,
428
+ `ConstrainedTanhSpring`, `ConstrainedGaussianSpring`, `ConstrainedLinearDamper` and
429
+ `ConstrainedTanhDamper` act along one direction (`normal`) only, leaving the plane normal to
430
+ it free. They give the forces of the lab's constrained elements, checked against them; the
431
+ tanh ones saturate along the normal rather than axis by axis.
432
+ - `vmc.identification.fit_stiffness_damping`: a robot's diagonal stiffness and damping from
433
+ logged runs under known motor torques, by least squares with K, D ≥ 0 in motor torques,
434
+ relative to a resting baseline, with the robot's masses and gravity known; each run can carry
435
+ its own gravity. It recovers the stiffness and damping of a simulated arm within a few percent.
436
+ - Docs: two single-arm examples, each about its own arm and its own experiments. The soft arm on
437
+ its side (`145-145-145`) reaches past an obstacle with two repulsive fields, over a sweep of
438
+ their strength, and a tanh spring limits the force on a string tied to the tip. The hanging
439
+ arm (`145-290-290`) is identified from simulated step responses with
440
+ `fit_stiffness_damping` and reaches around an obstacle with a tanh spring and two fields.
441
+ Both use the same stiffness and damping. The tutorials, the home page and the README use the
442
+ arm on its side; the Helyx geometries and the parametric template are on the soft-arm
443
+ kinematics page.
444
+
445
+ ### Changed
446
+
447
+ - Every robot's efficiency is 1 by default: models identified from the commanded torques
448
+ already include their transmission. The soft arm and the two arms take each torque as the
449
+ controller sends it again, with `helyx.SIM_STIFFNESS`, `helyx.SIM_DAMPING`,
450
+ `bimanual.STIFFNESS` and `bimanual.DAMPING` referred to the commanded torque (the identified
451
+ values divided by the 0.12 they were fitted with), as in 0.1.0. 0.2.0 applied 0.12 to every
452
+ torque with physical stiffness and damping: the same equilibria without gravity, but natural
453
+ frequencies about 2.9 times lower and a gravity compensation that cancelled only 12 % of the
454
+ weight. `helyx.EFFICIENCY`, `bimanual.EFFICIENCY`, `adapt.MOTOR_EFFICIENCY` and
455
+ `adapt.HAND_MOTOR_EFFICIENCY` stay as calibrations, never as defaults.
456
+ - A transmission's efficiency Param is now `efficiency.c1` (and `c2`, … for a polynomial);
457
+ transmissions saved by 0.2.0 still load.
458
+ - `import virtualmodelcontrol` no longer loads SciPy, which took about three quarters of its
459
+ import time; `identification.fit_stiffness_damping` loads it when called.
460
+ - Docs: the opening page has no left index (the pages of the five sections keep theirs) and
461
+ leads to the concepts and the reference. Installation: the conda recipe takes Python from
462
+ conda-forge, because conda's default channels stop a new installation until Anaconda's terms of
463
+ service are accepted, and shows how to keep ROS's `PYTHONPATH` out of a conda environment, where
464
+ pip otherwise ends with an error about ROS's packages and skips the ones ROS also ships.
465
+
466
+ ### Deprecated
467
+
468
+ - `vmc.ros` (`RosPlant`, `control`, `serve`, `LiveParams`, `JointIO`, `TOPICS`) and the direct
469
+ Dynamixel path (`hardware.DynamixelPlant`, `home`, `present_ticks`, `scan`, `latency_timer`,
470
+ `Bus`, `SdkBus`, `FakeBus`) warn when used, and leave in 0.4.0 together with the Dynamixel SDK
471
+ and pyserial dependencies and the ROS CI job. The library is communication-agnostic: it turns
472
+ measurements into torques, and how they reach the robot stays outside it. Hardware profiles
473
+ (`HardwareProfile`, `Motor`, `KT`, `MODES` and each robot's `hardware` template) stay. Python
474
+ shows a `DeprecationWarning` only for code run as a script or in a notebook; run a node with
475
+ `python -W default` to see them there.
476
+
477
+ ### Fixed
478
+
479
+ - `vmc.sim.run` needs only the plant's documented methods: when its guard trips, it sends zero
480
+ torque without reading the plant's last command `u`, which a plant of one's own may not have.
481
+ The zero command has one torque per motor rate, also on real time.
482
+ - `vmc.ros` is available after `import virtualmodelcontrol as vmc`, like `vmc.viz` and
483
+ `vmc.hardware`; it imports ROS only when a ROS class is first used.
484
+ - The hand example grasps the ball with the pads of the thumb, index and middle fingers: the
485
+ ball sits where the thumb opposes the fingers, and the grasp takes the thumb's tip at the end
486
+ of its last phalanx. Before, the thumb pressed on the ball with its side. The template's
487
+ kinematics are unchanged.
488
+ - Figure labels written as math where the figure font has no glyph (N·m on the efficiency
489
+ page); a test keeps figure text to characters the font draws.
490
+
491
+ ## [0.2.0] - 2026-10-04
492
+
493
+ ### Added
494
+
495
+ - Every dependency installs with the package: numpy, SciPy, CasADi, matplotlib, PyYAML, the
496
+ Dynamixel SDK and pyserial. CI runs on Ubuntu 22.04 and 24.04, with a clean-install job.
497
+ - Robot templates: `robots.bimanual` (two Helyx arms on one frame, with their identified
498
+ stiffness and damping and the transmission efficiency 0.12), `robots.adapt.hand` (five digits,
499
+ 13 motors, spread coupling, masses and joint limits), `robots.turtle` (two cranks and the
500
+ virtual-flywheel controller), `robots.ur5` (from DH parameters) and `ur5.with_hand()`.
501
+ - Every template is parametric in its geometry, with today's values as defaults:
502
+ `helyx.arm(lengths=..., section_radius=..., spool_radius=..., tendon_angles=..., masses=...)`
503
+ for any number of segments; `bimanual.arms(lengths=..., tendon_angles=...,
504
+ base_positions=..., efficiency=...)`, each one for both arms or by arm;
505
+ `adapt.finger(link_lengths=..., link_masses=..., link_cogs=..., joint_axes=...,
506
+ motor_radius=..., pulley_radius=..., pip_transmission=...)` and `adapt.finger_coupling`;
507
+ `adapt.hand(...)` and `ur5.with_hand(...)`, which replace any entry of the hand's geometry
508
+ tables by key (`tip_offsets={"thumb": ...}`), with the hand's mounting position on the
509
+ flange; `ur5.arm(d=..., a=..., alpha=...)`; joint-limit springs with custom ranges; output
510
+ stages and `add_dynamics` sized to the arm.
511
+ - `vmc.Kinematics`: positions, rotations, Jacobians, angular Jacobians and Hessians of any site,
512
+ from configuration or from motor angles.
513
+ - `models.JointSpace` for robots described by their joints only; `SerialChain.from_dh` and site
514
+ rotations; `Assembly` parts mounted on another part's frame.
515
+ - `TendonTransmission(efficiency=...)` and `Direct(efficiency=...)` (one value or one per
516
+ motor): the robot receives the commanded torque times the efficiency. `adapt.finger`,
517
+ `adapt.hand` and `ur5.with_hand` take `efficiency=...` and stay lossless by default: the
518
+ measured `adapt.MOTOR_EFFICIENCY` and `adapt.HAND_MOTOR_EFFICIENCY` are static calibrations for
519
+ force estimates, and unequal efficiencies on coupled motors make virtual elements
520
+ non-conservative in simulation.
521
+ - `SpeedRegulator`: drives a virtual state at a commanded speed, with a ramp.
522
+ - `control.output`, opt-in output stages for real hardware: `FrictionCompensation`,
523
+ `Pretension`, `TorqueOffset`, `TorqueLimit`; each template's own stage
524
+ (`helyx.output_stage()`, `bimanual.output_stage()`, `adapt.output_stage()`,
525
+ `adapt.hand_output_stage()`).
526
+ - `vmc.viz`: the lab figure style (`use_style`, `save` as PDF and SVG) and drawing helpers
527
+ (`draw_robot`, `draw_spring`, `draw_damper`, `draw_frame`, `draw_force`, `draw_goal`,
528
+ `label_axes`). `vmc.viz` is available after `import virtualmodelcontrol as vmc` and loads
529
+ matplotlib only when first used.
530
+ - `vmc.viz.animate`: an animation of a run (the robot, springs to fixed points, the path of a
531
+ site, anything else through a callback), saved as MP4, GIF or animated WebP. `imageio-ffmpeg`
532
+ is now a dependency, so MP4 works on every system.
533
+ - `vmc.sim.run(..., z0=...)` starts the controller from a given virtual state, and the run log
534
+ records the virtual state `z` when the controller has one.
535
+ - Contact as stiff one-sided springs: signed distances `PlaneDistance` and `SphereDistance`,
536
+ `ContactSpring` (optional smoothing for optimization) and `ContactDamper` (damps only in
537
+ contact); `adapt.add_dynamics` gives the finger and the hand their gravity for simulation.
538
+ - Documentation rebuilt for students: the Material layout (sections as tabs, the pages of each
539
+ section in the left sidebar), large type, the library's logo and navy colours;
540
+ installation and troubleshooting; tutorials (how it works, a first controller, coordinates
541
+ and components, parameters, energy, kinematics, tuning, contact, building a robot, extending
542
+ the library); an example per robot (soft arm, two arms, finger, hand and the UR5, turtle), each
543
+ opening with its robot's schematic and parameters; concepts (the library's structure, soft-arm
544
+ kinematics, conventions and glossary). Every figure, schematic, table value and animation is
545
+ computed when the documentation builds.
546
+ - `vmc.hardware.HardwareProfile`: the motors of a robot (bus ID, Dynamixel model, sign, mode,
547
+ motor constant, optional torque limit) in the library's motor order, with the bus settings;
548
+ conversions both ways between encoder ticks, raw velocities, goal currents and the published
549
+ degrees of a ROS driver and SI units, with commands clamped before the integer conversion so
550
+ they saturate instead of overflowing; saved and loaded as YAML. Each template has its
551
+ profile: `helyx.hardware()`, `bimanual.hardware()`, `adapt.finger_hardware()`,
552
+ `adapt.hand_hardware()`, `turtle.hardware()`.
553
+ - `vmc.hardware.DynamixelPlant`: a robot's Dynamixel motors as a plant through the Dynamixel
554
+ SDK, without ROS. It sets a safe goal before each motor's torque goes on, takes the start
555
+ positions as zero, reads angles and smoothed rates, writes torques as clamped goal currents,
556
+ sends zero torque when commands stop (a watchdog), and on leaving (exceptions and Ctrl-C
557
+ included) sends zero torque and switches the torque motors off; held motors keep their
558
+ position. `hardware.home` drives the motors slowly to recorded home positions and refuses a
559
+ motor that lost a turn; `hardware.scan` finds the motors and their baud rate;
560
+ `hardware.FakeBus` stands in for the bus in tests and dry runs.
561
+ - `vmc.sim.WallClock`: `vmc.sim.run` on real time, the loop of simulation unchanged. Each step
562
+ runs on the computer's clock with its measured time; a reading older than `stale` sends
563
+ zero torque; a late step starts the next one from now instead of catching up; the log
564
+ records each step's `dt`, and `log.info` the rate, the slowest step, the overruns and the
565
+ stale readings, with a warning when steps overran.
566
+ - `virtualmodelcontrol.ros` (ROS 2, any distribution; rclpy and std_msgs, loaded only when
567
+ used): `RosPlant`, the robot behind the lab driver's topics (degrees, the bus order, raw
568
+ signs, torques kept within the range of the driver's goal current); `serve`, a digital twin
569
+ that publishes a simulated robot on the same topics, with a lockstep mode in which a run over
570
+ ROS repeats the simulator's; `LiveParams`, a controller's live Params as ROS parameters,
571
+ applied between steps.
572
+
573
+ ### Changed
574
+
575
+ - The soft arm models the efficiency of its tendons: it receives η = 0.12 times the commanded
576
+ torque (`helyx.EFFICIENCY`), and `helyx.SIM_STIFFNESS` and `helyx.SIM_DAMPING` are the
577
+ identified, physical values. 0.1.0 divided them by 0.12 and delivered the full torque: the
578
+ same equilibria without gravity, but natural frequencies about 2.9 times too high and a sag
579
+ under gravity about 8 times too small. Controllers are unchanged and never divide their
580
+ torques by η, so the simulated arm receives η of every command, gravity compensation
581
+ included.
582
+ - The figure style without LaTeX uses matplotlib's own Computer Modern font (`cmr10`) instead
583
+ of DejaVu Serif, with tick labels set as math. Figures made with LaTeX are unchanged.
584
+
585
+ ### Fixed
586
+
587
+ - `RunLog` copies each row, so a signal updated in place (a controller's virtual state) is
588
+ recorded correctly at every step.
589
+ - `bimanual.add_dynamics` takes the stiffness and damping of one arm (a dict by arm, arrays
590
+ included) and keeps the other arm's identified values.
591
+ - `viz.draw_robot`: no joint markers along continuum arms mounted in an assembly; robots without
592
+ geometry (joint-space models) draw nothing instead of failing; serial chains end at their
593
+ `tool` site (the UR5 flange) as well as at a `tip`.
594
+
595
+ ## [0.1.0] - 2026-10-04
596
+
597
+ First public release.
598
+
599
+ ### Added
600
+
601
+ - Package scaffold: `pyproject.toml` (hatchling + hatch-vcs), tests, docs, CI workflows.
602
+ - `core`: `Param` and `ParamSet` with scopes (fixed, design, episode, stage) and a `Binding` that
603
+ keeps live Params symbolic and folds the rest in; spaces `Euclidean`, `SO2`, `Product`;
604
+ symbolic helpers; `Signals`; a registry with plugin entry points; unit strings.
605
+ - `mechanisms`: coordinates (`FramePoint`, `Joint`, `State`, `Ref`, `Difference`, `Slice`,
606
+ `Stack`, `Projection`, `Norm`, `Custom`), components (linear, tanh, Gaussian, sigmoid,
607
+ polynomial and limit springs; linear and tanh dampers; `PointMass`, `Inertance`; `ForceSource`,
608
+ `GravityCompensation`) and `Mechanism`. A tanh spring on a projection saturates at its maximum
609
+ force in every direction.
610
+ - `models`: parametric `PCC` with n segments, `TendonTransmission` (θ > 0 pulls), `Direct`
611
+ drive, and `SerialChain` (product of exponentials).
612
+ - `robots.helyx`: the three Helyx arm geometries with their default parameters.
613
+ - `VirtualMechanismSystem`, `compile()` and `VMCController`: about 20 µs per control step for
614
+ three springs and three dampers on a three-segment arm (`benchmarks/tick.py`).
615
+ - `compile_dynamics()`: robot dynamics assembled from the robot's components (canonical
616
+ residual, mass matrix, energy, power, linearly implicit Euler step); `Gravity` component.
617
+ - `sim`: `Plant` and `SimPlant` protocols, `ModelPlant`, `run()` with a `Guard` (zero torque on
618
+ missing or non-finite readings) and a `RunLog`.
619
+ - `models.Actuation` protocol; `helyx.add_dynamics` with the simulated arm's stiffness and
620
+ damping.
621
+ - Docs: closed-loop simulation tutorial and an "Extend the library" how-to.
622
+ - `models.LinearCoupling` (one motor driving several joints), `models.Assembly` (several models
623
+ mounted on one base) with `StackedActuation`; `FramePoint` accepts a part and an arc parameter.
624
+ - `robots.adapt`: the ADAPT finger (two motors, coupled distal joints), joint-angle coordinate
625
+ and joint-limit spring.
626
+
627
+ [Unreleased]: https://github.com/vigno0405/VirtualModelControl/compare/v0.3.0...HEAD
628
+ [0.3.0]: https://github.com/vigno0405/VirtualModelControl/compare/v0.2.0...v0.3.0
629
+ [0.2.0]: https://github.com/vigno0405/VirtualModelControl/compare/v0.1.0...v0.2.0
630
+ [0.1.0]: https://github.com/vigno0405/VirtualModelControl/releases/tag/v0.1.0