reachy-mini 1.2.5rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. reachy_mini/__init__.py +4 -0
  2. reachy_mini/apps/__init__.py +25 -0
  3. reachy_mini/apps/app.py +258 -0
  4. reachy_mini/apps/assistant.py +787 -0
  5. reachy_mini/apps/manager.py +312 -0
  6. reachy_mini/apps/sources/__init__.py +4 -0
  7. reachy_mini/apps/sources/hf_space.py +106 -0
  8. reachy_mini/apps/sources/local_common_venv.py +567 -0
  9. reachy_mini/apps/templates/README.md.j2 +12 -0
  10. reachy_mini/apps/templates/gitignore.j2 +3 -0
  11. reachy_mini/apps/templates/index.html.j2 +40 -0
  12. reachy_mini/apps/templates/main.py.j2 +74 -0
  13. reachy_mini/apps/templates/pyproject.toml.j2 +28 -0
  14. reachy_mini/apps/templates/static/index.html.j2 +27 -0
  15. reachy_mini/apps/templates/static/main.js.j2 +47 -0
  16. reachy_mini/apps/templates/static/style.css.j2 +25 -0
  17. reachy_mini/apps/templates/style.css.j2 +411 -0
  18. reachy_mini/apps/utils.py +30 -0
  19. reachy_mini/assets/config/hardware_config.yaml +164 -0
  20. reachy_mini/assets/confused1.wav +0 -0
  21. reachy_mini/assets/count.wav +0 -0
  22. reachy_mini/assets/dance1.wav +0 -0
  23. reachy_mini/assets/firmware/CHANGELOG.md +15 -0
  24. reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin +0 -0
  25. reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin +0 -0
  26. reachy_mini/assets/firmware/update.sh +9 -0
  27. reachy_mini/assets/go_sleep.wav +0 -0
  28. reachy_mini/assets/impatient1.wav +0 -0
  29. reachy_mini/assets/kinematics_data.json +253 -0
  30. reachy_mini/assets/models/fknetwork.dynamic.onnx +0 -0
  31. reachy_mini/assets/models/fknetwork.onnx +0 -0
  32. reachy_mini/assets/models/fknetwork_int8.onnx +0 -0
  33. reachy_mini/assets/models/iknetwork.onnx +0 -0
  34. reachy_mini/assets/wake_up.wav +0 -0
  35. reachy_mini/daemon/__init__.py +1 -0
  36. reachy_mini/daemon/app/__init__.py +1 -0
  37. reachy_mini/daemon/app/bg_job_register.py +142 -0
  38. reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg +40 -0
  39. reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg +42 -0
  40. reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg +6 -0
  41. reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg +6 -0
  42. reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg +50 -0
  43. reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg +6 -0
  44. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg +18 -0
  45. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg +6 -0
  46. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg +6 -0
  47. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg +6 -0
  48. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg +22 -0
  49. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg +41 -0
  50. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg +18 -0
  51. reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg +6 -0
  52. reachy_mini/daemon/app/dashboard/static/css/app.css +1433 -0
  53. reachy_mini/daemon/app/dashboard/static/fonts/Archivo-Italic-VariableFont_wdth,wght.ttf +0 -0
  54. reachy_mini/daemon/app/dashboard/static/fonts/Archivo-VariableFont_wdth,wght.ttf +0 -0
  55. reachy_mini/daemon/app/dashboard/static/fonts/Asap-Italic-VariableFont_wdth,wght.ttf +0 -0
  56. reachy_mini/daemon/app/dashboard/static/fonts/Asap-VariableFont_wdth,wght.ttf +0 -0
  57. reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js +5 -0
  58. reachy_mini/daemon/app/dashboard/static/js/apps.js +323 -0
  59. reachy_mini/daemon/app/dashboard/static/js/appstore.js +167 -0
  60. reachy_mini/daemon/app/dashboard/static/js/daemon.js +169 -0
  61. reachy_mini/daemon/app/dashboard/static/js/health_check.js +9 -0
  62. reachy_mini/daemon/app/dashboard/static/js/move_player.js +132 -0
  63. reachy_mini/daemon/app/dashboard/static/js/notification.js +41 -0
  64. reachy_mini/daemon/app/dashboard/static/js/update.js +132 -0
  65. reachy_mini/daemon/app/dashboard/static/js/volume_control.js +252 -0
  66. reachy_mini/daemon/app/dashboard/static/js/wifi.js +176 -0
  67. reachy_mini/daemon/app/dashboard/tailwindcss/README.md +15 -0
  68. reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json +1127 -0
  69. reachy_mini/daemon/app/dashboard/tailwindcss/package.json +6 -0
  70. reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml +608 -0
  71. reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js +6 -0
  72. reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css +185 -0
  73. reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js +11 -0
  74. reachy_mini/daemon/app/dashboard/templates/base.html +21 -0
  75. reachy_mini/daemon/app/dashboard/templates/index.html +20 -0
  76. reachy_mini/daemon/app/dashboard/templates/sections/apps.html +8 -0
  77. reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +35 -0
  78. reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +45 -0
  79. reachy_mini/daemon/app/dashboard/templates/sections/move_player.html +121 -0
  80. reachy_mini/daemon/app/dashboard/templates/sections/notification.html +19 -0
  81. reachy_mini/daemon/app/dashboard/templates/sections/update.html +54 -0
  82. reachy_mini/daemon/app/dashboard/templates/sections/wifi.html +46 -0
  83. reachy_mini/daemon/app/dashboard/templates/settings.html +14 -0
  84. reachy_mini/daemon/app/dependencies.py +41 -0
  85. reachy_mini/daemon/app/main.py +469 -0
  86. reachy_mini/daemon/app/models.py +149 -0
  87. reachy_mini/daemon/app/routers/apps.py +114 -0
  88. reachy_mini/daemon/app/routers/daemon.py +85 -0
  89. reachy_mini/daemon/app/routers/kinematics.py +57 -0
  90. reachy_mini/daemon/app/routers/motors.py +41 -0
  91. reachy_mini/daemon/app/routers/move.py +265 -0
  92. reachy_mini/daemon/app/routers/state.py +146 -0
  93. reachy_mini/daemon/app/routers/update.py +86 -0
  94. reachy_mini/daemon/app/routers/volume.py +423 -0
  95. reachy_mini/daemon/app/routers/wifi_config.py +219 -0
  96. reachy_mini/daemon/app/services/__init__.py +1 -0
  97. reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py +796 -0
  98. reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh +7 -0
  99. reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh +4 -0
  100. reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh +7 -0
  101. reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh +39 -0
  102. reachy_mini/daemon/app/services/gpio_shutdown/__init__.py +1 -0
  103. reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh +33 -0
  104. reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh +3 -0
  105. reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py +28 -0
  106. reachy_mini/daemon/app/services/wireless/generate_asoundrc.sh +70 -0
  107. reachy_mini/daemon/app/services/wireless/install_service.sh +33 -0
  108. reachy_mini/daemon/app/services/wireless/launcher.sh +5 -0
  109. reachy_mini/daemon/backend/__init__.py +1 -0
  110. reachy_mini/daemon/backend/abstract.py +815 -0
  111. reachy_mini/daemon/backend/mujoco/__init__.py +36 -0
  112. reachy_mini/daemon/backend/mujoco/backend.py +395 -0
  113. reachy_mini/daemon/backend/mujoco/utils.py +59 -0
  114. reachy_mini/daemon/backend/mujoco/video_udp.py +57 -0
  115. reachy_mini/daemon/backend/robot/__init__.py +8 -0
  116. reachy_mini/daemon/backend/robot/backend.py +597 -0
  117. reachy_mini/daemon/daemon.py +651 -0
  118. reachy_mini/daemon/utils.py +116 -0
  119. reachy_mini/descriptions/reachy_mini/mjcf/additional.xml +6 -0
  120. reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.part +13 -0
  121. reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.stl +0 -0
  122. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.part +13 -0
  123. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.stl +0 -0
  124. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.part +13 -0
  125. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.stl +0 -0
  126. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.part +13 -0
  127. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.stl +0 -0
  128. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.part +13 -0
  129. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.stl +0 -0
  130. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.part +13 -0
  131. reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.stl +0 -0
  132. reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.part +13 -0
  133. reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.stl +0 -0
  134. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.part +13 -0
  135. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.stl +0 -0
  136. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.part +13 -0
  137. reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.stl +0 -0
  138. reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.part +13 -0
  139. reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.stl +0 -0
  140. reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.part +13 -0
  141. reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.stl +0 -0
  142. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.part +13 -0
  143. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.stl +0 -0
  144. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.part +13 -0
  145. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.stl +0 -0
  146. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.part +13 -0
  147. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.stl +0 -0
  148. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.part +13 -0
  149. reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.stl +0 -0
  150. reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.part +13 -0
  151. reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.stl +0 -0
  152. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/README.m +1 -0
  153. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
  154. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
  155. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
  156. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
  157. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
  158. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
  159. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
  160. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
  161. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
  162. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
  163. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
  164. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
  165. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
  166. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
  167. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
  168. reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
  169. reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/croissant_1k.obj +5021 -0
  170. reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/textures/croissant_diff_1k.png +0 -0
  171. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.part +13 -0
  172. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.stl +0 -0
  173. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.part +13 -0
  174. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.stl +0 -0
  175. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.part +13 -0
  176. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.stl +0 -0
  177. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.part +13 -0
  178. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.stl +0 -0
  179. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.part +13 -0
  180. reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
  181. reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/food_apple_01_1k.obj +18045 -0
  182. reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/textures/food_apple_01_diff_1k.png +0 -0
  183. reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.part +13 -0
  184. reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.stl +0 -0
  185. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.part +13 -0
  186. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.stl +0 -0
  187. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.part +13 -0
  188. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.stl +0 -0
  189. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.part +13 -0
  190. reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.stl +0 -0
  191. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.part +13 -0
  192. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.stl +0 -0
  193. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.part +13 -0
  194. reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.stl +0 -0
  195. reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.part +13 -0
  196. reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
  197. reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.part +13 -0
  198. reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.stl +0 -0
  199. reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.part +13 -0
  200. reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.stl +0 -0
  201. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.part +13 -0
  202. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.stl +0 -0
  203. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.part +13 -0
  204. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
  205. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.part +13 -0
  206. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
  207. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.part +13 -0
  208. reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
  209. reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.part +13 -0
  210. reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.stl +0 -0
  211. reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/rubber_duck_toy_1k.obj +8940 -0
  212. reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/textures/rubber_duck_toy_diff_1k.png +0 -0
  213. reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.part +13 -0
  214. reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.stl +0 -0
  215. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.part +13 -0
  216. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.stl +0 -0
  217. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.part +13 -0
  218. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.stl +0 -0
  219. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.part +13 -0
  220. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.stl +0 -0
  221. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.part +13 -0
  222. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.stl +0 -0
  223. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.part +13 -0
  224. reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.stl +0 -0
  225. reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/textures/wooden_table_02_diff_1k.png +0 -0
  226. reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/wooden_table_02_1k.obj +485 -0
  227. reachy_mini/descriptions/reachy_mini/mjcf/config.json +21 -0
  228. reachy_mini/descriptions/reachy_mini/mjcf/joints_properties.xml +29 -0
  229. reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml +642 -0
  230. reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml.bak +442 -0
  231. reachy_mini/descriptions/reachy_mini/mjcf/scene.xml +24 -0
  232. reachy_mini/descriptions/reachy_mini/mjcf/scenes/empty.xml +27 -0
  233. reachy_mini/descriptions/reachy_mini/mjcf/scenes/minimal.xml +132 -0
  234. reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part +13 -0
  235. reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl +0 -0
  236. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part +13 -0
  237. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl +0 -0
  238. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part +13 -0
  239. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl +0 -0
  240. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part +13 -0
  241. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl +0 -0
  242. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part +13 -0
  243. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl +0 -0
  244. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part +13 -0
  245. reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl +0 -0
  246. reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part +13 -0
  247. reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl +0 -0
  248. reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part +13 -0
  249. reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl +0 -0
  250. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part +13 -0
  251. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl +0 -0
  252. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part +13 -0
  253. reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl +0 -0
  254. reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part +13 -0
  255. reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl +0 -0
  256. reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part +13 -0
  257. reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl +0 -0
  258. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part +13 -0
  259. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl +0 -0
  260. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part +13 -0
  261. reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl +0 -0
  262. reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part +13 -0
  263. reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl +0 -0
  264. reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part +13 -0
  265. reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl +0 -0
  266. reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part +13 -0
  267. reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl +0 -0
  268. reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part +13 -0
  269. reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl +0 -0
  270. reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part +13 -0
  271. reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl +0 -0
  272. reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part +13 -0
  273. reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl +0 -0
  274. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m +1 -0
  275. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
  276. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
  277. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
  278. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
  279. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
  280. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
  281. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
  282. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
  283. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
  284. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
  285. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
  286. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
  287. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
  288. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
  289. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
  290. reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
  291. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part +13 -0
  292. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl +0 -0
  293. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part +13 -0
  294. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl +0 -0
  295. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part +13 -0
  296. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl +0 -0
  297. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part +13 -0
  298. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl +0 -0
  299. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part +13 -0
  300. reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
  301. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part +14 -0
  302. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl +0 -0
  303. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part +14 -0
  304. reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl +0 -0
  305. reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part +13 -0
  306. reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl +0 -0
  307. reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part +13 -0
  308. reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl +0 -0
  309. reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part +13 -0
  310. reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl +0 -0
  311. reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part +13 -0
  312. reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl +0 -0
  313. reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part +13 -0
  314. reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl +0 -0
  315. reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part +13 -0
  316. reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl +0 -0
  317. reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part +13 -0
  318. reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl +0 -0
  319. reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part +13 -0
  320. reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl +0 -0
  321. reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part +13 -0
  322. reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl +0 -0
  323. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part +13 -0
  324. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl +0 -0
  325. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part +13 -0
  326. reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl +0 -0
  327. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part +13 -0
  328. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
  329. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part +13 -0
  330. reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl +0 -0
  331. reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part +13 -0
  332. reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl +0 -0
  333. reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part +13 -0
  334. reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl +0 -0
  335. reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part +13 -0
  336. reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl +0 -0
  337. reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part +13 -0
  338. reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl +0 -0
  339. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part +13 -0
  340. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl +0 -0
  341. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part +13 -0
  342. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
  343. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part +13 -0
  344. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
  345. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part +13 -0
  346. reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
  347. reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part +13 -0
  348. reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl +0 -0
  349. reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part +13 -0
  350. reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl +0 -0
  351. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part +13 -0
  352. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl +0 -0
  353. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part +13 -0
  354. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl +0 -0
  355. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part +13 -0
  356. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl +0 -0
  357. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part +13 -0
  358. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl +0 -0
  359. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part +13 -0
  360. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl +0 -0
  361. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part +13 -0
  362. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl +0 -0
  363. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part +13 -0
  364. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl +0 -0
  365. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part +13 -0
  366. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl +0 -0
  367. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part +13 -0
  368. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl +0 -0
  369. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part +13 -0
  370. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl +0 -0
  371. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part +13 -0
  372. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl +0 -0
  373. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part +13 -0
  374. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl +0 -0
  375. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part +13 -0
  376. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl +0 -0
  377. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part +13 -0
  378. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl +0 -0
  379. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part +13 -0
  380. reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl +0 -0
  381. reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part +13 -0
  382. reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl +0 -0
  383. reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part +13 -0
  384. reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl +0 -0
  385. reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part +13 -0
  386. reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl +0 -0
  387. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part +13 -0
  388. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl +0 -0
  389. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part +13 -0
  390. reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl +0 -0
  391. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part +13 -0
  392. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl +0 -0
  393. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part +13 -0
  394. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl +0 -0
  395. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part +13 -0
  396. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl +0 -0
  397. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part +13 -0
  398. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl +0 -0
  399. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part +13 -0
  400. reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl +0 -0
  401. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part +13 -0
  402. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl +0 -0
  403. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part +13 -0
  404. reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl +0 -0
  405. reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part +13 -0
  406. reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl +0 -0
  407. reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part +13 -0
  408. reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl +0 -0
  409. reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part +13 -0
  410. reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl +0 -0
  411. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part +14 -0
  412. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl +0 -0
  413. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part +14 -0
  414. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl +0 -0
  415. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part +14 -0
  416. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl +0 -0
  417. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part +14 -0
  418. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl +0 -0
  419. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part +14 -0
  420. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl +0 -0
  421. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part +14 -0
  422. reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl +0 -0
  423. reachy_mini/descriptions/reachy_mini/urdf/config.json +18 -0
  424. reachy_mini/descriptions/reachy_mini/urdf/robot.urdf +3281 -0
  425. reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak +3282 -0
  426. reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf +2316 -0
  427. reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf +2399 -0
  428. reachy_mini/io/__init__.py +15 -0
  429. reachy_mini/io/abstract.py +70 -0
  430. reachy_mini/io/audio_ws.py +242 -0
  431. reachy_mini/io/protocol.py +44 -0
  432. reachy_mini/io/video_ws.py +135 -0
  433. reachy_mini/io/ws_controller.py +120 -0
  434. reachy_mini/io/zenoh_client.py +273 -0
  435. reachy_mini/io/zenoh_server.py +230 -0
  436. reachy_mini/kinematics/__init__.py +68 -0
  437. reachy_mini/kinematics/analytical_kinematics.py +151 -0
  438. reachy_mini/kinematics/nn_kinematics.py +109 -0
  439. reachy_mini/kinematics/placo_kinematics.py +656 -0
  440. reachy_mini/media/__init__.py +1 -0
  441. reachy_mini/media/audio_base.py +111 -0
  442. reachy_mini/media/audio_control_utils.py +455 -0
  443. reachy_mini/media/audio_gstreamer.py +272 -0
  444. reachy_mini/media/audio_sounddevice.py +321 -0
  445. reachy_mini/media/audio_utils.py +114 -0
  446. reachy_mini/media/camera_base.py +100 -0
  447. reachy_mini/media/camera_constants.py +152 -0
  448. reachy_mini/media/camera_gstreamer.py +231 -0
  449. reachy_mini/media/camera_opencv.py +89 -0
  450. reachy_mini/media/camera_utils.py +111 -0
  451. reachy_mini/media/media_manager.py +281 -0
  452. reachy_mini/media/webrtc_client_gstreamer.py +288 -0
  453. reachy_mini/media/webrtc_daemon.py +334 -0
  454. reachy_mini/motion/__init__.py +4 -0
  455. reachy_mini/motion/goto.py +71 -0
  456. reachy_mini/motion/move.py +43 -0
  457. reachy_mini/motion/recorded_move.py +146 -0
  458. reachy_mini/reachy_mini.py +753 -0
  459. reachy_mini/tools/reflash_motors.py +116 -0
  460. reachy_mini/tools/setup_motor.py +422 -0
  461. reachy_mini/tools/setup_motor_rpi.py +108 -0
  462. reachy_mini/utils/__init__.py +46 -0
  463. reachy_mini/utils/constants.py +9 -0
  464. reachy_mini/utils/hardware_config/__init__.py +1 -0
  465. reachy_mini/utils/hardware_config/parser.py +65 -0
  466. reachy_mini/utils/interpolation.py +227 -0
  467. reachy_mini/utils/parse_urdf_for_kinematics.py +110 -0
  468. reachy_mini/utils/rerun.py +320 -0
  469. reachy_mini/utils/wireless_version/__init__.py +1 -0
  470. reachy_mini/utils/wireless_version/startup_check.py +144 -0
  471. reachy_mini/utils/wireless_version/update.py +20 -0
  472. reachy_mini/utils/wireless_version/update_available.py +61 -0
  473. reachy_mini/utils/wireless_version/utils.py +39 -0
  474. reachy_mini-1.2.5rc1.dist-info/METADATA +161 -0
  475. reachy_mini-1.2.5rc1.dist-info/RECORD +479 -0
  476. reachy_mini-1.2.5rc1.dist-info/WHEEL +5 -0
  477. reachy_mini-1.2.5rc1.dist-info/entry_points.txt +4 -0
  478. reachy_mini-1.2.5rc1.dist-info/licenses/LICENSE +201 -0
  479. reachy_mini-1.2.5rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,796 @@
1
+ #!/usr/bin/env python3
2
+ """Bluetooth service for Reachy Mini using direct DBus API.
3
+
4
+ Includes a fixed NoInputNoOutput agent for automatic Just Works pairing.
5
+ """
6
+ # mypy: ignore-errors
7
+
8
+ import logging
9
+ import os
10
+ import subprocess
11
+ from typing import Callable
12
+
13
+ import dbus
14
+ import dbus.mainloop.glib
15
+ import dbus.service
16
+ from gi.repository import GLib
17
+
18
+ logging.basicConfig(level=logging.INFO)
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # Service and Characteristic UUIDs
22
+ SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef0"
23
+ COMMAND_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef1"
24
+ RESPONSE_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef2"
25
+
26
+ # Device Information Service UUIDs (standard BLE service)
27
+ DEVICE_INFO_SERVICE_UUID = "0000180a-0000-1000-8000-00805f9b34fb"
28
+ MANUFACTURER_NAME_UUID = "00002a29-0000-1000-8000-00805f9b34fb"
29
+ MODEL_NUMBER_UUID = "00002a24-0000-1000-8000-00805f9b34fb"
30
+ FIRMWARE_REVISION_UUID = "00002a26-0000-1000-8000-00805f9b34fb"
31
+
32
+ # Custom Reachy Status Service UUIDs
33
+ REACHY_STATUS_SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef3"
34
+ NETWORK_STATUS_UUID = "12345678-1234-5678-1234-56789abcdef4"
35
+ SYSTEM_STATUS_UUID = "12345678-1234-5678-1234-56789abcdef5"
36
+ AVAILABLE_COMMANDS_UUID = "12345678-1234-5678-1234-56789abcdef6"
37
+
38
+ BLUEZ_SERVICE_NAME = "org.bluez"
39
+ GATT_MANAGER_IFACE = "org.bluez.GattManager1"
40
+ DBUS_OM_IFACE = "org.freedesktop.DBus.ObjectManager"
41
+ DBUS_PROP_IFACE = "org.freedesktop.DBus.Properties"
42
+ GATT_SERVICE_IFACE = "org.bluez.GattService1"
43
+ GATT_CHRC_IFACE = "org.bluez.GattCharacteristic1"
44
+ GATT_DESC_IFACE = "org.bluez.GattDescriptor1"
45
+ LE_ADVERTISING_MANAGER_IFACE = "org.bluez.LEAdvertisingManager1"
46
+ LE_ADVERTISEMENT_IFACE = "org.bluez.LEAdvertisement1"
47
+ AGENT_PATH = "/org/bluez/agent"
48
+
49
+ # Descriptor UUIDs
50
+ USER_DESCRIPTION_UUID = "00002901-0000-1000-8000-00805f9b34fb"
51
+
52
+
53
+ # =======================
54
+ # BLE Agent for Just Works
55
+ # =======================
56
+ class NoInputAgent(dbus.service.Object):
57
+ """BLE Agent for Just Works pairing."""
58
+
59
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
60
+ def Release(self, *args):
61
+ """Handle release of the agent."""
62
+ logger.info("Agent released")
63
+
64
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="s")
65
+ def RequestPinCode(self, *args):
66
+ """Automatically provide an empty pin code for Just Works pairing."""
67
+ logger.info(f"RequestPinCode called with args: {args}, returning empty")
68
+ return ""
69
+
70
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="u")
71
+ def RequestPasskey(self, *args):
72
+ """Automatically provide a passkey of 0 for Just Works pairing."""
73
+ logger.info(f"RequestPasskey called with args: {args}, returning 0")
74
+ return dbus.UInt32(0)
75
+
76
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
77
+ def RequestConfirmation(self, *args):
78
+ """Automatically confirm the pairing request."""
79
+ logger.info(
80
+ f"RequestConfirmation called with args: {args}, accepting automatically"
81
+ )
82
+ return
83
+
84
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
85
+ def DisplayPinCode(self, *args):
86
+ """Handle displaying the pin code (not used in Just Works)."""
87
+ logger.info(f"DisplayPinCode called with args: {args}")
88
+
89
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
90
+ def DisplayPasskey(self, *args):
91
+ """Handle displaying the passkey (not used in Just Works)."""
92
+ logger.info(f"DisplayPasskey called with args: {args}")
93
+
94
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
95
+ def AuthorizeService(self, *args):
96
+ """Handle service authorization requests."""
97
+ logger.info(f"AuthorizeService called with args: {args}")
98
+
99
+ @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
100
+ def Cancel(self, *args):
101
+ """Handle cancellation of the agent request."""
102
+ logger.info("Agent request canceled")
103
+
104
+
105
+ # =======================
106
+ # BLE Advertisement
107
+ # =======================
108
+ class Advertisement(dbus.service.Object):
109
+ """BLE Advertisement."""
110
+
111
+ PATH_BASE = "/org/bluez/advertisement"
112
+
113
+ def __init__(self, bus, index, advertising_type, local_name):
114
+ """Initialize the Advertisement."""
115
+ self.path = self.PATH_BASE + str(index)
116
+ self.bus = bus
117
+ self.ad_type = advertising_type
118
+ self.local_name = local_name
119
+ self.service_uuids = None
120
+ self.include_tx_power = False
121
+ dbus.service.Object.__init__(self, bus, self.path)
122
+
123
+ def get_properties(self):
124
+ """Return the properties of the advertisement."""
125
+ props = {"Type": self.ad_type}
126
+ if self.local_name:
127
+ props["LocalName"] = dbus.String(self.local_name)
128
+ if self.service_uuids:
129
+ props["ServiceUUIDs"] = dbus.Array(self.service_uuids, signature="s")
130
+ props["Appearance"] = dbus.UInt16(0x0000)
131
+ props["Duration"] = dbus.UInt16(0)
132
+ props["Timeout"] = dbus.UInt16(0)
133
+ return {LE_ADVERTISEMENT_IFACE: props}
134
+
135
+ def get_path(self):
136
+ """Return the object path."""
137
+ return dbus.ObjectPath(self.path)
138
+
139
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
140
+ def GetAll(self, interface):
141
+ """Return all properties of the advertisement."""
142
+ if interface != LE_ADVERTISEMENT_IFACE:
143
+ raise dbus.exceptions.DBusException(
144
+ "org.freedesktop.DBus.Error.InvalidArgs",
145
+ "Unknown interface " + interface,
146
+ )
147
+ return self.get_properties()[LE_ADVERTISEMENT_IFACE]
148
+
149
+ @dbus.service.method(LE_ADVERTISEMENT_IFACE, in_signature="", out_signature="")
150
+ def Release(self):
151
+ """Handle release of the advertisement."""
152
+ logger.info("Advertisement released")
153
+
154
+
155
+ # =======================
156
+ # BLE Characteristics & Service
157
+ # =======================
158
+ class Descriptor(dbus.service.Object):
159
+ """GATT Descriptor."""
160
+
161
+ def __init__(self, bus, index, uuid, flags, characteristic):
162
+ """Initialize the Descriptor."""
163
+ self.path = characteristic.path + "/desc" + str(index)
164
+ self.bus = bus
165
+ self.uuid = uuid
166
+ self.flags = flags
167
+ self.characteristic = characteristic
168
+ self.value = []
169
+ dbus.service.Object.__init__(self, bus, self.path)
170
+
171
+ def get_properties(self):
172
+ """Return the properties of the descriptor."""
173
+ return {
174
+ GATT_DESC_IFACE: {
175
+ "Characteristic": self.characteristic.get_path(),
176
+ "UUID": self.uuid,
177
+ "Flags": self.flags,
178
+ }
179
+ }
180
+
181
+ def get_path(self):
182
+ """Return the object path."""
183
+ return dbus.ObjectPath(self.path)
184
+
185
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
186
+ def GetAll(self, interface):
187
+ """Return all properties of the descriptor."""
188
+ if interface != GATT_DESC_IFACE:
189
+ raise dbus.exceptions.DBusException(
190
+ "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface"
191
+ )
192
+ return self.get_properties()[GATT_DESC_IFACE]
193
+
194
+ @dbus.service.method(GATT_DESC_IFACE, in_signature="a{sv}", out_signature="ay")
195
+ def ReadValue(self, options):
196
+ """Handle read from the descriptor."""
197
+ return dbus.Array(self.value, signature="y")
198
+
199
+ @dbus.service.method(GATT_DESC_IFACE, in_signature="aya{sv}")
200
+ def WriteValue(self, value, options):
201
+ """Handle write to the descriptor."""
202
+ self.value = value
203
+
204
+
205
+ class Characteristic(dbus.service.Object):
206
+ """GATT Characteristic."""
207
+
208
+ def __init__(self, bus, index, uuid, flags, service):
209
+ """Initialize the Characteristic."""
210
+ self.path = service.path + "/char" + str(index)
211
+ self.bus = bus
212
+ self.uuid = uuid
213
+ self.service = service
214
+ self.flags = flags
215
+ self.value = []
216
+ self.descriptors = []
217
+ dbus.service.Object.__init__(self, bus, self.path)
218
+
219
+ def get_properties(self):
220
+ """Return the properties of the characteristic."""
221
+ props = {
222
+ GATT_CHRC_IFACE: {
223
+ "Service": self.service.get_path(),
224
+ "UUID": self.uuid,
225
+ "Flags": self.flags,
226
+ }
227
+ }
228
+ if self.descriptors:
229
+ props[GATT_CHRC_IFACE]["Descriptors"] = [
230
+ d.get_path() for d in self.descriptors
231
+ ]
232
+ return props
233
+
234
+ def get_path(self):
235
+ """Return the object path."""
236
+ return dbus.ObjectPath(self.path)
237
+
238
+ def add_descriptor(self, descriptor):
239
+ """Add a descriptor to this characteristic."""
240
+ self.descriptors.append(descriptor)
241
+
242
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
243
+ def GetAll(self, interface):
244
+ """Return all properties of the characteristic."""
245
+ if interface != GATT_CHRC_IFACE:
246
+ raise dbus.exceptions.DBusException(
247
+ "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface"
248
+ )
249
+ return self.get_properties()[GATT_CHRC_IFACE]
250
+
251
+ @dbus.service.method(GATT_CHRC_IFACE, in_signature="a{sv}", out_signature="ay")
252
+ def ReadValue(self, options):
253
+ """Handle read from the characteristic."""
254
+ return dbus.Array(self.value, signature="y")
255
+
256
+ @dbus.service.method(GATT_CHRC_IFACE, in_signature="aya{sv}")
257
+ def WriteValue(self, value, options):
258
+ """Handle write to the characteristic."""
259
+ self.value = value
260
+
261
+
262
+ class CommandCharacteristic(Characteristic):
263
+ """Command Characteristic."""
264
+
265
+ def __init__(self, bus, index, service, command_handler: Callable[[bytes], str]):
266
+ """Initialize the Command Characteristic."""
267
+ super().__init__(bus, index, COMMAND_CHAR_UUID, ["write"], service)
268
+ self.command_handler = command_handler
269
+
270
+ def WriteValue(self, value, options):
271
+ """Handle write to the Command Characteristic."""
272
+ command_bytes = bytes(value)
273
+ response = self.command_handler(command_bytes)
274
+ self.service.response_char.value = [
275
+ dbus.Byte(b) for b in response.encode("utf-8")
276
+ ]
277
+ logger.info(f"Command received: {response}")
278
+
279
+
280
+ class ResponseCharacteristic(Characteristic):
281
+ """Response Characteristic.""" ""
282
+
283
+ def __init__(self, bus, index, service):
284
+ """Initialize the Response Characteristic."""
285
+ super().__init__(bus, index, RESPONSE_CHAR_UUID, ["read", "notify"], service)
286
+
287
+
288
+ class Service(dbus.service.Object):
289
+ """GATT Service."""
290
+
291
+ PATH_BASE = "/org/bluez/service"
292
+
293
+ def __init__(
294
+ self, bus, index, uuid, primary, command_handler: Callable[[bytes], str]
295
+ ):
296
+ """Initialize the GATT Service."""
297
+ self.path = self.PATH_BASE + str(index)
298
+ self.bus = bus
299
+ self.uuid = uuid
300
+ self.primary = primary
301
+ self.characteristics = []
302
+ dbus.service.Object.__init__(self, bus, self.path)
303
+ # Response characteristic first
304
+ self.response_char = ResponseCharacteristic(bus, 1, self)
305
+ self.add_characteristic(self.response_char)
306
+ # Command characteristic
307
+ self.add_characteristic(CommandCharacteristic(bus, 0, self, command_handler))
308
+
309
+ def get_properties(self):
310
+ """Return the properties of the service."""
311
+ return {
312
+ GATT_SERVICE_IFACE: {
313
+ "UUID": self.uuid,
314
+ "Primary": self.primary,
315
+ "Characteristics": [ch.get_path() for ch in self.characteristics],
316
+ }
317
+ }
318
+
319
+ def get_path(self):
320
+ """Return the object path."""
321
+ return dbus.ObjectPath(self.path)
322
+
323
+ def add_characteristic(self, ch):
324
+ """Add a characteristic to the service."""
325
+ self.characteristics.append(ch)
326
+
327
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
328
+ def GetAll(self, interface):
329
+ """Return all properties of the service."""
330
+ if interface != GATT_SERVICE_IFACE:
331
+ raise dbus.exceptions.DBusException(
332
+ "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface"
333
+ )
334
+ return self.get_properties()[GATT_SERVICE_IFACE]
335
+
336
+
337
+ class StaticCharacteristic(Characteristic):
338
+ """Read-only characteristic with static value."""
339
+
340
+ def __init__(
341
+ self, bus, index, uuid, service, value_str: str, description: str = None
342
+ ):
343
+ """Initialize the Static Characteristic."""
344
+ super().__init__(bus, index, uuid, ["read"], service)
345
+ self.value = [dbus.Byte(b) for b in value_str.encode("utf-8")]
346
+
347
+ # Add user description descriptor if provided
348
+ if description:
349
+ desc = Descriptor(bus, 0, USER_DESCRIPTION_UUID, ["read"], self)
350
+ desc.value = [dbus.Byte(b) for b in description.encode("utf-8")]
351
+ self.add_descriptor(desc)
352
+
353
+
354
+ class DynamicCharacteristic(Characteristic):
355
+ """Read-only characteristic with dynamically updatable value."""
356
+
357
+ def __init__(
358
+ self,
359
+ bus,
360
+ index,
361
+ uuid,
362
+ service,
363
+ value_getter: Callable[[], str],
364
+ description: str = None,
365
+ ):
366
+ """Initialize the Dynamic Characteristic."""
367
+ super().__init__(bus, index, uuid, ["read"], service)
368
+ self.value_getter = value_getter
369
+ self.update_value()
370
+
371
+ # Add user description descriptor if provided
372
+ if description:
373
+ desc = Descriptor(bus, 0, USER_DESCRIPTION_UUID, ["read"], self)
374
+ desc.value = [dbus.Byte(b) for b in description.encode("utf-8")]
375
+ self.add_descriptor(desc)
376
+
377
+ def update_value(self):
378
+ """Update the characteristic value from the getter function."""
379
+ value_str = self.value_getter()
380
+ self.value = [dbus.Byte(b) for b in value_str.encode("utf-8")]
381
+ return True # Keep periodic callback alive
382
+
383
+
384
+ class DeviceInfoService(dbus.service.Object):
385
+ """Device Information Service."""
386
+
387
+ PATH_BASE = "/org/bluez/device_info"
388
+
389
+ def __init__(self, bus, index):
390
+ """Initialize the Device Information Service."""
391
+ self.path = self.PATH_BASE + str(index)
392
+ self.bus = bus
393
+ self.uuid = DEVICE_INFO_SERVICE_UUID
394
+ self.primary = True
395
+ self.characteristics = []
396
+ dbus.service.Object.__init__(self, bus, self.path)
397
+
398
+ # Get hotspot IP and format it
399
+ hotspot_ip = get_hotspot_ip()
400
+ firmware_value = f"[HOTSPOT]:{hotspot_ip}"
401
+
402
+ # Add standard Device Info characteristics
403
+ self.add_characteristic(
404
+ StaticCharacteristic(
405
+ bus, 0, MANUFACTURER_NAME_UUID, self, "Pollen Robotics"
406
+ )
407
+ )
408
+ self.add_characteristic(
409
+ StaticCharacteristic(bus, 1, MODEL_NUMBER_UUID, self, "Reachy Mini")
410
+ )
411
+ self.add_characteristic(
412
+ StaticCharacteristic(bus, 2, FIRMWARE_REVISION_UUID, self, firmware_value)
413
+ )
414
+
415
+ def get_properties(self):
416
+ """Return the properties of the service."""
417
+ return {
418
+ GATT_SERVICE_IFACE: {
419
+ "UUID": self.uuid,
420
+ "Primary": self.primary,
421
+ "Characteristics": [ch.get_path() for ch in self.characteristics],
422
+ }
423
+ }
424
+
425
+ def get_path(self):
426
+ """Return the object path."""
427
+ return dbus.ObjectPath(self.path)
428
+
429
+ def add_characteristic(self, ch):
430
+ """Add a characteristic to the service."""
431
+ self.characteristics.append(ch)
432
+
433
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
434
+ def GetAll(self, interface):
435
+ """Return all properties of the service."""
436
+ if interface != GATT_SERVICE_IFACE:
437
+ raise dbus.exceptions.DBusException(
438
+ "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface"
439
+ )
440
+ return self.get_properties()[GATT_SERVICE_IFACE]
441
+
442
+
443
+ class ReachyStatusService(dbus.service.Object):
444
+ """Custom Reachy Status Service with network and system info."""
445
+
446
+ PATH_BASE = "/org/bluez/reachy_status"
447
+
448
+ def __init__(self, bus, index):
449
+ """Initialize the Reachy Status Service."""
450
+ self.path = self.PATH_BASE + str(index)
451
+ self.bus = bus
452
+ self.uuid = REACHY_STATUS_SERVICE_UUID
453
+ self.primary = True
454
+ self.characteristics = []
455
+ dbus.service.Object.__init__(self, bus, self.path)
456
+
457
+ # Get available commands (static)
458
+ import os
459
+
460
+ commands_dir = "commands"
461
+ available_cmds = []
462
+ if os.path.isdir(commands_dir):
463
+ for f in os.listdir(commands_dir):
464
+ if f.endswith(".sh"):
465
+ available_cmds.append(f.replace(".sh", ""))
466
+ commands_value = ", ".join(available_cmds) if available_cmds else "None"
467
+
468
+ # Add dynamic network status characteristic that auto-updates
469
+ self.network_char = DynamicCharacteristic(
470
+ bus, 0, NETWORK_STATUS_UUID, self, get_network_status, "Network Status"
471
+ )
472
+ self.add_characteristic(self.network_char)
473
+
474
+ # Add static characteristics
475
+ self.add_characteristic(
476
+ StaticCharacteristic(
477
+ bus, 1, SYSTEM_STATUS_UUID, self, "Online", "System Status"
478
+ )
479
+ )
480
+ self.add_characteristic(
481
+ StaticCharacteristic(
482
+ bus,
483
+ 2,
484
+ AVAILABLE_COMMANDS_UUID,
485
+ self,
486
+ commands_value,
487
+ "Available Commands",
488
+ )
489
+ )
490
+
491
+ def update_network_status(self):
492
+ """Update the network status characteristic value."""
493
+ if hasattr(self, "network_char"):
494
+ self.network_char.update_value()
495
+ return True # Keep periodic callback alive
496
+
497
+ def get_properties(self):
498
+ """Return the properties of the service."""
499
+ return {
500
+ GATT_SERVICE_IFACE: {
501
+ "UUID": self.uuid,
502
+ "Primary": self.primary,
503
+ "Characteristics": [ch.get_path() for ch in self.characteristics],
504
+ }
505
+ }
506
+
507
+ def get_path(self):
508
+ """Return the object path."""
509
+ return dbus.ObjectPath(self.path)
510
+
511
+ def add_characteristic(self, ch):
512
+ """Add a characteristic to the service."""
513
+ self.characteristics.append(ch)
514
+
515
+ @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}")
516
+ def GetAll(self, interface):
517
+ """Return all properties of the service."""
518
+ if interface != GATT_SERVICE_IFACE:
519
+ raise dbus.exceptions.DBusException(
520
+ "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface"
521
+ )
522
+ return self.get_properties()[GATT_SERVICE_IFACE]
523
+
524
+
525
+ class Application(dbus.service.Object):
526
+ """GATT Application."""
527
+
528
+ def __init__(self, bus, command_handler: Callable[[bytes], str]):
529
+ """Initialize the GATT Application."""
530
+ self.path = "/"
531
+ self.services = []
532
+ dbus.service.Object.__init__(self, bus, self.path)
533
+ # Add command service
534
+ self.services.append(Service(bus, 0, SERVICE_UUID, True, command_handler))
535
+ # Add Device Information Service
536
+ self.services.append(DeviceInfoService(bus, 1))
537
+ # Add Custom Reachy Status Service
538
+ self.reachy_status = ReachyStatusService(bus, 2)
539
+ self.services.append(self.reachy_status)
540
+
541
+ def get_path(self):
542
+ """Return the object path."""
543
+ return dbus.ObjectPath(self.path)
544
+
545
+ @dbus.service.method(DBUS_OM_IFACE, out_signature="a{oa{sa{sv}}}")
546
+ def GetManagedObjects(self):
547
+ """Return a dictionary of all managed objects."""
548
+ resp = {}
549
+ for service in self.services:
550
+ resp[service.get_path()] = service.get_properties()
551
+ for ch in service.characteristics:
552
+ resp[ch.get_path()] = ch.get_properties()
553
+ # Include descriptors
554
+ for desc in ch.descriptors:
555
+ resp[desc.get_path()] = desc.get_properties()
556
+ return resp
557
+
558
+
559
+ # =======================
560
+ # Bluetooth Command Server
561
+ # =======================
562
+ class BluetoothCommandService:
563
+ """Bluetooth Command Service."""
564
+
565
+ def __init__(self, device_name="ReachyMini", pin_code="00000"):
566
+ """Initialize the Bluetooth Command Service."""
567
+ self.device_name = device_name
568
+ self.pin_code = pin_code
569
+ self.connected = False
570
+ self.bus = None
571
+ self.app = None
572
+ self.adv = None
573
+ self.mainloop = None
574
+
575
+ def _handle_command(self, value: bytes) -> str:
576
+ command_str = value.decode("utf-8").strip()
577
+ logger.info(f"Received command: {command_str}")
578
+ # Custom command handling
579
+ if command_str.upper() == "PING":
580
+ return "PONG"
581
+ elif command_str.upper() == "STATUS":
582
+ # exec a "sudo ls" command and print the result
583
+ try:
584
+ result = subprocess.run(["sudo", "ls"], capture_output=True, text=True)
585
+ logger.info(f"Command output: {result.stdout}")
586
+ except Exception as e:
587
+ logger.error(f"Error executing command: {e}")
588
+ return "OK: System running"
589
+ elif command_str.startswith("PIN_"):
590
+ pin = command_str[4:].strip()
591
+ if pin == self.pin_code:
592
+ self.connected = True
593
+ return "OK: Connected"
594
+ else:
595
+ return "ERROR: Incorrect PIN"
596
+
597
+ # else if command starts with "CMD_xxxxx" check if commands directory contains the said named script command xxxx.sh and run its, show output or/and send to read
598
+ elif command_str.startswith("CMD_"):
599
+ if not self.connected:
600
+ return "ERROR: Not connected. Please authenticate first."
601
+ try:
602
+ script_name = command_str[4:].strip() + ".sh"
603
+ script_path = os.path.join("commands", script_name)
604
+ if os.path.isfile(script_path):
605
+ try:
606
+ result = subprocess.run(
607
+ ["sudo", script_path], capture_output=True, text=True
608
+ )
609
+ logger.info(f"Command output: {result.stdout}")
610
+ except Exception as e:
611
+ logger.error(f"Error executing command: {e}")
612
+ else:
613
+ return f"ERROR: Command '{script_name}' not found"
614
+ except Exception as e:
615
+ logger.error(f"Error processing command: {e}")
616
+ return "ERROR: Command execution failed"
617
+ finally:
618
+ self.connected = False # reset connection after command
619
+ else:
620
+ return f"ECHO: {command_str}"
621
+
622
+ def start(self):
623
+ """Start the Bluetooth Command Service."""
624
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
625
+ self.bus = dbus.SystemBus()
626
+
627
+ # BLE Agent registration
628
+ agent_manager = dbus.Interface(
629
+ self.bus.get_object("org.bluez", "/org/bluez"), "org.bluez.AgentManager1"
630
+ )
631
+ self.agent = NoInputAgent(self.bus, AGENT_PATH)
632
+ agent_manager.RegisterAgent(AGENT_PATH, "NoInputNoOutput")
633
+ agent_manager.RequestDefaultAgent(AGENT_PATH)
634
+ logger.info("BLE Agent registered for Just Works pairing")
635
+
636
+ # Find adapter
637
+ adapter = self._find_adapter()
638
+ if not adapter:
639
+ raise Exception("Bluetooth adapter not found")
640
+
641
+ adapter_props = dbus.Interface(adapter, DBUS_PROP_IFACE)
642
+ adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(True))
643
+ adapter_props.Set("org.bluez.Adapter1", "Discoverable", dbus.Boolean(True))
644
+ adapter_props.Set("org.bluez.Adapter1", "DiscoverableTimeout", dbus.UInt32(0))
645
+ adapter_props.Set("org.bluez.Adapter1", "Pairable", dbus.Boolean(True))
646
+
647
+ # Register GATT application
648
+ service_manager = dbus.Interface(adapter, GATT_MANAGER_IFACE)
649
+ self.app = Application(self.bus, self._handle_command)
650
+ service_manager.RegisterApplication(
651
+ self.app.get_path(),
652
+ {},
653
+ reply_handler=lambda: logger.info("GATT app registered"),
654
+ error_handler=lambda e: logger.error(f"Failed to register GATT app: {e}"),
655
+ )
656
+
657
+ # Register advertisement
658
+ ad_manager = dbus.Interface(adapter, LE_ADVERTISING_MANAGER_IFACE)
659
+ self.adv = Advertisement(self.bus, 0, "peripheral", self.device_name)
660
+ # Only advertise main service UUID to avoid advertisement size limits
661
+ # All services are still available when connected
662
+ self.adv.service_uuids = [REACHY_STATUS_SERVICE_UUID]
663
+ ad_manager.RegisterAdvertisement(
664
+ self.adv.get_path(),
665
+ {},
666
+ reply_handler=lambda: logger.info("Advertisement registered"),
667
+ error_handler=lambda e: logger.error(
668
+ f"Failed to register advertisement: {e}"
669
+ ),
670
+ )
671
+
672
+ # Setup periodic network status updates (every 10 seconds)
673
+ GLib.timeout_add_seconds(10, self.app.reachy_status.update_network_status)
674
+
675
+ logger.info(f"✓ Bluetooth service started as '{self.device_name}'")
676
+
677
+ def _find_adapter(self):
678
+ remote_om = dbus.Interface(
679
+ self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE
680
+ )
681
+ objects = remote_om.GetManagedObjects()
682
+ for path, props in objects.items():
683
+ if GATT_MANAGER_IFACE in props and LE_ADVERTISING_MANAGER_IFACE in props:
684
+ return self.bus.get_object(BLUEZ_SERVICE_NAME, path)
685
+ return None
686
+
687
+ def run(self):
688
+ """Run the Bluetooth Command Service."""
689
+ self.start()
690
+ self.mainloop = GLib.MainLoop()
691
+ try:
692
+ logger.info("Running. Press Ctrl+C to exit...")
693
+ self.mainloop.run()
694
+ except KeyboardInterrupt:
695
+ logger.info("Shutting down...")
696
+ self.mainloop.quit()
697
+
698
+
699
+ def get_pin() -> str:
700
+ """Extract the last 5 digits of the serial number from dfu-util -l output."""
701
+ default_pin = "46879"
702
+ try:
703
+ result = subprocess.run(["dfu-util", "-l"], capture_output=True, text=True)
704
+ lines = result.stdout.splitlines()
705
+ for line in lines:
706
+ if "serial=" in line:
707
+ # Extract serial number
708
+ serial_part = line.split("serial=")[-1].strip().strip('"')
709
+ if len(serial_part) >= 5:
710
+ return serial_part[-5:]
711
+ return default_pin # fallback if not found
712
+ except Exception as e:
713
+ logger.error(f"Error getting pin from serial: {e}")
714
+ return default_pin
715
+
716
+
717
+ def get_network_status() -> str:
718
+ """Get comprehensive network status with mode detection.
719
+
720
+ Returns formatted string: {MODE} [interface] address ; [interface] address
721
+ MODE: HOTSPOT (wlan0 is 10.0.0.x), CONNECTED (has IPs), OFFLINE (no IPs)
722
+ """
723
+ try:
724
+ # Get network interfaces and IPs using ifconfig
725
+ result = subprocess.run(
726
+ ["ip", "-4", "addr", "show"], capture_output=True, text=True
727
+ )
728
+
729
+ interfaces = {}
730
+ current_interface = None
731
+
732
+ for line in result.stdout.splitlines():
733
+ line = line.strip()
734
+ # Detect interface name (e.g., "2: wlan0: <BROADCAST...")
735
+ if line and not line.startswith("inet"):
736
+ parts = line.split(":")
737
+ if len(parts) >= 2 and parts[1].strip():
738
+ # Extract interface name (skip loopback)
739
+ iface = parts[1].strip()
740
+ if iface != "lo":
741
+ current_interface = iface
742
+ # Extract IP address
743
+ elif line.startswith("inet ") and current_interface:
744
+ inet_parts = line.split()
745
+ if len(inet_parts) >= 2:
746
+ ip_with_mask = inet_parts[1]
747
+ ip_addr = ip_with_mask.split("/")[0]
748
+ interfaces[current_interface] = ip_addr
749
+
750
+ # Determine mode
751
+ mode = "OFFLINE"
752
+ if interfaces:
753
+ # Check if wlan0 has 10.42.0.1 address (hotspot mode)
754
+ wlan0_ip = interfaces.get("wlan0", "")
755
+ if wlan0_ip.startswith("10.42.0.1"):
756
+ mode = "HOTSPOT"
757
+ else:
758
+ mode = "CONNECTED"
759
+
760
+ # Format output: {MODE} [interface] address ; [interface] address
761
+ if not interfaces:
762
+ return "OFFLINE"
763
+
764
+ interface_strings = [f"[{iface}] {ip}" for iface, ip in interfaces.items()]
765
+ return f"{mode} {' ; '.join(interface_strings)}"
766
+
767
+ except Exception as e:
768
+ logger.error(f"Error getting network status: {e}")
769
+ return "ERROR"
770
+
771
+
772
+ def get_hotspot_ip() -> str:
773
+ """Get the hotspot IP address from network interfaces (legacy function)."""
774
+ status = get_network_status()
775
+ # Extract first IP for backwards compatibility
776
+ if "[" in status and "]" in status:
777
+ try:
778
+ return status.split("]")[1].split(";")[0].strip()
779
+ except (IndexError, AttributeError):
780
+ return "0.0.0.0"
781
+ return "0.0.0.0"
782
+
783
+
784
+ # =======================
785
+ # Main
786
+ # =======================
787
+ def main():
788
+ """Run the Bluetooth Command Service."""
789
+ pin = get_pin()
790
+
791
+ bt_service = BluetoothCommandService(device_name="ReachyMini", pin_code=pin)
792
+ bt_service.run()
793
+
794
+
795
+ if __name__ == "__main__":
796
+ main()