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,163 @@
1
+ """Base classes for audio implementations.
2
+
3
+ The audio implementations support various backends and provide a unified
4
+ interface for audio input/output.
5
+ """
6
+
7
+ import logging
8
+ import struct
9
+ from abc import ABC, abstractmethod
10
+ from enum import Enum
11
+ from typing import List, Optional
12
+
13
+ import numpy as np
14
+ import numpy.typing as npt
15
+ import usb
16
+ from libusb_package import get_libusb1_backend
17
+
18
+
19
+ class AudioBackend(Enum):
20
+ """Audio backends."""
21
+
22
+ SOUNDDEVICE = "sounddevice"
23
+ GSTREAMER = "gstreamer"
24
+
25
+
26
+ class AudioBase(ABC):
27
+ """Abstract class for opening and managing audio devices."""
28
+
29
+ SAMPLE_RATE = 16000 # respeaker samplerate
30
+ TIMEOUT = 100000
31
+ PARAMETERS = {
32
+ "VERSION": (48, 0, 4, "ro", "uint8"),
33
+ "AEC_AZIMUTH_VALUES": (33, 75, 16 + 1, "ro", "radians"),
34
+ "DOA_VALUE": (20, 18, 4 + 1, "ro", "uint16"),
35
+ "DOA_VALUE_RADIANS": (20, 19, 8 + 1, "ro", "radians"),
36
+ }
37
+
38
+ def __init__(self, backend: AudioBackend, log_level: str = "INFO") -> None:
39
+ """Initialize the audio device."""
40
+ self.logger = logging.getLogger(__name__)
41
+ self.logger.setLevel(log_level)
42
+ self.backend = backend
43
+ self._respeaker = self._init_respeaker_usb()
44
+ # name, resid, cmdid, length, type
45
+
46
+ def __del__(self) -> None:
47
+ """Destructor to ensure resources are released."""
48
+ if self._respeaker:
49
+ usb.util.dispose_resources(self._respeaker)
50
+
51
+ @abstractmethod
52
+ def start_recording(self) -> None:
53
+ """Start recording audio."""
54
+ pass
55
+
56
+ @abstractmethod
57
+ def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]:
58
+ """Read audio data from the device. Returns the data or None if error."""
59
+ pass
60
+
61
+ @abstractmethod
62
+ def stop_recording(self) -> None:
63
+ """Close the audio device and release resources."""
64
+ pass
65
+
66
+ @abstractmethod
67
+ def start_playing(self) -> None:
68
+ """Start playing audio."""
69
+ pass
70
+
71
+ @abstractmethod
72
+ def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None:
73
+ """Push audio data to the output device."""
74
+ pass
75
+
76
+ @abstractmethod
77
+ def stop_playing(self) -> None:
78
+ """Stop playing audio and release resources."""
79
+ pass
80
+
81
+ @abstractmethod
82
+ def play_sound(self, sound_file: str) -> None:
83
+ """Play a sound file.
84
+
85
+ Args:
86
+ sound_file (str): Path to the sound file to play.
87
+
88
+ """
89
+ pass
90
+
91
+ def _init_respeaker_usb(self) -> Optional[usb.core.Device]:
92
+ try:
93
+ dev = usb.core.find(
94
+ idVendor=0x2886, idProduct=0x001A, backend=get_libusb1_backend()
95
+ )
96
+ return dev
97
+ except usb.core.NoBackendError:
98
+ self.logger.error(
99
+ "No USB backend was found ! Make sure libusb_package is correctly installed with `pip install libusb_package`."
100
+ )
101
+ return None
102
+
103
+ def _read_usb(self, name: str) -> Optional[List[int] | List[float]]:
104
+ try:
105
+ data = self.PARAMETERS[name]
106
+ except KeyError:
107
+ self.logger.error(f"Unknown parameter: {name}")
108
+ return None
109
+
110
+ if not self._respeaker:
111
+ self.logger.warning("ReSpeaker device not found.")
112
+ return None
113
+
114
+ resid = data[0]
115
+ cmdid = 0x80 | data[1]
116
+ length = data[2]
117
+
118
+ response = self._respeaker.ctrl_transfer(
119
+ usb.util.CTRL_IN
120
+ | usb.util.CTRL_TYPE_VENDOR
121
+ | usb.util.CTRL_RECIPIENT_DEVICE,
122
+ 0,
123
+ cmdid,
124
+ resid,
125
+ length,
126
+ self.TIMEOUT,
127
+ )
128
+
129
+ self.logger.debug(f"Response for {name}: {response}")
130
+
131
+ result: Optional[List[float] | List[int]] = None
132
+ if data[4] == "uint8":
133
+ result = response.tolist()
134
+ elif data[4] == "radians":
135
+ byte_data = response.tobytes()
136
+ num_values = (data[2] - 1) / 4
137
+ match_str = "<"
138
+ for i in range(int(num_values)):
139
+ match_str += "f"
140
+ result = [
141
+ float(x) for x in struct.unpack(match_str, byte_data[1 : data[2]])
142
+ ]
143
+ elif data[4] == "uint16":
144
+ result = response.tolist()
145
+
146
+ return result
147
+
148
+ def get_DoA(self) -> tuple[float, bool] | None:
149
+ """Get the Direction of Arrival (DoA) value from the ReSpeaker device.
150
+
151
+ 0° is left, 90° is front/back, 180° is right
152
+
153
+ Returns:
154
+ tuple: A tuple containing the DoA value as an integer and the speech detection, or None if the device is not found.
155
+
156
+ """
157
+ if not self._respeaker:
158
+ self.logger.warning("ReSpeaker device not found.")
159
+ return None
160
+ result = self._read_usb("DOA_VALUE_RADIANS")
161
+ if result is None:
162
+ return None
163
+ return float(result[0]), bool(result[1])
@@ -0,0 +1,195 @@
1
+ """GStreamer camera backend.
2
+
3
+ This module provides an implementation of the CameraBase class using GStreamer.
4
+ By default the module directly returns JPEG images as output by the camera.
5
+ """
6
+
7
+ from threading import Thread
8
+ from typing import Optional
9
+
10
+ import numpy as np
11
+ import numpy.typing as npt
12
+
13
+ try:
14
+ import gi
15
+ except ImportError as e:
16
+ raise ImportError(
17
+ "The 'gi' module is required for GStreamerCamera but could not be imported. \
18
+ Please install the GStreamer backend: pip install .[gstreamer]."
19
+ ) from e
20
+
21
+ gi.require_version("Gst", "1.0")
22
+ gi.require_version("GstApp", "1.0")
23
+
24
+
25
+ from gi.repository import GLib, Gst, GstApp # noqa: E402
26
+
27
+ from .audio_base import AudioBackend, AudioBase # noqa: E402
28
+
29
+
30
+ class GStreamerAudio(AudioBase):
31
+ """Audio implementation using GStreamer."""
32
+
33
+ def __init__(self, log_level: str = "INFO") -> None:
34
+ """Initialize the GStreamer audio."""
35
+ super().__init__(backend=AudioBackend.GSTREAMER, log_level=log_level)
36
+ Gst.init(None)
37
+ self._loop = GLib.MainLoop()
38
+ self._thread_bus_calls = Thread(target=lambda: self._loop.run(), daemon=True)
39
+ self._thread_bus_calls.start()
40
+
41
+ self._pipeline_record = Gst.Pipeline.new("audio_recorder")
42
+ self._appsink_audio: Optional[GstApp] = None
43
+ self._init_pipeline_record(self._pipeline_record)
44
+ self._bus_record = self._pipeline_record.get_bus()
45
+ self._bus_record.add_watch(
46
+ GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop
47
+ )
48
+
49
+ self._pipeline_playback = Gst.Pipeline.new("audio_player")
50
+ self._appsrc: Optional[GstApp] = None
51
+ self._init_pipeline_playback(self._pipeline_playback)
52
+ self._bus_playback = self._pipeline_playback.get_bus()
53
+ self._bus_playback.add_watch(
54
+ GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop
55
+ )
56
+
57
+ def _init_pipeline_record(self, pipeline: Gst.Pipeline) -> None:
58
+ self._appsink_audio = Gst.ElementFactory.make("appsink")
59
+ caps = Gst.Caps.from_string(
60
+ f"audio/x-raw,channels=2,rate={self.SAMPLE_RATE},format=F32LE"
61
+ )
62
+ self._appsink_audio.set_property("caps", caps)
63
+ self._appsink_audio.set_property("drop", True) # avoid overflow
64
+ self._appsink_audio.set_property("max-buffers", 500)
65
+
66
+ autoaudiosrc = Gst.ElementFactory.make("autoaudiosrc") # use default mic
67
+ # caps_respeaker = Gst.Caps.from_string(
68
+ # "audio/x-raw, layout=interleaved, format=S16LE, rate=16000, channels=2"
69
+ # )
70
+ # autoaudiosrc.set_property("filter-caps", caps_respeaker)
71
+ queue = Gst.ElementFactory.make("queue")
72
+ audioconvert = Gst.ElementFactory.make("audioconvert")
73
+ audioresample = Gst.ElementFactory.make("audioresample")
74
+
75
+ if not all(
76
+ [autoaudiosrc, queue, audioconvert, audioresample, self._appsink_audio]
77
+ ):
78
+ raise RuntimeError("Failed to create GStreamer elements")
79
+
80
+ pipeline.add(autoaudiosrc)
81
+ pipeline.add(queue)
82
+ pipeline.add(audioconvert)
83
+ pipeline.add(audioresample)
84
+ pipeline.add(self._appsink_audio)
85
+
86
+ autoaudiosrc.link(queue)
87
+ queue.link(audioconvert)
88
+ audioconvert.link(audioresample)
89
+ audioresample.link(self._appsink_audio)
90
+
91
+ def __del__(self) -> None:
92
+ """Destructor to ensure gstreamer resources are released."""
93
+ super().__del__()
94
+ self._loop.quit()
95
+ self._bus_record.remove_watch()
96
+ self._bus_playback.remove_watch()
97
+
98
+ def _init_pipeline_playback(self, pipeline: Gst.Pipeline) -> None:
99
+ self._appsrc = Gst.ElementFactory.make("appsrc")
100
+ self._appsrc.set_property("format", Gst.Format.TIME)
101
+ self._appsrc.set_property("is-live", True)
102
+ caps = Gst.Caps.from_string(
103
+ f"audio/x-raw,format=F32LE,channels=1,rate={self.SAMPLE_RATE},layout=interleaved"
104
+ )
105
+ self._appsrc.set_property("caps", caps)
106
+
107
+ audioconvert = Gst.ElementFactory.make("audioconvert")
108
+ audioresample = Gst.ElementFactory.make("audioresample")
109
+
110
+ queue = Gst.ElementFactory.make("queue")
111
+ audiosink = Gst.ElementFactory.make("autoaudiosink") # use default speaker
112
+
113
+ pipeline.add(queue)
114
+ pipeline.add(audiosink)
115
+ pipeline.add(self._appsrc)
116
+ pipeline.add(audioconvert)
117
+ pipeline.add(audioresample)
118
+
119
+ self._appsrc.link(queue)
120
+ queue.link(audioconvert)
121
+ audioconvert.link(audioresample)
122
+ audioresample.link(audiosink)
123
+
124
+ def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def]
125
+ t = msg.type
126
+ if t == Gst.MessageType.EOS:
127
+ self.logger.warning("End-of-stream")
128
+ return False
129
+
130
+ elif t == Gst.MessageType.ERROR:
131
+ err, debug = msg.parse_error()
132
+ self.logger.error(f"Error: {err} {debug}")
133
+ return False
134
+
135
+ return True
136
+
137
+ def start_recording(self) -> None:
138
+ """Open the audio card using GStreamer."""
139
+ self._pipeline_record.set_state(Gst.State.PLAYING)
140
+
141
+ def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]:
142
+ sample = appsink.try_pull_sample(20_000_000)
143
+ if sample is None:
144
+ return None
145
+ data = None
146
+ if isinstance(sample, Gst.Sample):
147
+ buf = sample.get_buffer()
148
+ if buf is None:
149
+ self.logger.warning("Buffer is None")
150
+
151
+ data = buf.extract_dup(0, buf.get_size())
152
+ return data
153
+
154
+ def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]:
155
+ """Read a sample from the audio card. Returns the sample or None if error.
156
+
157
+ Returns:
158
+ Optional[npt.NDArray[np.float32]]: The captured sample in raw format, or None if error.
159
+
160
+ """
161
+ sample = self._get_sample(self._appsink_audio)
162
+ if sample is None:
163
+ return None
164
+ return np.frombuffer(sample, dtype=np.float32).reshape(-1, 2)
165
+
166
+ def stop_recording(self) -> None:
167
+ """Release the camera resource."""
168
+ self._pipeline_record.set_state(Gst.State.NULL)
169
+
170
+ def start_playing(self) -> None:
171
+ """Open the audio output using GStreamer."""
172
+ self._pipeline_playback.set_state(Gst.State.PLAYING)
173
+
174
+ def stop_playing(self) -> None:
175
+ """Stop playing audio and release resources."""
176
+ self._pipeline_playback.set_state(Gst.State.NULL)
177
+
178
+ def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None:
179
+ """Push audio data to the output device."""
180
+ if self._appsrc is not None:
181
+ buf = Gst.Buffer.new_wrapped(data.tobytes())
182
+ self._appsrc.push_buffer(buf)
183
+ else:
184
+ self.logger.warning(
185
+ "AppSrc is not initialized. Call start_playing() first."
186
+ )
187
+
188
+ def play_sound(self, sound_file: str) -> None:
189
+ """Play a sound file.
190
+
191
+ Args:
192
+ sound_file (str): Path to the sound file to play.
193
+
194
+ """
195
+ self.logger.warning("play_sound is not implemented for GStreamerAudio.")
@@ -0,0 +1,226 @@
1
+ """Audio implementation using sounddevice backend."""
2
+
3
+ import os
4
+ import threading
5
+ import time
6
+ from typing import Any, List, Optional
7
+
8
+ import numpy as np
9
+ import numpy.typing as npt
10
+ import scipy
11
+ import sounddevice as sd
12
+ import soundfile as sf
13
+
14
+ from reachy_mini.utils.constants import ASSETS_ROOT_PATH
15
+
16
+ from .audio_base import AudioBackend, AudioBase
17
+
18
+
19
+ class SoundDeviceAudio(AudioBase):
20
+ """Audio device implementation using sounddevice."""
21
+
22
+ def __init__(
23
+ self,
24
+ frames_per_buffer: int = 1024,
25
+ log_level: str = "INFO",
26
+ ) -> None:
27
+ """Initialize the SoundDevice audio device."""
28
+ super().__init__(backend=AudioBackend.SOUNDDEVICE, log_level=log_level)
29
+ self.frames_per_buffer = frames_per_buffer
30
+ self.stream = None
31
+ self._output_stream = None
32
+ self._buffer: List[npt.NDArray[np.float32]] = []
33
+ self._output_device_id = self.get_output_device_id("respeaker")
34
+ self._input_device_id = self.get_input_device_id("respeaker")
35
+
36
+ def start_recording(self) -> None:
37
+ """Open the audio input stream, using ReSpeaker card if available."""
38
+ self.stream = sd.InputStream(
39
+ blocksize=self.frames_per_buffer,
40
+ device=self._input_device_id,
41
+ callback=self._callback,
42
+ samplerate=self.SAMPLE_RATE,
43
+ )
44
+ if self.stream is None:
45
+ raise RuntimeError("Failed to open SoundDevice audio stream.")
46
+ self._buffer.clear()
47
+ self.stream.start()
48
+ self.logger.info("SoundDevice audio stream opened.")
49
+
50
+ def _callback(
51
+ self,
52
+ indata: npt.NDArray[np.float32],
53
+ frames: int,
54
+ time: int,
55
+ status: sd.CallbackFlags,
56
+ ) -> None:
57
+ if status:
58
+ self.logger.warning(f"SoundDevice status: {status}")
59
+
60
+ self._buffer.append(indata.copy())
61
+
62
+ def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]:
63
+ """Read audio data from the buffer. Returns numpy array or None if empty."""
64
+ if self._buffer and len(self._buffer) > 0:
65
+ data: npt.NDArray[np.float32] = np.concatenate(self._buffer, axis=0)
66
+ self._buffer.clear()
67
+ return data
68
+ self.logger.debug("No audio data available in buffer.")
69
+ return None
70
+
71
+ def stop_recording(self) -> None:
72
+ """Close the audio stream and release resources."""
73
+ if self.stream is not None:
74
+ self.stream.stop()
75
+ self.stream.close()
76
+ self.stream = None
77
+ self.logger.info("SoundDevice audio stream closed.")
78
+
79
+ def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None:
80
+ """Push audio data to the output device."""
81
+ if self._output_stream is not None:
82
+ self._output_stream.write(data)
83
+ else:
84
+ self.logger.warning(
85
+ "Output stream is not open. Call start_playing() first."
86
+ )
87
+
88
+ def start_playing(self) -> None:
89
+ """Open the audio output stream."""
90
+ self._output_stream = sd.OutputStream(
91
+ samplerate=self.SAMPLE_RATE,
92
+ device=self._output_device_id,
93
+ channels=1,
94
+ )
95
+ if self._output_stream is None:
96
+ raise RuntimeError("Failed to open SoundDevice audio output stream.")
97
+ self._output_stream.start()
98
+
99
+ def stop_playing(self) -> None:
100
+ """Close the audio output stream."""
101
+ if self._output_stream is not None:
102
+ self._output_stream.stop()
103
+ self._output_stream.close()
104
+ self._output_stream = None
105
+ self.logger.info("SoundDevice audio output stream closed.")
106
+
107
+ def play_sound(self, sound_file: str, autoclean: bool = False) -> None:
108
+ """Play a sound file from the assets directory or a given path using sounddevice and soundfile."""
109
+ file_path = f"{ASSETS_ROOT_PATH}/{sound_file}"
110
+ if not os.path.exists(file_path):
111
+ raise FileNotFoundError(f"Sound file {file_path} not found.")
112
+
113
+ data, samplerate_in = sf.read(file_path, dtype="float32")
114
+
115
+ if samplerate_in != self.SAMPLE_RATE:
116
+ data = scipy.signal.resample(
117
+ data, int(len(data) * (self.SAMPLE_RATE / samplerate_in))
118
+ )
119
+ if data.ndim > 1: # convert to mono
120
+ data = np.mean(data, axis=1)
121
+
122
+ self.logger.debug(f"Playing sound '{file_path}' at {samplerate_in} Hz")
123
+
124
+ self.stop_playing()
125
+ start = [0] # using list to modify in callback
126
+ length = len(data)
127
+
128
+ def callback(
129
+ outdata: npt.NDArray[np.float32],
130
+ frames: int,
131
+ time: Any, # cdata 'struct PaStreamCallbackTimeInfo *
132
+ status: sd.CallbackFlags,
133
+ ) -> None:
134
+ """Actual playback."""
135
+ if status:
136
+ self.logger.warning(f"SoundDevice output status: {status}")
137
+
138
+ end = start[0] + frames
139
+ if end > length:
140
+ # Fill the output buffer with the audio data, or zeros if finished
141
+ outdata[: length - start[0], 0] = data[start[0] :]
142
+ outdata[length - start[0] :, 0] = 0
143
+ raise sd.CallbackStop()
144
+ else:
145
+ outdata[:, 0] = data[start[0] : end]
146
+ start[0] = end
147
+
148
+ event = threading.Event()
149
+
150
+ self._output_stream = sd.OutputStream(
151
+ samplerate=self.SAMPLE_RATE,
152
+ device=self._output_device_id,
153
+ channels=1,
154
+ callback=callback,
155
+ finished_callback=event.set, # release the device when done
156
+ )
157
+ if self._output_stream is None:
158
+ raise RuntimeError("Failed to open SoundDevice audio output stream.")
159
+ self._output_stream.start()
160
+
161
+ def _clean_up_thread() -> None:
162
+ """Thread to clean up the output stream after playback.
163
+
164
+ The daemon may play sound but should release the audio device.
165
+ """
166
+ event.wait()
167
+ timeout = 5 # seconds
168
+ waited = 0
169
+ while (
170
+ self._output_stream is not None
171
+ and self._output_stream.active
172
+ and waited < timeout
173
+ ):
174
+ time.sleep(0.1)
175
+ waited += 0.1
176
+ self.stop_playing()
177
+
178
+ if autoclean:
179
+ threading.Thread(
180
+ target=_clean_up_thread,
181
+ daemon=True,
182
+ ).start()
183
+
184
+ def get_output_device_id(self, name_contains: str) -> int:
185
+ """Return the output device id whose name contains the given string (case-insensitive).
186
+
187
+ If not found, return the default output device id.
188
+ """
189
+ devices = sd.query_devices()
190
+
191
+ for idx, dev in enumerate(devices):
192
+ if (
193
+ name_contains.lower() in dev["name"].lower()
194
+ and dev["max_output_channels"] > 0
195
+ ):
196
+ return idx
197
+ # Return default output device if not found
198
+ self.logger.warning(
199
+ f"No output device found containing '{name_contains}', using default."
200
+ )
201
+ return self._safe_query_device('output')
202
+
203
+ def get_input_device_id(self, name_contains: str) -> int:
204
+ """Return the input device id whose name contains the given string (case-insensitive).
205
+
206
+ If not found, return the default input device id.
207
+ """
208
+ devices = sd.query_devices()
209
+
210
+ for idx, dev in enumerate(devices):
211
+ if (
212
+ name_contains.lower() in dev["name"].lower()
213
+ and dev["max_input_channels"] > 0
214
+ ):
215
+ return idx
216
+ # Return default input device if not found
217
+ self.logger.warning(
218
+ f"No input device found containing '{name_contains}', using default."
219
+ )
220
+ return self._safe_query_device('input')
221
+
222
+ def _safe_query_device(self, kind: str) -> int:
223
+ try:
224
+ return int(sd.query_devices(None, kind)['index'])
225
+ except sd.PortAudioError:
226
+ return int(sd.default.device[1])
@@ -0,0 +1,27 @@
1
+ """Utility functions for audio handling, specifically for detecting the ReSpeaker sound card."""
2
+
3
+ import logging
4
+ import subprocess
5
+
6
+
7
+ def get_respeaker_card_number() -> int:
8
+ """Return the card number of the ReSpeaker sound card, or 0 if not found."""
9
+ try:
10
+ result = subprocess.run(
11
+ ["arecord", "-l"], capture_output=True, text=True, check=True
12
+ )
13
+ output = result.stdout
14
+
15
+ lines = output.split("\n")
16
+ for line in lines:
17
+ if "ReSpeaker" in line and "card" in line:
18
+ card_number = line.split(":")[0].split("card ")[1].strip()
19
+ logging.debug(f"Found ReSpeaker sound card: {card_number}")
20
+ return int(card_number)
21
+
22
+ logging.warning("ReSpeaker sound card not found. Returning default card")
23
+ return 0 # default sound card
24
+
25
+ except subprocess.CalledProcessError as e:
26
+ logging.error(f"Cannot find sound card: {e}")
27
+ return 0
@@ -0,0 +1,63 @@
1
+ """Base classes for camera implementations.
2
+
3
+ The camera implementations support various backends and provide a unified
4
+ interface for capturing images.
5
+ """
6
+
7
+ import logging
8
+ from abc import ABC, abstractmethod
9
+ from enum import Enum
10
+ from typing import Optional
11
+
12
+ import numpy as np
13
+ import numpy.typing as npt
14
+
15
+ from reachy_mini.media.camera_constants import CameraResolution
16
+
17
+
18
+ class CameraBackend(Enum):
19
+ """Camera backends."""
20
+
21
+ OPENCV = "opencv"
22
+ GSTREAMER = "gstreamer"
23
+
24
+
25
+ class CameraBase(ABC):
26
+ """Abstract class for opening and managing a camera."""
27
+
28
+ def __init__(
29
+ self,
30
+ backend: CameraBackend,
31
+ log_level: str = "INFO",
32
+ resolution: CameraResolution = CameraResolution.R1280x720,
33
+ ) -> None:
34
+ """Initialize the camera."""
35
+ self.logger = logging.getLogger(__name__)
36
+ self.logger.setLevel(log_level)
37
+ self.backend = backend
38
+ self._resolution = resolution
39
+
40
+ @property
41
+ def resolution(self) -> tuple[int, int]:
42
+ """Get the current camera resolution as a tuple (width, height)."""
43
+ return (self._resolution.value[0], self._resolution.value[1])
44
+
45
+ @property
46
+ def framerate(self) -> int:
47
+ """Get the current camera frames per second."""
48
+ return self._resolution.value[2]
49
+
50
+ @abstractmethod
51
+ def open(self) -> None:
52
+ """Open the camera."""
53
+ pass
54
+
55
+ @abstractmethod
56
+ def read(self) -> Optional[npt.NDArray[np.uint8]]:
57
+ """Read an image from the camera. Returns the image or None if error."""
58
+ pass
59
+
60
+ @abstractmethod
61
+ def close(self) -> None:
62
+ """Close the camera and release resources."""
63
+ pass
@@ -0,0 +1,13 @@
1
+ """Camera constants for Reachy Mini."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class CameraResolution(Enum):
7
+ """Camera resolutions. Arducam_12MP."""
8
+
9
+ R2304x1296 = (2304, 1296, 30)
10
+ R4608x2592 = (4608, 2592, 10)
11
+ R1920x1080 = (1920, 1080, 30)
12
+ R1600x1200 = (1600, 1200, 30)
13
+ R1280x720 = (1280, 720, 30)