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.
- reachy_mini/__init__.py +4 -0
- reachy_mini/apps/__init__.py +25 -0
- reachy_mini/apps/app.py +258 -0
- reachy_mini/apps/assistant.py +787 -0
- reachy_mini/apps/manager.py +312 -0
- reachy_mini/apps/sources/__init__.py +4 -0
- reachy_mini/apps/sources/hf_space.py +106 -0
- reachy_mini/apps/sources/local_common_venv.py +567 -0
- reachy_mini/apps/templates/README.md.j2 +12 -0
- reachy_mini/apps/templates/gitignore.j2 +3 -0
- reachy_mini/apps/templates/index.html.j2 +40 -0
- reachy_mini/apps/templates/main.py.j2 +74 -0
- reachy_mini/apps/templates/pyproject.toml.j2 +28 -0
- reachy_mini/apps/templates/static/index.html.j2 +27 -0
- reachy_mini/apps/templates/static/main.js.j2 +47 -0
- reachy_mini/apps/templates/static/style.css.j2 +25 -0
- reachy_mini/apps/templates/style.css.j2 +411 -0
- reachy_mini/apps/utils.py +30 -0
- reachy_mini/assets/config/hardware_config.yaml +164 -0
- reachy_mini/assets/confused1.wav +0 -0
- reachy_mini/assets/count.wav +0 -0
- reachy_mini/assets/dance1.wav +0 -0
- reachy_mini/assets/firmware/CHANGELOG.md +15 -0
- reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin +0 -0
- reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin +0 -0
- reachy_mini/assets/firmware/update.sh +9 -0
- reachy_mini/assets/go_sleep.wav +0 -0
- reachy_mini/assets/impatient1.wav +0 -0
- reachy_mini/assets/kinematics_data.json +253 -0
- reachy_mini/assets/models/fknetwork.dynamic.onnx +0 -0
- reachy_mini/assets/models/fknetwork.onnx +0 -0
- reachy_mini/assets/models/fknetwork_int8.onnx +0 -0
- reachy_mini/assets/models/iknetwork.onnx +0 -0
- reachy_mini/assets/wake_up.wav +0 -0
- reachy_mini/daemon/__init__.py +1 -0
- reachy_mini/daemon/app/__init__.py +1 -0
- reachy_mini/daemon/app/bg_job_register.py +142 -0
- reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg +40 -0
- reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg +42 -0
- reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg +50 -0
- reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg +18 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg +22 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg +41 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg +18 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/css/app.css +1433 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Archivo-Italic-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Archivo-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Asap-Italic-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Asap-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js +5 -0
- reachy_mini/daemon/app/dashboard/static/js/apps.js +323 -0
- reachy_mini/daemon/app/dashboard/static/js/appstore.js +167 -0
- reachy_mini/daemon/app/dashboard/static/js/daemon.js +169 -0
- reachy_mini/daemon/app/dashboard/static/js/health_check.js +9 -0
- reachy_mini/daemon/app/dashboard/static/js/move_player.js +132 -0
- reachy_mini/daemon/app/dashboard/static/js/notification.js +41 -0
- reachy_mini/daemon/app/dashboard/static/js/update.js +132 -0
- reachy_mini/daemon/app/dashboard/static/js/volume_control.js +252 -0
- reachy_mini/daemon/app/dashboard/static/js/wifi.js +176 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/README.md +15 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json +1127 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/package.json +6 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml +608 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js +6 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css +185 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js +11 -0
- reachy_mini/daemon/app/dashboard/templates/base.html +21 -0
- reachy_mini/daemon/app/dashboard/templates/index.html +20 -0
- reachy_mini/daemon/app/dashboard/templates/sections/apps.html +8 -0
- reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +35 -0
- reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +45 -0
- reachy_mini/daemon/app/dashboard/templates/sections/move_player.html +121 -0
- reachy_mini/daemon/app/dashboard/templates/sections/notification.html +19 -0
- reachy_mini/daemon/app/dashboard/templates/sections/update.html +54 -0
- reachy_mini/daemon/app/dashboard/templates/sections/wifi.html +46 -0
- reachy_mini/daemon/app/dashboard/templates/settings.html +14 -0
- reachy_mini/daemon/app/dependencies.py +41 -0
- reachy_mini/daemon/app/main.py +469 -0
- reachy_mini/daemon/app/models.py +149 -0
- reachy_mini/daemon/app/routers/apps.py +114 -0
- reachy_mini/daemon/app/routers/daemon.py +85 -0
- reachy_mini/daemon/app/routers/kinematics.py +57 -0
- reachy_mini/daemon/app/routers/motors.py +41 -0
- reachy_mini/daemon/app/routers/move.py +265 -0
- reachy_mini/daemon/app/routers/state.py +146 -0
- reachy_mini/daemon/app/routers/update.py +86 -0
- reachy_mini/daemon/app/routers/volume.py +423 -0
- reachy_mini/daemon/app/routers/wifi_config.py +219 -0
- reachy_mini/daemon/app/services/__init__.py +1 -0
- reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py +796 -0
- reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh +7 -0
- reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh +4 -0
- reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh +7 -0
- reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh +39 -0
- reachy_mini/daemon/app/services/gpio_shutdown/__init__.py +1 -0
- reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh +33 -0
- reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh +3 -0
- reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py +28 -0
- reachy_mini/daemon/app/services/wireless/generate_asoundrc.sh +70 -0
- reachy_mini/daemon/app/services/wireless/install_service.sh +33 -0
- reachy_mini/daemon/app/services/wireless/launcher.sh +5 -0
- reachy_mini/daemon/backend/__init__.py +1 -0
- reachy_mini/daemon/backend/abstract.py +815 -0
- reachy_mini/daemon/backend/mujoco/__init__.py +36 -0
- reachy_mini/daemon/backend/mujoco/backend.py +395 -0
- reachy_mini/daemon/backend/mujoco/utils.py +59 -0
- reachy_mini/daemon/backend/mujoco/video_udp.py +57 -0
- reachy_mini/daemon/backend/robot/__init__.py +8 -0
- reachy_mini/daemon/backend/robot/backend.py +597 -0
- reachy_mini/daemon/daemon.py +651 -0
- reachy_mini/daemon/utils.py +116 -0
- reachy_mini/descriptions/reachy_mini/mjcf/additional.xml +6 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/README.m +1 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/croissant_1k.obj +5021 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/textures/croissant_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/food_apple_01_1k.obj +18045 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/textures/food_apple_01_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/rubber_duck_toy_1k.obj +8940 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/textures/rubber_duck_toy_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/textures/wooden_table_02_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/wooden_table_02_1k.obj +485 -0
- reachy_mini/descriptions/reachy_mini/mjcf/config.json +21 -0
- reachy_mini/descriptions/reachy_mini/mjcf/joints_properties.xml +29 -0
- reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml +642 -0
- reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml.bak +442 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scene.xml +24 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scenes/empty.xml +27 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scenes/minimal.xml +132 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m +1 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/config.json +18 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot.urdf +3281 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak +3282 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf +2316 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf +2399 -0
- reachy_mini/io/__init__.py +15 -0
- reachy_mini/io/abstract.py +70 -0
- reachy_mini/io/audio_ws.py +242 -0
- reachy_mini/io/protocol.py +44 -0
- reachy_mini/io/video_ws.py +135 -0
- reachy_mini/io/ws_controller.py +120 -0
- reachy_mini/io/zenoh_client.py +273 -0
- reachy_mini/io/zenoh_server.py +230 -0
- reachy_mini/kinematics/__init__.py +68 -0
- reachy_mini/kinematics/analytical_kinematics.py +151 -0
- reachy_mini/kinematics/nn_kinematics.py +109 -0
- reachy_mini/kinematics/placo_kinematics.py +656 -0
- reachy_mini/media/__init__.py +1 -0
- reachy_mini/media/audio_base.py +111 -0
- reachy_mini/media/audio_control_utils.py +455 -0
- reachy_mini/media/audio_gstreamer.py +272 -0
- reachy_mini/media/audio_sounddevice.py +321 -0
- reachy_mini/media/audio_utils.py +114 -0
- reachy_mini/media/camera_base.py +100 -0
- reachy_mini/media/camera_constants.py +152 -0
- reachy_mini/media/camera_gstreamer.py +231 -0
- reachy_mini/media/camera_opencv.py +89 -0
- reachy_mini/media/camera_utils.py +111 -0
- reachy_mini/media/media_manager.py +281 -0
- reachy_mini/media/webrtc_client_gstreamer.py +288 -0
- reachy_mini/media/webrtc_daemon.py +334 -0
- reachy_mini/motion/__init__.py +4 -0
- reachy_mini/motion/goto.py +71 -0
- reachy_mini/motion/move.py +43 -0
- reachy_mini/motion/recorded_move.py +146 -0
- reachy_mini/reachy_mini.py +753 -0
- reachy_mini/tools/reflash_motors.py +116 -0
- reachy_mini/tools/setup_motor.py +422 -0
- reachy_mini/tools/setup_motor_rpi.py +108 -0
- reachy_mini/utils/__init__.py +46 -0
- reachy_mini/utils/constants.py +9 -0
- reachy_mini/utils/hardware_config/__init__.py +1 -0
- reachy_mini/utils/hardware_config/parser.py +65 -0
- reachy_mini/utils/interpolation.py +227 -0
- reachy_mini/utils/parse_urdf_for_kinematics.py +110 -0
- reachy_mini/utils/rerun.py +320 -0
- reachy_mini/utils/wireless_version/__init__.py +1 -0
- reachy_mini/utils/wireless_version/startup_check.py +144 -0
- reachy_mini/utils/wireless_version/update.py +20 -0
- reachy_mini/utils/wireless_version/update_available.py +61 -0
- reachy_mini/utils/wireless_version/utils.py +39 -0
- reachy_mini-1.2.5rc1.dist-info/METADATA +161 -0
- reachy_mini-1.2.5rc1.dist-info/RECORD +479 -0
- reachy_mini-1.2.5rc1.dist-info/WHEEL +5 -0
- reachy_mini-1.2.5rc1.dist-info/entry_points.txt +4 -0
- reachy_mini-1.2.5rc1.dist-info/licenses/LICENSE +201 -0
- reachy_mini-1.2.5rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Utility functions for audio handling, specifically for detecting the ReSpeaker sound card."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _process_card_number_output(output: str) -> int:
|
|
9
|
+
"""Process the output of 'arecord -l' to find the ReSpeaker or Reachy Mini Audio card number."""
|
|
10
|
+
lines = output.split("\n")
|
|
11
|
+
for line in lines:
|
|
12
|
+
if "reachy mini audio" in line.lower():
|
|
13
|
+
card_number = line.split(" ")[1].split(":")[0]
|
|
14
|
+
logging.debug(f"Found Reachy Mini Audio sound card: {card_number}")
|
|
15
|
+
return int(card_number)
|
|
16
|
+
elif "respeaker" in line.lower():
|
|
17
|
+
card_number = line.split(" ")[1].split(":")[0]
|
|
18
|
+
logging.warning(
|
|
19
|
+
f"Found ReSpeaker sound card: {card_number}. Please update firmware!"
|
|
20
|
+
)
|
|
21
|
+
return int(card_number)
|
|
22
|
+
|
|
23
|
+
logging.warning("Reachy Mini Audio sound card not found. Returning default card")
|
|
24
|
+
return 0 # default sound card
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_respeaker_card_number() -> int:
|
|
28
|
+
"""Return the card number of the ReSpeaker sound card, or 0 if not found."""
|
|
29
|
+
try:
|
|
30
|
+
result = subprocess.run(
|
|
31
|
+
["arecord", "-l"], capture_output=True, text=True, check=True
|
|
32
|
+
)
|
|
33
|
+
output = result.stdout
|
|
34
|
+
|
|
35
|
+
return _process_card_number_output(output)
|
|
36
|
+
|
|
37
|
+
except subprocess.CalledProcessError as e:
|
|
38
|
+
logging.error(f"Cannot find sound card: {e}")
|
|
39
|
+
return -1
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def has_reachymini_asoundrc() -> bool:
|
|
43
|
+
"""Check if ~/.asoundrc exists and contains both reachymini_audio_sink and reachymini_audio_src."""
|
|
44
|
+
asoundrc_path = Path.home().joinpath(".asoundrc")
|
|
45
|
+
if not asoundrc_path.exists():
|
|
46
|
+
return False
|
|
47
|
+
content = asoundrc_path.read_text(errors="ignore")
|
|
48
|
+
return "reachymini_audio_sink" in content and "reachymini_audio_src" in content
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def check_reachymini_asoundrc() -> bool:
|
|
52
|
+
"""Check if ~/.asoundrc exists and is correctly configured for Reachy Mini Audio."""
|
|
53
|
+
asoundrc_path = Path.home().joinpath(".asoundrc")
|
|
54
|
+
if not asoundrc_path.exists():
|
|
55
|
+
return False
|
|
56
|
+
content = asoundrc_path.read_text(errors="ignore")
|
|
57
|
+
card_id = get_respeaker_card_number()
|
|
58
|
+
# Check for both sink and src
|
|
59
|
+
if not ("reachymini_audio_sink" in content and "reachymini_audio_src" in content):
|
|
60
|
+
return False
|
|
61
|
+
# Check that the card number in .asoundrc matches the detected card_id
|
|
62
|
+
import re
|
|
63
|
+
|
|
64
|
+
card_numbers = set(re.findall(r"card\s+(\d+)", content))
|
|
65
|
+
if str(card_id) not in card_numbers:
|
|
66
|
+
return False
|
|
67
|
+
return True
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def write_asoundrc_to_home() -> None:
|
|
71
|
+
"""Write the .asoundrc file with Reachy Mini audio configuration to the user's home directory."""
|
|
72
|
+
card_id = get_respeaker_card_number()
|
|
73
|
+
asoundrc_content = f"""
|
|
74
|
+
pcm.!default {{
|
|
75
|
+
type hw
|
|
76
|
+
card {card_id}
|
|
77
|
+
}}
|
|
78
|
+
|
|
79
|
+
ctl.!default {{
|
|
80
|
+
type hw
|
|
81
|
+
card {card_id}
|
|
82
|
+
}}
|
|
83
|
+
|
|
84
|
+
pcm.reachymini_audio_sink {{
|
|
85
|
+
type dmix
|
|
86
|
+
ipc_key 4241
|
|
87
|
+
slave {{
|
|
88
|
+
pcm "hw:{card_id},0"
|
|
89
|
+
channels 2
|
|
90
|
+
period_size 1024
|
|
91
|
+
buffer_size 4096
|
|
92
|
+
rate 16000
|
|
93
|
+
}}
|
|
94
|
+
bindings {{
|
|
95
|
+
0 0
|
|
96
|
+
1 1
|
|
97
|
+
}}
|
|
98
|
+
}}
|
|
99
|
+
|
|
100
|
+
pcm.reachymini_audio_src {{
|
|
101
|
+
type dsnoop
|
|
102
|
+
ipc_key 4242
|
|
103
|
+
slave {{
|
|
104
|
+
pcm "hw:{card_id},0"
|
|
105
|
+
channels 2
|
|
106
|
+
rate 16000
|
|
107
|
+
period_size 1024
|
|
108
|
+
buffer_size 4096
|
|
109
|
+
}}
|
|
110
|
+
}}
|
|
111
|
+
"""
|
|
112
|
+
asoundrc_path = Path.home().joinpath(".asoundrc")
|
|
113
|
+
with open(asoundrc_path, "w") as f:
|
|
114
|
+
f.write(asoundrc_content)
|
|
@@ -0,0 +1,100 @@
|
|
|
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 typing import Optional
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import numpy.typing as npt
|
|
13
|
+
|
|
14
|
+
from reachy_mini.media.camera_constants import (
|
|
15
|
+
CameraResolution,
|
|
16
|
+
CameraSpecs,
|
|
17
|
+
MujocoCameraSpecs,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CameraBase(ABC):
|
|
22
|
+
"""Abstract class for opening and managing a camera."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
log_level: str = "INFO",
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Initialize the camera."""
|
|
29
|
+
self.logger = logging.getLogger(__name__)
|
|
30
|
+
self.logger.setLevel(log_level)
|
|
31
|
+
self._resolution: Optional[CameraResolution] = None
|
|
32
|
+
self.camera_specs: Optional[CameraSpecs] = None
|
|
33
|
+
self.resized_K: Optional[npt.NDArray[np.float64]] = None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def resolution(self) -> tuple[int, int]:
|
|
37
|
+
"""Get the current camera resolution as a tuple (width, height)."""
|
|
38
|
+
if self._resolution is None:
|
|
39
|
+
raise RuntimeError("Camera resolution is not set.")
|
|
40
|
+
return (self._resolution.value[0], self._resolution.value[1])
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def framerate(self) -> int:
|
|
44
|
+
"""Get the current camera frames per second."""
|
|
45
|
+
if self._resolution is None:
|
|
46
|
+
raise RuntimeError("Camera resolution is not set.")
|
|
47
|
+
return int(self._resolution.value[2])
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def K(self) -> Optional[npt.NDArray[np.float64]]:
|
|
51
|
+
"""Get the camera intrinsic matrix for the current resolution."""
|
|
52
|
+
return self.resized_K
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def D(self) -> Optional[npt.NDArray[np.float64]]:
|
|
56
|
+
"""Get the camera distortion coefficients."""
|
|
57
|
+
if self.camera_specs is not None:
|
|
58
|
+
return self.camera_specs.D
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def set_resolution(self, resolution: CameraResolution) -> None:
|
|
62
|
+
"""Set the camera resolution."""
|
|
63
|
+
if self.camera_specs is None:
|
|
64
|
+
raise RuntimeError(
|
|
65
|
+
"Camera specs not set. Open the camera before setting the resolution."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if isinstance(self.camera_specs, MujocoCameraSpecs):
|
|
69
|
+
raise RuntimeError(
|
|
70
|
+
"Cannot change resolution of Mujoco simulated camera for now."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if resolution not in self.camera_specs.available_resolutions:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"Resolution not supported by the camera. Available resolutions are : {self.camera_specs.available_resolutions}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
w_ratio = resolution.value[0] / self.camera_specs.default_resolution.value[0]
|
|
79
|
+
h_ratio = resolution.value[1] / self.camera_specs.default_resolution.value[1]
|
|
80
|
+
self.resized_K = self.camera_specs.K.copy()
|
|
81
|
+
|
|
82
|
+
self.resized_K[0, 0] *= w_ratio
|
|
83
|
+
self.resized_K[1, 1] *= h_ratio
|
|
84
|
+
self.resized_K[0, 2] *= w_ratio
|
|
85
|
+
self.resized_K[1, 2] *= h_ratio
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
def open(self) -> None:
|
|
89
|
+
"""Open the camera."""
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
@abstractmethod
|
|
93
|
+
def read(self) -> Optional[npt.NDArray[np.uint8]]:
|
|
94
|
+
"""Read an image from the camera. Returns the image or None if error."""
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
def close(self) -> None:
|
|
99
|
+
"""Close the camera and release resources."""
|
|
100
|
+
pass
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Camera constants for Reachy Mini."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import numpy.typing as npt
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CameraResolution(Enum):
|
|
12
|
+
"""Base class for camera resolutions."""
|
|
13
|
+
|
|
14
|
+
R1536x864at40fps = (1536, 864, 40)
|
|
15
|
+
|
|
16
|
+
R1280x720at60fps = (1280, 720, 60)
|
|
17
|
+
R1280x720at30fps = (1280, 720, 30)
|
|
18
|
+
|
|
19
|
+
R1920x1080at30fps = (1920, 1080, 30)
|
|
20
|
+
R1920x1080at60fps = (1920, 1080, 60)
|
|
21
|
+
|
|
22
|
+
R2304x1296at30fps = (2304, 1296, 30)
|
|
23
|
+
R1600x1200at30fps = (1600, 1200, 30)
|
|
24
|
+
|
|
25
|
+
R3264x2448at30fps = (3264, 2448, 30)
|
|
26
|
+
R3264x2448at10fps = (3264, 2448, 10)
|
|
27
|
+
|
|
28
|
+
R3840x2592at30fps = (3840, 2592, 30)
|
|
29
|
+
R3840x2592at10fps = (3840, 2592, 10)
|
|
30
|
+
R3840x2160at30fps = (3840, 2160, 30)
|
|
31
|
+
R3840x2160at10fps = (3840, 2160, 10)
|
|
32
|
+
|
|
33
|
+
R3072x1728at10fps = (3072, 1728, 10)
|
|
34
|
+
|
|
35
|
+
R4608x2592at10fps = (4608, 2592, 10)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class CameraSpecs:
|
|
40
|
+
"""Base camera specifications."""
|
|
41
|
+
|
|
42
|
+
name: str = ""
|
|
43
|
+
available_resolutions: List[CameraResolution] = field(default_factory=list)
|
|
44
|
+
default_resolution: CameraResolution = CameraResolution.R1280x720at30fps
|
|
45
|
+
vid = 0
|
|
46
|
+
pid = 0
|
|
47
|
+
K: npt.NDArray[np.float64] = field(default_factory=lambda: np.eye(3))
|
|
48
|
+
D: npt.NDArray[np.float64] = field(default_factory=lambda: np.zeros((5,)))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class ArducamSpecs(CameraSpecs):
|
|
53
|
+
"""Arducam camera specifications."""
|
|
54
|
+
|
|
55
|
+
name = "arducam"
|
|
56
|
+
available_resolutions = [
|
|
57
|
+
CameraResolution.R2304x1296at30fps,
|
|
58
|
+
CameraResolution.R4608x2592at10fps,
|
|
59
|
+
CameraResolution.R1920x1080at30fps,
|
|
60
|
+
CameraResolution.R1600x1200at30fps,
|
|
61
|
+
CameraResolution.R1280x720at30fps,
|
|
62
|
+
]
|
|
63
|
+
default_resolution = CameraResolution.R1280x720at30fps
|
|
64
|
+
vid = 0x0C45
|
|
65
|
+
pid = 0x636D
|
|
66
|
+
K = np.array([[550.3564, 0.0, 638.0112], [0.0, 549.1653, 364.589], [0.0, 0.0, 1.0]])
|
|
67
|
+
D = np.array([-0.0694, 0.1565, -0.0004, 0.0003, -0.0983])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class ReachyMiniLiteCamSpecs(CameraSpecs):
|
|
72
|
+
"""Reachy Mini Lite camera specifications."""
|
|
73
|
+
|
|
74
|
+
name = "lite"
|
|
75
|
+
available_resolutions = [
|
|
76
|
+
CameraResolution.R1920x1080at60fps,
|
|
77
|
+
CameraResolution.R3840x2592at30fps,
|
|
78
|
+
CameraResolution.R3840x2160at30fps,
|
|
79
|
+
CameraResolution.R3264x2448at30fps,
|
|
80
|
+
]
|
|
81
|
+
default_resolution = CameraResolution.R1920x1080at60fps
|
|
82
|
+
vid = 0x38FB
|
|
83
|
+
pid = 0x1002
|
|
84
|
+
K = np.array(
|
|
85
|
+
[
|
|
86
|
+
[821.515, 0.0, 962.241],
|
|
87
|
+
[0.0, 820.830, 542.459],
|
|
88
|
+
[0.0, 0.0, 1.0],
|
|
89
|
+
]
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
D = np.array(
|
|
93
|
+
[
|
|
94
|
+
-2.94475669e-02,
|
|
95
|
+
6.00511974e-02,
|
|
96
|
+
3.57813971e-06,
|
|
97
|
+
-2.96459394e-04,
|
|
98
|
+
-3.79243988e-02,
|
|
99
|
+
]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class ReachyMiniWirelessCamSpecs(ReachyMiniLiteCamSpecs):
|
|
105
|
+
"""Reachy Mini Wireless camera specifications."""
|
|
106
|
+
|
|
107
|
+
name = "wireless"
|
|
108
|
+
available_resolutions = [
|
|
109
|
+
CameraResolution.R1920x1080at30fps,
|
|
110
|
+
CameraResolution.R1280x720at60fps,
|
|
111
|
+
CameraResolution.R3840x2592at10fps,
|
|
112
|
+
CameraResolution.R3840x2160at10fps,
|
|
113
|
+
CameraResolution.R3264x2448at10fps,
|
|
114
|
+
CameraResolution.R3072x1728at10fps,
|
|
115
|
+
]
|
|
116
|
+
default_resolution = CameraResolution.R1920x1080at30fps
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
class OlderRPiCamSpecs(ReachyMiniLiteCamSpecs):
|
|
121
|
+
"""Older Raspberry Pi camera specifications. Keeping for compatibility."""
|
|
122
|
+
|
|
123
|
+
name = "older_rpi"
|
|
124
|
+
vid = 0x1BCF
|
|
125
|
+
pid = 0x28C4
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class MujocoCameraSpecs(CameraSpecs):
|
|
130
|
+
"""Mujoco simulated camera specifications."""
|
|
131
|
+
|
|
132
|
+
available_resolutions = [
|
|
133
|
+
CameraResolution.R1280x720at60fps,
|
|
134
|
+
]
|
|
135
|
+
default_resolution = CameraResolution.R1280x720at60fps
|
|
136
|
+
# ideal camera matrix
|
|
137
|
+
K = np.array(
|
|
138
|
+
[
|
|
139
|
+
[
|
|
140
|
+
CameraResolution.R1280x720at60fps.value[0],
|
|
141
|
+
0.0,
|
|
142
|
+
CameraResolution.R1280x720at60fps.value[0] / 2,
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
0.0,
|
|
146
|
+
CameraResolution.R1280x720at60fps.value[1],
|
|
147
|
+
CameraResolution.R1280x720at60fps.value[1] / 2,
|
|
148
|
+
],
|
|
149
|
+
[0.0, 0.0, 1.0],
|
|
150
|
+
]
|
|
151
|
+
)
|
|
152
|
+
D = np.zeros((5,)) # no distortion
|
|
@@ -0,0 +1,231 @@
|
|
|
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
|
+
import os
|
|
8
|
+
from threading import Thread
|
|
9
|
+
from typing import Optional, Tuple, cast
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import numpy.typing as npt
|
|
13
|
+
|
|
14
|
+
from reachy_mini.media.camera_constants import (
|
|
15
|
+
ArducamSpecs,
|
|
16
|
+
CameraResolution,
|
|
17
|
+
CameraSpecs,
|
|
18
|
+
ReachyMiniLiteCamSpecs,
|
|
19
|
+
ReachyMiniWirelessCamSpecs,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import gi
|
|
24
|
+
|
|
25
|
+
except ImportError as e:
|
|
26
|
+
raise ImportError(
|
|
27
|
+
"The 'gi' module is required for GStreamerCamera but could not be imported. \
|
|
28
|
+
Please install the GStreamer backend: pip install .[gstreamer]."
|
|
29
|
+
) from e
|
|
30
|
+
|
|
31
|
+
gi.require_version("Gst", "1.0")
|
|
32
|
+
gi.require_version("GstApp", "1.0")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
from gi.repository import GLib, Gst, GstApp # noqa: E402
|
|
36
|
+
|
|
37
|
+
from .camera_base import CameraBase # noqa: E402
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class GStreamerCamera(CameraBase):
|
|
41
|
+
"""Camera implementation using GStreamer."""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
log_level: str = "INFO",
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Initialize the GStreamer camera."""
|
|
48
|
+
super().__init__(log_level=log_level)
|
|
49
|
+
Gst.init(None)
|
|
50
|
+
self._loop = GLib.MainLoop()
|
|
51
|
+
self._thread_bus_calls: Optional[Thread] = None
|
|
52
|
+
|
|
53
|
+
self.pipeline = Gst.Pipeline.new("camera_recorder")
|
|
54
|
+
|
|
55
|
+
cam_path, self.camera_specs = self.get_video_device()
|
|
56
|
+
|
|
57
|
+
if self.camera_specs is None:
|
|
58
|
+
raise RuntimeError("Camera specs not set")
|
|
59
|
+
self._resolution = self.camera_specs.default_resolution
|
|
60
|
+
self.resized_K = self.camera_specs.K
|
|
61
|
+
|
|
62
|
+
if self._resolution is None:
|
|
63
|
+
raise RuntimeError("Failed to get default camera resolution.")
|
|
64
|
+
|
|
65
|
+
# note for some applications the jpeg image could be directly used
|
|
66
|
+
self._appsink_video: GstApp = Gst.ElementFactory.make("appsink")
|
|
67
|
+
self.set_resolution(self._resolution)
|
|
68
|
+
self._appsink_video.set_property("drop", True) # avoid overflow
|
|
69
|
+
self._appsink_video.set_property("max-buffers", 1) # keep last image only
|
|
70
|
+
self.pipeline.add(self._appsink_video)
|
|
71
|
+
|
|
72
|
+
if cam_path == "":
|
|
73
|
+
self.logger.warning("Recording pipeline set without camera.")
|
|
74
|
+
self.pipeline.remove(self._appsink_video)
|
|
75
|
+
elif cam_path == "/tmp/reachymini_camera_socket":
|
|
76
|
+
camsrc = Gst.ElementFactory.make("unixfdsrc")
|
|
77
|
+
camsrc.set_property("socket-path", "/tmp/reachymini_camera_socket")
|
|
78
|
+
self.pipeline.add(camsrc)
|
|
79
|
+
queue = Gst.ElementFactory.make("queue")
|
|
80
|
+
self.pipeline.add(queue)
|
|
81
|
+
videoconvert = Gst.ElementFactory.make("videoconvert")
|
|
82
|
+
self.pipeline.add(videoconvert)
|
|
83
|
+
camsrc.link(queue)
|
|
84
|
+
queue.link(videoconvert)
|
|
85
|
+
videoconvert.link(self._appsink_video)
|
|
86
|
+
elif cam_path == "imx708":
|
|
87
|
+
camsrc = Gst.ElementFactory.make("libcamerasrc")
|
|
88
|
+
self.pipeline.add(camsrc)
|
|
89
|
+
queue = Gst.ElementFactory.make("queue")
|
|
90
|
+
self.pipeline.add(queue)
|
|
91
|
+
videoconvert = Gst.ElementFactory.make("videoconvert")
|
|
92
|
+
self.pipeline.add(videoconvert)
|
|
93
|
+
camsrc.link(queue)
|
|
94
|
+
queue.link(videoconvert)
|
|
95
|
+
videoconvert.link(self._appsink_video)
|
|
96
|
+
else:
|
|
97
|
+
camsrc = Gst.ElementFactory.make("v4l2src")
|
|
98
|
+
camsrc.set_property("device", cam_path)
|
|
99
|
+
self.pipeline.add(camsrc)
|
|
100
|
+
queue = Gst.ElementFactory.make("queue")
|
|
101
|
+
self.pipeline.add(queue)
|
|
102
|
+
# use vaapijpegdec or nvjpegdec for hardware acceleration
|
|
103
|
+
jpegdec = Gst.ElementFactory.make("jpegdec")
|
|
104
|
+
self.pipeline.add(jpegdec)
|
|
105
|
+
videoconvert = Gst.ElementFactory.make("videoconvert")
|
|
106
|
+
self.pipeline.add(videoconvert)
|
|
107
|
+
camsrc.link(queue)
|
|
108
|
+
queue.link(jpegdec)
|
|
109
|
+
jpegdec.link(videoconvert)
|
|
110
|
+
videoconvert.link(self._appsink_video)
|
|
111
|
+
|
|
112
|
+
def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def]
|
|
113
|
+
t = msg.type
|
|
114
|
+
if t == Gst.MessageType.EOS:
|
|
115
|
+
self.logger.warning("End-of-stream")
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
elif t == Gst.MessageType.ERROR:
|
|
119
|
+
err, debug = msg.parse_error()
|
|
120
|
+
self.logger.error(f"Error: {err} {debug}")
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
def _handle_bus_calls(self) -> None:
|
|
126
|
+
self.logger.debug("starting bus message loop")
|
|
127
|
+
bus = self.pipeline.get_bus()
|
|
128
|
+
bus.add_watch(GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop)
|
|
129
|
+
self._loop.run()
|
|
130
|
+
bus.remove_watch()
|
|
131
|
+
self.logger.debug("bus message loop stopped")
|
|
132
|
+
|
|
133
|
+
def set_resolution(self, resolution: CameraResolution) -> None:
|
|
134
|
+
"""Set the camera resolution."""
|
|
135
|
+
super().set_resolution(resolution)
|
|
136
|
+
|
|
137
|
+
# Check if pipeline is not playing before changing resolution
|
|
138
|
+
if self.pipeline.get_state(0).state == Gst.State.PLAYING:
|
|
139
|
+
raise RuntimeError(
|
|
140
|
+
"Cannot change resolution while the camera is streaming. Please close the camera first."
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
self._resolution = resolution
|
|
144
|
+
caps_video = Gst.Caps.from_string(
|
|
145
|
+
f"video/x-raw,format=BGR, width={self._resolution.value[0]},height={self._resolution.value[1]},framerate={self.framerate}/1"
|
|
146
|
+
)
|
|
147
|
+
self._appsink_video.set_property("caps", caps_video)
|
|
148
|
+
|
|
149
|
+
def open(self) -> None:
|
|
150
|
+
"""Open the camera using GStreamer."""
|
|
151
|
+
self.pipeline.set_state(Gst.State.PLAYING)
|
|
152
|
+
self._thread_bus_calls = Thread(target=self._handle_bus_calls, daemon=True)
|
|
153
|
+
self._thread_bus_calls.start()
|
|
154
|
+
|
|
155
|
+
def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]:
|
|
156
|
+
sample = appsink.try_pull_sample(20_000_000)
|
|
157
|
+
if sample is None:
|
|
158
|
+
return None
|
|
159
|
+
data = None
|
|
160
|
+
if isinstance(sample, Gst.Sample):
|
|
161
|
+
buf = sample.get_buffer()
|
|
162
|
+
if buf is None:
|
|
163
|
+
self.logger.warning("Buffer is None")
|
|
164
|
+
|
|
165
|
+
data = buf.extract_dup(0, buf.get_size())
|
|
166
|
+
return data
|
|
167
|
+
|
|
168
|
+
def read(self) -> Optional[npt.NDArray[np.uint8]]:
|
|
169
|
+
"""Read a frame from the camera. Returns the frame or None if error.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Optional[npt.NDArray[np.uint8]]: The captured BGR frame as a NumPy array, or None if error.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
data = self._get_sample(self._appsink_video)
|
|
176
|
+
if data is None:
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
arr = np.frombuffer(data, dtype=np.uint8).reshape(
|
|
180
|
+
(self.resolution[1], self.resolution[0], 3)
|
|
181
|
+
)
|
|
182
|
+
return arr
|
|
183
|
+
|
|
184
|
+
def close(self) -> None:
|
|
185
|
+
"""Release the camera resource."""
|
|
186
|
+
self._loop.quit()
|
|
187
|
+
self.pipeline.set_state(Gst.State.NULL)
|
|
188
|
+
|
|
189
|
+
def get_video_device(self) -> Tuple[str, Optional[CameraSpecs]]:
|
|
190
|
+
"""Use Gst.DeviceMonitor to find the unix camera path /dev/videoX.
|
|
191
|
+
|
|
192
|
+
Returns the device path (e.g., '/dev/video2'), or '' if not found.
|
|
193
|
+
"""
|
|
194
|
+
if os.path.exists("/tmp/reachymini_camera_socket"):
|
|
195
|
+
camera_specs = cast(CameraSpecs, ReachyMiniWirelessCamSpecs)
|
|
196
|
+
self.logger.debug(
|
|
197
|
+
"Found wireless camera socket at /tmp/reachymini_camera_socket"
|
|
198
|
+
)
|
|
199
|
+
return "/tmp/reachymini_camera_socket", camera_specs
|
|
200
|
+
|
|
201
|
+
monitor = Gst.DeviceMonitor()
|
|
202
|
+
monitor.add_filter("Video/Source")
|
|
203
|
+
monitor.start()
|
|
204
|
+
|
|
205
|
+
cam_names = ["Reachy", "Arducam_12MP", "imx708"]
|
|
206
|
+
|
|
207
|
+
devices = monitor.get_devices()
|
|
208
|
+
for cam_name in cam_names:
|
|
209
|
+
for device in devices:
|
|
210
|
+
name = device.get_display_name()
|
|
211
|
+
device_props = device.get_properties()
|
|
212
|
+
|
|
213
|
+
if cam_name in name:
|
|
214
|
+
if device_props and device_props.has_field("api.v4l2.path"):
|
|
215
|
+
device_path = device_props.get_string("api.v4l2.path")
|
|
216
|
+
camera_specs = (
|
|
217
|
+
cast(CameraSpecs, ArducamSpecs)
|
|
218
|
+
if cam_name == "Arducam_12MP"
|
|
219
|
+
else cast(CameraSpecs, ReachyMiniLiteCamSpecs)
|
|
220
|
+
)
|
|
221
|
+
self.logger.debug(f"Found {cam_name} camera at {device_path}")
|
|
222
|
+
monitor.stop()
|
|
223
|
+
return str(device_path), camera_specs
|
|
224
|
+
elif cam_name == "imx708":
|
|
225
|
+
camera_specs = cast(CameraSpecs, ReachyMiniWirelessCamSpecs)
|
|
226
|
+
self.logger.debug(f"Found {cam_name} camera")
|
|
227
|
+
monitor.stop()
|
|
228
|
+
return cam_name, camera_specs
|
|
229
|
+
monitor.stop()
|
|
230
|
+
self.logger.warning("No camera found.")
|
|
231
|
+
return "", None
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""OpenCv camera backend.
|
|
2
|
+
|
|
3
|
+
This module provides an implementation of the CameraBase class using OpenCV.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Optional, cast
|
|
7
|
+
|
|
8
|
+
import cv2
|
|
9
|
+
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
11
|
+
|
|
12
|
+
from reachy_mini.media.camera_constants import (
|
|
13
|
+
CameraResolution,
|
|
14
|
+
CameraSpecs,
|
|
15
|
+
MujocoCameraSpecs,
|
|
16
|
+
)
|
|
17
|
+
from reachy_mini.media.camera_utils import find_camera
|
|
18
|
+
|
|
19
|
+
from .camera_base import CameraBase
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OpenCVCamera(CameraBase):
|
|
23
|
+
"""Camera implementation using OpenCV."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
log_level: str = "INFO",
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize the OpenCV camera."""
|
|
30
|
+
super().__init__(log_level=log_level)
|
|
31
|
+
self.cap: Optional[cv2.VideoCapture] = None
|
|
32
|
+
|
|
33
|
+
def set_resolution(self, resolution: CameraResolution) -> None:
|
|
34
|
+
"""Set the camera resolution."""
|
|
35
|
+
super().set_resolution(resolution)
|
|
36
|
+
|
|
37
|
+
self._resolution = resolution
|
|
38
|
+
if self.cap is not None:
|
|
39
|
+
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._resolution.value[0])
|
|
40
|
+
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1])
|
|
41
|
+
|
|
42
|
+
def open(self, udp_camera: Optional[str] = None) -> None:
|
|
43
|
+
"""Open the camera using OpenCV VideoCapture."""
|
|
44
|
+
if udp_camera:
|
|
45
|
+
self.cap = cv2.VideoCapture(udp_camera)
|
|
46
|
+
self.camera_specs = cast(CameraSpecs, MujocoCameraSpecs)
|
|
47
|
+
self._resolution = self.camera_specs.default_resolution
|
|
48
|
+
else:
|
|
49
|
+
self.cap, self.camera_specs = find_camera()
|
|
50
|
+
if self.cap is None or self.camera_specs is None:
|
|
51
|
+
raise RuntimeError("Camera not found")
|
|
52
|
+
|
|
53
|
+
self._resolution = self.camera_specs.default_resolution
|
|
54
|
+
if self._resolution is None:
|
|
55
|
+
raise RuntimeError("Failed to get default camera resolution.")
|
|
56
|
+
|
|
57
|
+
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._resolution.value[0])
|
|
58
|
+
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1])
|
|
59
|
+
|
|
60
|
+
self.resized_K = self.camera_specs.K
|
|
61
|
+
|
|
62
|
+
if not self.cap.isOpened():
|
|
63
|
+
raise RuntimeError("Failed to open camera")
|
|
64
|
+
|
|
65
|
+
def read(self) -> Optional[npt.NDArray[np.uint8]]:
|
|
66
|
+
"""Read a frame from the camera.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The frame as a uint8 numpy array, or None if no frame could be read.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
RuntimeError: If the camera is not opened.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
if self.cap is None:
|
|
76
|
+
raise RuntimeError("Camera is not opened.")
|
|
77
|
+
ret, frame = self.cap.read()
|
|
78
|
+
if not ret:
|
|
79
|
+
return None
|
|
80
|
+
# Ensure uint8 dtype
|
|
81
|
+
if frame.dtype != np.uint8:
|
|
82
|
+
frame = frame.astype(np.uint8, copy=False)
|
|
83
|
+
return cast(npt.NDArray[np.uint8], frame)
|
|
84
|
+
|
|
85
|
+
def close(self) -> None:
|
|
86
|
+
"""Release the camera resource."""
|
|
87
|
+
if self.cap is not None:
|
|
88
|
+
self.cap.release()
|
|
89
|
+
self.cap = None
|