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,750 @@
1
+ """Base class for robot backends, simulated or real.
2
+
3
+ This module defines the `Backend` class, which serves as a base for implementing
4
+ different types of robot backends, whether they are simulated (like Mujoco) or real
5
+ (connected via serial port). The class provides methods for managing joint positions,
6
+ torque control, and other backend-specific functionalities.
7
+ It is designed to be extended by subclasses that implement the specific behavior for
8
+ each type of backend.
9
+ """
10
+
11
+ import asyncio
12
+ import json
13
+ import logging
14
+ import threading
15
+ import time
16
+ import typing
17
+ from abc import abstractmethod
18
+ from enum import Enum
19
+ from pathlib import Path
20
+ from typing import Annotated, Any, Dict, Optional
21
+
22
+ import numpy as np
23
+ import zenoh
24
+ from numpy.typing import NDArray
25
+ from scipy.spatial.transform import Rotation as R
26
+
27
+ if typing.TYPE_CHECKING:
28
+ from reachy_mini.daemon.backend.mujoco.backend import MujocoBackendStatus
29
+ from reachy_mini.daemon.backend.robot.backend import RobotBackendStatus
30
+ from reachy_mini.kinematics import AnyKinematics
31
+ from reachy_mini.media.audio_sounddevice import SoundDeviceAudio
32
+ from reachy_mini.motion.goto import GotoMove
33
+ from reachy_mini.motion.move import Move
34
+ from reachy_mini.utils.constants import MODELS_ROOT_PATH, URDF_ROOT_PATH
35
+ from reachy_mini.utils.interpolation import (
36
+ InterpolationTechnique,
37
+ distance_between_poses,
38
+ time_trajectory,
39
+ )
40
+
41
+
42
+ class MotorControlMode(str, Enum):
43
+ """Enum for motor control modes."""
44
+
45
+ Enabled = "enabled" # Torque ON and controlled in position
46
+ Disabled = "disabled" # Torque OFF
47
+ GravityCompensation = "gravity_compensation" # Torque ON and controlled in current to compensate for gravity
48
+
49
+
50
+ class Backend:
51
+ """Base class for robot backends, simulated or real."""
52
+
53
+ def __init__(
54
+ self,
55
+ log_level: str = "INFO",
56
+ check_collision: bool = False,
57
+ kinematics_engine: str = "AnalyticalKinematics",
58
+ ) -> None:
59
+ """Initialize the backend."""
60
+ self.logger = logging.getLogger(__name__)
61
+ self.logger.setLevel(log_level)
62
+
63
+ self.should_stop = threading.Event()
64
+ self.ready = threading.Event()
65
+
66
+ self.check_collision = (
67
+ check_collision # Flag to enable/disable collision checking
68
+ )
69
+ self.kinematics_engine = kinematics_engine
70
+
71
+ self.logger.info(f"Using {self.kinematics_engine} kinematics engine")
72
+
73
+ if self.check_collision:
74
+ assert self.kinematics_engine == "Placo", (
75
+ "Collision checking is only available with Placo Kinematics"
76
+ )
77
+
78
+ self.gravity_compensation_mode = False # Flag for gravity compensation mode
79
+
80
+ if self.gravity_compensation_mode:
81
+ assert self.kinematics_engine == "Placo", (
82
+ "Gravity compensation is only available with Placo kinematics"
83
+ )
84
+
85
+ if self.kinematics_engine == "Placo":
86
+ from reachy_mini.kinematics import PlacoKinematics
87
+
88
+ self.head_kinematics: AnyKinematics = PlacoKinematics(
89
+ URDF_ROOT_PATH, check_collision=self.check_collision
90
+ )
91
+ elif self.kinematics_engine == "NN":
92
+ from reachy_mini.kinematics import NNKinematics
93
+
94
+ self.head_kinematics = NNKinematics(MODELS_ROOT_PATH)
95
+ elif self.kinematics_engine == "AnalyticalKinematics":
96
+ from reachy_mini.kinematics import AnalyticalKinematics
97
+
98
+ self.head_kinematics = AnalyticalKinematics()
99
+ else:
100
+ raise ValueError(
101
+ f"Unknown kinematics engine: {self.kinematics_engine}. Use 'Placo', 'NN' or 'AnalyticalKinematics'."
102
+ )
103
+
104
+ self.current_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = (
105
+ None # 4x4 pose matrix
106
+ )
107
+ self.target_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = (
108
+ None # 4x4 pose matrix
109
+ )
110
+ self.target_body_yaw: float | None = (
111
+ None # Last body yaw used in IK computations
112
+ )
113
+
114
+ self.target_head_joint_positions: (
115
+ Annotated[NDArray[np.float64], (7,)] | None
116
+ ) = None # [yaw, 0, 1, 2, 3, 4, 5]
117
+ self.current_head_joint_positions: (
118
+ Annotated[NDArray[np.float64], (7,)] | None
119
+ ) = None # [yaw, 0, 1, 2, 3, 4, 5]
120
+ self.target_antenna_joint_positions: (
121
+ Annotated[NDArray[np.float64], (2,)] | None
122
+ ) = None # [0, 1]
123
+ self.current_antenna_joint_positions: (
124
+ Annotated[NDArray[np.float64], (2,)] | None
125
+ ) = None # [0, 1]
126
+
127
+ self.joint_positions_publisher: zenoh.Publisher | None = None
128
+ self.pose_publisher: zenoh.Publisher | None = None
129
+ self.recording_publisher: zenoh.Publisher | None = None
130
+ self.error: str | None = None # To store any error that occurs during execution
131
+ self.is_recording = False # Flag to indicate if recording is active
132
+ self.recorded_data: list[dict[str, Any]] = [] # List to store recorded data
133
+
134
+ # variables to store the last computed head joint positions and pose
135
+ self._last_target_body_yaw: float | None = (
136
+ None # Last body yaw used in IK computations
137
+ )
138
+ self._last_target_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = (
139
+ None # Last head pose used in IK computations
140
+ )
141
+ self.target_head_joint_current: Annotated[NDArray[np.float64], (7,)] | None = (
142
+ None # Placeholder for head joint torque
143
+ )
144
+ self.ik_required = False # Flag to indicate if IK computation is required
145
+
146
+ self.is_shutting_down = False
147
+
148
+ # Tolerance for kinematics computations
149
+ # For Forward kinematics (around 0.25deg)
150
+ # - FK is calculated at each timestep and is susceptible to noise
151
+ self._fk_kin_tolerance = 1e-3 # rads
152
+ # For Inverse kinematics (around 0.5mm and 0.1 degrees)
153
+ # - IK is calculated only when the head pose is set by the user
154
+ self._ik_kin_tolerance = {
155
+ "rad": 2e-3, # rads
156
+ "m": 0.5e-3, # m
157
+ }
158
+
159
+ # Recording lock to guard buffer swaps and appends
160
+ self._rec_lock = threading.Lock()
161
+
162
+ self.audio = SoundDeviceAudio(log_level=log_level)
163
+
164
+ # Life cycle methods
165
+ def wrapped_run(self) -> None:
166
+ """Run the backend in a try-except block to store errors."""
167
+ try:
168
+ self.run()
169
+ except Exception as e:
170
+ self.error = str(e)
171
+ self.close()
172
+ raise e
173
+
174
+ def run(self) -> None:
175
+ """Run the backend.
176
+
177
+ This method is a placeholder and should be overridden by subclasses.
178
+ """
179
+ raise NotImplementedError("The method run should be overridden by subclasses.")
180
+
181
+ def close(self) -> None:
182
+ """Close the backend.
183
+
184
+ This method is a placeholder and should be overridden by subclasses.
185
+ """
186
+ raise NotImplementedError(
187
+ "The method close should be overridden by subclasses."
188
+ )
189
+
190
+ def get_status(self) -> "RobotBackendStatus | MujocoBackendStatus":
191
+ """Return backend statistics.
192
+
193
+ This method is a placeholder and should be overridden by subclasses.
194
+ """
195
+ raise NotImplementedError(
196
+ "The method get_status should be overridden by subclasses."
197
+ )
198
+
199
+ # Present/Target joint positions
200
+ def set_joint_positions_publisher(self, publisher: zenoh.Publisher) -> None:
201
+ """Set the publisher for joint positions.
202
+
203
+ Args:
204
+ publisher: A publisher object that will be used to publish joint positions.
205
+
206
+ """
207
+ self.joint_positions_publisher = publisher
208
+
209
+ def set_pose_publisher(self, publisher: zenoh.Publisher) -> None:
210
+ """Set the publisher for head pose.
211
+
212
+ Args:
213
+ publisher: A publisher object that will be used to publish head pose.
214
+
215
+ """
216
+ self.pose_publisher = publisher
217
+
218
+ def update_target_head_joints_from_ik(
219
+ self,
220
+ pose: Annotated[NDArray[np.float64], (4, 4)] | None = None,
221
+ body_yaw: float | None = None,
222
+ ) -> None:
223
+ """Update the target head joint positions from inverse kinematics.
224
+
225
+ Args:
226
+ pose (np.ndarray): 4x4 pose matrix representing the head pose.
227
+ body_yaw (float): The yaw angle of the body, used to adjust the head pose.
228
+
229
+ """
230
+ if pose is None:
231
+ pose = (
232
+ self.target_head_pose
233
+ if self.target_head_pose is not None
234
+ else np.eye(4)
235
+ )
236
+
237
+ if body_yaw is None:
238
+ body_yaw = self.target_body_yaw if self.target_body_yaw is not None else 0.0
239
+
240
+ # Compute the inverse kinematics to get the head joint positions
241
+ joints = self.head_kinematics.ik(pose, body_yaw=body_yaw)
242
+ if joints is None or np.any(np.isnan(joints)):
243
+ raise ValueError("WARNING: Collision detected or head pose not achievable!")
244
+
245
+ # update the target head pose and body yaw
246
+ self._last_target_head_pose = pose
247
+ self._last_target_body_yaw = body_yaw
248
+
249
+ self.target_head_joint_positions = joints
250
+
251
+ def set_target_head_pose(
252
+ self,
253
+ pose: Annotated[NDArray[np.float64], (4, 4)],
254
+ ) -> None:
255
+ """Set the target head pose for the robot.
256
+
257
+ Args:
258
+ pose (np.ndarray): 4x4 pose matrix representing the head pose.
259
+
260
+ """
261
+ self.target_head_pose = pose
262
+ self.ik_required = True
263
+
264
+ def set_target_body_yaw(self, body_yaw: float) -> None:
265
+ """Set the target body yaw for the robot.
266
+
267
+ Only used when doing a set_target() with a standalone body_yaw (no head pose).
268
+
269
+ Args:
270
+ body_yaw (float): The yaw angle of the body
271
+
272
+ """
273
+ self.target_body_yaw = body_yaw
274
+ self.ik_required = True # Do we need that here?
275
+
276
+ def set_target_head_joint_positions(
277
+ self, positions: Annotated[NDArray[np.float64], (7,)] | None
278
+ ) -> None:
279
+ """Set the head joint positions.
280
+
281
+ Args:
282
+ positions (List[float]): A list of joint positions for the head.
283
+
284
+ """
285
+ self.target_head_joint_positions = positions
286
+ self.ik_required = False
287
+
288
+ def set_target(
289
+ self,
290
+ head: Annotated[NDArray[np.float64], (4, 4)] | None = None, # 4x4 pose matrix
291
+ antennas: Annotated[NDArray[np.float64], (2,)]
292
+ | None = None, # [right_angle, left_angle] (in rads)
293
+ body_yaw: float = 0.0, # Body yaw angle in radians
294
+ ) -> None:
295
+ """Set the target head pose and/or antenna positions and/or body_yaw."""
296
+ if head is not None:
297
+ self.set_target_head_pose(head)
298
+
299
+ if body_yaw is not None:
300
+ self.set_target_body_yaw(body_yaw)
301
+
302
+ if antennas is not None:
303
+ self.set_target_antenna_joint_positions(antennas)
304
+
305
+ def set_target_antenna_joint_positions(
306
+ self,
307
+ positions: Annotated[NDArray[np.float64], (2,)],
308
+ ) -> None:
309
+ """Set the antenna joint positions.
310
+
311
+ Args:
312
+ positions (List[float]): A list of joint positions for the antenna.
313
+
314
+ """
315
+ self.target_antenna_joint_positions = positions
316
+
317
+ def set_target_head_joint_current(
318
+ self,
319
+ current: Annotated[NDArray[np.float64], (7,)],
320
+ ) -> None:
321
+ """Set the head joint current.
322
+
323
+ Args:
324
+ current (Annotated[NDArray[np.float64], (7,)]): A list of current values for the head motors.
325
+
326
+ """
327
+ self.target_head_joint_current = current
328
+ self.ik_required = False
329
+
330
+ async def play_move(
331
+ self,
332
+ move: Move,
333
+ play_frequency: float = 100.0,
334
+ initial_goto_duration: float = 0.0,
335
+ ) -> None:
336
+ """Asynchronously play a Move.
337
+
338
+ Args:
339
+ move (Move): The Move object to be played.
340
+ play_frequency (float): The frequency at which to evaluate the move (in Hz).
341
+ initial_goto_duration (float): Duration for an initial goto to the move's starting position. If 0.0, no initial goto is performed.
342
+
343
+ """
344
+ if initial_goto_duration > 0.0:
345
+ start_head_pose, start_antennas_positions, start_body_yaw = move.evaluate(
346
+ 0.0
347
+ )
348
+ await self.goto_target(
349
+ head=start_head_pose,
350
+ antennas=start_antennas_positions,
351
+ duration=initial_goto_duration,
352
+ body_yaw=start_body_yaw,
353
+ )
354
+ sleep_period = 1.0 / play_frequency
355
+
356
+ t0 = time.time()
357
+ while time.time() - t0 < move.duration:
358
+ t = time.time() - t0
359
+
360
+ head, antennas, body_yaw = move.evaluate(t)
361
+ if head is not None:
362
+ self.set_target_head_pose(head)
363
+ if body_yaw is not None:
364
+ self.set_target_body_yaw(body_yaw)
365
+ if antennas is not None:
366
+ self.set_target_antenna_joint_positions(antennas)
367
+
368
+ elapsed = time.time() - t0 - t
369
+ if elapsed < sleep_period:
370
+ await asyncio.sleep(sleep_period - elapsed)
371
+ else:
372
+ await asyncio.sleep(0.001)
373
+
374
+ async def goto_target(
375
+ self,
376
+ head: Annotated[NDArray[np.float64], (4, 4)] | None = None, # 4x4 pose matrix
377
+ antennas: Annotated[NDArray[np.float64], (2,)]
378
+ | None = None, # [right_angle, left_angle] (in rads)
379
+ duration: float = 0.5, # Duration in seconds for the movement, default is 0.5 seconds.
380
+ method: InterpolationTechnique = InterpolationTechnique.MIN_JERK, # can be "linear", "minjerk", "ease" or "cartoon", default is "minjerk"
381
+ body_yaw: float | None = 0.0, # Body yaw angle in radians
382
+ ) -> None:
383
+ """Asynchronously go to a target head pose and/or antennas position using task space interpolation, in "duration" seconds.
384
+
385
+ Args:
386
+ head (np.ndarray | None): 4x4 pose matrix representing the target head pose.
387
+ antennas (np.ndarray | list[float] | None): 1D array with two elements representing the angles of the antennas in radians.
388
+ duration (float): Duration of the movement in seconds.
389
+ method (str): Interpolation method to use ("linear", "minjerk", "ease", "cartoon"). Default is "minjerk".
390
+ body_yaw (float | None): Body yaw angle in radians.
391
+
392
+ Raises:
393
+ ValueError: If neither head nor antennas are provided, or if duration is not positive.
394
+
395
+ """
396
+ return await self.play_move(
397
+ move=GotoMove(
398
+ start_head_pose=self.get_present_head_pose(),
399
+ target_head_pose=head,
400
+ start_body_yaw=self.get_present_body_yaw(),
401
+ target_body_yaw=body_yaw,
402
+ start_antennas=np.array(self.get_present_antenna_joint_positions()),
403
+ target_antennas=np.array(antennas) if antennas is not None else None,
404
+ duration=duration,
405
+ method=method,
406
+ )
407
+ )
408
+
409
+ async def goto_joint_positions(
410
+ self,
411
+ head_joint_positions: list[float]
412
+ | None = None, # [yaw, stewart_platform x 6] length 7
413
+ antennas_joint_positions: list[float]
414
+ | None = None, # [right_angle, left_angle] length 2
415
+ duration: float = 0.5, # Duration in seconds for the movement
416
+ method: InterpolationTechnique = InterpolationTechnique.MIN_JERK, # can be "linear", "minjerk", "ease" or "cartoon", default is "minjerk"
417
+ ) -> None:
418
+ """Asynchronously go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds.
419
+
420
+ Go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds.
421
+
422
+ Args:
423
+ head_joint_positions (Optional[List[float]]): List of head joint positions in radians (length 7).
424
+ antennas_joint_positions (Optional[List[float]]): List of antennas joint positions in radians (length 2).
425
+ duration (float): Duration of the movement in seconds. Default is 0.5 seconds.
426
+ method (str): Interpolation method to use ("linear", "minjerk", "ease", "cartoon"). Default is "minjerk".
427
+
428
+ Raises:
429
+ ValueError: If neither head_joint_positions nor antennas_joint_positions are provided, or if duration is not positive.
430
+
431
+ """
432
+ if duration <= 0.0:
433
+ raise ValueError(
434
+ "Duration must be positive and non-zero. Use set_target() for immediate position setting."
435
+ )
436
+
437
+ start_head = np.array(self.get_present_head_joint_positions())
438
+ start_antennas = np.array(self.get_present_antenna_joint_positions())
439
+
440
+ target_head = (
441
+ np.array(head_joint_positions)
442
+ if head_joint_positions is not None
443
+ else start_head
444
+ )
445
+ target_antennas = (
446
+ np.array(antennas_joint_positions)
447
+ if antennas_joint_positions is not None
448
+ else start_antennas
449
+ )
450
+
451
+ t0 = time.time()
452
+ while time.time() - t0 < duration:
453
+ t = time.time() - t0
454
+
455
+ interp_time = time_trajectory(t / duration, method=method)
456
+
457
+ head_joint = start_head + (target_head - start_head) * interp_time
458
+ antennas_joint = (
459
+ start_antennas + (target_antennas - start_antennas) * interp_time
460
+ )
461
+
462
+ self.set_target_head_joint_positions(head_joint)
463
+ self.set_target_antenna_joint_positions(antennas_joint)
464
+ await asyncio.sleep(0.01)
465
+
466
+ def set_recording_publisher(self, publisher: zenoh.Publisher) -> None:
467
+ """Set the publisher for recording data.
468
+
469
+ Args:
470
+ publisher: A publisher object that will be used to publish recorded data.
471
+
472
+ """
473
+ self.recording_publisher = publisher
474
+
475
+ def append_record(self, record: dict[str, Any]) -> None:
476
+ """Append a record to the recorded data.
477
+
478
+ Args:
479
+ record (dict): A dictionary containing the record data to be appended.
480
+
481
+ """
482
+ if not self.is_recording:
483
+ return
484
+ # Double-check under lock to avoid race with stop_recording
485
+ with self._rec_lock:
486
+ if self.is_recording:
487
+ self.recorded_data.append(record)
488
+
489
+ def start_recording(self) -> None:
490
+ """Start recording data."""
491
+ with self._rec_lock:
492
+ self.recorded_data = []
493
+ self.is_recording = True
494
+
495
+ def stop_recording(self) -> None:
496
+ """Stop recording data and publish the recorded data."""
497
+ # Swap buffer under lock so writers cannot touch the published list
498
+ with self._rec_lock:
499
+ self.is_recording = False
500
+ recorded_data, self.recorded_data = self.recorded_data, []
501
+ # Publish outside the lock
502
+ if self.recording_publisher is not None:
503
+ self.recording_publisher.put(json.dumps(recorded_data))
504
+ else:
505
+ self.logger.warning(
506
+ "stop_recording called but recording_publisher is not set; dropping data."
507
+ )
508
+
509
+ def get_present_head_joint_positions(self) -> Annotated[NDArray[np.float64], (7,)]:
510
+ """Return the present head joint positions.
511
+
512
+ This method is a placeholder and should be overridden by subclasses.
513
+ """
514
+ raise NotImplementedError(
515
+ "The method get_present_head_joint_positions should be overridden by subclasses."
516
+ )
517
+
518
+ def get_present_body_yaw(self) -> float:
519
+ """Return the present body yaw."""
520
+ yaw: float = self.get_present_head_joint_positions()[0]
521
+ return yaw
522
+
523
+ def get_present_head_pose(self) -> Annotated[NDArray[np.float64], (4, 4)]:
524
+ """Return the present head pose as a 4x4 matrix."""
525
+ assert self.current_head_pose is not None, (
526
+ "The current head pose is not set. Please call the update_head_kinematics_model method first."
527
+ )
528
+ return self.current_head_pose
529
+
530
+ def get_current_head_pose(self) -> Annotated[NDArray[np.float64], (4, 4)]:
531
+ """Return the present head pose as a 4x4 matrix."""
532
+ return self.get_present_head_pose()
533
+
534
+ def get_present_antenna_joint_positions(
535
+ self,
536
+ ) -> Annotated[NDArray[np.float64], (2,)]:
537
+ """Return the present antenna joint positions.
538
+
539
+ This method is a placeholder and should be overridden by subclasses.
540
+ """
541
+ raise NotImplementedError(
542
+ "The method get_present_antenna_joint_positions should be overridden by subclasses."
543
+ )
544
+
545
+ # Kinematics methods
546
+ def update_head_kinematics_model(
547
+ self,
548
+ head_joint_positions: Annotated[NDArray[np.float64], (7,)] | None = None,
549
+ antennas_joint_positions: Annotated[NDArray[np.float64], (2,)] | None = None,
550
+ ) -> None:
551
+ """Update the placo kinematics of the robot.
552
+
553
+ Args:
554
+ head_joint_positions (List[float] | None): The joint positions of the head.
555
+ antennas_joint_positions (List[float] | None): The joint positions of the antennas.
556
+
557
+ Returns:
558
+ None: This method does not return anything.
559
+
560
+ This method updates the head kinematics model with the given joint positions.
561
+ - If the joint positions are not provided, it will use the current joint positions.
562
+ - If the head joint positions have not changed, it will return without recomputing the forward kinematics.
563
+ - If the head joint positions have changed, it will compute the forward kinematics to get the current head pose.
564
+ - If the forward kinematics fails, it will raise an assertion error.
565
+ - If the antennas joint positions are provided, it will update the current antenna joint positions.
566
+
567
+ Note:
568
+ This method will update the `current_head_pose` and `current_head_joint_positions`
569
+ attributes of the backend instance with the computed values. And the `current_antenna_joint_positions` if provided.
570
+
571
+ """
572
+ if head_joint_positions is None:
573
+ head_joint_positions = self.get_present_head_joint_positions()
574
+
575
+ # Compute the forward kinematics to get the current head pose
576
+ self.current_head_pose = self.head_kinematics.fk(head_joint_positions)
577
+
578
+ # Check if the FK was successful
579
+ assert self.current_head_pose is not None, (
580
+ "FK failed to compute the current head pose."
581
+ )
582
+
583
+ # Store the last head joint positions
584
+ self.current_head_joint_positions = head_joint_positions
585
+
586
+ if antennas_joint_positions is not None:
587
+ self.current_antenna_joint_positions = antennas_joint_positions
588
+
589
+ def set_automatic_body_yaw(self, body_yaw: float) -> None:
590
+ """Set the automatic body yaw.
591
+
592
+ Args:
593
+ body_yaw (float): The yaw angle of the body.
594
+
595
+ """
596
+ self.head_kinematics.start_body_yaw = body_yaw
597
+
598
+ def get_urdf(self) -> str:
599
+ """Get the URDF representation of the robot."""
600
+ urdf_path = Path(URDF_ROOT_PATH) / "robot.urdf"
601
+
602
+ with open(urdf_path, "r") as f:
603
+ return f.read()
604
+
605
+ # Multimedia methods
606
+ def play_sound(self, sound_file: str) -> None:
607
+ """Play a sound file from the assets directory.
608
+
609
+ If the file is not found in the assets directory, try to load the path itself.
610
+
611
+ Args:
612
+ sound_file (str): The name of the sound file to play (e.g., "wake_up.wav").
613
+
614
+ """
615
+ self.audio.play_sound(sound_file, autoclean=True)
616
+
617
+ # Basic move definitions
618
+ INIT_HEAD_POSE = np.eye(4)
619
+
620
+ SLEEP_HEAD_JOINT_POSITIONS = [
621
+ 0,
622
+ -0.9848156658225817,
623
+ 1.2624661884298831,
624
+ -0.24390294527381684,
625
+ 0.20555342557667577,
626
+ -1.2363885150358267,
627
+ 1.0032234352772091,
628
+ ]
629
+
630
+ SLEEP_ANTENNAS_JOINT_POSITIONS = np.array((-3.05, 3.05))
631
+ SLEEP_HEAD_POSE = np.array(
632
+ [
633
+ [0.911, 0.004, 0.413, -0.021],
634
+ [-0.004, 1.0, -0.001, 0.001],
635
+ [-0.413, -0.001, 0.911, -0.044],
636
+ [0.0, 0.0, 0.0, 1.0],
637
+ ]
638
+ )
639
+
640
+ async def wake_up(self) -> None:
641
+ """Wake up the robot - go to the initial head position and play the wake up emote and sound."""
642
+ await asyncio.sleep(0.1)
643
+
644
+ _, _, magic_distance = distance_between_poses(
645
+ self.get_current_head_pose(), self.INIT_HEAD_POSE
646
+ )
647
+
648
+ await self.goto_target(
649
+ self.INIT_HEAD_POSE,
650
+ antennas=np.array((0.0, 0.0)),
651
+ duration=magic_distance * 20 / 1000, # ms_per_magic_mm = 10
652
+ )
653
+ await asyncio.sleep(0.1)
654
+
655
+ # Toudoum
656
+ self.play_sound("wake_up.wav")
657
+
658
+ # Roll 20° to the left
659
+ pose = self.INIT_HEAD_POSE.copy()
660
+ pose[:3, :3] = R.from_euler("xyz", [20, 0, 0], degrees=True).as_matrix()
661
+ await self.goto_target(pose, duration=0.2)
662
+
663
+ # Go back to the initial position
664
+ await self.goto_target(self.INIT_HEAD_POSE, duration=0.2)
665
+
666
+ async def goto_sleep(self) -> None:
667
+ """Put the robot to sleep by moving the head and antennas to a predefined sleep position.
668
+
669
+ - If we are already very close to the sleep position, we do nothing.
670
+ - If we are far from the sleep position:
671
+ - If we are far from the initial position, we move there first.
672
+ - If we are close to the initial position, we move directly to the sleep position.
673
+ """
674
+ # Magic units
675
+ _, _, dist_to_sleep_pose = distance_between_poses(
676
+ self.get_current_head_pose(), self.SLEEP_HEAD_POSE
677
+ )
678
+ _, _, dist_to_init_pose = distance_between_poses(
679
+ self.get_current_head_pose(), self.INIT_HEAD_POSE
680
+ )
681
+ sleep_time = 2.0
682
+
683
+ # Thresholds found empirically.
684
+ if dist_to_sleep_pose > 10:
685
+ if dist_to_init_pose > 30:
686
+ # Move to the initial position
687
+ await self.goto_target(
688
+ self.INIT_HEAD_POSE, antennas=np.array((0.0, 0.0)), duration=1
689
+ )
690
+ await asyncio.sleep(0.2)
691
+
692
+ self.play_sound("go_sleep.wav")
693
+
694
+ # Move to the sleep position
695
+ await self.goto_target(
696
+ self.SLEEP_HEAD_POSE,
697
+ antennas=self.SLEEP_ANTENNAS_JOINT_POSITIONS,
698
+ duration=2,
699
+ )
700
+ else:
701
+ # The sound doesn't play fully if we don't wait enough
702
+ self.play_sound("go_sleep.wav")
703
+ sleep_time += 3
704
+
705
+ self._last_head_pose = self.SLEEP_HEAD_POSE
706
+ await asyncio.sleep(sleep_time)
707
+
708
+ # Motor control modes
709
+ @abstractmethod
710
+ def get_motor_control_mode(self) -> MotorControlMode:
711
+ """Get the motor control mode."""
712
+ pass
713
+
714
+ @abstractmethod
715
+ def set_motor_control_mode(self, mode: MotorControlMode) -> None:
716
+ """Set the motor control mode."""
717
+ pass
718
+
719
+ def get_present_passive_joint_positions(self) -> Optional[Dict[str, float]]:
720
+ """Get the present passive joint positions.
721
+
722
+ Requires the Placo kinematics engine.
723
+ """
724
+ # This is would be better, and fix mypy issues, but Placo is dynamically imported
725
+ # if not isinstance(self.head_kinematics, PlacoKinematics):
726
+ if self.kinematics_engine != "Placo":
727
+ return None
728
+ return {
729
+ "passive_1_x": self.head_kinematics.get_joint("passive_1_x"), # type: ignore [union-attr]
730
+ "passive_1_y": self.head_kinematics.get_joint("passive_1_y"), # type: ignore [union-attr]
731
+ "passive_1_z": self.head_kinematics.get_joint("passive_1_z"), # type: ignore [union-attr]
732
+ "passive_2_x": self.head_kinematics.get_joint("passive_2_x"), # type: ignore [union-attr]
733
+ "passive_2_y": self.head_kinematics.get_joint("passive_2_y"), # type: ignore [union-attr]
734
+ "passive_2_z": self.head_kinematics.get_joint("passive_2_z"), # type: ignore [union-attr]
735
+ "passive_3_x": self.head_kinematics.get_joint("passive_3_x"), # type: ignore [union-attr]
736
+ "passive_3_y": self.head_kinematics.get_joint("passive_3_y"), # type: ignore [union-attr]
737
+ "passive_3_z": self.head_kinematics.get_joint("passive_3_z"), # type: ignore [union-attr]
738
+ "passive_4_x": self.head_kinematics.get_joint("passive_4_x"), # type: ignore [union-attr]
739
+ "passive_4_y": self.head_kinematics.get_joint("passive_4_y"), # type: ignore [union-attr]
740
+ "passive_4_z": self.head_kinematics.get_joint("passive_4_z"), # type: ignore [union-attr]
741
+ "passive_5_x": self.head_kinematics.get_joint("passive_5_x"), # type: ignore [union-attr]
742
+ "passive_5_y": self.head_kinematics.get_joint("passive_5_y"), # type: ignore [union-attr]
743
+ "passive_5_z": self.head_kinematics.get_joint("passive_5_z"), # type: ignore [union-attr]
744
+ "passive_6_x": self.head_kinematics.get_joint("passive_6_x"), # type: ignore [union-attr]
745
+ "passive_6_y": self.head_kinematics.get_joint("passive_6_y"), # type: ignore [union-attr]
746
+ "passive_6_z": self.head_kinematics.get_joint("passive_6_z"), # type: ignore [union-attr]
747
+ "passive_7_x": self.head_kinematics.get_joint("passive_7_x"), # type: ignore [union-attr]
748
+ "passive_7_y": self.head_kinematics.get_joint("passive_7_y"), # type: ignore [union-attr]
749
+ "passive_7_z": self.head_kinematics.get_joint("passive_7_z"), # type: ignore [union-attr]
750
+ }