reachy-mini 1.0.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.

Potentially problematic release.


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

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