reachy-mini 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reachy-mini might be problematic. Click here for more details.
- reachy_mini/__init__.py +4 -0
- reachy_mini/apps/__init__.py +24 -0
- reachy_mini/apps/app.py +121 -0
- reachy_mini/apps/manager.py +183 -0
- reachy_mini/apps/sources/__init__.py +4 -0
- reachy_mini/apps/sources/hf_space.py +25 -0
- reachy_mini/apps/sources/local_common_venv.py +44 -0
- reachy_mini/apps/templates/README.md.j2 +1 -0
- reachy_mini/apps/templates/main.py.j2 +46 -0
- reachy_mini/apps/templates/pyproject.toml.j2 +18 -0
- reachy_mini/apps/utils.py +30 -0
- reachy_mini/assets/config/hardware_config.yaml +119 -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/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/js/3rdparty/gstwebrtc-api-2.0.0.min.js +5 -0
- reachy_mini/daemon/app/dashboard/static/js/apps.js +304 -0
- reachy_mini/daemon/app/dashboard/static/js/appstore.js +150 -0
- reachy_mini/daemon/app/dashboard/static/js/daemon.js +163 -0
- reachy_mini/daemon/app/dashboard/static/js/move_player.js +132 -0
- reachy_mini/daemon/app/dashboard/static/js/setup_wifi.js +94 -0
- reachy_mini/daemon/app/dashboard/static/js/update.js +80 -0
- reachy_mini/daemon/app/dashboard/static/style.css +83 -0
- reachy_mini/daemon/app/dashboard/templates/base.html +23 -0
- reachy_mini/daemon/app/dashboard/templates/index.html +17 -0
- reachy_mini/daemon/app/dashboard/templates/sections/apps.html +8 -0
- reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +29 -0
- reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +36 -0
- reachy_mini/daemon/app/dashboard/templates/sections/move_player.html +27 -0
- reachy_mini/daemon/app/dashboard/update.html +22 -0
- reachy_mini/daemon/app/dashboard/wifi_config.html +41 -0
- reachy_mini/daemon/app/dependencies.py +41 -0
- reachy_mini/daemon/app/main.py +262 -0
- reachy_mini/daemon/app/models.py +147 -0
- reachy_mini/daemon/app/routers/apps.py +114 -0
- reachy_mini/daemon/app/routers/daemon.py +80 -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 +257 -0
- reachy_mini/daemon/app/routers/state.py +146 -0
- reachy_mini/daemon/backend/__init__.py +1 -0
- reachy_mini/daemon/backend/abstract.py +750 -0
- reachy_mini/daemon/backend/mujoco/__init__.py +36 -0
- reachy_mini/daemon/backend/mujoco/backend.py +304 -0
- reachy_mini/daemon/backend/mujoco/utils.py +59 -0
- reachy_mini/daemon/backend/mujoco/video_udp.py +53 -0
- reachy_mini/daemon/backend/robot/__init__.py +8 -0
- reachy_mini/daemon/backend/robot/backend.py +535 -0
- reachy_mini/daemon/daemon.py +444 -0
- reachy_mini/daemon/utils.py +114 -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/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 +613 -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 +131 -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/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/io/__init__.py +1 -0
- reachy_mini/io/abstract.py +70 -0
- reachy_mini/io/protocol.py +44 -0
- reachy_mini/io/zenoh_client.py +258 -0
- reachy_mini/io/zenoh_server.py +183 -0
- reachy_mini/kinematics/__init__.py +68 -0
- reachy_mini/kinematics/analytical_kinematics.py +102 -0
- reachy_mini/kinematics/nn_kinematics.py +100 -0
- reachy_mini/kinematics/placo_kinematics.py +666 -0
- reachy_mini/media/__init__.py +1 -0
- reachy_mini/media/audio_base.py +163 -0
- reachy_mini/media/audio_gstreamer.py +195 -0
- reachy_mini/media/audio_sounddevice.py +226 -0
- reachy_mini/media/audio_utils.py +27 -0
- reachy_mini/media/camera_base.py +63 -0
- reachy_mini/media/camera_constants.py +13 -0
- reachy_mini/media/camera_gstreamer.py +162 -0
- reachy_mini/media/camera_opencv.py +61 -0
- reachy_mini/media/camera_utils.py +60 -0
- reachy_mini/media/media_manager.py +194 -0
- reachy_mini/motion/__init__.py +4 -0
- reachy_mini/motion/goto.py +71 -0
- reachy_mini/motion/move.py +36 -0
- reachy_mini/motion/recorded_move.py +132 -0
- reachy_mini/reachy_mini.py +705 -0
- reachy_mini/utils/__init__.py +46 -0
- reachy_mini/utils/constants.py +9 -0
- reachy_mini/utils/interpolation.py +227 -0
- reachy_mini/utils/parse_urdf_for_kinematics.py +110 -0
- reachy_mini/utils/rerun.py +546 -0
- reachy_mini-1.0.0.dist-info/METADATA +286 -0
- reachy_mini-1.0.0.dist-info/RECORD +385 -0
- reachy_mini-1.0.0.dist-info/WHEEL +5 -0
- reachy_mini-1.0.0.dist-info/entry_points.txt +3 -0
- reachy_mini-1.0.0.dist-info/licenses/LICENSE +201 -0
- reachy_mini-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
"""Daemon for Reachy Mini robot.
|
|
2
|
+
|
|
3
|
+
This module provides a daemon that runs a backend for either a simulated Reachy Mini using Mujoco or a real Reachy Mini robot using a serial connection.
|
|
4
|
+
It includes methods to start, stop, and restart the daemon, as well as to check its status.
|
|
5
|
+
It also provides a command-line interface for easy interaction.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import time
|
|
11
|
+
from dataclasses import asdict, dataclass
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from threading import Event, Thread
|
|
14
|
+
from typing import Any, Optional
|
|
15
|
+
|
|
16
|
+
from reachy_mini.daemon.backend.abstract import MotorControlMode
|
|
17
|
+
from reachy_mini.daemon.utils import (
|
|
18
|
+
convert_enum_to_dict,
|
|
19
|
+
find_serial_port,
|
|
20
|
+
get_ip_address,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from ..io.zenoh_server import ZenohServer
|
|
24
|
+
from .backend.mujoco import MujocoBackend, MujocoBackendStatus
|
|
25
|
+
from .backend.robot import RobotBackend, RobotBackendStatus
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Daemon:
|
|
29
|
+
"""Daemon for simulated or real Reachy Mini robot.
|
|
30
|
+
|
|
31
|
+
Runs the server with the appropriate backend (Mujoco for simulation or RobotBackend for real hardware).
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, log_level: str = "INFO", wireless_version: bool = False) -> None:
|
|
35
|
+
"""Initialize the Reachy Mini daemon."""
|
|
36
|
+
self.log_level = log_level
|
|
37
|
+
self.logger = logging.getLogger(__name__)
|
|
38
|
+
self.logger.setLevel(self.log_level)
|
|
39
|
+
|
|
40
|
+
self.wireless_version = wireless_version
|
|
41
|
+
|
|
42
|
+
self.backend: "RobotBackend | MujocoBackend | None" = None
|
|
43
|
+
self._status = DaemonStatus(
|
|
44
|
+
state=DaemonState.NOT_INITIALIZED,
|
|
45
|
+
wireless_version=wireless_version,
|
|
46
|
+
simulation_enabled=None,
|
|
47
|
+
backend_status=None,
|
|
48
|
+
error=None,
|
|
49
|
+
wlan_ip=None,
|
|
50
|
+
)
|
|
51
|
+
self._thread_event_publish_status = Event()
|
|
52
|
+
|
|
53
|
+
async def start(
|
|
54
|
+
self,
|
|
55
|
+
sim: bool = False,
|
|
56
|
+
serialport: str = "auto",
|
|
57
|
+
scene: str = "empty",
|
|
58
|
+
localhost_only: bool = True,
|
|
59
|
+
wake_up_on_start: bool = True,
|
|
60
|
+
check_collision: bool = False,
|
|
61
|
+
kinematics_engine: str = "AnalyticalKinematics",
|
|
62
|
+
headless: bool = False,
|
|
63
|
+
) -> "DaemonState":
|
|
64
|
+
"""Start the Reachy Mini daemon.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
sim (bool): If True, run in simulation mode using Mujoco. Defaults to False.
|
|
68
|
+
serialport (str): Serial port for real motors. Defaults to "auto", which will try to find the port automatically.
|
|
69
|
+
scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to "empty".
|
|
70
|
+
localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to True.
|
|
71
|
+
wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to True.
|
|
72
|
+
check_collision (bool): If True, enable collision checking. Defaults to False.
|
|
73
|
+
kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics".
|
|
74
|
+
headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to False.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
DaemonState: The current state of the daemon after attempting to start it.
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
if self._status.state == DaemonState.RUNNING:
|
|
81
|
+
self.logger.warning("Daemon is already running.")
|
|
82
|
+
return self._status.state
|
|
83
|
+
|
|
84
|
+
self._status.simulation_enabled = sim
|
|
85
|
+
|
|
86
|
+
if not localhost_only:
|
|
87
|
+
self._status.wlan_ip = get_ip_address()
|
|
88
|
+
|
|
89
|
+
self._start_params = {
|
|
90
|
+
"sim": sim,
|
|
91
|
+
"serialport": serialport,
|
|
92
|
+
"headless": headless,
|
|
93
|
+
"scene": scene,
|
|
94
|
+
"localhost_only": localhost_only,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
self.logger.info("Starting Reachy Mini daemon...")
|
|
98
|
+
self._status.state = DaemonState.STARTING
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
self.backend = self._setup_backend(
|
|
102
|
+
wireless_version=self.wireless_version,
|
|
103
|
+
sim=sim,
|
|
104
|
+
serialport=serialport,
|
|
105
|
+
scene=scene,
|
|
106
|
+
check_collision=check_collision,
|
|
107
|
+
kinematics_engine=kinematics_engine,
|
|
108
|
+
headless=headless,
|
|
109
|
+
)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
self._status.state = DaemonState.ERROR
|
|
112
|
+
self._status.error = str(e)
|
|
113
|
+
raise e
|
|
114
|
+
|
|
115
|
+
self.server = ZenohServer(self.backend, localhost_only=localhost_only)
|
|
116
|
+
self.server.start()
|
|
117
|
+
|
|
118
|
+
self._thread_publish_status = Thread(target=self._publish_status, daemon=True)
|
|
119
|
+
self._thread_publish_status.start()
|
|
120
|
+
|
|
121
|
+
def backend_wrapped_run() -> None:
|
|
122
|
+
assert self.backend is not None, (
|
|
123
|
+
"Backend should be initialized before running."
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
self.backend.wrapped_run()
|
|
128
|
+
except Exception as e:
|
|
129
|
+
self.logger.error(f"Backend encountered an error: {e}")
|
|
130
|
+
self._status.state = DaemonState.ERROR
|
|
131
|
+
self._status.error = str(e)
|
|
132
|
+
self.server.stop()
|
|
133
|
+
self.backend = None
|
|
134
|
+
|
|
135
|
+
self.backend_run_thread = Thread(target=backend_wrapped_run)
|
|
136
|
+
self.backend_run_thread.start()
|
|
137
|
+
|
|
138
|
+
if not self.backend.ready.wait(timeout=2.0):
|
|
139
|
+
self.logger.error(
|
|
140
|
+
"Backend is not ready after 2 seconds. Some error occurred."
|
|
141
|
+
)
|
|
142
|
+
self._status.state = DaemonState.ERROR
|
|
143
|
+
self._status.error = self.backend.error
|
|
144
|
+
return self._status.state
|
|
145
|
+
|
|
146
|
+
if wake_up_on_start:
|
|
147
|
+
try:
|
|
148
|
+
self.logger.info("Waking up Reachy Mini...")
|
|
149
|
+
self.backend.set_motor_control_mode(MotorControlMode.Enabled)
|
|
150
|
+
await self.backend.wake_up()
|
|
151
|
+
except Exception as e:
|
|
152
|
+
self.logger.error(f"Error while waking up Reachy Mini: {e}")
|
|
153
|
+
self._status.state = DaemonState.ERROR
|
|
154
|
+
self._status.error = str(e)
|
|
155
|
+
return self._status.state
|
|
156
|
+
except KeyboardInterrupt:
|
|
157
|
+
self.logger.warning("Wake up interrupted by user.")
|
|
158
|
+
self._status.state = DaemonState.STOPPING
|
|
159
|
+
return self._status.state
|
|
160
|
+
|
|
161
|
+
self.logger.info("Daemon started successfully.")
|
|
162
|
+
self._status.state = DaemonState.RUNNING
|
|
163
|
+
return self._status.state
|
|
164
|
+
|
|
165
|
+
async def stop(self, goto_sleep_on_stop: bool = True) -> "DaemonState":
|
|
166
|
+
"""Stop the Reachy Mini daemon.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to True.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
DaemonState: The current state of the daemon after attempting to stop it.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
if self._status.state == DaemonState.STOPPED:
|
|
176
|
+
self.logger.warning("Daemon is already stopped.")
|
|
177
|
+
return self._status.state
|
|
178
|
+
|
|
179
|
+
if self.backend is None:
|
|
180
|
+
self.logger.info("Daemon backend is not initialized.")
|
|
181
|
+
self._status.state = DaemonState.STOPPED
|
|
182
|
+
return self._status.state
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
if self._status.state in (DaemonState.STOPPING, DaemonState.ERROR):
|
|
186
|
+
goto_sleep_on_stop = False
|
|
187
|
+
|
|
188
|
+
self.logger.info("Stopping Reachy Mini daemon...")
|
|
189
|
+
self._status.state = DaemonState.STOPPING
|
|
190
|
+
self.backend.is_shutting_down = True
|
|
191
|
+
self._thread_event_publish_status.set()
|
|
192
|
+
self.server.stop()
|
|
193
|
+
|
|
194
|
+
if goto_sleep_on_stop:
|
|
195
|
+
try:
|
|
196
|
+
self.logger.info("Putting Reachy Mini to sleep...")
|
|
197
|
+
self.backend.set_motor_control_mode(MotorControlMode.Enabled)
|
|
198
|
+
await self.backend.goto_sleep()
|
|
199
|
+
self.backend.set_motor_control_mode(MotorControlMode.Disabled)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self.logger.error(f"Error while putting Reachy Mini to sleep: {e}")
|
|
202
|
+
self._status.state = DaemonState.ERROR
|
|
203
|
+
self._status.error = str(e)
|
|
204
|
+
except KeyboardInterrupt:
|
|
205
|
+
self.logger.warning("Sleep interrupted by user.")
|
|
206
|
+
self._status.state = DaemonState.STOPPING
|
|
207
|
+
|
|
208
|
+
self.backend.should_stop.set()
|
|
209
|
+
self.backend_run_thread.join(timeout=5.0)
|
|
210
|
+
if self.backend_run_thread.is_alive():
|
|
211
|
+
self.logger.warning("Backend did not stop in time, forcing shutdown.")
|
|
212
|
+
self._status.state = DaemonState.ERROR
|
|
213
|
+
|
|
214
|
+
self.backend.close()
|
|
215
|
+
self.backend.ready.clear()
|
|
216
|
+
|
|
217
|
+
if self._status.state != DaemonState.ERROR:
|
|
218
|
+
self.logger.info("Daemon stopped successfully.")
|
|
219
|
+
self._status.state = DaemonState.STOPPED
|
|
220
|
+
except Exception as e:
|
|
221
|
+
self.logger.error(f"Error while stopping the daemon: {e}")
|
|
222
|
+
self._status.state = DaemonState.ERROR
|
|
223
|
+
self._status.error = str(e)
|
|
224
|
+
except KeyboardInterrupt:
|
|
225
|
+
self.logger.warning("Daemon already stopping...")
|
|
226
|
+
|
|
227
|
+
if self.backend is not None:
|
|
228
|
+
backend_status = self.backend.get_status()
|
|
229
|
+
if backend_status.error:
|
|
230
|
+
self._status.state = DaemonState.ERROR
|
|
231
|
+
|
|
232
|
+
self.backend = None
|
|
233
|
+
|
|
234
|
+
return self._status.state
|
|
235
|
+
|
|
236
|
+
async def restart(
|
|
237
|
+
self,
|
|
238
|
+
sim: Optional[bool] = None,
|
|
239
|
+
serialport: Optional[str] = None,
|
|
240
|
+
scene: Optional[str] = None,
|
|
241
|
+
headless: Optional[bool] = None,
|
|
242
|
+
localhost_only: Optional[bool] = None,
|
|
243
|
+
wake_up_on_start: Optional[bool] = None,
|
|
244
|
+
goto_sleep_on_stop: Optional[bool] = None,
|
|
245
|
+
) -> "DaemonState":
|
|
246
|
+
"""Restart the Reachy Mini daemon.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
sim (bool): If True, run in simulation mode using Mujoco. Defaults to None (uses the previous value).
|
|
250
|
+
serialport (str): Serial port for real motors. Defaults to None (uses the previous value).
|
|
251
|
+
scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to None (uses the previous value).
|
|
252
|
+
headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to None (uses the previous value).
|
|
253
|
+
localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to None (uses the previous value).
|
|
254
|
+
wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to None (don't wake up).
|
|
255
|
+
goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to None (don't go to sleep).
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
DaemonState: The current state of the daemon after attempting to restart it.
|
|
259
|
+
|
|
260
|
+
"""
|
|
261
|
+
if self._status.state == DaemonState.STOPPED:
|
|
262
|
+
self.logger.warning("Daemon is not running.")
|
|
263
|
+
return self._status.state
|
|
264
|
+
|
|
265
|
+
if self._status.state in (DaemonState.RUNNING, DaemonState.ERROR):
|
|
266
|
+
self.logger.info("Restarting Reachy Mini daemon...")
|
|
267
|
+
|
|
268
|
+
await self.stop(
|
|
269
|
+
goto_sleep_on_stop=goto_sleep_on_stop
|
|
270
|
+
if goto_sleep_on_stop is not None
|
|
271
|
+
else False
|
|
272
|
+
)
|
|
273
|
+
params: dict[str, Any] = {
|
|
274
|
+
"sim": sim if sim is not None else self._start_params["sim"],
|
|
275
|
+
"serialport": serialport
|
|
276
|
+
if serialport is not None
|
|
277
|
+
else self._start_params["serialport"],
|
|
278
|
+
"scene": scene if scene is not None else self._start_params["scene"],
|
|
279
|
+
"headless": headless
|
|
280
|
+
if headless is not None
|
|
281
|
+
else self._start_params["headless"],
|
|
282
|
+
"localhost_only": localhost_only
|
|
283
|
+
if localhost_only is not None
|
|
284
|
+
else self._start_params["localhost_only"],
|
|
285
|
+
"wake_up_on_start": wake_up_on_start
|
|
286
|
+
if wake_up_on_start is not None
|
|
287
|
+
else False,
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return await self.start(**params)
|
|
291
|
+
|
|
292
|
+
raise NotImplementedError(
|
|
293
|
+
"Restarting is only supported when the daemon is in RUNNING or ERROR state."
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
def status(self) -> "DaemonStatus":
|
|
297
|
+
"""Get the current status of the Reachy Mini daemon."""
|
|
298
|
+
if self.backend is not None:
|
|
299
|
+
self._status.backend_status = self.backend.get_status()
|
|
300
|
+
|
|
301
|
+
assert self._status.backend_status is not None, (
|
|
302
|
+
"Backend status should not be None after backend initialization."
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if self._status.backend_status.error:
|
|
306
|
+
self._status.state = DaemonState.ERROR
|
|
307
|
+
self._status.error = self._status.backend_status.error
|
|
308
|
+
else:
|
|
309
|
+
self._status.backend_status = None
|
|
310
|
+
|
|
311
|
+
return self._status
|
|
312
|
+
|
|
313
|
+
def _publish_status(self) -> None:
|
|
314
|
+
self._thread_event_publish_status.clear()
|
|
315
|
+
while self._thread_event_publish_status.is_set() is False:
|
|
316
|
+
json_str = json.dumps(
|
|
317
|
+
asdict(self.status(), dict_factory=convert_enum_to_dict)
|
|
318
|
+
)
|
|
319
|
+
self.server.pub_status.put(json_str)
|
|
320
|
+
time.sleep(1)
|
|
321
|
+
|
|
322
|
+
async def run4ever(
|
|
323
|
+
self,
|
|
324
|
+
sim: bool = False,
|
|
325
|
+
serialport: str = "auto",
|
|
326
|
+
scene: str = "empty",
|
|
327
|
+
localhost_only: bool = True,
|
|
328
|
+
wake_up_on_start: bool = True,
|
|
329
|
+
goto_sleep_on_stop: bool = True,
|
|
330
|
+
check_collision: bool = False,
|
|
331
|
+
kinematics_engine: str = "AnalyticalKinematics",
|
|
332
|
+
headless: bool = False,
|
|
333
|
+
) -> None:
|
|
334
|
+
"""Run the Reachy Mini daemon indefinitely.
|
|
335
|
+
|
|
336
|
+
First, it starts the daemon, then it keeps checking the status and allows for graceful shutdown on user interrupt (Ctrl+C).
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
sim (bool): If True, run in simulation mode using Mujoco. Defaults to False.
|
|
340
|
+
serialport (str): Serial port for real motors. Defaults to "auto", which will try to find the port automatically.
|
|
341
|
+
scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to "empty".
|
|
342
|
+
localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to True.
|
|
343
|
+
wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to True.
|
|
344
|
+
goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to True
|
|
345
|
+
check_collision (bool): If True, enable collision checking. Defaults to False.
|
|
346
|
+
kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics".
|
|
347
|
+
headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to False.
|
|
348
|
+
|
|
349
|
+
"""
|
|
350
|
+
await self.start(
|
|
351
|
+
sim=sim,
|
|
352
|
+
serialport=serialport,
|
|
353
|
+
scene=scene,
|
|
354
|
+
localhost_only=localhost_only,
|
|
355
|
+
wake_up_on_start=wake_up_on_start,
|
|
356
|
+
check_collision=check_collision,
|
|
357
|
+
kinematics_engine=kinematics_engine,
|
|
358
|
+
headless=headless,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if self._status.state == DaemonState.RUNNING:
|
|
362
|
+
try:
|
|
363
|
+
self.logger.info("Daemon is running. Press Ctrl+C to stop.")
|
|
364
|
+
while self.backend_run_thread.is_alive():
|
|
365
|
+
self.logger.info(f"Daemon status: {self.status()}")
|
|
366
|
+
for _ in range(10):
|
|
367
|
+
self.backend_run_thread.join(timeout=1.0)
|
|
368
|
+
else:
|
|
369
|
+
self.logger.error("Backend thread has stopped unexpectedly.")
|
|
370
|
+
self._status.state = DaemonState.ERROR
|
|
371
|
+
except KeyboardInterrupt:
|
|
372
|
+
self.logger.warning("Daemon interrupted by user.")
|
|
373
|
+
except Exception as e:
|
|
374
|
+
self.logger.error(f"An error occurred: {e}")
|
|
375
|
+
self._status.state = DaemonState.ERROR
|
|
376
|
+
self._status.error = str(e)
|
|
377
|
+
|
|
378
|
+
await self.stop(goto_sleep_on_stop)
|
|
379
|
+
|
|
380
|
+
def _setup_backend(
|
|
381
|
+
self,
|
|
382
|
+
wireless_version: bool,
|
|
383
|
+
sim: bool,
|
|
384
|
+
serialport: str,
|
|
385
|
+
scene: str,
|
|
386
|
+
check_collision: bool,
|
|
387
|
+
kinematics_engine: str,
|
|
388
|
+
headless: bool,
|
|
389
|
+
) -> "RobotBackend | MujocoBackend":
|
|
390
|
+
if sim:
|
|
391
|
+
return MujocoBackend(
|
|
392
|
+
scene=scene,
|
|
393
|
+
check_collision=check_collision,
|
|
394
|
+
kinematics_engine=kinematics_engine,
|
|
395
|
+
headless=headless,
|
|
396
|
+
)
|
|
397
|
+
else:
|
|
398
|
+
if serialport == "auto":
|
|
399
|
+
ports = find_serial_port(wireless_version=wireless_version)
|
|
400
|
+
|
|
401
|
+
if len(ports) == 0:
|
|
402
|
+
raise RuntimeError(
|
|
403
|
+
"No Reachy Mini serial port found. "
|
|
404
|
+
"Check USB connection and permissions. "
|
|
405
|
+
"Or directly specify the serial port using --serialport."
|
|
406
|
+
)
|
|
407
|
+
elif len(ports) > 1:
|
|
408
|
+
raise RuntimeError(
|
|
409
|
+
f"Multiple Reachy Mini serial ports found {ports}."
|
|
410
|
+
"Please specify the serial port using --serialport."
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
serialport = ports[0]
|
|
414
|
+
self.logger.info(f"Found Reachy Mini serial port: {serialport}")
|
|
415
|
+
|
|
416
|
+
return RobotBackend(
|
|
417
|
+
serialport=serialport,
|
|
418
|
+
log_level=self.log_level,
|
|
419
|
+
check_collision=check_collision,
|
|
420
|
+
kinematics_engine=kinematics_engine,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class DaemonState(Enum):
|
|
425
|
+
"""Enum representing the state of the Reachy Mini daemon."""
|
|
426
|
+
|
|
427
|
+
NOT_INITIALIZED = "not_initialized"
|
|
428
|
+
STARTING = "starting"
|
|
429
|
+
RUNNING = "running"
|
|
430
|
+
STOPPING = "stopping"
|
|
431
|
+
STOPPED = "stopped"
|
|
432
|
+
ERROR = "error"
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass
|
|
436
|
+
class DaemonStatus:
|
|
437
|
+
"""Dataclass representing the status of the Reachy Mini daemon."""
|
|
438
|
+
|
|
439
|
+
state: DaemonState
|
|
440
|
+
wireless_version: bool
|
|
441
|
+
simulation_enabled: Optional[bool]
|
|
442
|
+
backend_status: Optional[RobotBackendStatus | MujocoBackendStatus]
|
|
443
|
+
error: Optional[str] = None
|
|
444
|
+
wlan_ip: Optional[str] = None
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Utilities for managing the Reachy Mini daemon."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import socket
|
|
5
|
+
import struct
|
|
6
|
+
import subprocess
|
|
7
|
+
import time
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, List
|
|
10
|
+
|
|
11
|
+
import psutil
|
|
12
|
+
import serial.tools.list_ports
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def daemon_check(spawn_daemon: bool, use_sim: bool) -> None:
|
|
16
|
+
"""Check if the Reachy Mini daemon is running and spawn it if necessary."""
|
|
17
|
+
|
|
18
|
+
def is_python_script_running(
|
|
19
|
+
script_name: str,
|
|
20
|
+
) -> tuple[bool, int | None, bool | None]:
|
|
21
|
+
"""Check if a specific Python script is running."""
|
|
22
|
+
found_script = False
|
|
23
|
+
simluation_enabled = False
|
|
24
|
+
for proc in psutil.process_iter(["pid", "name", "cmdline"]):
|
|
25
|
+
try:
|
|
26
|
+
for cmd in proc.info["cmdline"]:
|
|
27
|
+
if script_name in cmd:
|
|
28
|
+
found_script = True
|
|
29
|
+
if "--sim" in cmd:
|
|
30
|
+
simluation_enabled = True
|
|
31
|
+
if found_script:
|
|
32
|
+
return True, proc.pid, simluation_enabled
|
|
33
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
34
|
+
continue
|
|
35
|
+
return False, None, None
|
|
36
|
+
|
|
37
|
+
if spawn_daemon:
|
|
38
|
+
daemon_is_running, pid, sim = is_python_script_running("reachy-mini-daemon")
|
|
39
|
+
if daemon_is_running and sim == use_sim:
|
|
40
|
+
print(
|
|
41
|
+
f"Reachy Mini daemon is already running (PID: {pid}). "
|
|
42
|
+
"No need to spawn a new one."
|
|
43
|
+
)
|
|
44
|
+
return
|
|
45
|
+
elif daemon_is_running and sim != use_sim:
|
|
46
|
+
print(
|
|
47
|
+
f"Reachy Mini daemon is already running (PID: {pid}) with a different configuration. "
|
|
48
|
+
)
|
|
49
|
+
print("Killing the existing daemon...")
|
|
50
|
+
assert pid is not None, "PID should not be None if daemon is running"
|
|
51
|
+
os.kill(pid, 9)
|
|
52
|
+
time.sleep(1)
|
|
53
|
+
|
|
54
|
+
print("Starting a new daemon...")
|
|
55
|
+
subprocess.Popen(
|
|
56
|
+
["reachy-mini-daemon", "--sim"] if use_sim else ["reachy-mini-daemon"],
|
|
57
|
+
start_new_session=True,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def find_serial_port(
|
|
62
|
+
wireless_version: bool = False,
|
|
63
|
+
vid: str = "1a86",
|
|
64
|
+
pid: str = "55d3",
|
|
65
|
+
pi_uart: str = "/dev/ttyAMA3",
|
|
66
|
+
) -> list[str]:
|
|
67
|
+
"""Find the serial port for Reachy Mini based on VID and PID or the Raspberry Pi UART for the wireless version.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
wireless_version (bool): Whether to look for the wireless version using the Raspberry Pi UART.
|
|
71
|
+
vid (str): Vendor ID of the device. (eg. "1a86").
|
|
72
|
+
pid (str): Product ID of the device. (eg. "55d3").
|
|
73
|
+
pi_uart (str): Path to the Raspberry Pi UART device. (eg. "/dev/ttyAMA3").
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
# If it's a wireless version, we should use the Raspberry Pi UART
|
|
77
|
+
if wireless_version:
|
|
78
|
+
return [pi_uart] if os.path.exists(pi_uart) else []
|
|
79
|
+
|
|
80
|
+
# If it's a lite version, we should find it using the VID and PID
|
|
81
|
+
ports = serial.tools.list_ports.comports()
|
|
82
|
+
|
|
83
|
+
vid = vid.upper()
|
|
84
|
+
pid = pid.upper()
|
|
85
|
+
|
|
86
|
+
return [p.device for p in ports if f"USB VID:PID={vid}:{pid}" in p.hwid]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_ip_address(ifname: str = "wlan0") -> str | None:
|
|
90
|
+
"""Get the IP address of a specific network interface (Linux Only)."""
|
|
91
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
92
|
+
try:
|
|
93
|
+
import fcntl
|
|
94
|
+
return socket.inet_ntoa(
|
|
95
|
+
fcntl.ioctl(
|
|
96
|
+
s.fileno(),
|
|
97
|
+
0x8915, # SIOCGIFADDR
|
|
98
|
+
struct.pack("256s", ifname[:15].encode("utf-8")),
|
|
99
|
+
)[20:24]
|
|
100
|
+
)
|
|
101
|
+
except OSError:
|
|
102
|
+
print(f"Could not get IP address for interface {ifname}.")
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def convert_enum_to_dict(data: List[Any]) -> dict[str, Any]:
|
|
107
|
+
"""Convert a dataclass containing Enums to a dictionary with enum values."""
|
|
108
|
+
|
|
109
|
+
def convert_value(obj: Any) -> Any:
|
|
110
|
+
if isinstance(obj, Enum):
|
|
111
|
+
return obj.value
|
|
112
|
+
return obj
|
|
113
|
+
|
|
114
|
+
return dict((k, convert_value(v)) for k, v in data)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "48f0e86376312f8ca242a082",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MUIOPFRAXdyRYA5/y",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "5W_SPEAKER <1>",
|
|
10
|
+
"partId": "JFD",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "d5df0bcac25cddb763b3a090",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MT+KnYpqaZ58+3raS",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "antenna <2>",
|
|
10
|
+
"partId": "JFD",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "41e19b342cf83e0d866fde9b",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "M6OWFp5hfkfES9FmB",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "Antenna_body_3DPrint <2>",
|
|
10
|
+
"partId": "JF/",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "41e19b342cf83e0d866fde9b",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MHVB1f7lyvjCWrFJe",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "Antenna_Holder-L_3DPrint <1>",
|
|
10
|
+
"partId": "KFDB",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "41e19b342cf83e0d866fde9b",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MX6Uc6wQ4cFgySRks",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "Antenna_Holder-R_3DPrint <1>",
|
|
10
|
+
"partId": "JFv",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "41e19b342cf83e0d866fde9b",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MObKCzX1Fco0wvr0/",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "Antenna_interface_3DPrint <2>",
|
|
10
|
+
"partId": "JF7",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configuration": "default",
|
|
3
|
+
"documentId": "7836ed39be931c6ece17e007",
|
|
4
|
+
"documentMicroversion": "ac3fd0c16468a1e3078617de",
|
|
5
|
+
"elementId": "ae2c63bc6f578a46d35cd365",
|
|
6
|
+
"fullConfiguration": "default",
|
|
7
|
+
"id": "MDupaBfND/yK9FERm",
|
|
8
|
+
"isStandardContent": false,
|
|
9
|
+
"name": "Arducam <1>",
|
|
10
|
+
"partId": "JGD",
|
|
11
|
+
"suppressed": false,
|
|
12
|
+
"type": "Part"
|
|
13
|
+
}
|
|
Binary file
|