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,535 @@
|
|
|
1
|
+
"""Robot Backend for Reachy Mini.
|
|
2
|
+
|
|
3
|
+
This module provides the `RobotBackend` class, which interfaces with the Reachy Mini motor controller to control the robot's movements and manage its status.
|
|
4
|
+
It handles the control loop, joint positions, torque enabling/disabling, and provides a status report of the robot's backend.
|
|
5
|
+
It uses the `ReachyMiniMotorController` to communicate with the robot's motors.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import time
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from datetime import timedelta
|
|
13
|
+
from multiprocessing import Event # It seems to be more accurate than threading.Event
|
|
14
|
+
from typing import Annotated, Any
|
|
15
|
+
|
|
16
|
+
import log_throttling
|
|
17
|
+
import numpy as np
|
|
18
|
+
import numpy.typing as npt
|
|
19
|
+
from reachy_mini_motor_controller import ReachyMiniPyControlLoop
|
|
20
|
+
|
|
21
|
+
from ..abstract import Backend, MotorControlMode
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RobotBackend(Backend):
|
|
25
|
+
"""Real robot backend for Reachy Mini."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
serialport: str,
|
|
30
|
+
log_level: str = "INFO",
|
|
31
|
+
check_collision: bool = False,
|
|
32
|
+
kinematics_engine: str = "AnalyticalKinematics",
|
|
33
|
+
hardware_error_check_frequency: float = 1.0,
|
|
34
|
+
):
|
|
35
|
+
"""Initialize the RobotBackend.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
serialport (str): The serial port to which the Reachy Mini is connected.
|
|
39
|
+
log_level (str): The logging level for the backend. Default is "INFO".
|
|
40
|
+
check_collision (bool): If True, enable collision checking. Default is False.
|
|
41
|
+
kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics".
|
|
42
|
+
hardware_error_check_frequency (float): Frequency in seconds to check for hardware errors. Default is 1.0.
|
|
43
|
+
|
|
44
|
+
Tries to connect to the Reachy Mini motor controller and initializes the control loop.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(
|
|
48
|
+
check_collision=check_collision, kinematics_engine=kinematics_engine
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
self.logger = logging.getLogger(__name__)
|
|
52
|
+
self.logger.setLevel(log_level)
|
|
53
|
+
|
|
54
|
+
self.control_loop_frequency = 50.0 # Hz
|
|
55
|
+
self.c: ReachyMiniPyControlLoop | None = ReachyMiniPyControlLoop(
|
|
56
|
+
serialport,
|
|
57
|
+
read_position_loop_period=timedelta(
|
|
58
|
+
seconds=1.0 / self.control_loop_frequency
|
|
59
|
+
),
|
|
60
|
+
allowed_retries=5,
|
|
61
|
+
stats_pub_period=None,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self.motor_control_mode = self._infer_control_mode()
|
|
65
|
+
self._torque_enabled = self.motor_control_mode != MotorControlMode.Disabled
|
|
66
|
+
self.logger.info(f"Motor control mode: {self.motor_control_mode}")
|
|
67
|
+
self.last_alive: float | None = None
|
|
68
|
+
|
|
69
|
+
self._status = RobotBackendStatus(
|
|
70
|
+
motor_control_mode=self.motor_control_mode,
|
|
71
|
+
ready=False,
|
|
72
|
+
last_alive=None,
|
|
73
|
+
control_loop_stats={},
|
|
74
|
+
)
|
|
75
|
+
self._stats_record_period = 1.0 # seconds
|
|
76
|
+
self._stats: dict[str, Any] = {
|
|
77
|
+
"timestamps": [],
|
|
78
|
+
"nb_error": 0,
|
|
79
|
+
"record_period": self._stats_record_period,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
self._current_head_operation_mode = -1 # Default to torque control mode
|
|
83
|
+
self._current_antennas_operation_mode = -1 # Default to torque control mode
|
|
84
|
+
self.target_antenna_joint_current = None # Placeholder for antenna joint torque
|
|
85
|
+
self.target_head_joint_current = None # Placeholder for head joint torque
|
|
86
|
+
|
|
87
|
+
self.hardware_error_check_frequency = hardware_error_check_frequency # seconds
|
|
88
|
+
|
|
89
|
+
def run(self) -> None:
|
|
90
|
+
"""Run the control loop for the robot backend.
|
|
91
|
+
|
|
92
|
+
This method continuously updates the motor controller at a specified frequency.
|
|
93
|
+
It reads the joint positions, updates the motor controller, and publishes the joint positions.
|
|
94
|
+
It also handles errors and retries if the motor controller is not responding.
|
|
95
|
+
"""
|
|
96
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
97
|
+
|
|
98
|
+
period = 1.0 / self.control_loop_frequency # Control loop period in seconds
|
|
99
|
+
|
|
100
|
+
self.retries = 5
|
|
101
|
+
self.stats_record_t0 = time.time()
|
|
102
|
+
|
|
103
|
+
self.last_hardware_error_check_time = time.time()
|
|
104
|
+
|
|
105
|
+
next_call_event = Event()
|
|
106
|
+
|
|
107
|
+
# Compute the forward kinematics to get the initial head pose
|
|
108
|
+
# IMPORTANT for wake_up
|
|
109
|
+
head_positions, _ = self.get_all_joint_positions()
|
|
110
|
+
# make sure to converge fully (a lot of iterations)
|
|
111
|
+
self.current_head_pose = self.head_kinematics.fk(
|
|
112
|
+
np.array(head_positions),
|
|
113
|
+
no_iterations=20,
|
|
114
|
+
)
|
|
115
|
+
assert self.current_head_pose is not None
|
|
116
|
+
|
|
117
|
+
self.head_kinematics.ik(self.current_head_pose, no_iterations=20)
|
|
118
|
+
|
|
119
|
+
while not self.should_stop.is_set():
|
|
120
|
+
start_t = time.time()
|
|
121
|
+
self._stats["timestamps"].append(time.time())
|
|
122
|
+
self._update()
|
|
123
|
+
took = time.time() - start_t
|
|
124
|
+
|
|
125
|
+
sleep_time = period - took
|
|
126
|
+
if sleep_time < 0:
|
|
127
|
+
self.logger.debug(
|
|
128
|
+
f"Control loop took too long: {took * 1000:.3f} ms, expected {period * 1000:.3f} ms"
|
|
129
|
+
)
|
|
130
|
+
sleep_time = 0.001
|
|
131
|
+
|
|
132
|
+
next_call_event.clear()
|
|
133
|
+
next_call_event.wait(sleep_time)
|
|
134
|
+
|
|
135
|
+
def _update(self) -> None:
|
|
136
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
137
|
+
|
|
138
|
+
if self._torque_enabled:
|
|
139
|
+
if self._current_head_operation_mode != 0: # if position control mode
|
|
140
|
+
if self.target_head_joint_positions is not None:
|
|
141
|
+
self.c.set_stewart_platform_position(
|
|
142
|
+
self.target_head_joint_positions[1:].tolist()
|
|
143
|
+
)
|
|
144
|
+
self.c.set_body_rotation(self.target_head_joint_positions[0])
|
|
145
|
+
else: # it's in torque control mode
|
|
146
|
+
if self.gravity_compensation_mode:
|
|
147
|
+
# This function will set the head_joint_current
|
|
148
|
+
# to the current necessary to compensate for gravity
|
|
149
|
+
self.compensate_head_gravity()
|
|
150
|
+
if self.target_head_joint_current is not None:
|
|
151
|
+
self.c.set_stewart_platform_goal_current(
|
|
152
|
+
np.round(self.target_head_joint_current[1:], 0)
|
|
153
|
+
.astype(int)
|
|
154
|
+
.tolist()
|
|
155
|
+
)
|
|
156
|
+
# Body rotation torque control is not supported with feetech motors
|
|
157
|
+
# self.c.set_body_rotation_goal_current(int(self.target_head_joint_current[0]))
|
|
158
|
+
|
|
159
|
+
if self._current_antennas_operation_mode != 0: # if position control mode
|
|
160
|
+
if self.target_antenna_joint_positions is not None:
|
|
161
|
+
self.c.set_antennas_positions(
|
|
162
|
+
self.target_antenna_joint_positions.tolist()
|
|
163
|
+
)
|
|
164
|
+
# Antenna torque control is not supported with feetech motors
|
|
165
|
+
# else:
|
|
166
|
+
# if self.target_antenna_joint_current is not None:
|
|
167
|
+
# self.c.set_antennas_goal_current(
|
|
168
|
+
# np.round(self.target_antenna_joint_current, 0).astype(int).tolist()
|
|
169
|
+
# )
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
self.joint_positions_publisher is not None
|
|
173
|
+
and self.pose_publisher is not None
|
|
174
|
+
):
|
|
175
|
+
try:
|
|
176
|
+
head_positions, antenna_positions = self.get_all_joint_positions()
|
|
177
|
+
|
|
178
|
+
# Update the head kinematics model with the current head positions
|
|
179
|
+
self.update_head_kinematics_model(
|
|
180
|
+
np.array(head_positions),
|
|
181
|
+
np.array(antenna_positions),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Update the target head joint positions from IK if necessary
|
|
185
|
+
# - does nothing if the targets did not change
|
|
186
|
+
if self.ik_required:
|
|
187
|
+
try:
|
|
188
|
+
self.update_target_head_joints_from_ik(
|
|
189
|
+
self.target_head_pose, self.target_body_yaw
|
|
190
|
+
)
|
|
191
|
+
except ValueError as e:
|
|
192
|
+
log_throttling.by_time(self.logger, interval=0.5).warning(
|
|
193
|
+
f"IK error: {e}"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if not self.is_shutting_down:
|
|
197
|
+
self.joint_positions_publisher.put(
|
|
198
|
+
json.dumps(
|
|
199
|
+
{
|
|
200
|
+
"head_joint_positions": head_positions,
|
|
201
|
+
"antennas_joint_positions": antenna_positions,
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
self.pose_publisher.put(
|
|
206
|
+
json.dumps(
|
|
207
|
+
{
|
|
208
|
+
"head_pose": self.get_present_head_pose().tolist(),
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
self.last_alive = time.time()
|
|
214
|
+
|
|
215
|
+
self.ready.set() # Mark the backend as ready
|
|
216
|
+
except RuntimeError as e:
|
|
217
|
+
self._stats["nb_error"] += 1
|
|
218
|
+
# self.logger.warning(f"Error reading positions: {e}")
|
|
219
|
+
|
|
220
|
+
assert self.last_alive is not None
|
|
221
|
+
|
|
222
|
+
if self.last_alive + 1 < time.time():
|
|
223
|
+
self.error = (
|
|
224
|
+
"No response from the robot's motor for the last second."
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
self.logger.error(
|
|
228
|
+
"No response from the robot for the last second, stopping."
|
|
229
|
+
)
|
|
230
|
+
raise e
|
|
231
|
+
|
|
232
|
+
if time.time() - self.stats_record_t0 > self._stats_record_period:
|
|
233
|
+
dt = np.diff(self._stats["timestamps"])
|
|
234
|
+
if len(dt) > 1:
|
|
235
|
+
self._status.control_loop_stats["mean_control_loop_frequency"] = (
|
|
236
|
+
float(np.mean(1.0 / dt))
|
|
237
|
+
)
|
|
238
|
+
self._status.control_loop_stats["max_control_loop_interval"] = (
|
|
239
|
+
float(np.max(dt))
|
|
240
|
+
)
|
|
241
|
+
self._status.control_loop_stats["nb_error"] = self._stats[
|
|
242
|
+
"nb_error"
|
|
243
|
+
]
|
|
244
|
+
|
|
245
|
+
self._stats["timestamps"].clear()
|
|
246
|
+
self._stats["nb_error"] = 0
|
|
247
|
+
self.stats_record_t0 = time.time()
|
|
248
|
+
|
|
249
|
+
if (
|
|
250
|
+
time.time() - self.last_hardware_error_check_time
|
|
251
|
+
> self.hardware_error_check_frequency
|
|
252
|
+
):
|
|
253
|
+
hardware_errors = self.read_hardware_errors()
|
|
254
|
+
if hardware_errors:
|
|
255
|
+
for motor_name, errors in hardware_errors.items():
|
|
256
|
+
self.logger.error(
|
|
257
|
+
f"Motor '{motor_name}' hardware errors: {errors}"
|
|
258
|
+
)
|
|
259
|
+
self.last_hardware_error_check_time = time.time()
|
|
260
|
+
|
|
261
|
+
def close(self) -> None:
|
|
262
|
+
"""Close the motor controller connection."""
|
|
263
|
+
if self.c is not None:
|
|
264
|
+
self.c.close()
|
|
265
|
+
self.c = None
|
|
266
|
+
|
|
267
|
+
def get_status(self) -> "RobotBackendStatus":
|
|
268
|
+
"""Get the current status of the robot backend."""
|
|
269
|
+
self._status.error = self.error
|
|
270
|
+
self._status.motor_control_mode = self.motor_control_mode
|
|
271
|
+
return self._status
|
|
272
|
+
|
|
273
|
+
def enable_motors(self) -> None:
|
|
274
|
+
"""Enable the motors by turning the torque on."""
|
|
275
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
276
|
+
|
|
277
|
+
self.c.enable_torque()
|
|
278
|
+
self._torque_enabled = True
|
|
279
|
+
|
|
280
|
+
def disable_motors(self) -> None:
|
|
281
|
+
"""Disable the motors by turning the torque off."""
|
|
282
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
283
|
+
|
|
284
|
+
self.c.disable_torque()
|
|
285
|
+
self._torque_enabled = False
|
|
286
|
+
|
|
287
|
+
def set_head_operation_mode(self, mode: int) -> None:
|
|
288
|
+
"""Change the operation mode of the head motors.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
mode (int): The operation mode for the head motors.
|
|
292
|
+
|
|
293
|
+
The operation modes can be:
|
|
294
|
+
0: torque control
|
|
295
|
+
3: position control
|
|
296
|
+
5: current-based position control.
|
|
297
|
+
|
|
298
|
+
Important:
|
|
299
|
+
This method does not work well with the current feetech motors (body rotation), as they do not support torque control.
|
|
300
|
+
So the method disables the antennas when in torque control mode.
|
|
301
|
+
The dynamixel motors used for the head do support torque control, so this method works as expected.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
mode (int): The operation mode for the head motors.
|
|
305
|
+
This could be a specific mode like position control, velocity control, or torque control.
|
|
306
|
+
|
|
307
|
+
"""
|
|
308
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
309
|
+
assert mode in [0, 3, 5], (
|
|
310
|
+
"Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]."
|
|
311
|
+
f" Got {mode} instead"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# if motors are enabled, disable them before changing the mode
|
|
315
|
+
if self._torque_enabled:
|
|
316
|
+
self.c.enable_stewart_platform(False)
|
|
317
|
+
# set the new operation mode
|
|
318
|
+
self.c.set_stewart_platform_operating_mode(mode)
|
|
319
|
+
|
|
320
|
+
if mode != 0:
|
|
321
|
+
# if the mode is not torque control, we need to set the head joint positions
|
|
322
|
+
# to the current positions to avoid sudden movements
|
|
323
|
+
motor_pos = self.c.get_last_position()
|
|
324
|
+
self.target_head_joint_positions = np.array(
|
|
325
|
+
[motor_pos.body_yaw] + motor_pos.stewart
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
self.c.set_stewart_platform_position(
|
|
329
|
+
self.target_head_joint_positions[1:].tolist()
|
|
330
|
+
)
|
|
331
|
+
self.c.set_body_rotation(self.target_head_joint_positions[0])
|
|
332
|
+
self.c.enable_body_rotation(True)
|
|
333
|
+
self.c.set_body_rotation_operating_mode(0)
|
|
334
|
+
else:
|
|
335
|
+
self.c.enable_body_rotation(False)
|
|
336
|
+
|
|
337
|
+
if self._torque_enabled:
|
|
338
|
+
self.c.enable_stewart_platform(True)
|
|
339
|
+
|
|
340
|
+
self._current_head_operation_mode = mode
|
|
341
|
+
|
|
342
|
+
def set_antennas_operation_mode(self, mode: int) -> None:
|
|
343
|
+
"""Change the operation mode of the antennas motors.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
mode (int): The operation mode for the antennas motors (0: torque control, 3: position control, 5: current-based position control).
|
|
347
|
+
|
|
348
|
+
Important:
|
|
349
|
+
This method does not work well with the current feetech motors, as they do not support torque control.
|
|
350
|
+
So the method disables the antennas when in torque control mode.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
mode (int): The operation mode for the antennas motors.
|
|
354
|
+
This could be a specific mode like position control, velocity control, or torque control.
|
|
355
|
+
|
|
356
|
+
"""
|
|
357
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
358
|
+
assert mode in [0, 3, 5], (
|
|
359
|
+
"Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]."
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
if self._current_antennas_operation_mode != mode:
|
|
363
|
+
if mode != 0:
|
|
364
|
+
# if the mode is not torque control, we need to set the head joint positions
|
|
365
|
+
# to the current positions to avoid sudden movements
|
|
366
|
+
self.target_antenna_joint_positions = np.array(
|
|
367
|
+
self.c.get_last_position().antennas
|
|
368
|
+
)
|
|
369
|
+
self.c.set_antennas_positions(
|
|
370
|
+
self.target_antenna_joint_positions.tolist()
|
|
371
|
+
)
|
|
372
|
+
self.c.enable_antennas(True)
|
|
373
|
+
else:
|
|
374
|
+
self.c.enable_antennas(False)
|
|
375
|
+
|
|
376
|
+
self._current_antennas_operation_mode = mode
|
|
377
|
+
|
|
378
|
+
def get_all_joint_positions(self) -> tuple[list[float], list[float]]:
|
|
379
|
+
"""Get the current joint positions of the robot.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
tuple: A tuple containing two lists - the first list is for the head joint positions,
|
|
383
|
+
and the second list is for the antenna joint positions.
|
|
384
|
+
|
|
385
|
+
"""
|
|
386
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
387
|
+
positions = self.c.get_last_position()
|
|
388
|
+
|
|
389
|
+
yaw = positions.body_yaw
|
|
390
|
+
antennas = positions.antennas
|
|
391
|
+
dofs = positions.stewart
|
|
392
|
+
|
|
393
|
+
return [yaw] + list(dofs), list(antennas)
|
|
394
|
+
|
|
395
|
+
def get_present_head_joint_positions(
|
|
396
|
+
self,
|
|
397
|
+
) -> Annotated[npt.NDArray[np.float64], (7,)]:
|
|
398
|
+
"""Get the current joint positions of the head.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
list: A list of joint positions for the head, including the body rotation.
|
|
402
|
+
|
|
403
|
+
"""
|
|
404
|
+
return np.array(self.get_all_joint_positions()[0])
|
|
405
|
+
|
|
406
|
+
def get_present_antenna_joint_positions(
|
|
407
|
+
self,
|
|
408
|
+
) -> Annotated[npt.NDArray[np.float64], (2,)]:
|
|
409
|
+
"""Get the current joint positions of the antennas.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
list: A list of joint positions for the antennas.
|
|
413
|
+
|
|
414
|
+
"""
|
|
415
|
+
return np.array(self.get_all_joint_positions()[1])
|
|
416
|
+
|
|
417
|
+
def compensate_head_gravity(self) -> None:
|
|
418
|
+
"""Calculate the currents necessary to compensate for gravity."""
|
|
419
|
+
assert self.kinematics_engine == "Placo", (
|
|
420
|
+
"Gravity compensation is only supported with the Placo kinematics engine."
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# Even though in their docs dynamixes says that 1 count is 1 mA, in practice I've found it to be 3mA.
|
|
424
|
+
# I am not sure why this happens
|
|
425
|
+
# Another explanation is that our model is bad and the current is overestimated 3x (but I have not had these issues with other robots)
|
|
426
|
+
# So I am using a magic number to compensate for this.
|
|
427
|
+
# for currents under 30mA the constant is around 1
|
|
428
|
+
from_Nm_to_mA = 1.47 / 0.52 * 1000
|
|
429
|
+
# Conversion factor from Nm to mA for the Stewart platform motors
|
|
430
|
+
# The torque constant is not linear, so we need to use a correction factor
|
|
431
|
+
# This is a magic number that should be determined experimentally
|
|
432
|
+
# For currents under 30mA, the constant is around 4.0
|
|
433
|
+
# Then it drops to 1.0 for currents above 1.5A
|
|
434
|
+
correction_factor = 4.0
|
|
435
|
+
# Get the current head joint positions
|
|
436
|
+
head_joints = self.get_present_head_joint_positions()
|
|
437
|
+
gravity_torque = self.head_kinematics.compute_gravity_torque( # type: ignore [union-attr]
|
|
438
|
+
np.array(head_joints)
|
|
439
|
+
)
|
|
440
|
+
# Convert the torque from Nm to mA
|
|
441
|
+
current = gravity_torque * from_Nm_to_mA / correction_factor
|
|
442
|
+
# Set the head joint current
|
|
443
|
+
self.set_target_head_joint_current(current)
|
|
444
|
+
|
|
445
|
+
def get_motor_control_mode(self) -> MotorControlMode:
|
|
446
|
+
"""Get the motor control mode."""
|
|
447
|
+
return self.motor_control_mode
|
|
448
|
+
|
|
449
|
+
def set_motor_control_mode(self, mode: MotorControlMode) -> None:
|
|
450
|
+
"""Set the motor control mode."""
|
|
451
|
+
# Check if the mode is already set
|
|
452
|
+
if mode == self.motor_control_mode:
|
|
453
|
+
return
|
|
454
|
+
|
|
455
|
+
if mode == MotorControlMode.Enabled:
|
|
456
|
+
if self.motor_control_mode == MotorControlMode.GravityCompensation:
|
|
457
|
+
# First, make sure we switch to position control
|
|
458
|
+
self.disable_motors()
|
|
459
|
+
self.set_head_operation_mode(3)
|
|
460
|
+
self.set_antennas_operation_mode(3)
|
|
461
|
+
|
|
462
|
+
self.gravity_compensation_mode = False
|
|
463
|
+
self.enable_motors()
|
|
464
|
+
|
|
465
|
+
elif mode == MotorControlMode.Disabled:
|
|
466
|
+
self.gravity_compensation_mode = False
|
|
467
|
+
self.disable_motors()
|
|
468
|
+
|
|
469
|
+
elif mode == MotorControlMode.GravityCompensation:
|
|
470
|
+
if self.kinematics_engine != "Placo":
|
|
471
|
+
raise RuntimeError(
|
|
472
|
+
"Gravity compensation mode is only supported with the Placo kinematics engine."
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
self.disable_motors()
|
|
476
|
+
self.set_head_operation_mode(0)
|
|
477
|
+
self.set_antennas_operation_mode(0)
|
|
478
|
+
self.gravity_compensation_mode = True
|
|
479
|
+
self.enable_motors()
|
|
480
|
+
|
|
481
|
+
self.motor_control_mode = mode
|
|
482
|
+
|
|
483
|
+
def _infer_control_mode(self) -> MotorControlMode:
|
|
484
|
+
assert self.c is not None, "Motor controller not initialized or already closed."
|
|
485
|
+
|
|
486
|
+
torque = self.c.is_torque_enabled()
|
|
487
|
+
|
|
488
|
+
if not torque:
|
|
489
|
+
return MotorControlMode.Disabled
|
|
490
|
+
|
|
491
|
+
mode = self.c.get_stewart_platform_operating_mode()
|
|
492
|
+
if mode == 3:
|
|
493
|
+
return MotorControlMode.Enabled
|
|
494
|
+
elif mode == 1:
|
|
495
|
+
return MotorControlMode.GravityCompensation
|
|
496
|
+
else:
|
|
497
|
+
raise ValueError(f"Unknown motor control mode: {mode}")
|
|
498
|
+
|
|
499
|
+
def read_hardware_errors(self) -> dict[str, list[str]]:
|
|
500
|
+
"""Read hardware errors from the motor controller."""
|
|
501
|
+
if self.c is None:
|
|
502
|
+
return {}
|
|
503
|
+
|
|
504
|
+
def decode_hardware_error_byte(err_byte: int) -> list[str]:
|
|
505
|
+
# https://emanual.robotis.com/docs/en/dxl/x/xl330-m288/#hardware-error-status
|
|
506
|
+
bits_to_error = {
|
|
507
|
+
0: "Input Voltage Error",
|
|
508
|
+
2: "Overheating Error",
|
|
509
|
+
4: "Electrical Shock Error",
|
|
510
|
+
5: "Overload Error",
|
|
511
|
+
}
|
|
512
|
+
err_bits = [i for i in range(8) if (err_byte & (1 << i)) != 0]
|
|
513
|
+
return [bits_to_error[b] for b in err_bits if b in bits_to_error]
|
|
514
|
+
|
|
515
|
+
errors = {}
|
|
516
|
+
for name, id in self.c.get_motor_name_id().items():
|
|
517
|
+
# https://emanual.robotis.com/docs/en/dxl/x/xl330-m288/#hardware-error-status
|
|
518
|
+
err_byte = self.c.async_read_raw_bytes(id, 70, 1)
|
|
519
|
+
assert len(err_byte) == 1
|
|
520
|
+
err = decode_hardware_error_byte(err_byte[0])
|
|
521
|
+
if err:
|
|
522
|
+
errors[name] = err
|
|
523
|
+
|
|
524
|
+
return errors
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
@dataclass
|
|
528
|
+
class RobotBackendStatus:
|
|
529
|
+
"""Status of the Robot Backend."""
|
|
530
|
+
|
|
531
|
+
ready: bool
|
|
532
|
+
motor_control_mode: MotorControlMode
|
|
533
|
+
last_alive: float | None
|
|
534
|
+
control_loop_stats: dict[str, Any]
|
|
535
|
+
error: str | None = None
|