reachy-mini 1.0.0rc1__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.

Potentially problematic release.


This version of reachy-mini might be problematic. Click here for more details.

Files changed (359) hide show
  1. reachy_mini/__init__.py +4 -0
  2. reachy_mini/apps/__init__.py +23 -0
  3. reachy_mini/apps/app.py +119 -0
  4. reachy_mini/apps/manager.py +178 -0
  5. reachy_mini/apps/sources/__init__.py +4 -0
  6. reachy_mini/apps/sources/hf_space.py +25 -0
  7. reachy_mini/apps/sources/local_common_venv.py +38 -0
  8. reachy_mini/apps/templates/README.md.j2 +1 -0
  9. reachy_mini/apps/templates/main.py.j2 +46 -0
  10. reachy_mini/apps/templates/pyproject.toml.j2 +18 -0
  11. reachy_mini/apps/utils.py +30 -0
  12. reachy_mini/assets/config/hardware_config.yaml +119 -0
  13. reachy_mini/assets/confused1.wav +0 -0
  14. reachy_mini/assets/count.wav +0 -0
  15. reachy_mini/assets/dance1.wav +0 -0
  16. reachy_mini/assets/go_sleep.wav +0 -0
  17. reachy_mini/assets/impatient1.wav +0 -0
  18. reachy_mini/assets/kinematics_data.json +253 -0
  19. reachy_mini/assets/models/fknetwork.dynamic.onnx +3 -0
  20. reachy_mini/assets/models/fknetwork.onnx +3 -0
  21. reachy_mini/assets/models/fknetwork_int8.onnx +3 -0
  22. reachy_mini/assets/models/iknetwork.onnx +3 -0
  23. reachy_mini/assets/wake_up.wav +0 -0
  24. reachy_mini/daemon/__init__.py +1 -0
  25. reachy_mini/daemon/app/__init__.py +1 -0
  26. reachy_mini/daemon/app/dashboard/apps_manager.html +202 -0
  27. reachy_mini/daemon/app/dashboard/js/3rdparty/gstwebrtc-api-2.0.0.min.js +5 -0
  28. reachy_mini/daemon/app/dashboard/js/dashboard.js +121 -0
  29. reachy_mini/daemon/app/dashboard/live_robot_state.html +242 -0
  30. reachy_mini/daemon/app/dashboard/style.css +37 -0
  31. reachy_mini/daemon/app/dependencies.py +36 -0
  32. reachy_mini/daemon/app/main.py +271 -0
  33. reachy_mini/daemon/app/models.py +146 -0
  34. reachy_mini/daemon/app/routers/apps.py +220 -0
  35. reachy_mini/daemon/app/routers/daemon.py +53 -0
  36. reachy_mini/daemon/app/routers/kinematics.py +36 -0
  37. reachy_mini/daemon/app/routers/motors.py +41 -0
  38. reachy_mini/daemon/app/routers/move.py +200 -0
  39. reachy_mini/daemon/app/routers/state.py +137 -0
  40. reachy_mini/daemon/app/templates/dashboard.html +40 -0
  41. reachy_mini/daemon/backend/__init__.py +1 -0
  42. reachy_mini/daemon/backend/abstract.py +717 -0
  43. reachy_mini/daemon/backend/mujoco/__init__.py +36 -0
  44. reachy_mini/daemon/backend/mujoco/backend.py +304 -0
  45. reachy_mini/daemon/backend/mujoco/utils.py +59 -0
  46. reachy_mini/daemon/backend/mujoco/video_udp.py +53 -0
  47. reachy_mini/daemon/backend/robot/__init__.py +8 -0
  48. reachy_mini/daemon/backend/robot/backend.py +490 -0
  49. reachy_mini/daemon/daemon.py +442 -0
  50. reachy_mini/daemon/utils.py +114 -0
  51. reachy_mini/descriptions/reachy_mini/mjcf/additional.xml +6 -0
  52. reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.part +13 -0
  53. reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.stl +3 -0
  54. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.part +13 -0
  55. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.stl +3 -0
  56. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.part +13 -0
  57. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.stl +3 -0
  58. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.part +13 -0
  59. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.stl +3 -0
  60. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.part +13 -0
  61. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.stl +3 -0
  62. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.part +13 -0
  63. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.stl +3 -0
  64. reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.part +13 -0
  65. reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.stl +3 -0
  66. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.part +13 -0
  67. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.stl +3 -0
  68. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.part +13 -0
  69. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.stl +3 -0
  70. reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.part +13 -0
  71. reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.stl +3 -0
  72. reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.part +13 -0
  73. reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.stl +3 -0
  74. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.part +13 -0
  75. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.stl +3 -0
  76. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.part +13 -0
  77. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.stl +3 -0
  78. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.part +13 -0
  79. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.stl +3 -0
  80. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.part +13 -0
  81. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.stl +3 -0
  82. reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.part +13 -0
  83. reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.stl +3 -0
  84. reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/croissant_1k.obj +3 -0
  85. reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/textures/croissant_diff_1k.png +3 -0
  86. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.part +13 -0
  87. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.stl +3 -0
  88. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.part +13 -0
  89. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.stl +3 -0
  90. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.part +13 -0
  91. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.stl +3 -0
  92. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.part +13 -0
  93. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.stl +3 -0
  94. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.part +13 -0
  95. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.stl +3 -0
  96. reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/food_apple_01_1k.obj +3 -0
  97. reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/textures/food_apple_01_diff_1k.png +3 -0
  98. reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.part +13 -0
  99. reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.stl +3 -0
  100. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.part +13 -0
  101. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.stl +3 -0
  102. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.part +13 -0
  103. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.stl +3 -0
  104. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.part +13 -0
  105. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.stl +3 -0
  106. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.part +13 -0
  107. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.stl +3 -0
  108. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.part +13 -0
  109. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.stl +3 -0
  110. reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.part +13 -0
  111. reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.stl +3 -0
  112. reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.part +13 -0
  113. reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.stl +3 -0
  114. reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.part +13 -0
  115. reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.stl +3 -0
  116. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.part +13 -0
  117. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.stl +3 -0
  118. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.part +13 -0
  119. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.stl +3 -0
  120. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.part +13 -0
  121. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.stl +3 -0
  122. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.part +13 -0
  123. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.stl +3 -0
  124. reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.part +13 -0
  125. reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.stl +3 -0
  126. reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/rubber_duck_toy_1k.obj +3 -0
  127. reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/textures/rubber_duck_toy_diff_1k.png +3 -0
  128. reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.part +13 -0
  129. reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.stl +3 -0
  130. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.part +13 -0
  131. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.stl +3 -0
  132. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.part +13 -0
  133. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.stl +3 -0
  134. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.part +13 -0
  135. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.stl +3 -0
  136. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.part +13 -0
  137. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.stl +3 -0
  138. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.part +13 -0
  139. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.stl +3 -0
  140. reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/textures/wooden_table_02_diff_1k.png +3 -0
  141. reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/wooden_table_02_1k.obj +3 -0
  142. reachy_mini/descriptions/reachy_mini/mjcf/config.json +21 -0
  143. reachy_mini/descriptions/reachy_mini/mjcf/joints_properties.xml +29 -0
  144. reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml +613 -0
  145. reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml.bak +442 -0
  146. reachy_mini/descriptions/reachy_mini/mjcf/scene.xml +24 -0
  147. reachy_mini/descriptions/reachy_mini/mjcf/scenes/empty.xml +27 -0
  148. reachy_mini/descriptions/reachy_mini/mjcf/scenes/minimal.xml +131 -0
  149. reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part +13 -0
  150. reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl +3 -0
  151. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part +13 -0
  152. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl +3 -0
  153. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part +13 -0
  154. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl +3 -0
  155. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part +13 -0
  156. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl +3 -0
  157. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part +13 -0
  158. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl +3 -0
  159. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part +13 -0
  160. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl +3 -0
  161. reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part +13 -0
  162. reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl +3 -0
  163. reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part +13 -0
  164. reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl +3 -0
  165. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part +13 -0
  166. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl +3 -0
  167. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part +13 -0
  168. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl +3 -0
  169. reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part +13 -0
  170. reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl +3 -0
  171. reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part +13 -0
  172. reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl +3 -0
  173. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part +13 -0
  174. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl +3 -0
  175. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part +13 -0
  176. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl +3 -0
  177. reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part +13 -0
  178. reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl +3 -0
  179. reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part +13 -0
  180. reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl +3 -0
  181. reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part +13 -0
  182. reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl +3 -0
  183. reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part +13 -0
  184. reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl +3 -0
  185. reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part +13 -0
  186. reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl +3 -0
  187. reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part +13 -0
  188. reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl +3 -0
  189. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part +13 -0
  190. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl +3 -0
  191. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part +13 -0
  192. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl +3 -0
  193. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part +13 -0
  194. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl +3 -0
  195. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part +13 -0
  196. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl +3 -0
  197. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part +13 -0
  198. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl +3 -0
  199. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part +14 -0
  200. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl +3 -0
  201. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part +14 -0
  202. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl +3 -0
  203. reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part +13 -0
  204. reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl +3 -0
  205. reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part +13 -0
  206. reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl +3 -0
  207. reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part +13 -0
  208. reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl +3 -0
  209. reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part +13 -0
  210. reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl +3 -0
  211. reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part +13 -0
  212. reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl +3 -0
  213. reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part +13 -0
  214. reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl +3 -0
  215. reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part +13 -0
  216. reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl +3 -0
  217. reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part +13 -0
  218. reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl +3 -0
  219. reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part +13 -0
  220. reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl +3 -0
  221. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part +13 -0
  222. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl +3 -0
  223. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part +13 -0
  224. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl +3 -0
  225. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part +13 -0
  226. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl +3 -0
  227. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part +13 -0
  228. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl +3 -0
  229. reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part +13 -0
  230. reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl +3 -0
  231. reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part +13 -0
  232. reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl +3 -0
  233. reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part +13 -0
  234. reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl +3 -0
  235. reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part +13 -0
  236. reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl +3 -0
  237. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part +13 -0
  238. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl +3 -0
  239. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part +13 -0
  240. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl +3 -0
  241. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part +13 -0
  242. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl +3 -0
  243. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part +13 -0
  244. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl +3 -0
  245. reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part +13 -0
  246. reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl +3 -0
  247. reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part +13 -0
  248. reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl +3 -0
  249. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part +13 -0
  250. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl +3 -0
  251. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part +13 -0
  252. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl +3 -0
  253. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part +13 -0
  254. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl +3 -0
  255. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part +13 -0
  256. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl +3 -0
  257. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part +13 -0
  258. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl +3 -0
  259. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part +13 -0
  260. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl +3 -0
  261. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part +13 -0
  262. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl +3 -0
  263. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part +13 -0
  264. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl +3 -0
  265. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part +13 -0
  266. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl +3 -0
  267. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part +13 -0
  268. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl +3 -0
  269. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part +13 -0
  270. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl +3 -0
  271. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part +13 -0
  272. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl +3 -0
  273. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part +13 -0
  274. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl +3 -0
  275. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part +13 -0
  276. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl +3 -0
  277. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part +13 -0
  278. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl +3 -0
  279. reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part +13 -0
  280. reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl +3 -0
  281. reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part +13 -0
  282. reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl +3 -0
  283. reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part +13 -0
  284. reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl +3 -0
  285. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part +13 -0
  286. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl +3 -0
  287. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part +13 -0
  288. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl +3 -0
  289. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part +13 -0
  290. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl +3 -0
  291. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part +13 -0
  292. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl +3 -0
  293. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part +13 -0
  294. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl +3 -0
  295. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part +13 -0
  296. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl +3 -0
  297. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part +13 -0
  298. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl +3 -0
  299. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part +13 -0
  300. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl +3 -0
  301. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part +13 -0
  302. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl +3 -0
  303. reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part +13 -0
  304. reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl +3 -0
  305. reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part +13 -0
  306. reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl +3 -0
  307. reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part +13 -0
  308. reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl +3 -0
  309. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part +14 -0
  310. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl +3 -0
  311. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part +14 -0
  312. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl +3 -0
  313. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part +14 -0
  314. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl +3 -0
  315. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part +14 -0
  316. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl +3 -0
  317. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part +14 -0
  318. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl +3 -0
  319. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part +14 -0
  320. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl +3 -0
  321. reachy_mini/descriptions/reachy_mini/urdf/config.json +18 -0
  322. reachy_mini/descriptions/reachy_mini/urdf/robot.urdf +3282 -0
  323. reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak +3282 -0
  324. reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf +2316 -0
  325. reachy_mini/io/__init__.py +1 -0
  326. reachy_mini/io/abstract.py +70 -0
  327. reachy_mini/io/protocol.py +44 -0
  328. reachy_mini/io/zenoh_client.py +258 -0
  329. reachy_mini/io/zenoh_server.py +183 -0
  330. reachy_mini/kinematics/__init__.py +68 -0
  331. reachy_mini/kinematics/analytical_kinematics.py +102 -0
  332. reachy_mini/kinematics/nn_kinematics.py +100 -0
  333. reachy_mini/kinematics/placo_kinematics.py +662 -0
  334. reachy_mini/media/__init__.py +1 -0
  335. reachy_mini/media/audio_base.py +75 -0
  336. reachy_mini/media/audio_gstreamer.py +194 -0
  337. reachy_mini/media/audio_sounddevice.py +207 -0
  338. reachy_mini/media/audio_utils.py +27 -0
  339. reachy_mini/media/camera_base.py +58 -0
  340. reachy_mini/media/camera_constants.py +13 -0
  341. reachy_mini/media/camera_gstreamer.py +144 -0
  342. reachy_mini/media/camera_opencv.py +61 -0
  343. reachy_mini/media/camera_utils.py +60 -0
  344. reachy_mini/media/media_manager.py +186 -0
  345. reachy_mini/motion/__init__.py +4 -0
  346. reachy_mini/motion/goto.py +71 -0
  347. reachy_mini/motion/move.py +36 -0
  348. reachy_mini/motion/recorded_move.py +132 -0
  349. reachy_mini/reachy_mini.py +705 -0
  350. reachy_mini/utils/__init__.py +46 -0
  351. reachy_mini/utils/constants.py +9 -0
  352. reachy_mini/utils/interpolation.py +227 -0
  353. reachy_mini/utils/parse_urdf_for_kinematics.py +85 -0
  354. reachy_mini-1.0.0rc1.dist-info/METADATA +261 -0
  355. reachy_mini-1.0.0rc1.dist-info/RECORD +359 -0
  356. reachy_mini-1.0.0rc1.dist-info/WHEEL +5 -0
  357. reachy_mini-1.0.0rc1.dist-info/entry_points.txt +3 -0
  358. reachy_mini-1.0.0rc1.dist-info/licenses/LICENSE +201 -0
  359. reachy_mini-1.0.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,490 @@
1
+ """Robot Backend for Reachy Mini.
2
+
3
+ This module provides the `RobotBackend` class, which interfaces with the Reachy Mini motor controller to control the robot's movements and manage its status.
4
+ It handles the control loop, joint positions, torque enabling/disabling, and provides a status report of the robot's backend.
5
+ It uses the `ReachyMiniMotorController` to communicate with the robot's motors.
6
+ """
7
+
8
+ import json
9
+ import logging
10
+ import time
11
+ from dataclasses import dataclass
12
+ from datetime import timedelta
13
+ from multiprocessing import Event
14
+ from typing import Annotated, Any # It seems to be more accurate than threading.Event
15
+
16
+ import log_throttling
17
+ import numpy as np
18
+ import numpy.typing as npt
19
+ from reachy_mini_motor_controller import ReachyMiniPyControlLoop
20
+
21
+ from ..abstract import Backend, MotorControlMode
22
+
23
+
24
+ class RobotBackend(Backend):
25
+ """Real robot backend for Reachy Mini."""
26
+
27
+ def __init__(
28
+ self,
29
+ serialport: str,
30
+ log_level: str = "INFO",
31
+ check_collision: bool = False,
32
+ kinematics_engine: str = "AnalyticalKinematics",
33
+ ):
34
+ """Initialize the RobotBackend.
35
+
36
+ Args:
37
+ serialport (str): The serial port to which the Reachy Mini is connected.
38
+ log_level (str): The logging level for the backend. Default is "INFO".
39
+ check_collision (bool): If True, enable collision checking. Default is False.
40
+ kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics".
41
+
42
+ Tries to connect to the Reachy Mini motor controller and initializes the control loop.
43
+
44
+ """
45
+ super().__init__(
46
+ check_collision=check_collision, kinematics_engine=kinematics_engine
47
+ )
48
+
49
+ self.logger = logging.getLogger(__name__)
50
+ self.logger.setLevel(log_level)
51
+
52
+ self.control_loop_frequency = 50.0 # Hz
53
+ self.c: ReachyMiniPyControlLoop | None = ReachyMiniPyControlLoop(
54
+ serialport,
55
+ read_position_loop_period=timedelta(
56
+ seconds=1.0 / self.control_loop_frequency
57
+ ),
58
+ allowed_retries=5,
59
+ stats_pub_period=None,
60
+ )
61
+
62
+ self.motor_control_mode = self._infer_control_mode()
63
+ self._torque_enabled = self.motor_control_mode != MotorControlMode.Disabled
64
+ self.logger.info(f"Motor control mode: {self.motor_control_mode}")
65
+ self.last_alive: float | None = None
66
+
67
+ self._status = RobotBackendStatus(
68
+ motor_control_mode=self.motor_control_mode,
69
+ ready=False,
70
+ last_alive=None,
71
+ control_loop_stats={},
72
+ )
73
+ self._stats_record_period = 1.0 # seconds
74
+ self._stats: dict[str, Any] = {
75
+ "timestamps": [],
76
+ "nb_error": 0,
77
+ "record_period": self._stats_record_period,
78
+ }
79
+
80
+ self._current_head_operation_mode = -1 # Default to torque control mode
81
+ self._current_antennas_operation_mode = -1 # Default to torque control mode
82
+ self.target_antenna_joint_current = None # Placeholder for antenna joint torque
83
+ self.target_head_joint_current = None # Placeholder for head joint torque
84
+
85
+ def run(self) -> None:
86
+ """Run the control loop for the robot backend.
87
+
88
+ This method continuously updates the motor controller at a specified frequency.
89
+ It reads the joint positions, updates the motor controller, and publishes the joint positions.
90
+ It also handles errors and retries if the motor controller is not responding.
91
+ """
92
+ assert self.c is not None, "Motor controller not initialized or already closed."
93
+
94
+ period = 1.0 / self.control_loop_frequency # Control loop period in seconds
95
+
96
+ self.retries = 5
97
+ self.stats_record_t0 = time.time()
98
+
99
+ next_call_event = Event()
100
+
101
+ # Compute the forward kinematics to get the initial head pose
102
+ # IMPORTANT for wake_up
103
+ head_positions, _ = self.get_all_joint_positions()
104
+ # make sure to converge fully (a lot of iterations)
105
+ self.current_head_pose = self.head_kinematics.fk(
106
+ np.array(head_positions),
107
+ no_iterations=20,
108
+ )
109
+ assert self.current_head_pose is not None
110
+
111
+ self.head_kinematics.ik(self.current_head_pose, no_iterations=20)
112
+
113
+ while not self.should_stop.is_set():
114
+ start_t = time.time()
115
+ self._stats["timestamps"].append(time.time())
116
+ self._update()
117
+ took = time.time() - start_t
118
+
119
+ sleep_time = period - took
120
+ if sleep_time < 0:
121
+ self.logger.debug(
122
+ f"Control loop took too long: {took * 1000:.3f} ms, expected {period * 1000:.3f} ms"
123
+ )
124
+ sleep_time = 0.001
125
+
126
+ next_call_event.clear()
127
+ next_call_event.wait(sleep_time)
128
+
129
+ def _update(self) -> None:
130
+ assert self.c is not None, "Motor controller not initialized or already closed."
131
+
132
+ if self._torque_enabled:
133
+ if self._current_head_operation_mode != 0: # if position control mode
134
+ if self.target_head_joint_positions is not None:
135
+ self.c.set_stewart_platform_position(
136
+ self.target_head_joint_positions[1:].tolist()
137
+ )
138
+ self.c.set_body_rotation(self.target_head_joint_positions[0])
139
+ else: # it's in torque control mode
140
+ if self.gravity_compensation_mode:
141
+ # This function will set the head_joint_current
142
+ # to the current necessary to compensate for gravity
143
+ self.compensate_head_gravity()
144
+ if self.target_head_joint_current is not None:
145
+ self.c.set_stewart_platform_goal_current(
146
+ np.round(self.target_head_joint_current[1:], 0)
147
+ .astype(int)
148
+ .tolist()
149
+ )
150
+ # Body rotation torque control is not supported with feetech motors
151
+ # self.c.set_body_rotation_goal_current(int(self.target_head_joint_current[0]))
152
+
153
+ if self._current_antennas_operation_mode != 0: # if position control mode
154
+ if self.target_antenna_joint_positions is not None:
155
+ self.c.set_antennas_positions(
156
+ self.target_antenna_joint_positions.tolist()
157
+ )
158
+ # Antenna torque control is not supported with feetech motors
159
+ # else:
160
+ # if self.target_antenna_joint_current is not None:
161
+ # self.c.set_antennas_goal_current(
162
+ # np.round(self.target_antenna_joint_current, 0).astype(int).tolist()
163
+ # )
164
+
165
+ if (
166
+ self.joint_positions_publisher is not None
167
+ and self.pose_publisher is not None
168
+ ):
169
+ try:
170
+ head_positions, antenna_positions = self.get_all_joint_positions()
171
+
172
+ # Update the head kinematics model with the current head positions
173
+ self.update_head_kinematics_model(
174
+ np.array(head_positions),
175
+ np.array(antenna_positions),
176
+ )
177
+
178
+ # Update the target head joint positions from IK if necessary
179
+ # - does nothing if the targets did not change
180
+ if self.ik_required:
181
+ try:
182
+ self.update_target_head_joints_from_ik(
183
+ self.target_head_pose, self.target_body_yaw
184
+ )
185
+ except ValueError as e:
186
+ log_throttling.by_time(self.logger, interval=0.5).warning(
187
+ f"IK error: {e}"
188
+ )
189
+
190
+ if not self.is_shutting_down:
191
+ self.joint_positions_publisher.put(
192
+ json.dumps(
193
+ {
194
+ "head_joint_positions": head_positions,
195
+ "antennas_joint_positions": antenna_positions,
196
+ }
197
+ )
198
+ )
199
+ self.pose_publisher.put(
200
+ json.dumps(
201
+ {
202
+ "head_pose": self.get_present_head_pose().tolist(),
203
+ }
204
+ )
205
+ )
206
+
207
+ self.last_alive = time.time()
208
+
209
+ self.ready.set() # Mark the backend as ready
210
+ except RuntimeError as e:
211
+ self._stats["nb_error"] += 1
212
+ # self.logger.warning(f"Error reading positions: {e}")
213
+
214
+ assert self.last_alive is not None
215
+
216
+ if self.last_alive + 1 < time.time():
217
+ self.error = (
218
+ "No response from the robot's motor for the last second."
219
+ )
220
+
221
+ self.logger.error(
222
+ "No response from the robot for the last second, stopping."
223
+ )
224
+ raise e
225
+
226
+ if time.time() - self.stats_record_t0 > self._stats_record_period:
227
+ dt = np.diff(self._stats["timestamps"])
228
+ if len(dt) > 1:
229
+ self._status.control_loop_stats["mean_control_loop_frequency"] = (
230
+ float(np.mean(1.0 / dt))
231
+ )
232
+ self._status.control_loop_stats["max_control_loop_interval"] = (
233
+ float(np.max(dt))
234
+ )
235
+ self._status.control_loop_stats["nb_error"] = self._stats[
236
+ "nb_error"
237
+ ]
238
+
239
+ self._stats["timestamps"].clear()
240
+ self._stats["nb_error"] = 0
241
+ self.stats_record_t0 = time.time()
242
+
243
+ def close(self) -> None:
244
+ """Close the motor controller connection."""
245
+ if self.c is not None:
246
+ self.c.close()
247
+ self.c = None
248
+
249
+ def get_status(self) -> "RobotBackendStatus":
250
+ """Get the current status of the robot backend."""
251
+ self._status.error = self.error
252
+ self._status.motor_control_mode = self.motor_control_mode
253
+ return self._status
254
+
255
+ def enable_motors(self) -> None:
256
+ """Enable the motors by turning the torque on."""
257
+ assert self.c is not None, "Motor controller not initialized or already closed."
258
+
259
+ self.c.enable_torque()
260
+ self._torque_enabled = True
261
+
262
+ def disable_motors(self) -> None:
263
+ """Disable the motors by turning the torque off."""
264
+ assert self.c is not None, "Motor controller not initialized or already closed."
265
+
266
+ self.c.disable_torque()
267
+ self._torque_enabled = False
268
+
269
+ def set_head_operation_mode(self, mode: int) -> None:
270
+ """Change the operation mode of the head motors.
271
+
272
+ Args:
273
+ mode (int): The operation mode for the head motors.
274
+
275
+ The operation modes can be:
276
+ 0: torque control
277
+ 3: position control
278
+ 5: current-based position control.
279
+
280
+ Important:
281
+ This method does not work well with the current feetech motors (body rotation), as they do not support torque control.
282
+ So the method disables the antennas when in torque control mode.
283
+ The dynamixel motors used for the head do support torque control, so this method works as expected.
284
+
285
+ Args:
286
+ mode (int): The operation mode for the head motors.
287
+ This could be a specific mode like position control, velocity control, or torque control.
288
+
289
+ """
290
+ assert self.c is not None, "Motor controller not initialized or already closed."
291
+ assert mode in [0, 3, 5], (
292
+ "Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]."
293
+ f" Got {mode} instead"
294
+ )
295
+
296
+ # if motors are enabled, disable them before changing the mode
297
+ if self._torque_enabled:
298
+ self.c.enable_stewart_platform(False)
299
+ # set the new operation mode
300
+ self.c.set_stewart_platform_operating_mode(mode)
301
+
302
+ if mode != 0:
303
+ # if the mode is not torque control, we need to set the head joint positions
304
+ # to the current positions to avoid sudden movements
305
+ motor_pos = self.c.get_last_position()
306
+ self.target_head_joint_positions = np.array(
307
+ [motor_pos.body_yaw] + motor_pos.stewart
308
+ )
309
+
310
+ self.c.set_stewart_platform_position(
311
+ self.target_head_joint_positions[1:].tolist()
312
+ )
313
+ self.c.set_body_rotation(self.target_head_joint_positions[0])
314
+ self.c.enable_body_rotation(True)
315
+ self.c.set_body_rotation_operating_mode(0)
316
+ else:
317
+ self.c.enable_body_rotation(False)
318
+
319
+ if self._torque_enabled:
320
+ self.c.enable_stewart_platform(True)
321
+
322
+ self._current_head_operation_mode = mode
323
+
324
+ def set_antennas_operation_mode(self, mode: int) -> None:
325
+ """Change the operation mode of the antennas motors.
326
+
327
+ Args:
328
+ mode (int): The operation mode for the antennas motors (0: torque control, 3: position control, 5: current-based position control).
329
+
330
+ Important:
331
+ This method does not work well with the current feetech motors, as they do not support torque control.
332
+ So the method disables the antennas when in torque control mode.
333
+
334
+ Args:
335
+ mode (int): The operation mode for the antennas motors.
336
+ This could be a specific mode like position control, velocity control, or torque control.
337
+
338
+ """
339
+ assert self.c is not None, "Motor controller not initialized or already closed."
340
+ assert mode in [0, 3, 5], (
341
+ "Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]."
342
+ )
343
+
344
+ if self._current_antennas_operation_mode != mode:
345
+ if mode != 0:
346
+ # if the mode is not torque control, we need to set the head joint positions
347
+ # to the current positions to avoid sudden movements
348
+ self.target_antenna_joint_positions = np.array(
349
+ self.c.get_last_position().antennas
350
+ )
351
+ self.c.set_antennas_positions(
352
+ self.target_antenna_joint_positions.tolist()
353
+ )
354
+ self.c.enable_antennas(True)
355
+ else:
356
+ self.c.enable_antennas(False)
357
+
358
+ self._current_antennas_operation_mode = mode
359
+
360
+ def get_all_joint_positions(self) -> tuple[list[float], list[float]]:
361
+ """Get the current joint positions of the robot.
362
+
363
+ Returns:
364
+ tuple: A tuple containing two lists - the first list is for the head joint positions,
365
+ and the second list is for the antenna joint positions.
366
+
367
+ """
368
+ assert self.c is not None, "Motor controller not initialized or already closed."
369
+ positions = self.c.get_last_position()
370
+
371
+ yaw = positions.body_yaw
372
+ antennas = positions.antennas
373
+ dofs = positions.stewart
374
+
375
+ return [yaw] + list(dofs), list(antennas)
376
+
377
+ def get_present_head_joint_positions(
378
+ self,
379
+ ) -> Annotated[npt.NDArray[np.float64], (7,)]:
380
+ """Get the current joint positions of the head.
381
+
382
+ Returns:
383
+ list: A list of joint positions for the head, including the body rotation.
384
+
385
+ """
386
+ return np.array(self.get_all_joint_positions()[0])
387
+
388
+ def get_present_antenna_joint_positions(
389
+ self,
390
+ ) -> Annotated[npt.NDArray[np.float64], (2,)]:
391
+ """Get the current joint positions of the antennas.
392
+
393
+ Returns:
394
+ list: A list of joint positions for the antennas.
395
+
396
+ """
397
+ return np.array(self.get_all_joint_positions()[1])
398
+
399
+ def compensate_head_gravity(self) -> None:
400
+ """Calculate the currents necessary to compensate for gravity."""
401
+ assert self.kinematics_engine == "Placo", (
402
+ "Gravity compensation is only supported with the Placo kinematics engine."
403
+ )
404
+
405
+ # Even though in their docs dynamixes says that 1 count is 1 mA, in practice I've found it to be 3mA.
406
+ # I am not sure why this happens
407
+ # Another explanation is that our model is bad and the current is overestimated 3x (but I have not had these issues with other robots)
408
+ # So I am using a magic number to compensate for this.
409
+ # for currents under 30mA the constant is around 1
410
+ from_Nm_to_mA = 1.47 / 0.52 * 1000
411
+ # Conversion factor from Nm to mA for the Stewart platform motors
412
+ # The torque constant is not linear, so we need to use a correction factor
413
+ # This is a magic number that should be determined experimentally
414
+ # For currents under 30mA, the constant is around 3
415
+ # Then it drops to 1.0 for currents above 1.5A
416
+ correction_factor = 3.0
417
+ # Get the current head joint positions
418
+ head_joints = self.get_present_head_joint_positions()
419
+ gravity_torque = self.head_kinematics.compute_gravity_torque( # type: ignore [union-attr]
420
+ np.array(head_joints)
421
+ )
422
+ # Convert the torque from Nm to mA
423
+ current = gravity_torque * from_Nm_to_mA / correction_factor
424
+ # Set the head joint current
425
+ self.set_target_head_joint_current(current)
426
+
427
+ def get_motor_control_mode(self) -> MotorControlMode:
428
+ """Get the motor control mode."""
429
+ return self.motor_control_mode
430
+
431
+ def set_motor_control_mode(self, mode: MotorControlMode) -> None:
432
+ """Set the motor control mode."""
433
+ # Check if the mode is already set
434
+ if mode == self.motor_control_mode:
435
+ return
436
+
437
+ if mode == MotorControlMode.Enabled:
438
+ if self.motor_control_mode == MotorControlMode.GravityCompensation:
439
+ # First, make sure we switch to position control
440
+ self.disable_motors()
441
+ self.set_head_operation_mode(3)
442
+ self.set_antennas_operation_mode(3)
443
+
444
+ self.gravity_compensation_mode = False
445
+ self.enable_motors()
446
+
447
+ elif mode == MotorControlMode.Disabled:
448
+ self.gravity_compensation_mode = False
449
+ self.disable_motors()
450
+
451
+ elif mode == MotorControlMode.GravityCompensation:
452
+ if self.kinematics_engine != "Placo":
453
+ raise RuntimeError(
454
+ "Gravity compensation mode is only supported with the Placo kinematics engine."
455
+ )
456
+
457
+ self.disable_motors()
458
+ self.set_head_operation_mode(0)
459
+ self.set_antennas_operation_mode(0)
460
+ self.gravity_compensation_mode = True
461
+ self.enable_motors()
462
+
463
+ self.motor_control_mode = mode
464
+
465
+ def _infer_control_mode(self) -> MotorControlMode:
466
+ assert self.c is not None, "Motor controller not initialized or already closed."
467
+
468
+ torque = self.c.is_torque_enabled()
469
+
470
+ if not torque:
471
+ return MotorControlMode.Disabled
472
+
473
+ mode = self.c.get_stewart_platform_operating_mode()
474
+ if mode == 3:
475
+ return MotorControlMode.Enabled
476
+ elif mode == 1:
477
+ return MotorControlMode.GravityCompensation
478
+ else:
479
+ raise ValueError(f"Unknown motor control mode: {mode}")
480
+
481
+
482
+ @dataclass
483
+ class RobotBackendStatus:
484
+ """Status of the Robot Backend."""
485
+
486
+ ready: bool
487
+ motor_control_mode: MotorControlMode
488
+ last_alive: float | None
489
+ control_loop_stats: dict[str, Any]
490
+ error: str | None = None