pySimBlocks 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. examples/advanced/hardware/block_diagram.py +162 -0
  2. examples/advanced/hardware/camera.py +93 -0
  3. examples/advanced/hardware/gui_emio.py +231 -0
  4. examples/advanced/hardware/lmi.py +69 -0
  5. examples/advanced/hardware/main.py +57 -0
  6. examples/advanced/hardware/parameters.py +54 -0
  7. examples/advanced/qp_problem/params.py +10 -0
  8. examples/advanced/qp_problem/run.py +14 -0
  9. examples/advanced/sofa/gui/finger/Finger.py +108 -0
  10. examples/advanced/sofa/gui/finger/FingerController.py +53 -0
  11. examples/advanced/sofa/gui/finger/parameters_auto.py +22 -0
  12. examples/advanced/sofa/gui/sofa_plant/run.py +14 -0
  13. examples/advanced/sofa/python/Finger.py +107 -0
  14. examples/advanced/sofa/python/FingerController.py +48 -0
  15. examples/advanced/sofa/python/closedloop.py +64 -0
  16. examples/advanced/sofa/python/openloop.py +58 -0
  17. examples/basics/algebraic_function/g.py +7 -0
  18. examples/basics/algebraic_function/run.py +14 -0
  19. examples/basics/dc_motor/gui/run.py +14 -0
  20. examples/basics/dc_motor/multiple_order.py +91 -0
  21. examples/basics/dc_motor/openloop.py +62 -0
  22. examples/basics/dc_motor/pi.py +99 -0
  23. examples/basics/dc_motor/pid.py +118 -0
  24. examples/basics/dc_motor/pid_block.py +82 -0
  25. examples/basics/dc_motor/pid_block_vs_manual.py +143 -0
  26. examples/basics/external/parameters.py +4 -0
  27. examples/basics/external/run.py +14 -0
  28. examples/basics/file_sources/temp.py +16 -0
  29. examples/basics/observer.py +76 -0
  30. examples/basics/state_feedback/gui/parameters.py +9 -0
  31. examples/basics/state_feedback/gui/run.py +14 -0
  32. examples/basics/state_feedback/state_feedback.py +102 -0
  33. examples/basics/state_space/linear/gui/run.py +14 -0
  34. examples/basics/state_space/linear/ss_block.py +89 -0
  35. examples/basics/state_space/linear/ss_manual.py +105 -0
  36. examples/basics/state_space/non_linear/nlss.py +47 -0
  37. examples/basics/state_space/non_linear/run.py +14 -0
  38. examples/basics/state_space/polytope/params.py +39 -0
  39. examples/basics/state_space/polytope/weights.py +12 -0
  40. examples/comparison/simulink/convert.py +29 -0
  41. examples/comparison/simulink/openloop.py +127 -0
  42. examples/comparison/simulink/pi.py +148 -0
  43. examples/comparison/simulink/pid.py +154 -0
  44. examples/comparison/simulink/pid_backward.py +155 -0
  45. examples/quick_start/filter.py +35 -0
  46. examples/quick_start/gui/run.py +14 -0
  47. examples/tutorials/tutorial_1_python/main.py +99 -0
  48. examples/tutorials/tutorial_3_sofa/finger/Finger.py +120 -0
  49. examples/tutorials/tutorial_3_sofa/finger/FingerController.py +37 -0
  50. pySimBlocks/__init__.py +35 -0
  51. pySimBlocks/blocks/__init__.py +68 -0
  52. pySimBlocks/blocks/controllers/__init__.py +27 -0
  53. pySimBlocks/blocks/controllers/pid.py +250 -0
  54. pySimBlocks/blocks/controllers/state_feedback.py +141 -0
  55. pySimBlocks/blocks/interfaces/__init__.py +27 -0
  56. pySimBlocks/blocks/interfaces/external_input.py +107 -0
  57. pySimBlocks/blocks/interfaces/external_output.py +113 -0
  58. pySimBlocks/blocks/observers/__init__.py +23 -0
  59. pySimBlocks/blocks/observers/luenberger.py +175 -0
  60. pySimBlocks/blocks/operators/__init__.py +47 -0
  61. pySimBlocks/blocks/operators/algebraic_function.py +258 -0
  62. pySimBlocks/blocks/operators/dead_zone.py +186 -0
  63. pySimBlocks/blocks/operators/delay.py +254 -0
  64. pySimBlocks/blocks/operators/demux.py +123 -0
  65. pySimBlocks/blocks/operators/discrete_derivator.py +237 -0
  66. pySimBlocks/blocks/operators/discrete_integrator.py +265 -0
  67. pySimBlocks/blocks/operators/gain.py +294 -0
  68. pySimBlocks/blocks/operators/mux.py +131 -0
  69. pySimBlocks/blocks/operators/product.py +194 -0
  70. pySimBlocks/blocks/operators/rate_limiter.py +214 -0
  71. pySimBlocks/blocks/operators/saturation.py +178 -0
  72. pySimBlocks/blocks/operators/sum.py +188 -0
  73. pySimBlocks/blocks/operators/zero_order_hold.py +141 -0
  74. pySimBlocks/blocks/optimizers/__init__.py +23 -0
  75. pySimBlocks/blocks/optimizers/quadratic_program.py +326 -0
  76. pySimBlocks/blocks/sources/__init__.py +37 -0
  77. pySimBlocks/blocks/sources/chirp.py +168 -0
  78. pySimBlocks/blocks/sources/constant.py +82 -0
  79. pySimBlocks/blocks/sources/file_source.py +294 -0
  80. pySimBlocks/blocks/sources/function_source.py +197 -0
  81. pySimBlocks/blocks/sources/ramp.py +99 -0
  82. pySimBlocks/blocks/sources/sinusoidal.py +113 -0
  83. pySimBlocks/blocks/sources/step.py +138 -0
  84. pySimBlocks/blocks/sources/white_noise.py +107 -0
  85. pySimBlocks/blocks/systems/__init__.py +27 -0
  86. pySimBlocks/blocks/systems/linear_state_space.py +180 -0
  87. pySimBlocks/blocks/systems/non_linear_state_space.py +309 -0
  88. pySimBlocks/blocks/systems/polytopic_state_space.py +193 -0
  89. pySimBlocks/blocks/systems/sofa/__init__.py +30 -0
  90. pySimBlocks/blocks/systems/sofa/sofa_controller.py +472 -0
  91. pySimBlocks/blocks/systems/sofa/sofa_exchange_i_o.py +120 -0
  92. pySimBlocks/blocks/systems/sofa/sofa_plant.py +306 -0
  93. pySimBlocks/cli.py +127 -0
  94. pySimBlocks/core/__init__.py +32 -0
  95. pySimBlocks/core/block.py +167 -0
  96. pySimBlocks/core/block_source.py +94 -0
  97. pySimBlocks/core/config.py +90 -0
  98. pySimBlocks/core/fixed_time_manager.py +46 -0
  99. pySimBlocks/core/model.py +250 -0
  100. pySimBlocks/core/scheduler.py +30 -0
  101. pySimBlocks/core/simulator.py +329 -0
  102. pySimBlocks/core/task.py +73 -0
  103. pySimBlocks/docs/blocks/controllers/pid.md +78 -0
  104. pySimBlocks/docs/blocks/controllers/state_feedback.md +60 -0
  105. pySimBlocks/docs/blocks/interfaces/external_input.md +39 -0
  106. pySimBlocks/docs/blocks/interfaces/external_output.md +39 -0
  107. pySimBlocks/docs/blocks/observers/luenberger.md +70 -0
  108. pySimBlocks/docs/blocks/operators/algebraic_function.md +76 -0
  109. pySimBlocks/docs/blocks/operators/dead_zone.md +67 -0
  110. pySimBlocks/docs/blocks/operators/delay.md +76 -0
  111. pySimBlocks/docs/blocks/operators/demux.md +64 -0
  112. pySimBlocks/docs/blocks/operators/discrete_derivator.md +61 -0
  113. pySimBlocks/docs/blocks/operators/discrete_integrator.md +87 -0
  114. pySimBlocks/docs/blocks/operators/gain.md +97 -0
  115. pySimBlocks/docs/blocks/operators/mux.md +64 -0
  116. pySimBlocks/docs/blocks/operators/product.md +51 -0
  117. pySimBlocks/docs/blocks/operators/rate_limiter.md +70 -0
  118. pySimBlocks/docs/blocks/operators/saturation.md +62 -0
  119. pySimBlocks/docs/blocks/operators/sum.md +49 -0
  120. pySimBlocks/docs/blocks/operators/zero_order_hold.md +61 -0
  121. pySimBlocks/docs/blocks/optimizers/quadratic_program.md +98 -0
  122. pySimBlocks/docs/blocks/sources/chirp.md +102 -0
  123. pySimBlocks/docs/blocks/sources/constant.md +53 -0
  124. pySimBlocks/docs/blocks/sources/file_source.md +51 -0
  125. pySimBlocks/docs/blocks/sources/function_source.md +52 -0
  126. pySimBlocks/docs/blocks/sources/ramp.md +58 -0
  127. pySimBlocks/docs/blocks/sources/sinusoidal.md +60 -0
  128. pySimBlocks/docs/blocks/sources/step.md +63 -0
  129. pySimBlocks/docs/blocks/sources/white_noise.md +58 -0
  130. pySimBlocks/docs/blocks/systems/linear_state_space.md +66 -0
  131. pySimBlocks/docs/blocks/systems/non_linear_state_space.md +90 -0
  132. pySimBlocks/docs/blocks/systems/polytopic_state_space.md +72 -0
  133. pySimBlocks/docs/blocks/systems/sofa/sofa_exchange_i_o.md +63 -0
  134. pySimBlocks/docs/blocks/systems/sofa/sofa_plant.md +62 -0
  135. pySimBlocks/gui/__init__.py +20 -0
  136. pySimBlocks/gui/addons/__init__.py +19 -0
  137. pySimBlocks/gui/addons/sofa/__init__.py +19 -0
  138. pySimBlocks/gui/addons/sofa/sofa_dialog.py +190 -0
  139. pySimBlocks/gui/addons/sofa/sofa_service.py +209 -0
  140. pySimBlocks/gui/blocks/block_dialog_session.py +47 -0
  141. pySimBlocks/gui/blocks/block_meta.py +408 -0
  142. pySimBlocks/gui/blocks/controllers/pid.py +116 -0
  143. pySimBlocks/gui/blocks/controllers/state_feedback.py +80 -0
  144. pySimBlocks/gui/blocks/interfaces/external_input.py +64 -0
  145. pySimBlocks/gui/blocks/interfaces/external_output.py +63 -0
  146. pySimBlocks/gui/blocks/observers/luenberger.py +108 -0
  147. pySimBlocks/gui/blocks/operators/algebraic_function.py +232 -0
  148. pySimBlocks/gui/blocks/operators/dead_zone.py +79 -0
  149. pySimBlocks/gui/blocks/operators/delay.py +79 -0
  150. pySimBlocks/gui/blocks/operators/demux.py +98 -0
  151. pySimBlocks/gui/blocks/operators/discrete_derivator.py +67 -0
  152. pySimBlocks/gui/blocks/operators/discrete_integrator.py +80 -0
  153. pySimBlocks/gui/blocks/operators/gain.py +79 -0
  154. pySimBlocks/gui/blocks/operators/mux.py +100 -0
  155. pySimBlocks/gui/blocks/operators/product.py +109 -0
  156. pySimBlocks/gui/blocks/operators/rate_limiter.py +79 -0
  157. pySimBlocks/gui/blocks/operators/saturation.py +72 -0
  158. pySimBlocks/gui/blocks/operators/sum.py +91 -0
  159. pySimBlocks/gui/blocks/operators/zero_order_hold.py +64 -0
  160. pySimBlocks/gui/blocks/optimizers/quadratic_program.py +128 -0
  161. pySimBlocks/gui/blocks/parameter_meta.py +34 -0
  162. pySimBlocks/gui/blocks/port_meta.py +31 -0
  163. pySimBlocks/gui/blocks/sources/chirp.py +146 -0
  164. pySimBlocks/gui/blocks/sources/constant.py +63 -0
  165. pySimBlocks/gui/blocks/sources/file_source.py +196 -0
  166. pySimBlocks/gui/blocks/sources/function_source.py +202 -0
  167. pySimBlocks/gui/blocks/sources/ramp.py +73 -0
  168. pySimBlocks/gui/blocks/sources/sinusoidal.py +81 -0
  169. pySimBlocks/gui/blocks/sources/step.py +83 -0
  170. pySimBlocks/gui/blocks/sources/white_noise.py +70 -0
  171. pySimBlocks/gui/blocks/systems/linear_state_space.py +102 -0
  172. pySimBlocks/gui/blocks/systems/non_linear_state_space.py +233 -0
  173. pySimBlocks/gui/blocks/systems/polytopic_state_space.py +109 -0
  174. pySimBlocks/gui/blocks/systems/sofa/sofa_exchange_i_o.py +221 -0
  175. pySimBlocks/gui/blocks/systems/sofa/sofa_plant.py +220 -0
  176. pySimBlocks/gui/dialogs/__init__.py +19 -0
  177. pySimBlocks/gui/dialogs/block_dialog.py +125 -0
  178. pySimBlocks/gui/dialogs/display_yaml_dialog.py +89 -0
  179. pySimBlocks/gui/dialogs/help_dialog.py +39 -0
  180. pySimBlocks/gui/dialogs/plot_dialog.py +230 -0
  181. pySimBlocks/gui/dialogs/settings/plots.py +187 -0
  182. pySimBlocks/gui/dialogs/settings/project.py +146 -0
  183. pySimBlocks/gui/dialogs/settings/simulation.py +137 -0
  184. pySimBlocks/gui/dialogs/settings_dialog.py +88 -0
  185. pySimBlocks/gui/dialogs/unsaved_dialog.py +92 -0
  186. pySimBlocks/gui/editor.py +49 -0
  187. pySimBlocks/gui/graphics/__init__.py +29 -0
  188. pySimBlocks/gui/graphics/block_item.py +289 -0
  189. pySimBlocks/gui/graphics/connection_item.py +266 -0
  190. pySimBlocks/gui/graphics/port_item.py +153 -0
  191. pySimBlocks/gui/graphics/theme.py +119 -0
  192. pySimBlocks/gui/main_window.py +162 -0
  193. pySimBlocks/gui/models/__init__.py +31 -0
  194. pySimBlocks/gui/models/block_instance.py +114 -0
  195. pySimBlocks/gui/models/connection_instance.py +43 -0
  196. pySimBlocks/gui/models/port_instance.py +52 -0
  197. pySimBlocks/gui/models/project_simulation_params.py +50 -0
  198. pySimBlocks/gui/models/project_state.py +114 -0
  199. pySimBlocks/gui/project_controller.py +302 -0
  200. pySimBlocks/gui/services/__init__.py +20 -0
  201. pySimBlocks/gui/services/project_loader.py +381 -0
  202. pySimBlocks/gui/services/project_saver.py +68 -0
  203. pySimBlocks/gui/services/simulation_runner.py +66 -0
  204. pySimBlocks/gui/services/yaml_tools.py +261 -0
  205. pySimBlocks/gui/widgets/__init__.py +19 -0
  206. pySimBlocks/gui/widgets/block_list.py +131 -0
  207. pySimBlocks/gui/widgets/diagram_view.py +312 -0
  208. pySimBlocks/gui/widgets/toolbar_view.py +161 -0
  209. pySimBlocks/project/__init__.py +35 -0
  210. pySimBlocks/project/build_model.py +92 -0
  211. pySimBlocks/project/generate_run_script.py +109 -0
  212. pySimBlocks/project/generate_sofa_controller.py +215 -0
  213. pySimBlocks/project/load_project_config.py +197 -0
  214. pySimBlocks/project/load_simulation_config.py +166 -0
  215. pySimBlocks/project/load_simulator.py +45 -0
  216. pySimBlocks/project/plot_from_config.py +174 -0
  217. pySimBlocks/project/pySimBlocks_blocks_index.yaml +106 -0
  218. pySimBlocks/real_time/__init__.py +23 -0
  219. pySimBlocks/real_time/real_time_runner.py +148 -0
  220. pySimBlocks/tools/__init__.py +19 -0
  221. pySimBlocks/tools/blocks_registry.py +141 -0
  222. pySimBlocks/tools/generate_blocks_index.py +124 -0
  223. pysimblocks-0.1.0.dist-info/METADATA +180 -0
  224. pysimblocks-0.1.0.dist-info/RECORD +262 -0
  225. pysimblocks-0.1.0.dist-info/WHEEL +5 -0
  226. pysimblocks-0.1.0.dist-info/entry_points.txt +2 -0
  227. pysimblocks-0.1.0.dist-info/licenses/LICENSE.md +165 -0
  228. pysimblocks-0.1.0.dist-info/top_level.txt +3 -0
  229. tests/blocks/controllers/test_pid.py +143 -0
  230. tests/blocks/controllers/test_state_feedback.py +193 -0
  231. tests/blocks/observers/test_luenberger.py +225 -0
  232. tests/blocks/operators/test_algebraic_function.py +230 -0
  233. tests/blocks/operators/test_dead_zone.py +106 -0
  234. tests/blocks/operators/test_delay.py +167 -0
  235. tests/blocks/operators/test_demux.py +111 -0
  236. tests/blocks/operators/test_discrete_derivator.py +160 -0
  237. tests/blocks/operators/test_discrete_integrator.py +149 -0
  238. tests/blocks/operators/test_gain.py +182 -0
  239. tests/blocks/operators/test_mux.py +101 -0
  240. tests/blocks/operators/test_product.py +171 -0
  241. tests/blocks/operators/test_rate_limiter.py +166 -0
  242. tests/blocks/operators/test_saturation.py +157 -0
  243. tests/blocks/operators/test_sum.py +183 -0
  244. tests/blocks/operators/test_zero_order_hold.py +106 -0
  245. tests/blocks/sources/test_chirp.py +157 -0
  246. tests/blocks/sources/test_constant.py +55 -0
  247. tests/blocks/sources/test_file_source.py +185 -0
  248. tests/blocks/sources/test_function_source.py +135 -0
  249. tests/blocks/sources/test_ramp.py +110 -0
  250. tests/blocks/sources/test_sinusoidal.py +113 -0
  251. tests/blocks/sources/test_step.py +76 -0
  252. tests/blocks/sources/test_white_noise.py +108 -0
  253. tests/blocks/systems/test_linear_state_space.py +135 -0
  254. tests/blocks/systems/test_polytopic_state_space.py +133 -0
  255. tests/core/test_core_errors_and_determinism.py +82 -0
  256. tests/core/test_core_multirate_tasks.py +88 -0
  257. tests/core/test_core_two_phase_and_propagation.py +132 -0
  258. tests/gui/main_window_open_test.py +162 -0
  259. tests/gui/test_block_meta_param_cache.py +16 -0
  260. tests/gui/test_file_source_meta.py +17 -0
  261. tests/gui/test_function_source_meta.py +28 -0
  262. tests/regression/test_simulink_dc_motor.py +217 -0
@@ -0,0 +1,108 @@
1
+ import os
2
+
3
+ import numpy as np
4
+ import Sofa
5
+
6
+ dir_path = os.path.dirname(os.path.abspath(__file__))
7
+ path = os.path.join(dir_path, 'mesh')
8
+
9
+
10
+ def createScene(rootNode):
11
+ from FingerController import FingerController
12
+
13
+ rootNode.addObject("RequiredPlugin", name='SoftRobots')
14
+ rootNode.addObject("RequiredPlugin", name='SofaPython3')
15
+ rootNode.addObject('RequiredPlugin', pluginName=[
16
+ "Sofa.Component.AnimationLoop", # Needed to use components FreeMotionAnimationLoop
17
+ "Sofa.Component.Constraint.Lagrangian.Correction", # Needed to use components GenericConstraintCorrection
18
+ "Sofa.Component.Constraint.Lagrangian.Solver", # Needed to use components GenericConstraintSolver
19
+ "Sofa.Component.Engine.Select", # Needed to use components BoxROI
20
+ "Sofa.Component.IO.Mesh", # Needed to use components MeshSTLLoader, MeshVTKLoader
21
+ "Sofa.Component.LinearSolver.Direct", # Needed to use components SparseLDLSolver
22
+ "Sofa.Component.Mass", # Needed to use components UniformMass
23
+ "Sofa.Component.ODESolver.Backward", # Needed to use components EulerImplicitSolver
24
+ "Sofa.Component.Setting", # Needed to use components BackgroundSetting
25
+ "Sofa.Component.SolidMechanics.FEM.Elastic", # Needed to use components TetrahedronFEMForceField
26
+ "Sofa.Component.SolidMechanics.Spring", # Needed to use components RestShapeSpringsForceField
27
+ "Sofa.Component.Topology.Container.Constant", # Needed to use components MeshTopology
28
+ "Sofa.Component.Visual", # Needed to use components VisualStyle
29
+ "Sofa.GL.Component.Rendering3D", # Needed to use components OglModel, OglSceneFrame
30
+ "Sofa.Component.StateContainer",
31
+ 'Sofa.Component.Mapping.Linear'
32
+ ])
33
+ rootNode.addObject('VisualStyle',
34
+ displayFlags='showVisualModels hideBehaviorModels showCollisionModels hideBoundingCollisionModels hideForceFields showInteractionForceFields hideWireframe')
35
+
36
+ rootNode.addObject('FreeMotionAnimationLoop')
37
+ rootNode.addObject('DefaultVisualManagerLoop')
38
+
39
+ rootNode.addObject('GenericConstraintSolver', tolerance=1e-5, maxIterations=100)
40
+
41
+ rootNode.gravity = [0, -9810, 0]
42
+ rootNode.dt = 0.01
43
+
44
+ ##########################################
45
+ # FEM Model #
46
+ ##########################################
47
+ finger = rootNode.addChild('finger')
48
+ finger.addObject('EulerImplicitSolver', name='odesolver', rayleighMass=0.1, rayleighStiffness=0.1)
49
+ finger.addObject('SparseLDLSolver', template='CompressedRowSparseMatrixMat3x3d')
50
+
51
+ # Add a component to load a VTK tetrahedral mesh and expose the resulting topology in the scene .
52
+ finger.addObject('MeshVTKLoader', name='loader', filename=os.path.join(path, 'finger.vtk'))
53
+ finger.addObject('MeshTopology', src='@loader', name='container')
54
+
55
+ # Create a MechanicaObject component to stores the DoFs of the model
56
+ finger.addObject('MechanicalObject', name='tetras', template='Vec3', showIndices=False, showIndicesScale=4e-5)
57
+
58
+ finger.addObject('UniformMass', totalMass=0.075)
59
+ finger.addObject('TetrahedronFEMForceField', template='Vec3', name='FEM', method='large', poissonRatio=0.45,
60
+ youngModulus=600)
61
+ finger.addObject('BoxROI', name='roi', box=[-15, 0, 0, 5, 10, 15], drawBoxes=True)
62
+ finger.addObject('RestShapeSpringsForceField', points=finger.roi.indices.getLinkPath(), stiffness=1e12)
63
+ finger.addObject('GenericConstraintCorrection')
64
+
65
+ ##########################################
66
+ # Cable #
67
+ ##########################################
68
+
69
+ cable = finger.addChild('cable')
70
+ cable.addObject('MechanicalObject',
71
+ position=[
72
+ [-17.5, 12.5, 2.5],
73
+ [-32.5, 12.5, 2.5],
74
+ [-47.5, 12.5, 2.5],
75
+ [-62.5, 12.5, 2.5],
76
+ [-77.5, 12.5, 2.5],
77
+
78
+ [-85.5, 12.5, 6.5],
79
+ [-85.5, 12.5, 8.5],
80
+ [-83.5, 12.5, 4.5],
81
+ [-83.5, 12.5, 10.5],
82
+
83
+ [-77.5, 12.5, 12.5],
84
+ [-62.5, 12.5, 12.5],
85
+ [-47.5, 12.5, 12.5],
86
+ [-32.5, 12.5, 12.5],
87
+ [-17.5, 12.5, 12.5]])
88
+
89
+ cable.addObject('CableConstraint', name="aCableActuator",
90
+ indices=list(range(0, 14)),
91
+ minForce=0, # Set that the cable can't push
92
+ pullPoint=[0.0, 12.5, 2.5])
93
+ cable.addObject('BarycentricMapping')
94
+
95
+ controller = FingerController(rootNode, cable.aCableActuator, finger.tetras)
96
+ finger.addObject(controller)
97
+
98
+ ##########################################
99
+ # Visualization #
100
+ ##########################################
101
+ fingerVisu = finger.addChild('visu')
102
+
103
+ # Add to this empty node a rendering model made of triangles and loaded from a stl file.
104
+ fingerVisu.addObject('MeshSTLLoader', filename=os.path.join(path, "finger.stl"), name="loader")
105
+ fingerVisu.addObject('OglModel', src="@loader", color=[0.0, 0.7, 0.7, 1])
106
+ fingerVisu.addObject('BarycentricMapping')
107
+
108
+ return rootNode, controller
@@ -0,0 +1,53 @@
1
+ import numpy as np
2
+ from pySimBlocks.blocks.systems.sofa import SofaPysimBlocksController
3
+
4
+ import Sofa
5
+
6
+ from pathlib import Path
7
+
8
+ BASE_DIR = Path(__file__).resolve().parent
9
+
10
+
11
+
12
+
13
+ class FingerController(SofaPysimBlocksController):
14
+
15
+ def __init__(self, root, actuator, mo, tip_index=121, name="FingerController"):
16
+ super().__init__(root, name=name)
17
+ self.project_yaml = str((BASE_DIR / '../sofa_plant/project.yaml').resolve())
18
+
19
+ self.mo = mo
20
+ self.actuator = actuator
21
+ self.tip_index = tip_index
22
+ self.dt = root.dt.value
23
+ self.verbose = True
24
+
25
+ # Inputs & outputs dictionaries
26
+ self.inputs = { "cable": None }
27
+ self.outputs = { "tip": None, "measure": None }
28
+
29
+
30
+ def get_outputs(self):
31
+ tip = self.mo.position[self.tip_index].copy()
32
+ self.outputs["tip"] = np.asarray(tip).reshape(-1, 1)
33
+ self.outputs["measure"] = np.asarray(tip[1]).reshape(-1, 1)
34
+
35
+ def set_inputs(self):
36
+ # 1. READ INPUT -------------------------------------
37
+ val = self.inputs["cable"]
38
+
39
+ # Safe default for first initialization call
40
+ if val is None:
41
+ # ↓↓↓ Valeur par défaut pour l’initialisation
42
+ val = 0.0
43
+
44
+ # Convert input to Sofa format
45
+ if isinstance(val, np.ndarray):
46
+ processed = val.flatten().tolist()
47
+ elif isinstance(val, (list, tuple)):
48
+ processed = val
49
+ else:
50
+ processed = [float(val)]
51
+
52
+ # Apply to actuator
53
+ self.actuator.value = processed
@@ -0,0 +1,22 @@
1
+ import numpy as np
2
+
3
+ step_value_before = np.array([[0]])
4
+ step_value_after = np.array([[8.0]])
5
+ step_start_time = 0.4
6
+
7
+ error_num_inputs = 2
8
+ error_signs = np.array([1.0, -1.0])
9
+
10
+ Kp_gain = np.array([[0.5]])
11
+
12
+ Ki_gain = np.array([[0.8]])
13
+
14
+ discrete_integrator_initial_state = np.array([[0.0]])
15
+
16
+ sum_num_inputs = 2
17
+
18
+ sofa_input_keys = np.array(['cable'])
19
+ sofa_output_keys = np.array(['tip', 'measure'])
20
+
21
+ dt = 0.01
22
+ T = 5.0
@@ -0,0 +1,14 @@
1
+ from pathlib import Path
2
+ from pySimBlocks.project import load_simulator_from_project
3
+ from pySimBlocks.project.plot_from_config import plot_from_config
4
+
5
+ try:
6
+ BASE_DIR = Path(__file__).parent.resolve()
7
+ except Exception:
8
+ BASE_DIR = Path("")
9
+
10
+ sim, plot_cfg = load_simulator_from_project(BASE_DIR / "project.yaml")
11
+
12
+ logs = sim.run()
13
+ if True and plot_cfg is not None:
14
+ plot_from_config(logs, plot_cfg)
@@ -0,0 +1,107 @@
1
+ import os
2
+ import Sofa
3
+
4
+ dir_path = os.path.dirname(os.path.abspath(__file__))
5
+ # sys.path.append(specific_path) # Si jamais besoin de fichier externe
6
+ path = os.path.join(dir_path, 'mesh')
7
+
8
+
9
+ def createScene(rootNode):
10
+ from FingerController import FingerController
11
+
12
+ rootNode.addObject("RequiredPlugin", name='SoftRobots')
13
+ rootNode.addObject("RequiredPlugin", name='SofaPython3')
14
+ rootNode.addObject('RequiredPlugin', pluginName=[
15
+ "Sofa.Component.AnimationLoop", # Needed to use components FreeMotionAnimationLoop
16
+ "Sofa.Component.Constraint.Lagrangian.Correction", # Needed to use components GenericConstraintCorrection
17
+ "Sofa.Component.Constraint.Lagrangian.Solver", # Needed to use components GenericConstraintSolver
18
+ "Sofa.Component.Engine.Select", # Needed to use components BoxROI
19
+ "Sofa.Component.IO.Mesh", # Needed to use components MeshSTLLoader, MeshVTKLoader
20
+ "Sofa.Component.LinearSolver.Direct", # Needed to use components SparseLDLSolver
21
+ "Sofa.Component.Mass", # Needed to use components UniformMass
22
+ "Sofa.Component.ODESolver.Backward", # Needed to use components EulerImplicitSolver
23
+ "Sofa.Component.Setting", # Needed to use components BackgroundSetting
24
+ "Sofa.Component.SolidMechanics.FEM.Elastic", # Needed to use components TetrahedronFEMForceField
25
+ "Sofa.Component.SolidMechanics.Spring", # Needed to use components RestShapeSpringsForceField
26
+ "Sofa.Component.Topology.Container.Constant", # Needed to use components MeshTopology
27
+ "Sofa.Component.Visual", # Needed to use components VisualStyle
28
+ "Sofa.GL.Component.Rendering3D", # Needed to use components OglModel, OglSceneFrame
29
+ "Sofa.Component.StateContainer",
30
+ 'Sofa.Component.Mapping.Linear'
31
+ ])
32
+ rootNode.addObject('VisualStyle',
33
+ displayFlags='showVisualModels hideBehaviorModels showCollisionModels hideBoundingCollisionModels hideForceFields showInteractionForceFields hideWireframe')
34
+
35
+ rootNode.addObject('FreeMotionAnimationLoop')
36
+ rootNode.addObject('DefaultVisualManagerLoop')
37
+
38
+ rootNode.addObject('GenericConstraintSolver', tolerance=1e-5, maxIterations=100)
39
+
40
+ rootNode.gravity = [0, -9810, 0]
41
+ rootNode.dt = 0.01
42
+
43
+ ##########################################
44
+ # FEM Model #
45
+ ##########################################
46
+ finger = rootNode.addChild('finger')
47
+ finger.addObject('EulerImplicitSolver', name='odesolver', rayleighMass=0.1, rayleighStiffness=0.1)
48
+ finger.addObject('SparseLDLSolver', template='CompressedRowSparseMatrixMat3x3d')
49
+
50
+ # Add a component to load a VTK tetrahedral mesh and expose the resulting topology in the scene .
51
+ finger.addObject('MeshVTKLoader', name='loader', filename=os.path.join(path, 'finger.vtk'))
52
+ finger.addObject('MeshTopology', src='@loader', name='container')
53
+
54
+ # Create a MechanicaObject component to stores the DoFs of the model
55
+ finger.addObject('MechanicalObject', name='tetras', template='Vec3', showIndices=False, showIndicesScale=4e-5)
56
+
57
+ finger.addObject('UniformMass', totalMass=0.075)
58
+ finger.addObject('TetrahedronFEMForceField', template='Vec3', name='FEM', method='large', poissonRatio=0.45,
59
+ youngModulus=600)
60
+ finger.addObject('BoxROI', name='roi', box=[-15, 0, 0, 5, 10, 15], drawBoxes=True)
61
+ finger.addObject('RestShapeSpringsForceField', points=finger.roi.indices.getLinkPath(), stiffness=1e12)
62
+ finger.addObject('GenericConstraintCorrection')
63
+
64
+ ##########################################
65
+ # Cable #
66
+ ##########################################
67
+
68
+ cable = finger.addChild('cable')
69
+ cable.addObject('MechanicalObject',
70
+ position=[
71
+ [-17.5, 12.5, 2.5],
72
+ [-32.5, 12.5, 2.5],
73
+ [-47.5, 12.5, 2.5],
74
+ [-62.5, 12.5, 2.5],
75
+ [-77.5, 12.5, 2.5],
76
+
77
+ [-85.5, 12.5, 6.5],
78
+ [-85.5, 12.5, 8.5],
79
+ [-83.5, 12.5, 4.5],
80
+ [-83.5, 12.5, 10.5],
81
+
82
+ [-77.5, 12.5, 12.5],
83
+ [-62.5, 12.5, 12.5],
84
+ [-47.5, 12.5, 12.5],
85
+ [-32.5, 12.5, 12.5],
86
+ [-17.5, 12.5, 12.5]])
87
+
88
+ cable.addObject('CableConstraint', name="aCableActuator",
89
+ indices=list(range(0, 14)),
90
+ minForce=0, # Set that the cable can't push
91
+ pullPoint=[0.0, 12.5, 2.5])
92
+ cable.addObject('BarycentricMapping')
93
+
94
+ controller = FingerController(rootNode, cable.aCableActuator, finger.tetras)
95
+ finger.addObject(controller)
96
+
97
+ ##########################################
98
+ # Visualization #
99
+ ##########################################
100
+ fingerVisu = finger.addChild('visu')
101
+
102
+ # Add to this empty node a rendering model made of triangles and loaded from a stl file.
103
+ fingerVisu.addObject('MeshSTLLoader', filename=os.path.join(path, "finger.stl"), name="loader")
104
+ fingerVisu.addObject('OglModel', src="@loader", color=[0.0, 0.7, 0.7, 1])
105
+ fingerVisu.addObject('BarycentricMapping')
106
+
107
+ return rootNode, controller
@@ -0,0 +1,48 @@
1
+ import numpy as np
2
+ from pySimBlocks.blocks.systems.sofa import SofaPysimBlocksController
3
+
4
+ import Sofa
5
+
6
+
7
+ class FingerController(SofaPysimBlocksController):
8
+
9
+ def __init__(self, root, actuator, mo, tip_index=121, name="FingerController"):
10
+ super().__init__(root, name=name)
11
+
12
+ self.mo = mo
13
+ self.actuator = actuator
14
+ self.tip_index = tip_index
15
+ self.dt = root.dt.value
16
+
17
+ # Inputs & outputs dictionaries
18
+ self.inputs = { "cable": None }
19
+ self.outputs = { "tip": None, "measure": None }
20
+
21
+ def prepare_scene(self):
22
+ if self.step_index == 10:
23
+ self.IS_READY = True
24
+
25
+ def get_outputs(self):
26
+ tip = self.mo.position[self.tip_index].copy()
27
+ self.outputs["tip"] = np.asarray(tip).reshape(-1, 1)
28
+ self.outputs["measure"] = np.asarray(tip[1]).reshape(-1, 1)
29
+
30
+ def set_inputs(self):
31
+ # 1. READ INPUT -------------------------------------
32
+ val = self.inputs["cable"]
33
+
34
+ # Safe default for first initialization call
35
+ if val is None:
36
+ # ↓↓↓ Valeur par défaut pour l’initialisation
37
+ val = 0.0
38
+
39
+ # Convert input to Sofa format
40
+ if isinstance(val, np.ndarray):
41
+ processed = val.flatten().tolist()
42
+ elif isinstance(val, (list, tuple)):
43
+ processed = val
44
+ else:
45
+ processed = [float(val)]
46
+
47
+ # Apply to actuator
48
+ self.actuator.value = processed
@@ -0,0 +1,64 @@
1
+ import os
2
+
3
+ from pySimBlocks import Model, Simulator, SimulationConfig, PlotConfig
4
+ from pySimBlocks.blocks.systems.sofa import SofaPlant
5
+ from pySimBlocks.blocks.sources import Step
6
+ from pySimBlocks.blocks.operators import Sum
7
+ from pySimBlocks.blocks.controllers import Pid
8
+ from pySimBlocks.project import plot_from_config
9
+
10
+
11
+ def main():
12
+
13
+ path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Finger.py')
14
+
15
+ # --- Create Blocks ---
16
+ step = Step(name="step", value_before=[[0.0]], value_after=[[8.0]], start_time=2.)
17
+ error = Sum(name="error", signs="+-")
18
+ pid = Pid("pid", controller="PI", Kp=0.3, Ki=0.8)
19
+
20
+ sofa_block = SofaPlant(
21
+ name="sofa_finger",
22
+ scene_file=path,
23
+ input_keys=["cable"],
24
+ output_keys=["tip", "measure"],
25
+ )
26
+
27
+ # --- Build the model ---
28
+ model = Model(name="sofa_finger_model")
29
+ for block in [step, error, pid, sofa_block]:
30
+ model.add_block(block)
31
+
32
+ model.connect("step", "out", "error", "in1")
33
+ model.connect("sofa_finger", "measure", "error", "in2")
34
+ model.connect("error", "out", "pid", "e")
35
+ model.connect("pid", "u", "sofa_finger", "cable")
36
+
37
+
38
+ # --- Create the simulator ---
39
+ dt = 0.01
40
+ T = 5.0
41
+ sim_cfg = SimulationConfig(dt, T)
42
+ sim = Simulator(model, sim_cfg, verbose=False)
43
+
44
+ # --- Run simulation ---
45
+ logs = sim.run(logging=[
46
+ "step.outputs.out",
47
+ "sofa_finger.outputs.measure",
48
+ "pid.outputs.u"
49
+ ],
50
+ )
51
+
52
+ # --- Inspect / print some results ---
53
+ plot_cfg = PlotConfig([
54
+ {'title': 'Ref vs Output',
55
+ 'signals': ['step.outputs.out', 'sofa_finger.outputs.measure']},
56
+ {'title': 'Command',
57
+ 'signals': ['pid.outputs.u']}
58
+ ])
59
+ plot_from_config(logs, plot_cfg)
60
+
61
+
62
+
63
+ if __name__ == '__main__':
64
+ main()
@@ -0,0 +1,58 @@
1
+ import os
2
+
3
+ from pySimBlocks import Model, Simulator, SimulationConfig, PlotConfig
4
+ from pySimBlocks.blocks.systems.sofa import SofaPlant
5
+ from pySimBlocks.blocks.sources import Step
6
+ from pySimBlocks.project.plot_from_config import plot_from_config
7
+
8
+
9
+ def main():
10
+
11
+ path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Finger.py')
12
+
13
+
14
+ # --- Create Blocks ---
15
+ step = Step(
16
+ name="step",
17
+ value_before=0.0,
18
+ value_after=1.0,
19
+ start_time=0.5,
20
+ )
21
+
22
+ sofa_block = SofaPlant(
23
+ name="sofa_finger",
24
+ scene_file=path,
25
+ input_keys=["cable"],
26
+ output_keys=["tip"],
27
+ )
28
+
29
+ # --- Build the model ---
30
+ model = Model(name="sofa_finger_model")
31
+ model.add_block(step)
32
+ model.add_block(sofa_block)
33
+ model.connect("step", "out", "sofa_finger", "cable")
34
+
35
+
36
+ # --- Create the simulator ---
37
+ dt = 0.01
38
+ T = 5.0
39
+ sim_cfg = SimulationConfig(dt, T)
40
+ sim = Simulator(model, sim_cfg)
41
+
42
+ # --- Run simulation ---
43
+ logs = sim.run(logging=[
44
+ "step.outputs.out",
45
+ "sofa_finger.outputs.tip",
46
+ ],
47
+ )
48
+
49
+ # --- Plotting ---
50
+ plot_cfg = PlotConfig([
51
+ {'title': 'Finger Tip Position',
52
+ 'signals': ['step.outputs.out', 'sofa_finger.outputs.tip']}
53
+ ])
54
+ plot_from_config(logs, plot_cfg)
55
+
56
+
57
+ if __name__ == '__main__':
58
+ main()
@@ -0,0 +1,7 @@
1
+ def g(t, dt, u1, u2):
2
+ y1 = 3 * u1
3
+ y2 = 2 * u2 + dt
4
+ return {
5
+ "y1": y1,
6
+ "y2": y2
7
+ }
@@ -0,0 +1,14 @@
1
+ from pathlib import Path
2
+ from pySimBlocks.project import load_simulator_from_project
3
+ from pySimBlocks.project.plot_from_config import plot_from_config
4
+
5
+ try:
6
+ BASE_DIR = Path(__file__).parent.resolve()
7
+ except Exception:
8
+ BASE_DIR = Path("")
9
+
10
+ sim, plot_cfg = load_simulator_from_project(BASE_DIR / 'project.yaml')
11
+
12
+ logs = sim.run()
13
+ if True and plot_cfg is not None:
14
+ plot_from_config(logs, plot_cfg)
@@ -0,0 +1,14 @@
1
+ from pathlib import Path
2
+ from pySimBlocks.project import load_simulator_from_project
3
+ from pySimBlocks.project.plot_from_config import plot_from_config
4
+
5
+ try:
6
+ BASE_DIR = Path(__file__).parent.resolve()
7
+ except Exception:
8
+ BASE_DIR = Path("")
9
+
10
+ sim, plot_cfg = load_simulator_from_project(BASE_DIR / "project.yaml")
11
+
12
+ logs = sim.run()
13
+ if True and plot_cfg is not None:
14
+ plot_from_config(logs, plot_cfg)
@@ -0,0 +1,91 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+
4
+ from pySimBlocks import Model, Simulator, SimulationConfig
5
+ from pySimBlocks.blocks.sources import Step
6
+ from pySimBlocks.blocks.systems import LinearStateSpace
7
+ from pySimBlocks.blocks.operators import Gain, Sum, DiscreteIntegrator
8
+
9
+
10
+ def main():
11
+ # DC Motor parameters
12
+ R = 0.1
13
+ L = 0.5
14
+ J = 0.01
15
+ K = 0.1
16
+ a = 0.001
17
+
18
+ Kp = 0.001
19
+ Ki = 0.02
20
+
21
+ # Simulation parameters
22
+ dt = 0.01
23
+ T = 100.
24
+
25
+ # State-space matrices
26
+ A = np.array([[1-dt*R/L, -dt*K/L], [dt*K/J, 1-dt*a/J]])
27
+ B = np.array([[dt/L], [0]])
28
+ C = np.array([[0, 1]])
29
+
30
+ # Model
31
+ test_order = [
32
+ [0, 6, 2, 1, 3, 4, 5],
33
+ [0, 3, 2, 1, 6, 4, 5],
34
+ [0, 1, 2, 3, 4, 5, 6],
35
+ [0, 1, 2, 6, 4, 5, 3],
36
+ [3, 2, 0, 1, 6, 4, 5],
37
+ [4, 2, 6, 0, 1, 3, 5]
38
+ ]
39
+ for order in test_order:
40
+ ref = Step("ref", start_time=1., value_before=0., value_after=1.)
41
+ motor = LinearStateSpace("motor", A, B, C)
42
+ error = Sum("error", signs="+-")
43
+ kp = Gain("Kp", Kp)
44
+ ki = Gain("Ki", Ki)
45
+ integrator = DiscreteIntegrator("integrator")
46
+ sum = Sum("sum", signs="++")
47
+
48
+ blocks = [ref, error, kp, integrator, ki, sum, motor]
49
+
50
+ model = Model("DC Motor Control")
51
+ for i in order:
52
+ model.add_block(blocks[i])
53
+ model.connect("ref", "out", "error", "in1")
54
+ model.connect("motor", "y", "error", "in2")
55
+ model.connect("error", "out", "Kp", "in")
56
+ model.connect("error", "out", "Ki", "in")
57
+ model.connect("Ki", "out", "integrator", "in")
58
+ model.connect("integrator", "out", "sum", "in2")
59
+ model.connect("Kp", "out", "sum", "in1")
60
+ model.connect("sum", "out", "motor", "u")
61
+
62
+ # Simulator
63
+ sim_cfg = SimulationConfig(dt, T)
64
+ sim = Simulator(model, sim_cfg, verbose=False)
65
+
66
+ logs = sim.run(logging=[
67
+ "ref.outputs.out",
68
+ "motor.outputs.y",
69
+ "sum.outputs.out"
70
+ ])
71
+
72
+ time = sim.get_data("time")
73
+ r = sim.get_data("ref.outputs.out").squeeze()
74
+ w = sim.get_data("motor.outputs.y").squeeze()
75
+ u = sim.get_data("sum.outputs.out").squeeze()
76
+
77
+ print(w[-5:].flatten())
78
+
79
+ plt.figure()
80
+ plt.step(time, r, '--r', label="Reference (rad/s)", where='post')
81
+ plt.step(time, w, '--b', label="Motor Speed (rad/s)", where='post')
82
+ plt.step(time, u, '--g', label="Control Input (V)", where='post')
83
+ plt.xlabel("Time (s)")
84
+ plt.ylabel("Speed (rad/s)")
85
+ plt.title("DC Motor Speed Response")
86
+ plt.legend()
87
+ plt.grid()
88
+ plt.show()
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -0,0 +1,62 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from pySimBlocks import Model, Simulator, SimulationConfig
4
+ from pySimBlocks.blocks.sources import Step
5
+ from pySimBlocks.blocks.systems import LinearStateSpace
6
+
7
+
8
+ def main():
9
+ # DC Motor parameters
10
+ R = 0.1
11
+ L = 0.5
12
+ J = 0.01
13
+ K = 0.1
14
+ a = 0.001
15
+
16
+ # Simulation parameters
17
+ dt = 0.01
18
+ T = 100.
19
+
20
+ # State-space matrices
21
+ A = np.array([[1-dt*R/L, -dt*K/L], [dt*K/J, 1-dt*a/J]])
22
+ B = np.array([[dt/L], [0]])
23
+ C = np.array([[0, 1]])
24
+
25
+ # Blocks
26
+ ref = Step("command", start_time=1., value_before=0., value_after=1.)
27
+ motor = LinearStateSpace("motor", A, B, C)
28
+
29
+
30
+ # Model
31
+ model = Model("DC Motor Control")
32
+ for block in [ref, motor]:
33
+ model.add_block(block)
34
+ model.connect("command", "out", "motor", "u")
35
+
36
+ # Simulator
37
+ sim_cfg = SimulationConfig(dt, T, logging=[
38
+ "command.outputs.out",
39
+ "motor.outputs.y"
40
+ ])
41
+ sim = Simulator(model, sim_cfg)
42
+ logs = sim.run()
43
+
44
+ time = sim.get_data("time")
45
+ u = sim.get_data("command.outputs.out").squeeze()
46
+ w = sim.get_data("motor.outputs.y").squeeze()
47
+
48
+ print("Open-Loop DC Motor Response:")
49
+ print(w[-5:].flatten())
50
+
51
+ plt.figure()
52
+ plt.step(time, w, '--b', label="Motor Speed (rad/s)")
53
+ plt.step(time, u, '--g', label="Control Input (V)")
54
+ plt.xlabel("Time (s)")
55
+ plt.ylabel("Speed (rad/s)")
56
+ plt.legend()
57
+ plt.grid()
58
+ plt.title("Open-Loop DC Motor Response")
59
+ plt.show()
60
+
61
+ if __name__ == "__main__":
62
+ main()