virtualmodelcontrol 0.1.0__tar.gz → 0.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 (202) hide show
  1. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/.gitignore +8 -1
  2. virtualmodelcontrol-0.2.0/CHANGELOG.md +148 -0
  3. virtualmodelcontrol-0.2.0/PKG-INFO +162 -0
  4. virtualmodelcontrol-0.2.0/README.md +120 -0
  5. virtualmodelcontrol-0.2.0/docs/_ext/video.py +49 -0
  6. virtualmodelcontrol-0.2.0/docs/_static/create-lab.png +0 -0
  7. virtualmodelcontrol-0.2.0/docs/_static/custom.css +171 -0
  8. virtualmodelcontrol-0.2.0/docs/_static/favicon.svg +1 -0
  9. virtualmodelcontrol-0.2.0/docs/_static/logo-light.svg +1 -0
  10. virtualmodelcontrol-0.2.0/docs/_static/logo.svg +1 -0
  11. virtualmodelcontrol-0.2.0/docs/_static/readme-hero.svg +1910 -0
  12. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/docs/_templates/autosummary/module.rst +1 -1
  13. virtualmodelcontrol-0.2.0/docs/_templates/partials/toc.html +25 -0
  14. virtualmodelcontrol-0.2.0/docs/api/index.md +22 -0
  15. virtualmodelcontrol-0.2.0/docs/concepts/conventions.md +70 -0
  16. virtualmodelcontrol-0.2.0/docs/concepts/library.md +59 -0
  17. virtualmodelcontrol-0.2.0/docs/concepts/pcc.md +68 -0
  18. virtualmodelcontrol-0.2.0/docs/conf.py +110 -0
  19. virtualmodelcontrol-0.2.0/docs/development/contributing.md +81 -0
  20. virtualmodelcontrol-0.2.0/docs/development/roadmap.md +2 -0
  21. virtualmodelcontrol-0.2.0/docs/docs_setup.py +10 -0
  22. virtualmodelcontrol-0.2.0/docs/examples/finger.md +188 -0
  23. virtualmodelcontrol-0.2.0/docs/examples/hand.md +190 -0
  24. virtualmodelcontrol-0.2.0/docs/examples/soft-arm.md +253 -0
  25. virtualmodelcontrol-0.2.0/docs/examples/turtle.md +162 -0
  26. virtualmodelcontrol-0.2.0/docs/examples/two-arms.md +179 -0
  27. virtualmodelcontrol-0.2.0/docs/index.md +134 -0
  28. virtualmodelcontrol-0.2.0/docs/installation.md +114 -0
  29. virtualmodelcontrol-0.2.0/docs/schematics/__init__.py +1 -0
  30. virtualmodelcontrol-0.2.0/docs/schematics/_draw.py +107 -0
  31. virtualmodelcontrol-0.2.0/docs/schematics/bimanual.py +56 -0
  32. virtualmodelcontrol-0.2.0/docs/schematics/control_loop.py +29 -0
  33. virtualmodelcontrol-0.2.0/docs/schematics/energy_flow.py +42 -0
  34. virtualmodelcontrol-0.2.0/docs/schematics/finger.py +70 -0
  35. virtualmodelcontrol-0.2.0/docs/schematics/four_steps.py +52 -0
  36. virtualmodelcontrol-0.2.0/docs/schematics/hand.py +49 -0
  37. virtualmodelcontrol-0.2.0/docs/schematics/helyx.py +79 -0
  38. virtualmodelcontrol-0.2.0/docs/schematics/library_map.py +62 -0
  39. virtualmodelcontrol-0.2.0/docs/schematics/mechanism.py +132 -0
  40. virtualmodelcontrol-0.2.0/docs/schematics/params.py +37 -0
  41. virtualmodelcontrol-0.2.0/docs/schematics/pcc.py +40 -0
  42. virtualmodelcontrol-0.2.0/docs/schematics/turtle.py +84 -0
  43. virtualmodelcontrol-0.2.0/docs/schematics/ur5.py +105 -0
  44. virtualmodelcontrol-0.2.0/docs/scripts/readme_figure.py +52 -0
  45. virtualmodelcontrol-0.2.0/docs/troubleshooting.md +66 -0
  46. virtualmodelcontrol-0.2.0/docs/tutorials/build-a-robot.md +181 -0
  47. virtualmodelcontrol-0.2.0/docs/tutorials/contact.md +198 -0
  48. virtualmodelcontrol-0.2.0/docs/tutorials/coordinates-and-components.md +160 -0
  49. virtualmodelcontrol-0.2.0/docs/tutorials/energy.md +202 -0
  50. virtualmodelcontrol-0.2.0/docs/tutorials/extend.md +191 -0
  51. virtualmodelcontrol-0.2.0/docs/tutorials/first-controller.md +162 -0
  52. virtualmodelcontrol-0.2.0/docs/tutorials/introduction.md +80 -0
  53. virtualmodelcontrol-0.2.0/docs/tutorials/kinematics.md +144 -0
  54. virtualmodelcontrol-0.2.0/docs/tutorials/parameters.md +185 -0
  55. virtualmodelcontrol-0.2.0/docs/tutorials/tuning.md +202 -0
  56. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/pyproject.toml +43 -9
  57. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/__init__.py +28 -0
  58. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/_version.py +2 -2
  59. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/control/__init__.py +12 -0
  60. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/control/controller.py +15 -5
  61. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/control/output.py +81 -0
  62. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/__init__.py +22 -0
  63. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/bus.py +202 -0
  64. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/check.py +40 -0
  65. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/dynamixel.py +161 -0
  66. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/homing.py +70 -0
  67. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/hardware/profile.py +194 -0
  68. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/__init__.py +10 -0
  69. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/__init__.py +6 -2
  70. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/dissipation.py +22 -0
  71. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/sources.py +25 -1
  72. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/storage.py +32 -0
  73. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/__init__.py +3 -0
  74. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/mechanisms/coordinates/geometry.py +74 -0
  75. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/__init__.py +4 -0
  76. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/actuation.py +27 -11
  77. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/assembly.py +26 -9
  78. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/models/joint_space.py +33 -0
  79. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/kinematic.py +14 -3
  80. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/models/kinematics.py +93 -0
  81. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/rigid/poe.py +71 -8
  82. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/__init__.py +5 -0
  83. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/adapt.py +612 -0
  84. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/bimanual.py +170 -0
  85. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/helyx.py +148 -0
  86. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/turtle.py +94 -0
  87. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/robots/ur5.py +72 -0
  88. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/ros/__init__.py +23 -0
  89. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/ros/joint_io.py +51 -0
  90. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/ros/params.py +43 -0
  91. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/ros/plant.py +121 -0
  92. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/ros/twin.py +82 -0
  93. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/sim/__init__.py +2 -2
  94. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/sim/run.py +158 -0
  95. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/viz/__init__.py +35 -0
  96. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/viz/animation.py +141 -0
  97. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/viz/draw.py +269 -0
  98. virtualmodelcontrol-0.2.0/src/virtualmodelcontrol/viz/style.py +91 -0
  99. virtualmodelcontrol-0.2.0/tests/control/test_output.py +63 -0
  100. virtualmodelcontrol-0.2.0/tests/data/derivatives.npz +0 -0
  101. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/data/dynamics.npz +0 -0
  102. virtualmodelcontrol-0.2.0/tests/data/hand.npz +0 -0
  103. virtualmodelcontrol-0.2.0/tests/data/turtle.npz +0 -0
  104. virtualmodelcontrol-0.2.0/tests/hardware/test_dynamixel.py +169 -0
  105. virtualmodelcontrol-0.2.0/tests/hardware/test_profile.py +85 -0
  106. virtualmodelcontrol-0.2.0/tests/hardware/test_templates.py +47 -0
  107. virtualmodelcontrol-0.2.0/tests/mechanisms/test_contact.py +69 -0
  108. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/models/test_actuation.py +13 -0
  109. virtualmodelcontrol-0.2.0/tests/models/test_kinematics.py +57 -0
  110. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/robots/test_adapt.py +27 -0
  111. virtualmodelcontrol-0.2.0/tests/robots/test_bimanual.py +53 -0
  112. virtualmodelcontrol-0.2.0/tests/robots/test_hand.py +84 -0
  113. virtualmodelcontrol-0.2.0/tests/robots/test_parametric.py +136 -0
  114. virtualmodelcontrol-0.2.0/tests/robots/test_turtle.py +50 -0
  115. virtualmodelcontrol-0.2.0/tests/robots/test_ur5.py +78 -0
  116. virtualmodelcontrol-0.2.0/tests/ros/conftest.py +9 -0
  117. virtualmodelcontrol-0.2.0/tests/ros/test_joint_io.py +29 -0
  118. virtualmodelcontrol-0.2.0/tests/ros/test_ros.py +98 -0
  119. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/sim/test_run.py +37 -1
  120. virtualmodelcontrol-0.2.0/tests/sim/test_wallclock.py +99 -0
  121. virtualmodelcontrol-0.2.0/tests/test_docs.py +43 -0
  122. virtualmodelcontrol-0.2.0/tests/test_import.py +30 -0
  123. virtualmodelcontrol-0.2.0/tests/test_readme.py +18 -0
  124. virtualmodelcontrol-0.2.0/tests/viz/test_animate.py +88 -0
  125. virtualmodelcontrol-0.2.0/tests/viz/test_viz.py +66 -0
  126. virtualmodelcontrol-0.1.0/CHANGELOG.md +0 -40
  127. virtualmodelcontrol-0.1.0/PKG-INFO +0 -82
  128. virtualmodelcontrol-0.1.0/README.md +0 -47
  129. virtualmodelcontrol-0.1.0/docs/_static/custom.css +0 -4
  130. virtualmodelcontrol-0.1.0/docs/conf.py +0 -51
  131. virtualmodelcontrol-0.1.0/docs/development/architecture.md +0 -44
  132. virtualmodelcontrol-0.1.0/docs/development/contributing.md +0 -49
  133. virtualmodelcontrol-0.1.0/docs/getting-started/first-controller.md +0 -79
  134. virtualmodelcontrol-0.1.0/docs/getting-started/install.md +0 -50
  135. virtualmodelcontrol-0.1.0/docs/getting-started/simulate.md +0 -67
  136. virtualmodelcontrol-0.1.0/docs/how-to/add-a-model.md +0 -92
  137. virtualmodelcontrol-0.1.0/docs/how-to/extend.md +0 -111
  138. virtualmodelcontrol-0.1.0/docs/index.md +0 -57
  139. virtualmodelcontrol-0.1.0/docs/reference/api.md +0 -9
  140. virtualmodelcontrol-0.1.0/docs/reference/conventions.md +0 -75
  141. virtualmodelcontrol-0.1.0/docs/robots/helyx.md +0 -42
  142. virtualmodelcontrol-0.1.0/docs/theory/mechanisms.md +0 -61
  143. virtualmodelcontrol-0.1.0/docs/theory/pcc.md +0 -64
  144. virtualmodelcontrol-0.1.0/src/virtualmodelcontrol/control/__init__.py +0 -5
  145. virtualmodelcontrol-0.1.0/src/virtualmodelcontrol/robots/__init__.py +0 -5
  146. virtualmodelcontrol-0.1.0/src/virtualmodelcontrol/robots/adapt.py +0 -98
  147. virtualmodelcontrol-0.1.0/src/virtualmodelcontrol/robots/helyx.py +0 -79
  148. virtualmodelcontrol-0.1.0/src/virtualmodelcontrol/sim/run.py +0 -73
  149. virtualmodelcontrol-0.1.0/tests/test_import.py +0 -13
  150. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/CITATION.cff +0 -0
  151. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/LICENSE +0 -0
  152. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/benchmarks/tick.py +0 -0
  153. {virtualmodelcontrol-0.1.0/docs/reference → virtualmodelcontrol-0.2.0/docs/development}/changelog.md +0 -0
  154. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/compiler.py +0 -0
  155. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/__init__.py +0 -0
  156. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/params.py +0 -0
  157. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/registry.py +0 -0
  158. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/signals.py +0 -0
  159. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/space.py +0 -0
  160. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/symbolic.py +0 -0
  161. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/core/units.py +0 -0
  162. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/dynamics.py +0 -0
  163. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/base.py +0 -0
  164. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/components/inertance.py +0 -0
  165. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/base.py +0 -0
  166. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/frames.py +0 -0
  167. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/joints.py +0 -0
  168. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/ops.py +0 -0
  169. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/coordinates/references.py +0 -0
  170. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/mechanisms/mechanism.py +0 -0
  171. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/continuum/__init__.py +0 -0
  172. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/continuum/pcc.py +0 -0
  173. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/rigid/__init__.py +0 -0
  174. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/models/rigid/couplings.py +0 -0
  175. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/py.typed +0 -0
  176. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/sim/model_plant.py +0 -0
  177. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/sim/plant.py +0 -0
  178. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/src/virtualmodelcontrol/system.py +0 -0
  179. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/conftest.py +0 -0
  180. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/control/test_honesty.py +0 -0
  181. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/control/test_vmc_golden.py +0 -0
  182. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/core/test_params.py +0 -0
  183. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/core/test_registry.py +0 -0
  184. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/core/test_signals.py +0 -0
  185. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/core/test_space.py +0 -0
  186. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/core/test_symbolic.py +0 -0
  187. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/data/components.npz +0 -0
  188. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/data/finger.npz +0 -0
  189. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/data/pcc.npz +0 -0
  190. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/data/vmc.npz +0 -0
  191. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/helpers.py +0 -0
  192. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/mechanisms/test_components.py +0 -0
  193. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/mechanisms/test_components_golden.py +0 -0
  194. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/mechanisms/test_coordinates.py +0 -0
  195. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/mechanisms/test_mechanism.py +0 -0
  196. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/models/test_assembly.py +0 -0
  197. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/models/test_pcc.py +0 -0
  198. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/models/test_poe.py +0 -0
  199. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/robots/test_helyx.py +0 -0
  200. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/test_benchmark.py +0 -0
  201. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/test_compiler.py +0 -0
  202. {virtualmodelcontrol-0.1.0 → virtualmodelcontrol-0.2.0}/tests/test_dynamics.py +0 -0
@@ -12,7 +12,6 @@ dist/
12
12
  src/virtualmodelcontrol/_version.py
13
13
  docs/_build/
14
14
  docs/jupyter_execute/
15
- docs/reference/generated/
16
15
 
17
16
  # Tool caches
18
17
  .pytest_cache/
@@ -22,3 +21,11 @@ docs/reference/generated/
22
21
 
23
22
  # Papers stay out of the repository
24
23
  *.pdf
24
+ docs/api/generated/
25
+ # Animations written by the docs build
26
+ docs/**/*.mp4
27
+ docs/**/*.gif
28
+ docs/**/*.webp
29
+
30
+ # Lock file written by editor tooling; the project pins nothing
31
+ uv.lock
@@ -0,0 +1,148 @@
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 still change between minor
6
+ versions, with one minor version of deprecation before a removal).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-10-04
11
+
12
+ ### Added
13
+
14
+ - Every dependency installs with the package: numpy, SciPy, CasADi, matplotlib, PyYAML, the
15
+ Dynamixel SDK and pyserial. CI runs on Ubuntu 22.04 and 24.04, with a clean-install job.
16
+ - Robot templates: `robots.bimanual` (two Helyx arms on one frame, with their identified
17
+ stiffness and damping and the transmission efficiency 0.12), `robots.adapt.hand` (five digits,
18
+ 13 motors, spread coupling, masses and joint limits), `robots.turtle` (two cranks and the
19
+ virtual-flywheel controller), `robots.ur5` (from DH parameters) and `ur5.with_hand()`.
20
+ - Every template is parametric in its geometry, with today's values as defaults:
21
+ `helyx.arm(lengths=..., section_radius=..., spool_radius=..., tendon_angles=..., masses=...)`
22
+ for any number of segments; `bimanual.arms(lengths=..., tendon_angles=...,
23
+ base_positions=..., efficiency=...)`, each one for both arms or by arm;
24
+ `adapt.finger(link_lengths=..., link_masses=..., link_cogs=..., joint_axes=...,
25
+ motor_radius=..., pulley_radius=..., pip_transmission=...)` and `adapt.finger_coupling`;
26
+ `adapt.hand(...)` and `ur5.with_hand(...)`, which replace any entry of the hand's geometry
27
+ tables by key (`tip_offsets={"thumb": ...}`), with the hand's mounting position on the
28
+ flange; `ur5.arm(d=..., a=..., alpha=...)`; joint-limit springs with custom ranges; output
29
+ stages and `add_dynamics` sized to the arm.
30
+ - `vmc.Kinematics`: positions, rotations, Jacobians, angular Jacobians and Hessians of any site,
31
+ from configuration or from motor angles.
32
+ - `models.JointSpace` for robots described by their joints only; `SerialChain.from_dh` and site
33
+ rotations; `Assembly` parts mounted on another part's frame.
34
+ - `TendonTransmission(efficiency=...)` and `Direct(efficiency=...)` (one value or one per
35
+ motor): the robot receives the commanded torque times the efficiency. `adapt.finger`,
36
+ `adapt.hand` and `ur5.with_hand` take `efficiency=...` and stay lossless by default: the
37
+ measured `adapt.MOTOR_EFFICIENCY` and `adapt.HAND_MOTOR_EFFICIENCY` are static calibrations for
38
+ force estimates, and unequal efficiencies on coupled motors make virtual elements
39
+ non-conservative in simulation.
40
+ - `SpeedRegulator`: drives a virtual state at a commanded speed, with a ramp.
41
+ - `control.output`, opt-in output stages for real hardware: `FrictionCompensation`,
42
+ `Pretension`, `TorqueOffset`, `TorqueLimit`; each template's own stage
43
+ (`helyx.output_stage()`, `bimanual.output_stage()`, `adapt.output_stage()`,
44
+ `adapt.hand_output_stage()`).
45
+ - `vmc.viz`: the lab figure style (`use_style`, `save` as PDF and SVG) and drawing helpers
46
+ (`draw_robot`, `draw_spring`, `draw_damper`, `draw_frame`, `draw_force`, `draw_goal`,
47
+ `label_axes`). `vmc.viz` is available after `import virtualmodelcontrol as vmc` and loads
48
+ matplotlib only when first used.
49
+ - `vmc.viz.animate`: an animation of a run (the robot, springs to fixed points, the path of a
50
+ site, anything else through a callback), saved as MP4, GIF or animated WebP. `imageio-ffmpeg`
51
+ is now a dependency, so MP4 works on every system.
52
+ - `vmc.sim.run(..., z0=...)` starts the controller from a given virtual state, and the run log
53
+ records the virtual state `z` when the controller has one.
54
+ - Contact as stiff one-sided springs: signed distances `PlaneDistance` and `SphereDistance`,
55
+ `ContactSpring` (optional smoothing for optimization) and `ContactDamper` (damps only in
56
+ contact); `adapt.add_dynamics` gives the finger and the hand their gravity for simulation.
57
+ - Documentation rebuilt for students: the Material layout (sections as tabs, the pages of each
58
+ section in the left sidebar), large type, the library's logo and navy colours;
59
+ installation and troubleshooting; tutorials (how it works, a first controller, coordinates
60
+ and components, parameters, energy, kinematics, tuning, contact, building a robot, extending
61
+ the library); an example per robot (soft arm, two arms, finger, hand and the UR5, turtle), each
62
+ opening with its robot's schematic and parameters; concepts (the library's structure, soft-arm
63
+ kinematics, conventions and glossary). Every figure, schematic, table value and animation is
64
+ computed when the documentation builds.
65
+ - `vmc.hardware.HardwareProfile`: the motors of a robot (bus ID, Dynamixel model, sign, mode,
66
+ motor constant, optional torque limit) in the library's motor order, with the bus settings;
67
+ conversions both ways between encoder ticks, raw velocities, goal currents and the published
68
+ degrees of a ROS driver and SI units, with commands clamped before the integer conversion so
69
+ they saturate instead of overflowing; saved and loaded as YAML. Each template has its
70
+ profile: `helyx.hardware()`, `bimanual.hardware()`, `adapt.finger_hardware()`,
71
+ `adapt.hand_hardware()`, `turtle.hardware()`.
72
+ - `vmc.hardware.DynamixelPlant`: a robot's Dynamixel motors as a plant through the Dynamixel
73
+ SDK, without ROS. It sets a safe goal before each motor's torque goes on, takes the start
74
+ positions as zero, reads angles and smoothed rates, writes torques as clamped goal currents,
75
+ sends zero torque when commands stop (a watchdog), and on leaving (exceptions and Ctrl-C
76
+ included) sends zero torque and switches the torque motors off; held motors keep their
77
+ position. `hardware.home` drives the motors slowly to recorded home positions and refuses a
78
+ motor that lost a turn; `hardware.scan` finds the motors and their baud rate;
79
+ `hardware.FakeBus` stands in for the bus in tests and dry runs.
80
+ - `vmc.sim.WallClock`: `vmc.sim.run` on real time, the loop of simulation unchanged. Each step
81
+ runs on the computer's clock with its measured time; a reading older than `stale` sends
82
+ zero torque; a late step starts the next one from now instead of catching up; the log
83
+ records each step's `dt`, and `log.info` the rate, the slowest step, the overruns and the
84
+ stale readings, with a warning when steps overran.
85
+ - `virtualmodelcontrol.ros` (ROS 2, any distribution; rclpy and std_msgs, loaded only when
86
+ used): `RosPlant`, the robot behind the lab driver's topics (degrees, the bus order, raw
87
+ signs, torques kept within the range of the driver's goal current); `serve`, a digital twin
88
+ that publishes a simulated robot on the same topics, with a lockstep mode in which a run over
89
+ ROS repeats the simulator's; `LiveParams`, a controller's live Params as ROS parameters,
90
+ applied between steps.
91
+
92
+ ### Changed
93
+
94
+ - The soft arm models the efficiency of its tendons: it receives η = 0.12 times the commanded
95
+ torque (`helyx.EFFICIENCY`), and `helyx.SIM_STIFFNESS` and `helyx.SIM_DAMPING` are the
96
+ identified, physical values. 0.1.0 divided them by 0.12 and delivered the full torque: the
97
+ same equilibria without gravity, but natural frequencies about 2.9 times too high and a sag
98
+ under gravity about 8 times too small. Controllers are unchanged and never divide their
99
+ torques by η, so the simulated arm receives η of every command, gravity compensation
100
+ included.
101
+ - The figure style without LaTeX uses matplotlib's own Computer Modern font (`cmr10`) instead
102
+ of DejaVu Serif, with tick labels set as math. Figures made with LaTeX are unchanged.
103
+
104
+ ### Fixed
105
+
106
+ - `RunLog` copies each row, so a signal updated in place (a controller's virtual state) is
107
+ recorded correctly at every step.
108
+ - `bimanual.add_dynamics` takes the stiffness and damping of one arm (a dict by arm, arrays
109
+ included) and keeps the other arm's identified values.
110
+ - `viz.draw_robot`: no joint markers along continuum arms mounted in an assembly; robots without
111
+ geometry (joint-space models) draw nothing instead of failing; serial chains end at their
112
+ `tool` site (the UR5 flange) as well as at a `tip`.
113
+
114
+ ## [0.1.0] - 2026-10-04
115
+
116
+ First public release.
117
+
118
+ ### Added
119
+
120
+ - Package scaffold: `pyproject.toml` (hatchling + hatch-vcs), tests, docs, CI workflows.
121
+ - `core`: `Param` and `ParamSet` with scopes (fixed, design, episode, stage) and a `Binding` that
122
+ keeps live Params symbolic and folds the rest in; spaces `Euclidean`, `SO2`, `Product`;
123
+ symbolic helpers; `Signals`; a registry with plugin entry points; unit strings.
124
+ - `mechanisms`: coordinates (`FramePoint`, `Joint`, `State`, `Ref`, `Difference`, `Slice`,
125
+ `Stack`, `Projection`, `Norm`, `Custom`), components (linear, tanh, Gaussian, sigmoid,
126
+ polynomial and limit springs; linear and tanh dampers; `PointMass`, `Inertance`; `ForceSource`,
127
+ `GravityCompensation`) and `Mechanism`. A tanh spring on a projection saturates at its maximum
128
+ force in every direction.
129
+ - `models`: parametric `PCC` with n segments, `TendonTransmission` (θ > 0 pulls), `Direct`
130
+ drive, and `SerialChain` (product of exponentials).
131
+ - `robots.helyx`: the three Helyx arm geometries with their default parameters.
132
+ - `VirtualMechanismSystem`, `compile()` and `VMCController`: about 20 µs per control step for
133
+ three springs and three dampers on a three-segment arm (`benchmarks/tick.py`).
134
+ - `compile_dynamics()`: robot dynamics assembled from the robot's components (canonical
135
+ residual, mass matrix, energy, power, linearly implicit Euler step); `Gravity` component.
136
+ - `sim`: `Plant` and `SimPlant` protocols, `ModelPlant`, `run()` with a `Guard` (zero torque on
137
+ missing or non-finite readings) and a `RunLog`.
138
+ - `models.Actuation` protocol; `helyx.add_dynamics` with the simulated arm's stiffness and
139
+ damping.
140
+ - Docs: closed-loop simulation tutorial and an "Extend the library" how-to.
141
+ - `models.LinearCoupling` (one motor driving several joints), `models.Assembly` (several models
142
+ mounted on one base) with `StackedActuation`; `FramePoint` accepts a part and an arc parameter.
143
+ - `robots.adapt`: the ADAPT finger (two motors, coupled distal joints), joint-angle coordinate
144
+ and joint-limit spring.
145
+
146
+ [Unreleased]: https://github.com/vigno0405/VirtualModelControl/compare/v0.2.0...HEAD
147
+ [0.2.0]: https://github.com/vigno0405/VirtualModelControl/compare/v0.1.0...v0.2.0
148
+ [0.1.0]: https://github.com/vigno0405/VirtualModelControl/releases/tag/v0.1.0
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.5
2
+ Name: virtualmodelcontrol
3
+ Version: 0.2.0
4
+ Summary: Virtual Model Control: robots and controllers as mechanisms of springs, dampers and inertances, compiled with CasADi.
5
+ Project-URL: Repository, https://github.com/vigno0405/VirtualModelControl
6
+ Project-URL: Documentation, https://vigno0405.github.io/VirtualModelControl/
7
+ Author: Lorenzo Vignoli
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: casadi,control,passivity,robotics,soft robots,virtual model control
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: casadi>=3.6
24
+ Requires-Dist: dynamixel-sdk>=3.7
25
+ Requires-Dist: imageio-ffmpeg>=0.5
26
+ Requires-Dist: matplotlib>=3.8
27
+ Requires-Dist: numpy>=1.26
28
+ Requires-Dist: pyserial>=3.5
29
+ Requires-Dist: pyyaml>=6
30
+ Requires-Dist: scipy>=1.11
31
+ Provides-Extra: dev
32
+ Requires-Dist: import-linter>=2.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.10; extra == 'dev'
34
+ Requires-Dist: pre-commit>=3.5; extra == 'dev'
35
+ Requires-Dist: pytest>=8; extra == 'dev'
36
+ Requires-Dist: ruff>=0.6; extra == 'dev'
37
+ Provides-Extra: docs
38
+ Requires-Dist: myst-nb>=1.1; extra == 'docs'
39
+ Requires-Dist: sphinx-immaterial>=0.13; extra == 'docs'
40
+ Requires-Dist: sphinx>=7.2; extra == 'docs'
41
+ Description-Content-Type: text/markdown
42
+
43
+ <a href="https://www.epfl.ch/labs/create/"><img align="right" height="72" src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/create-lab.png" alt="CREATE Lab, EPFL"></a>
44
+
45
+ # VirtualModelControl
46
+
47
+ `virtualmodelcontrol` is a Python library for Virtual Model Control. You build a controller by
48
+ attaching virtual springs, dampers and masses to your robot, and the library turns them into
49
+ motor torques at the control rate, in simulation and on the real robot.
50
+
51
+ <p align="center">
52
+ <a href="https://vigno0405.github.io/VirtualModelControl/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/logo-light.svg"><img src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/logo.svg" height="64" align="middle" alt="virtualmodelcontrol logo"></picture></a>
53
+ &nbsp;
54
+ <a href="https://vigno0405.github.io/VirtualModelControl/"><img src="https://img.shields.io/badge/Documentation-tutorials%20%C2%B7%20examples%20%C2%B7%20API-3c5488?style=for-the-badge&labelColor=13294b" align="middle" alt="Documentation: tutorials, examples, API"></a>
55
+ </p>
56
+
57
+ <p align="center">
58
+ <img src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/readme-hero.svg" width="820" alt="A soft arm whose tip a virtual spring pulls towards a goal, and the distance from the tip to the goal over time">
59
+ </p>
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ pip install virtualmodelcontrol
65
+ ```
66
+
67
+ The newest code, from GitHub, before it is released (the same line updates an existing install):
68
+
69
+ ```bash
70
+ pip install --upgrade "git+https://github.com/vigno0405/VirtualModelControl.git"
71
+ ```
72
+
73
+ Virtual environments, conda, ROS 2 and pinned versions are covered in [Installation][install].
74
+
75
+ ## Requirements
76
+
77
+ Python 3.10 or newer, tested with 3.10 to 3.14 on Ubuntu 22.04 and 24.04. Nothing to compile;
78
+ ROS and LaTeX are not needed.
79
+
80
+ ## Dependencies
81
+
82
+ pip installs them with the library:
83
+
84
+ | Package | Version | Used for |
85
+ | --- | --- | --- |
86
+ | [numpy](https://numpy.org) | 1.26 or newer, 2.x included | arrays |
87
+ | [CasADi](https://web.casadi.org) | 3.6 or newer | the symbolic models, their derivatives and the compiled controllers |
88
+ | [SciPy](https://scipy.org) | 1.11 or newer | rotations of chains built from DH tables |
89
+ | [matplotlib](https://matplotlib.org) | 3.8 or newer | figures and animations |
90
+ | [imageio-ffmpeg](https://github.com/imageio/imageio-ffmpeg) | 0.5 or newer | MP4 videos of the animations |
91
+ | [PyYAML](https://pyyaml.org) | 6 or newer | robot and hardware files |
92
+ | [Dynamixel SDK](https://github.com/ROBOTIS-GIT/DynamixelSDK) | 3.7 or newer | Dynamixel motors |
93
+ | [pyserial](https://github.com/pyserial/pyserial) | 3.5 or newer | serial sensors |
94
+
95
+ ## The example in the figure
96
+
97
+ The robot and the controller are two separate mechanisms: the robot mechanism describes the
98
+ hardware, and the controller holds the virtual elements placed on it.
99
+
100
+ ```python
101
+ import numpy as np
102
+ import virtualmodelcontrol as vmc
103
+ from virtualmodelcontrol.robots import helyx
104
+
105
+ arm = helyx.arm("145-290-290") # a soft arm with nine tendon motors
106
+ tip = arm.point(s=1.0)
107
+
108
+ ctrl = vmc.Mechanism("ctrl")
109
+ ctrl.add("reach", vmc.LinearSpring(tip - [0.25, 0.0, 0.55], 600.0)) # [N/m]
110
+ ctrl.add("damp", vmc.LinearDamper(tip, 5.0)) # [N·s/m]
111
+ ctrl.add("gravity", vmc.GravityCompensation(arm))
112
+ controller = vmc.VMCController(vmc.compile(vmc.VirtualMechanismSystem(arm, ctrl)))
113
+
114
+ meas = vmc.Signals(0.0, motor_position=np.zeros(9), motor_velocity=np.zeros(9))
115
+ torques = controller.step(0.0, meas)["motor_torque"] # [N·m], one per motor
116
+ ```
117
+
118
+ The same controller runs on a simulation built from the robot's own masses, stiffness and
119
+ damping; [readme_figure.py][figure] draws the figure from this run.
120
+
121
+ ```python
122
+ arm = helyx.add_dynamics(arm)
123
+ plant = vmc.sim.ModelPlant(arm)
124
+ log = vmc.sim.run(plant, controller, vmc.sim.SimClock(dt=1 / 330), T=3.0)
125
+ ```
126
+
127
+ ## Examples
128
+
129
+ Each example builds a ready-made robot, controls it in simulation and animates the run:
130
+
131
+ - [Soft arm][soft-arm]: reach a point, avoid an obstacle, shape the whole arm.
132
+ - [Two arms][two-arms]: squeeze an object between the tips of two soft arms.
133
+ - [Finger][finger]: a stiff fingertip and soft joint limits.
134
+ - [Hand][hand]: grasp a ball, alone or mounted on a UR5 arm.
135
+ - [Turtle][turtle]: two cranks that follow a virtual flywheel.
136
+
137
+ ## Documentation
138
+
139
+ The [documentation][docs] holds the tutorials, the examples, the concepts and the API. What
140
+ changed is in the [changelog][changelog], what comes next in the [roadmap][roadmap], and how to
141
+ contribute in [Contributing][contributing].
142
+
143
+ ## Authors
144
+
145
+ Lorenzo Vignoli, at the [CREATE Lab][lab] of EPFL (Prof. Josie Hughes), in a collaboration
146
+ with the University of Cambridge (Prof. Fulvio Forni). To cite the library, see [CITATION.cff][cite].
147
+ The code is under the [MIT license][license].
148
+
149
+ [lab]: https://www.epfl.ch/labs/create/
150
+ [install]: https://vigno0405.github.io/VirtualModelControl/installation.html
151
+ [figure]: https://github.com/vigno0405/VirtualModelControl/blob/main/docs/scripts/readme_figure.py
152
+ [soft-arm]: https://vigno0405.github.io/VirtualModelControl/examples/soft-arm.html
153
+ [two-arms]: https://vigno0405.github.io/VirtualModelControl/examples/two-arms.html
154
+ [finger]: https://vigno0405.github.io/VirtualModelControl/examples/finger.html
155
+ [hand]: https://vigno0405.github.io/VirtualModelControl/examples/hand.html
156
+ [turtle]: https://vigno0405.github.io/VirtualModelControl/examples/turtle.html
157
+ [docs]: https://vigno0405.github.io/VirtualModelControl/
158
+ [changelog]: https://vigno0405.github.io/VirtualModelControl/development/changelog.html
159
+ [roadmap]: https://vigno0405.github.io/VirtualModelControl/development/roadmap.html
160
+ [contributing]: https://vigno0405.github.io/VirtualModelControl/development/contributing.html
161
+ [cite]: https://github.com/vigno0405/VirtualModelControl/blob/main/CITATION.cff
162
+ [license]: https://github.com/vigno0405/VirtualModelControl/blob/main/LICENSE
@@ -0,0 +1,120 @@
1
+ <a href="https://www.epfl.ch/labs/create/"><img align="right" height="72" src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/create-lab.png" alt="CREATE Lab, EPFL"></a>
2
+
3
+ # VirtualModelControl
4
+
5
+ `virtualmodelcontrol` is a Python library for Virtual Model Control. You build a controller by
6
+ attaching virtual springs, dampers and masses to your robot, and the library turns them into
7
+ motor torques at the control rate, in simulation and on the real robot.
8
+
9
+ <p align="center">
10
+ <a href="https://vigno0405.github.io/VirtualModelControl/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/logo-light.svg"><img src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/logo.svg" height="64" align="middle" alt="virtualmodelcontrol logo"></picture></a>
11
+ &nbsp;
12
+ <a href="https://vigno0405.github.io/VirtualModelControl/"><img src="https://img.shields.io/badge/Documentation-tutorials%20%C2%B7%20examples%20%C2%B7%20API-3c5488?style=for-the-badge&labelColor=13294b" align="middle" alt="Documentation: tutorials, examples, API"></a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <img src="https://raw.githubusercontent.com/vigno0405/VirtualModelControl/main/docs/_static/readme-hero.svg" width="820" alt="A soft arm whose tip a virtual spring pulls towards a goal, and the distance from the tip to the goal over time">
17
+ </p>
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install virtualmodelcontrol
23
+ ```
24
+
25
+ The newest code, from GitHub, before it is released (the same line updates an existing install):
26
+
27
+ ```bash
28
+ pip install --upgrade "git+https://github.com/vigno0405/VirtualModelControl.git"
29
+ ```
30
+
31
+ Virtual environments, conda, ROS 2 and pinned versions are covered in [Installation][install].
32
+
33
+ ## Requirements
34
+
35
+ Python 3.10 or newer, tested with 3.10 to 3.14 on Ubuntu 22.04 and 24.04. Nothing to compile;
36
+ ROS and LaTeX are not needed.
37
+
38
+ ## Dependencies
39
+
40
+ pip installs them with the library:
41
+
42
+ | Package | Version | Used for |
43
+ | --- | --- | --- |
44
+ | [numpy](https://numpy.org) | 1.26 or newer, 2.x included | arrays |
45
+ | [CasADi](https://web.casadi.org) | 3.6 or newer | the symbolic models, their derivatives and the compiled controllers |
46
+ | [SciPy](https://scipy.org) | 1.11 or newer | rotations of chains built from DH tables |
47
+ | [matplotlib](https://matplotlib.org) | 3.8 or newer | figures and animations |
48
+ | [imageio-ffmpeg](https://github.com/imageio/imageio-ffmpeg) | 0.5 or newer | MP4 videos of the animations |
49
+ | [PyYAML](https://pyyaml.org) | 6 or newer | robot and hardware files |
50
+ | [Dynamixel SDK](https://github.com/ROBOTIS-GIT/DynamixelSDK) | 3.7 or newer | Dynamixel motors |
51
+ | [pyserial](https://github.com/pyserial/pyserial) | 3.5 or newer | serial sensors |
52
+
53
+ ## The example in the figure
54
+
55
+ The robot and the controller are two separate mechanisms: the robot mechanism describes the
56
+ hardware, and the controller holds the virtual elements placed on it.
57
+
58
+ ```python
59
+ import numpy as np
60
+ import virtualmodelcontrol as vmc
61
+ from virtualmodelcontrol.robots import helyx
62
+
63
+ arm = helyx.arm("145-290-290") # a soft arm with nine tendon motors
64
+ tip = arm.point(s=1.0)
65
+
66
+ ctrl = vmc.Mechanism("ctrl")
67
+ ctrl.add("reach", vmc.LinearSpring(tip - [0.25, 0.0, 0.55], 600.0)) # [N/m]
68
+ ctrl.add("damp", vmc.LinearDamper(tip, 5.0)) # [N·s/m]
69
+ ctrl.add("gravity", vmc.GravityCompensation(arm))
70
+ controller = vmc.VMCController(vmc.compile(vmc.VirtualMechanismSystem(arm, ctrl)))
71
+
72
+ meas = vmc.Signals(0.0, motor_position=np.zeros(9), motor_velocity=np.zeros(9))
73
+ torques = controller.step(0.0, meas)["motor_torque"] # [N·m], one per motor
74
+ ```
75
+
76
+ The same controller runs on a simulation built from the robot's own masses, stiffness and
77
+ damping; [readme_figure.py][figure] draws the figure from this run.
78
+
79
+ ```python
80
+ arm = helyx.add_dynamics(arm)
81
+ plant = vmc.sim.ModelPlant(arm)
82
+ log = vmc.sim.run(plant, controller, vmc.sim.SimClock(dt=1 / 330), T=3.0)
83
+ ```
84
+
85
+ ## Examples
86
+
87
+ Each example builds a ready-made robot, controls it in simulation and animates the run:
88
+
89
+ - [Soft arm][soft-arm]: reach a point, avoid an obstacle, shape the whole arm.
90
+ - [Two arms][two-arms]: squeeze an object between the tips of two soft arms.
91
+ - [Finger][finger]: a stiff fingertip and soft joint limits.
92
+ - [Hand][hand]: grasp a ball, alone or mounted on a UR5 arm.
93
+ - [Turtle][turtle]: two cranks that follow a virtual flywheel.
94
+
95
+ ## Documentation
96
+
97
+ The [documentation][docs] holds the tutorials, the examples, the concepts and the API. What
98
+ changed is in the [changelog][changelog], what comes next in the [roadmap][roadmap], and how to
99
+ contribute in [Contributing][contributing].
100
+
101
+ ## Authors
102
+
103
+ Lorenzo Vignoli, at the [CREATE Lab][lab] of EPFL (Prof. Josie Hughes), in a collaboration
104
+ with the University of Cambridge (Prof. Fulvio Forni). To cite the library, see [CITATION.cff][cite].
105
+ The code is under the [MIT license][license].
106
+
107
+ [lab]: https://www.epfl.ch/labs/create/
108
+ [install]: https://vigno0405.github.io/VirtualModelControl/installation.html
109
+ [figure]: https://github.com/vigno0405/VirtualModelControl/blob/main/docs/scripts/readme_figure.py
110
+ [soft-arm]: https://vigno0405.github.io/VirtualModelControl/examples/soft-arm.html
111
+ [two-arms]: https://vigno0405.github.io/VirtualModelControl/examples/two-arms.html
112
+ [finger]: https://vigno0405.github.io/VirtualModelControl/examples/finger.html
113
+ [hand]: https://vigno0405.github.io/VirtualModelControl/examples/hand.html
114
+ [turtle]: https://vigno0405.github.io/VirtualModelControl/examples/turtle.html
115
+ [docs]: https://vigno0405.github.io/VirtualModelControl/
116
+ [changelog]: https://vigno0405.github.io/VirtualModelControl/development/changelog.html
117
+ [roadmap]: https://vigno0405.github.io/VirtualModelControl/development/roadmap.html
118
+ [contributing]: https://vigno0405.github.io/VirtualModelControl/development/contributing.html
119
+ [cite]: https://github.com/vigno0405/VirtualModelControl/blob/main/CITATION.cff
120
+ [license]: https://github.com/vigno0405/VirtualModelControl/blob/main/LICENSE
@@ -0,0 +1,49 @@
1
+ """A ``video`` directive: embeds an MP4 that the page's own code wrote, looping and muted."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import html
6
+ from pathlib import Path
7
+ from typing import ClassVar
8
+
9
+ from docutils import nodes
10
+ from docutils.parsers.rst import directives
11
+ from sphinx.application import Sphinx
12
+ from sphinx.util import logging
13
+ from sphinx.util.docutils import SphinxDirective
14
+
15
+ LIMIT = 2_000_000 # [bytes] per video, so pages stay light on a phone
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class Video(SphinxDirective):
20
+ """``video <path>`` (relative to the page) with an optional ``:caption:``."""
21
+
22
+ required_arguments = 1
23
+ option_spec: ClassVar = {"caption": directives.unchanged}
24
+
25
+ def run(self) -> list[nodes.Node]:
26
+ rel, path = self.env.relfn2path(self.arguments[0], self.env.docname)
27
+ if not Path(path).is_file():
28
+ logger.warning(f"video not found: {path}", location=self.get_location())
29
+ return []
30
+ size = Path(path).stat().st_size
31
+ if size > LIMIT:
32
+ logger.warning(f"video over 2 MB ({size} bytes): {path}", location=self.get_location())
33
+ self.env.note_dependency(rel)
34
+ dest = self.env.dlfiles.add_file(self.env.docname, rel)
35
+ src = "../" * self.env.docname.count("/") + "_downloads/" + Path(dest).as_posix()
36
+ caption = self.options.get("caption")
37
+ figcaption = f"<figcaption>{html.escape(caption)}</figcaption>" if caption else ""
38
+ markup = (
39
+ '<figure class="video">'
40
+ f'<video src="{src}" controls autoplay muted loop playsinline preload="metadata">'
41
+ "</video>"
42
+ f"{figcaption}</figure>"
43
+ )
44
+ return [nodes.raw("", markup, format="html")]
45
+
46
+
47
+ def setup(app: Sphinx) -> dict[str, bool]:
48
+ app.add_directive("video", Video)
49
+ return {"parallel_read_safe": True, "parallel_write_safe": True}
@@ -0,0 +1,171 @@
1
+ /* Large type: about 17 px text, 19 px on wide screens (the theme's root size grows with the
2
+ window). Bold titles. */
3
+ .md-typeset {
4
+ font-size: 0.85rem;
5
+ }
6
+ .md-typeset h1,
7
+ .md-typeset h2 {
8
+ color: var(--md-default-fg-color);
9
+ font-weight: 700;
10
+ }
11
+ .md-typeset h3 {
12
+ font-weight: 600;
13
+ }
14
+ /* The page title links to the page already; its hidden permalink would wrap on phones. */
15
+ .md-typeset h1 .headerlink {
16
+ display: none;
17
+ }
18
+
19
+ /* The library's logo in the header, large enough to read. */
20
+ .md-header__button.md-logo img {
21
+ height: 2rem;
22
+ }
23
+
24
+ /* The lab's logo, on the right above the page outline, on every page (not in the phone menu,
25
+ which reuses the outline). */
26
+ .md-sidebar--secondary .lab-logo {
27
+ display: inline-block;
28
+ margin: 0 0 1.2rem 0.6rem;
29
+ }
30
+ .md-sidebar--secondary .lab-logo img {
31
+ display: block;
32
+ height: 4rem;
33
+ width: auto;
34
+ }
35
+ .md-nav--primary .lab-logo {
36
+ display: none;
37
+ }
38
+ /* Narrow windows and phones have no right column: the logo sits at the right end of the
39
+ header instead, so it is always on screen. */
40
+ @media screen and (max-width: 59.9375em) {
41
+ .md-header__inner::after {
42
+ content: "";
43
+ flex-shrink: 0;
44
+ width: 2rem;
45
+ height: 2rem;
46
+ margin: 0 0.2rem 0 0.4rem;
47
+ background: url("create-lab.png") center / contain no-repeat;
48
+ }
49
+ }
50
+
51
+ /* The layout fills wide windows. */
52
+ .md-grid {
53
+ max-width: 68rem;
54
+ }
55
+
56
+ /* The home page belongs to no section: its sidebar lists all of them. */
57
+ @media screen and (min-width: 76.25em) {
58
+ .md-nav--lifted > .md-nav__list:not(:has(> .md-nav__item--active)) > .md-nav__item {
59
+ display: block;
60
+ }
61
+ }
62
+
63
+ /* Code cells like the theme's code blocks: no coloured margin. */
64
+ :root {
65
+ --mystnb-source-border-color: transparent;
66
+ --mystnb-source-margin-color: transparent;
67
+ }
68
+
69
+ /* Colours: a deep navy header on a cool, very light page; in dark mode, deep blues throughout.
70
+ Links in blue, the figures' red as the accent. */
71
+ [data-md-color-primary="custom"] {
72
+ --md-primary-fg-color: #13294b;
73
+ --md-primary-fg-color--light: #1f3d6b;
74
+ --md-primary-fg-color--dark: #0b1b33;
75
+ --md-primary-bg-color: #ffffff;
76
+ --md-primary-bg-color--light: rgba(255, 255, 255, 0.72);
77
+ }
78
+ [data-md-color-accent="custom"] {
79
+ --md-accent-fg-color: #e64b35;
80
+ --md-accent-fg-color--transparent: rgba(230, 75, 53, 0.1);
81
+ --md-accent-bg-color: #ffffff;
82
+ --md-accent-bg-color--light: rgba(255, 255, 255, 0.72);
83
+ }
84
+ [data-md-color-scheme="default"] {
85
+ --md-default-bg-color: #f5f8fc;
86
+ --md-code-bg-color: #e9eff7;
87
+ --md-typeset-a-color: #2b5797;
88
+ --md-footer-bg-color: #13294b;
89
+ --md-footer-bg-color--dark: #0b1b33;
90
+ }
91
+ [data-md-color-scheme="slate"] {
92
+ --mystnb-source-border-color: transparent;
93
+ --md-hue: 216;
94
+ --md-default-bg-color: #0d1a2d;
95
+ --md-default-bg-color--light: rgba(13, 26, 45, 0.54);
96
+ --md-default-bg-color--lighter: rgba(13, 26, 45, 0.26);
97
+ --md-default-bg-color--lightest: rgba(13, 26, 45, 0.07);
98
+ --md-code-bg-color: #13243d;
99
+ --md-typeset-a-color: #8ab4f8;
100
+ --md-footer-bg-color: #08121f;
101
+ --md-footer-bg-color--dark: #050c16;
102
+ }
103
+ [data-md-color-scheme="slate"][data-md-color-primary="custom"] {
104
+ --md-primary-fg-color: #08121f;
105
+ --md-primary-fg-color--light: #12223a;
106
+ --md-primary-fg-color--dark: #050c16;
107
+ }
108
+ [data-md-color-scheme="slate"][data-md-color-accent="custom"] {
109
+ --md-accent-fg-color: #ff7b66;
110
+ --md-accent-fg-color--transparent: rgba(255, 123, 102, 0.12);
111
+ }
112
+
113
+ /* Animations written by the pages (the video directive), shown at their own size or smaller. */
114
+ figure.video {
115
+ margin: 1.5em 0;
116
+ text-align: center;
117
+ }
118
+ figure.video video {
119
+ display: inline-block;
120
+ width: auto;
121
+ height: auto;
122
+ max-width: 100%;
123
+ border: 1px solid var(--md-default-fg-color--lightest);
124
+ border-radius: 0.2rem;
125
+ }
126
+ figure.video figcaption {
127
+ font-size: 0.85em;
128
+ color: var(--md-default-fg-color--light);
129
+ margin-top: 0.5em;
130
+ }
131
+
132
+ /* Figures: white background in dark mode too, never wider than the text. */
133
+ .cell_output img {
134
+ max-width: 100%;
135
+ height: auto;
136
+ background: #fff;
137
+ border-radius: 0.2rem;
138
+ }
139
+
140
+ /* Task lists (the roadmap): the checkbox replaces the bullet. */
141
+ ul.contains-task-list {
142
+ list-style: none;
143
+ padding-left: 0.25rem;
144
+ }
145
+
146
+ /* Reference tables: names on one line and a readable last column; on a phone a wide table
147
+ scrolls sideways inside itself instead of squeezing its columns. */
148
+ .md-typeset table.docutils td code {
149
+ white-space: nowrap;
150
+ word-break: normal;
151
+ overflow-wrap: normal;
152
+ }
153
+ .md-typeset table.docutils td:last-child {
154
+ min-width: 14em;
155
+ }
156
+
157
+ /* Display equations: a wide one scrolls sideways inside itself on a phone, not the page. */
158
+ .md-typeset mjx-container[display="true"] {
159
+ overflow-x: auto;
160
+ overflow-y: hidden;
161
+ max-width: 100%;
162
+ }
163
+
164
+ /* The general index: its two columns stack on a phone, and long module names wrap. */
165
+ @media screen and (max-width: 44.9375em) {
166
+ table.genindextable td {
167
+ display: block;
168
+ width: auto !important;
169
+ overflow-wrap: anywhere;
170
+ }
171
+ }