From e6e8dd7d229e5dca7fa33f4fd5d10d06d1c28d33 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 03:28:10 +0100 Subject: [PATCH 1/8] Create new structure --- config/_default/menus/menus.en.toml | 536 +----------------- config/_default/params.toml | 2 +- content/developing/_index.md | 10 + content/developing/advanced-tutos/_index.md | 10 + .../advanced-tutos/reachy-awakening.md | 17 + .../advanced-tutos/reachy-the-greengrocer.md | 17 + .../advanced-tutos/reachy-the-mime.md | 17 + content/developing/basics/1-hello-world.md | 17 + .../developing/basics/2-understand-moves.md | 17 + .../developing/basics/3-basic-arm-control.md | 17 + .../developing/basics/4-use-arm-kinematics.md | 17 + content/developing/basics/5-control-head.md | 17 + .../basics/6-get-images-from-cameras.md | 17 + .../basics/7-record-replay-trajectories.md | 17 + .../developing/basics/8-use-mobile-base.md | 17 + content/developing/basics/_index.md | 10 + .../developing/getting-started-sdk/_index.md | 10 + .../getting-started-sdk/connect-reachy2.md | 17 + .../getting-started-sdk/installation.md | 17 + .../visualize-fake-robot.md | 17 + content/developing/simulation/_index.md | 10 + .../simulation/simulation-installation.md | 17 + content/getting-started/_index.md | 10 + content/getting-started/dashboard/_index.md | 11 + content/getting-started/dashboard/discover.md | 17 + .../getting-started/safety-first/_index.md | 9 + .../safety-first/safety-guidelines.md | 17 + .../getting-started/setup-reachy2/_index.md | 10 + .../setup-reachy2/assemble-and-plug.md | 17 + .../setup-reachy2/connect-reachy2.md | 17 + .../setup-reachy2/start-reachy2.md | 17 + .../setup-reachy2/stop-reachy2.md | 17 + .../getting-started/update-reachy2/_index.md | 10 + .../update-reachy2/update-software.md | 17 + content/hardware-guide/_index.md | 10 + content/hardware-guide/makers/_index.md | 10 + content/hardware-guide/makers/cad-files.md | 17 + .../hardware-guide/specifications/_index.md | 10 + .../hardware-guide/specifications/audio.md | 17 + .../hardware-guide/specifications/general.md | 17 + .../hardware-guide/specifications/grippers.md | 17 + .../specifications/mobile-base.md | 17 + .../specifications/motors-actuators.md | 17 + .../hardware-guide/specifications/vision.md | 17 + content/help/contact-support/_index.md | 10 + content/help/contact-support/need-somebody.md | 54 ++ content/help/debug/_index.md | 10 + content/help/debug/debug-checklist.md | 54 ++ content/help/faq/_index.md | 10 + content/help/faq/robot-faq.md | 54 ++ content/help/faq/sdk-faq.md | 54 ++ content/help/faq/teleoperation-faq.md | 54 ++ content/teleoperation/_index.md | 10 + .../compatibility-specs/_index.md | 10 + .../compatibility-specs/compatible-devices.md | 17 + .../compatibility-specs/latency-network.md | 17 + .../getting-started-teleoperation/_index.md | 10 + .../best-practice.md | 17 + .../connect-reachy2.md | 17 + .../installation.md | 17 + .../teleoperation/using-application/_index.md | 10 + .../using-application/control-mobile-base.md | 17 + .../using-application/controllers-inputs.md | 17 + .../customize-teleop-session.md | 17 + .../using-application/emergency-stop.md | 17 + .../using-application/step-by-step.md | 17 + .../teleoperation-messages.md | 17 + 67 files changed, 1160 insertions(+), 528 deletions(-) create mode 100644 content/developing/_index.md create mode 100644 content/developing/advanced-tutos/_index.md create mode 100644 content/developing/advanced-tutos/reachy-awakening.md create mode 100644 content/developing/advanced-tutos/reachy-the-greengrocer.md create mode 100644 content/developing/advanced-tutos/reachy-the-mime.md create mode 100644 content/developing/basics/1-hello-world.md create mode 100644 content/developing/basics/2-understand-moves.md create mode 100644 content/developing/basics/3-basic-arm-control.md create mode 100644 content/developing/basics/4-use-arm-kinematics.md create mode 100644 content/developing/basics/5-control-head.md create mode 100644 content/developing/basics/6-get-images-from-cameras.md create mode 100644 content/developing/basics/7-record-replay-trajectories.md create mode 100644 content/developing/basics/8-use-mobile-base.md create mode 100644 content/developing/basics/_index.md create mode 100644 content/developing/getting-started-sdk/_index.md create mode 100644 content/developing/getting-started-sdk/connect-reachy2.md create mode 100644 content/developing/getting-started-sdk/installation.md create mode 100644 content/developing/getting-started-sdk/visualize-fake-robot.md create mode 100644 content/developing/simulation/_index.md create mode 100644 content/developing/simulation/simulation-installation.md create mode 100644 content/getting-started/_index.md create mode 100644 content/getting-started/dashboard/_index.md create mode 100644 content/getting-started/dashboard/discover.md create mode 100644 content/getting-started/safety-first/_index.md create mode 100644 content/getting-started/safety-first/safety-guidelines.md create mode 100644 content/getting-started/setup-reachy2/_index.md create mode 100644 content/getting-started/setup-reachy2/assemble-and-plug.md create mode 100644 content/getting-started/setup-reachy2/connect-reachy2.md create mode 100644 content/getting-started/setup-reachy2/start-reachy2.md create mode 100644 content/getting-started/setup-reachy2/stop-reachy2.md create mode 100644 content/getting-started/update-reachy2/_index.md create mode 100644 content/getting-started/update-reachy2/update-software.md create mode 100644 content/hardware-guide/_index.md create mode 100644 content/hardware-guide/makers/_index.md create mode 100644 content/hardware-guide/makers/cad-files.md create mode 100644 content/hardware-guide/specifications/_index.md create mode 100644 content/hardware-guide/specifications/audio.md create mode 100644 content/hardware-guide/specifications/general.md create mode 100644 content/hardware-guide/specifications/grippers.md create mode 100644 content/hardware-guide/specifications/mobile-base.md create mode 100644 content/hardware-guide/specifications/motors-actuators.md create mode 100644 content/hardware-guide/specifications/vision.md create mode 100644 content/help/contact-support/_index.md create mode 100644 content/help/contact-support/need-somebody.md create mode 100644 content/help/debug/_index.md create mode 100644 content/help/debug/debug-checklist.md create mode 100644 content/help/faq/_index.md create mode 100644 content/help/faq/robot-faq.md create mode 100644 content/help/faq/sdk-faq.md create mode 100644 content/help/faq/teleoperation-faq.md create mode 100644 content/teleoperation/_index.md create mode 100644 content/teleoperation/compatibility-specs/_index.md create mode 100644 content/teleoperation/compatibility-specs/compatible-devices.md create mode 100644 content/teleoperation/compatibility-specs/latency-network.md create mode 100644 content/teleoperation/getting-started-teleoperation/_index.md create mode 100644 content/teleoperation/getting-started-teleoperation/best-practice.md create mode 100644 content/teleoperation/getting-started-teleoperation/connect-reachy2.md create mode 100644 content/teleoperation/getting-started-teleoperation/installation.md create mode 100644 content/teleoperation/using-application/_index.md create mode 100644 content/teleoperation/using-application/control-mobile-base.md create mode 100644 content/teleoperation/using-application/controllers-inputs.md create mode 100644 content/teleoperation/using-application/customize-teleop-session.md create mode 100644 content/teleoperation/using-application/emergency-stop.md create mode 100644 content/teleoperation/using-application/step-by-step.md create mode 100644 content/teleoperation/using-application/teleoperation-messages.md diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 818e2c28..7bf777bf 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -1,549 +1,31 @@ -############################################# -# Menu docs -############################################# - -################## -## Getting started section -################## - -[[docs]] - name = "Getting started" - weight = 10 - identifier = "docs-getting-started" - -[[docs]] - name = "Unpack Reachy 2" - weight = 100 - parent = "docs-getting-started" - url = "/docs/getting-started/unpack/" - -[[docs]] - name = "Safety guidelines" - weight = 110 - parent = "docs-getting-started" - url = "/docs/getting-started/safety/" - -[[docs]] - name = "Start your robot" - weight = 120 - parent = "docs-getting-started" - url = "/docs/getting-started/turn-on/" - -[[docs]] - name = "Connect your robot to the network" - weight = 130 - parent = "docs-getting-started" - url = "/docs/getting-started/network/" - -[[docs]] - name = "Connect to the dashboard" - weight = 140 - parent = "docs-getting-started" - url = "/docs/getting-started/dashboard/" - -[[docs]] - name = "Hello world" - weight = 150 - parent = "docs-getting-started" - url = "/docs/getting-started/hello-world/" - -[[docs]] - name = "Stop your robot" - weight = 160 - parent = "docs-getting-started" - url = "/docs/getting-started/turn-off/" - -################## -## Simulation section -################## - -[[docs]] - name = "Simulation" - weight = 20 - identifier = "docs-simulation" - -[[docs]] - name = "Simulation installation" - weight = 200 - parent = "docs-simulation" - url = "/docs/simulation/simulation-installation/" - -################## -## Update section -################## - -[[docs]] - name = "Update Reachy 2" - weight = 30 - identifier = "docs-update" - -[[docs]] - name = "Update Reachy 2 software" - weight = 300 - url = "/docs/update/update" - parent = "docs-update" - -################## -## Advanced section -################## - -[[docs]] - name = "Advanced" - weight = 40 - identifier = "docs-advanced" - -[[docs]] - name = "Access Reachy 2 computer" - weight = 400 - url = "/docs/advanced/access-computer" - parent = "docs-advanced" - -[[docs]] - name = "Calibrate teleop cameras" - weight = 410 - url = "/docs/advanced/calibrate-cameras" - parent = "docs-advanced" - -############################################# -# Menu dashboard -############################################# - -####################### -## Introduction section -####################### - -[[dashboard]] - name = "Introduction" - weight = 10 - identifier = "dashboard-introduction" - -[[dashboard]] - name = "Introduction" - weight = 100 - parent = "dashboard-introduction" - url = "/dashboard/introduction/introduction/" - -[[dashboard]] - name = "Connection" - weight = 110 - parent = "dashboard-introduction" - url = "/dashboard/introduction/connection/" - -####################### -## Content section -####################### - -[[dashboard]] - name = "Content" - weight = 20 - identifier = "dashboard-content" - -[[dashboard]] - name = "Services" - weight = 200 - parent = "dashboard-content" - url = "/dashboard/content/services/" - -[[dashboard]] - name = "Network" - weight = 210 - parent = "dashboard-content" - url = "/dashboard/content/network/" - -[[dashboard]] - name = "Updates" - weight = 220 - parent = "dashboard-content" - url = "/dashboard/content/updates/" - -[[dashboard]] - name = "Visualization tools" - weight = 230 - parent = "dashboard-content" - url = "/dashboard/content/visualization/" - -[[dashboard]] - name = "Reachy control" - weight = 240 - parent = "dashboard-content" - url = "/dashboard/content/dashboard/" - -############################################# -# Menu SDK -############################################# - -################## -## Getting started section -################## - -[[sdk]] - name = "Introduction" - weight = 10 - identifier = "sdk-introduction" - -[[sdk]] - name = "Introduction" - weight = 100 - parent = "sdk-introduction" - url = "/sdk/introduction/introduction" - -################## -## Getting started section -################## - -[[sdk]] - name = "Getting started" - weight = 20 - identifier = "sdk-getting-started" - -[[sdk]] - name = "Installation" - weight = 200 - parent = "sdk-getting-started" - url = "/sdk/getting-started/install" - -[[sdk]] - name = "Connect to Reachy 2" - weight = 210 - parent = "sdk-getting-started" - url = "/sdk/getting-started/connect" - -[[sdk]] - name = "Hello World" - weight = 220 - parent = "sdk-getting-started" - url = "/sdk/getting-started/hello-world" - -[[sdk]] - name = "SDK Overview" - weight = 230 - parent = "sdk-getting-started" - url = "/sdk/getting-started/overview" - -[[sdk]] - name = "Safety first" - weight = 240 - parent = "sdk-getting-started" - url = "/sdk/getting-started/safety" - -################## -## First moves section -################## - -[[sdk]] - name = "First moves" - weight = 30 - identifier = "sdk-first-moves" - -[[sdk]] - name = "1. Start with Reachy 2" - weight = 300 - parent = "sdk-first-moves" - url = "/sdk/first-moves/intro" - -[[sdk]] - name = "2. Understand moves in Reachy 2" - weight = 310 - parent = "sdk-first-moves" - url = "/sdk/first-moves/moves" - -[[sdk]] - name = "3. Basic arm control" - weight = 320 - parent = "sdk-first-moves" - url = "/sdk/first-moves/arm" - -[[sdk]] - name = "4. Use arm kinematics" - weight = 330 - parent = "sdk-first-moves" - url = "/sdk/first-moves/kinematics" - -[[sdk]] - name = "5. Control the head" - weight = 340 - parent = "sdk-first-moves" - url = "/sdk/first-moves/head" - -[[sdk]] - name = "6. Get images from cameras" - weight = 350 - parent = "sdk-first-moves" - url = "/sdk/first-moves/cameras" - -[[sdk]] - name = "7. Record and replay trajectories" - weight = 360 - parent = "sdk-first-moves" - url = "/sdk/first-moves/record" - -[[sdk]] - name = "8. Use the mobile base" - weight = 370 - parent = "sdk-first-moves" - url = "/sdk/first-moves/mobile-base" - -################## -## Advanced section -################## - -[[sdk]] - name = "Advanced" - weight = 40 - identifier = "sdk-advanced" - -[[sdk]] - name = "Mobile base modes" - weight = 400 - parent = "sdk-advanced" - url = "/sdk/advanced/mobile-base" - ############################################# # Menu main - add parts to main page nav menu here! ############################################# [[main]] - name = "Setup Reachy 2" - url = "/docs/getting-started/unpack/" + name = "Getting started" + url = "/getting-started/safety-first/safety-guidelines/" weight = 10 [[main]] - name = "Python SDK" - url = "/sdk/introduction/introduction/" + name = "Hardware guide" + url = "/hardware-guide/specifications/general/" weight = 20 [[main]] - name = "Teleoperation" - url = "/vr/introduction/introduction/" + name = "Developing with Reachy 2" + url = "/developing/getting-started-sdk/installation/" weight = 30 [[main]] - name = "Dashboard" + name = "Teleoperation" weight = 40 - url = "/dashboard/introduction/introduction/" + url = "/teleoperation/compatibility-specs/compatible-devices/" [[main]] name = "Help" weight = 50 - url = "/help/help/recovering/" - -############################################# -# Menu VR -############################################# - -################## -## Intro section -################## - -[[vr]] - name = "Introduction" - weight = 10 - identifier = "vr-introduction" - -[[vr]] - name = "Introduction" - weight = 100 - parent = "vr-introduction" - url = "vr/introduction/introduction" - -################## -## Compatibility section -################## - -[[vr]] - name = "Compatibility" - weight = 20 - identifier = "vr-compatibility" - -[[vr]] - name = "Compatible headsets" - weight = 200 - parent = "vr-compatibility" - url = "vr/compatibility/headsets" - -[[vr]] - name = "PC requirements" - weight = 210 - parent = "vr-compatibility" - url = "vr/compatibility/pc-requirements" - -################## -## Getting started section -################## - -[[vr]] - name = "Getting started" - weight = 30 - identifier = "vr-getting-started" - -[[vr]] - name = "Installation" - weight = 300 - parent = "vr-getting-started" - url = "vr/getting-started/installation" - -[[vr]] - name = "Check robot is ready" - weight = 310 - parent = "vr-getting-started" - url = "vr/getting-started/check-robot" - -[[vr]] - name = "Connect to Reachy 2" - weight = 320 - parent = "vr-getting-started" - url = "vr/getting-started/connect" - -[[vr]] - name = "Setup your teleop session" - weight = 330 - parent = "vr-getting-started" - url = "vr/getting-started/setup" - -################## -## Using section -################## - -[[vr]] - name = "Using the app" - weight = 40 - identifier = "vr-use" - -[[vr]] - name = "🚨 Best practice" - weight = 400 - parent = "vr-use" - url = "vr/use-teleop/best-practice" - -[[vr]] - name = "Controllers inputs" - weight = 410 - parent = "vr-use" - url = "vr/use-teleop/commands" - -[[vr]] - name = "Teleoperate Reachy" - weight = 430 - parent = "vr-use" - url = "vr/use-teleop/start" - -[[vr]] - name = "Control the mobile base" - weight = 440 - parent = "vr-use" - url = "vr/use-teleop/mobile-base" - -[[vr]] - name = "Reduce motion sickness" - weight = 440 - parent = "vr-use" - url = "vr/use-teleop/motion-sickness" - -[[vr]] - name = "Teleoperation messages" - weight = 450 - parent = "vr-use" - url = "vr/use-teleop/messages" - -[[vr]] - name = "Emergency stop" - weight = 460 - parent = "vr-use" - url = "vr/use-teleop/emergency-stop" - -################## -## Problem section -################## - -[[vr]] - name = "Problem" - weight = 50 - identifier = "vr-problem" - -[[vr]] - name = "Debug" - weight = 500 - parent = "vr-problem" - url = "vr/problem/debug" - -[[vr]] - name = "Support" - weight = 510 - parent = "vr-problem" - url = "vr/problem/support-vr" - -############################################# -# Menu help -############################################# - -################ -## Help Section -################ - -[[help]] - name = "Help" - weight = 10 - identifier = "help-debug" - -[[help]] - name = "Recovering" - weight = 100 - parent="help-debug" - url = "/help/help/recovering/" - -[[help]] - name = "Debug" - weight = 110 - parent="help-debug" - url = "/help/help/debug/" - -[[help]] - name = "Hardware intervention" - weight = 120 - parent="help-debug" - url = "/help/help/torso/" - -[[help]] - name = "Support" - weight = 130 - parent="help-debug" - url = "/help/help/support/" - -################# -## System section -################# - -[[help]] - name = "System" - weight = 20 - identifier = "help-system" - -[[help]] - name = "Finding Reachy 2's IP" - weight = 200 - parent="help-system" - url = "/help/system/find-my-ip/" - -################# -## Safety section -################# - -[[help]] - name = "Safety" - weight = 30 - identifier = "help-safety" - -[[help]] - name = "Use Reachy 2 properly" - weight = 300 - parent="help-safety" - url = "/help/safety/correct-use/" - -[[help]] - name = "Use VR teleoperation" - weight = 310 - parent="help-safety" - url = "/help/safety/vr-use/" + url = "/help/debug/debug-checklist/" ############################################# [[social]] diff --git a/config/_default/params.toml b/config/_default/params.toml index f567470b..fbc4b597 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -92,7 +92,7 @@ lastMod = false instantPage = true flexSearch = true searchSectionsShow = [] - searchSectionsIndex = ["advanced", "dashboard", "docs", "dashboard", "SDK", "VR", "help"] + searchSectionsIndex = ["getting-started", "hardware-guide", "developing-with", "teleoperation", "help"] darkMode = true bootStrapJs = true breadCrumb = false diff --git a/content/developing/_index.md b/content/developing/_index.md new file mode 100644 index 00000000..6c7a7ec5 --- /dev/null +++ b/content/developing/_index.md @@ -0,0 +1,10 @@ +--- +title: "Developing with Reachy 2" +description: "How to create your own applications with Reachy 2" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/developing/advanced-tutos/_index.md b/content/developing/advanced-tutos/_index.md new file mode 100644 index 00000000..1d759032 --- /dev/null +++ b/content/developing/advanced-tutos/_index.md @@ -0,0 +1,10 @@ +--- +title: "Advanced tutos" +description: "Practice the use of the SDK with advanced tutorials" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/developing/advanced-tutos/reachy-awakening.md b/content/developing/advanced-tutos/reachy-awakening.md new file mode 100644 index 00000000..daf008f3 --- /dev/null +++ b/content/developing/advanced-tutos/reachy-awakening.md @@ -0,0 +1,17 @@ +--- +title: "Reachy's Awakening" +description: "" +lead: "Your first tracking with head using arm kinematics" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Advanced tutorials" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/advanced-tutos/reachy-the-greengrocer.md b/content/developing/advanced-tutos/reachy-the-greengrocer.md new file mode 100644 index 00000000..c1e5c832 --- /dev/null +++ b/content/developing/advanced-tutos/reachy-the-greengrocer.md @@ -0,0 +1,17 @@ +--- +title: "Reachy the Greengrocer" +description: "" +lead: "Use pollen_vision to plug an vision model with the SDK for fruit detection and manipulation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Advanced tutorials" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/advanced-tutos/reachy-the-mime.md b/content/developing/advanced-tutos/reachy-the-mime.md new file mode 100644 index 00000000..55f6e33c --- /dev/null +++ b/content/developing/advanced-tutos/reachy-the-mime.md @@ -0,0 +1,17 @@ +--- +title: "Reachy the Mime" +description: "" +lead: "Synchronize head, arm and mobile base movements" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Advanced tutorials" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/1-hello-world.md b/content/developing/basics/1-hello-world.md new file mode 100644 index 00000000..0ddbc8e4 --- /dev/null +++ b/content/developing/basics/1-hello-world.md @@ -0,0 +1,17 @@ +--- +title: "1. Hello World" +description: "Basic connection to the robot with the Python SDK" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/2-understand-moves.md b/content/developing/basics/2-understand-moves.md new file mode 100644 index 00000000..53a67763 --- /dev/null +++ b/content/developing/basics/2-understand-moves.md @@ -0,0 +1,17 @@ +--- +title: "2. Understand moves in Reachy 2" +description: "How gotos work" +lead: "How gotos work to create movements sequences" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/3-basic-arm-control.md b/content/developing/basics/3-basic-arm-control.md new file mode 100644 index 00000000..57eb4297 --- /dev/null +++ b/content/developing/basics/3-basic-arm-control.md @@ -0,0 +1,17 @@ +--- +title: "3. Basic arm control" +description: "First moves of the arms using the Python SDK" +lead: "First moves of the arms using the Python SDK" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/4-use-arm-kinematics.md b/content/developing/basics/4-use-arm-kinematics.md new file mode 100644 index 00000000..bfb730f7 --- /dev/null +++ b/content/developing/basics/4-use-arm-kinematics.md @@ -0,0 +1,17 @@ +--- +title: "4. Use arm kinematics" +description: "Harness arm kinematics to create movements using the Python SDK" +lead: "Harness arm kinematics to create movements" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/5-control-head.md b/content/developing/basics/5-control-head.md new file mode 100644 index 00000000..1571b09d --- /dev/null +++ b/content/developing/basics/5-control-head.md @@ -0,0 +1,17 @@ +--- +title: "5. Control the head" +description: "First head movements using the Python SDK" +lead: "First head movements" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/6-get-images-from-cameras.md b/content/developing/basics/6-get-images-from-cameras.md new file mode 100644 index 00000000..6b0e1b6c --- /dev/null +++ b/content/developing/basics/6-get-images-from-cameras.md @@ -0,0 +1,17 @@ +--- +title: "6. Get images from cameras" +description: "Images acquisition using the Python SDK" +lead: "Images acquisition " +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/7-record-replay-trajectories.md b/content/developing/basics/7-record-replay-trajectories.md new file mode 100644 index 00000000..78cc797b --- /dev/null +++ b/content/developing/basics/7-record-replay-trajectories.md @@ -0,0 +1,17 @@ +--- +title: "7. Record and replay trajectories" +description: "Record and replay trajectories using the Python SDK" +lead: "Record and replay trajectories" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/8-use-mobile-base.md b/content/developing/basics/8-use-mobile-base.md new file mode 100644 index 00000000..f19c1e60 --- /dev/null +++ b/content/developing/basics/8-use-mobile-base.md @@ -0,0 +1,17 @@ +--- +title: "8. Use the mobile base" +description: "First mobile base movements using the Python SDK" +lead: "First mobile base movements" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "SDK basics" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/basics/_index.md b/content/developing/basics/_index.md new file mode 100644 index 00000000..db5a7434 --- /dev/null +++ b/content/developing/basics/_index.md @@ -0,0 +1,10 @@ +--- +title: "SDK basics" +description: "Discover the basics of the Python SDK" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/developing/getting-started-sdk/_index.md b/content/developing/getting-started-sdk/_index.md new file mode 100644 index 00000000..b9d4914c --- /dev/null +++ b/content/developing/getting-started-sdk/_index.md @@ -0,0 +1,10 @@ +--- +title: "Getting started with the SDK" +description: "First steps with Reachy 2 SDK" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/developing/getting-started-sdk/connect-reachy2.md b/content/developing/getting-started-sdk/connect-reachy2.md new file mode 100644 index 00000000..76b8a5f2 --- /dev/null +++ b/content/developing/getting-started-sdk/connect-reachy2.md @@ -0,0 +1,17 @@ +--- +title: "Connect to Reachy 2" +description: "Establish a connection to the robot with the Python SDK" +lead: "Establish a connection to the robot with the Python SDK" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Getting started with the SDK" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/getting-started-sdk/installation.md b/content/developing/getting-started-sdk/installation.md new file mode 100644 index 00000000..8fcc3b69 --- /dev/null +++ b/content/developing/getting-started-sdk/installation.md @@ -0,0 +1,17 @@ +--- +title: "Installation" +description: "Install the Python SDK for Reachy 2" +lead: "Install the Python SDK for Reachy 2" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Getting started with the SDK" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/getting-started-sdk/visualize-fake-robot.md b/content/developing/getting-started-sdk/visualize-fake-robot.md new file mode 100644 index 00000000..e56dc96e --- /dev/null +++ b/content/developing/getting-started-sdk/visualize-fake-robot.md @@ -0,0 +1,17 @@ +--- +title: "Visualize with fake robot" +description: "Use a fake robot mode to test your moves before using the real robot" +lead: "Use a fake robot mode to test your moves before using the real robot" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Getting started with the SDK" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/developing/simulation/_index.md b/content/developing/simulation/_index.md new file mode 100644 index 00000000..8a62daff --- /dev/null +++ b/content/developing/simulation/_index.md @@ -0,0 +1,10 @@ +--- +title: "Simulation" +description: "Use gazebo to simulate the robot" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/developing/simulation/simulation-installation.md b/content/developing/simulation/simulation-installation.md new file mode 100644 index 00000000..9ae55a02 --- /dev/null +++ b/content/developing/simulation/simulation-installation.md @@ -0,0 +1,17 @@ +--- +title: "Simulation installation" +description: "How to install a simulation of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + developing: + parent: "Simulation" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/getting-started/_index.md b/content/getting-started/_index.md new file mode 100644 index 00000000..d577c879 --- /dev/null +++ b/content/getting-started/_index.md @@ -0,0 +1,10 @@ +--- +title: "Getting started" +description: "Assemble and start using your Reachy 2." +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/getting-started/dashboard/_index.md b/content/getting-started/dashboard/_index.md new file mode 100644 index 00000000..1fba4e97 --- /dev/null +++ b/content/getting-started/dashboard/_index.md @@ -0,0 +1,11 @@ +--- +title: "Dashboard" +description: "Overview of the dashboard content, an insightful tool." +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +weigth: 1000 +--- diff --git a/content/getting-started/dashboard/discover.md b/content/getting-started/dashboard/discover.md new file mode 100644 index 00000000..6c13ade7 --- /dev/null +++ b/content/getting-started/dashboard/discover.md @@ -0,0 +1,17 @@ +--- +title: "Discover the dashboard" +description: "Understand the dashboard features" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Dashboard" +weight: 1000 +toc: true +--- + +This is the dashboard \ No newline at end of file diff --git a/content/getting-started/safety-first/_index.md b/content/getting-started/safety-first/_index.md new file mode 100644 index 00000000..7d72640e --- /dev/null +++ b/content/getting-started/safety-first/_index.md @@ -0,0 +1,9 @@ +--- +title: "Safety first" +description: "Mandatory safety guidelines before using the robot." +date: 2023-07-25T15:34:19+02:00 +lastmod: 2023-07-25T15:34:19+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/getting-started/safety-first/safety-guidelines.md b/content/getting-started/safety-first/safety-guidelines.md new file mode 100644 index 00000000..9e3b8799 --- /dev/null +++ b/content/getting-started/safety-first/safety-guidelines.md @@ -0,0 +1,17 @@ +--- +title: "Safety guidelines" +description: "Safety guidelines as mandatory reading" +lead: "Everything you must know before using Reachyh 2 for a safe experience with the robot" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Safety first" +weight: 100 +toc: true +--- + +Ohlala it's safe now \ No newline at end of file diff --git a/content/getting-started/setup-reachy2/_index.md b/content/getting-started/setup-reachy2/_index.md new file mode 100644 index 00000000..a8c4f89f --- /dev/null +++ b/content/getting-started/setup-reachy2/_index.md @@ -0,0 +1,10 @@ +--- +title: "Setup Reachy 2" +description: "From assembling to your first robot move." +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/getting-started/setup-reachy2/assemble-and-plug.md b/content/getting-started/setup-reachy2/assemble-and-plug.md new file mode 100644 index 00000000..ef15e467 --- /dev/null +++ b/content/getting-started/setup-reachy2/assemble-and-plug.md @@ -0,0 +1,17 @@ +--- +title: "Assemble & Plug Reachy 2" +description: "Steps to assemble Reachy 2" +lead: "Follow these steps to finish assembling your robot" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Setup Reachy 2" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/getting-started/setup-reachy2/connect-reachy2.md b/content/getting-started/setup-reachy2/connect-reachy2.md new file mode 100644 index 00000000..9efcd0c3 --- /dev/null +++ b/content/getting-started/setup-reachy2/connect-reachy2.md @@ -0,0 +1,17 @@ +--- +title: "Connect Reachy 2" +description: "Connect your robot to the network" +lead: "Follow these steps to make your first connection to Reachy 2" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Setup Reachy 2" +weight: 400 +toc: true +--- + +This is how you connect your robot \ No newline at end of file diff --git a/content/getting-started/setup-reachy2/start-reachy2.md b/content/getting-started/setup-reachy2/start-reachy2.md new file mode 100644 index 00000000..f1e59a70 --- /dev/null +++ b/content/getting-started/setup-reachy2/start-reachy2.md @@ -0,0 +1,17 @@ +--- +title: "Start Reachy 2" +description: "Turn on the robot" +lead: "Follow these steps to start the robot" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Setup Reachy 2" +weight: 300 +toc: true +--- + +This is how you start your robot \ No newline at end of file diff --git a/content/getting-started/setup-reachy2/stop-reachy2.md b/content/getting-started/setup-reachy2/stop-reachy2.md new file mode 100644 index 00000000..a8ff99f9 --- /dev/null +++ b/content/getting-started/setup-reachy2/stop-reachy2.md @@ -0,0 +1,17 @@ +--- +title: "Stop Reachy 2" +description: "Turn off the robot" +lead: "At the end, stop your robot" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Setup Reachy 2" +weight: 500 +toc: true +--- + +This is how you stop your robot \ No newline at end of file diff --git a/content/getting-started/update-reachy2/_index.md b/content/getting-started/update-reachy2/_index.md new file mode 100644 index 00000000..ab6f6805 --- /dev/null +++ b/content/getting-started/update-reachy2/_index.md @@ -0,0 +1,10 @@ +--- +title: "Update Reachy 2" +description: "Update your robot to get the latest features." +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/getting-started/update-reachy2/update-software.md b/content/getting-started/update-reachy2/update-software.md new file mode 100644 index 00000000..1eb47e41 --- /dev/null +++ b/content/getting-started/update-reachy2/update-software.md @@ -0,0 +1,17 @@ +--- +title: "Update Reachy 2 software" +description: "Steps to update Reachy 2 software to have the latest features" +lead: "Get the latest features by updating your robot software" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + getting-started: + parent: "Update Reachy 2" +weight: 200 +toc: true +--- + +This is how to update the robot \ No newline at end of file diff --git a/content/hardware-guide/_index.md b/content/hardware-guide/_index.md new file mode 100644 index 00000000..c126b4ff --- /dev/null +++ b/content/hardware-guide/_index.md @@ -0,0 +1,10 @@ +--- +title: "Hardware guide" +description: "Find hardware specifications and CAD files" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/hardware-guide/makers/_index.md b/content/hardware-guide/makers/_index.md new file mode 100644 index 00000000..3e0c001e --- /dev/null +++ b/content/hardware-guide/makers/_index.md @@ -0,0 +1,10 @@ +--- +title: "Makers" +description: "Find elements to make or customize your robot" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/hardware-guide/makers/cad-files.md b/content/hardware-guide/makers/cad-files.md new file mode 100644 index 00000000..5a90be9d --- /dev/null +++ b/content/hardware-guide/makers/cad-files.md @@ -0,0 +1,17 @@ +--- +title: "Find CAD Files" +description: "Find CAD files to create, repair or customize your robot" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Makers" +weight: 500 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/_index.md b/content/hardware-guide/specifications/_index.md new file mode 100644 index 00000000..0704196c --- /dev/null +++ b/content/hardware-guide/specifications/_index.md @@ -0,0 +1,10 @@ +--- +title: "Specifications" +description: "Find Reachy 2 hardware specifications" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/hardware-guide/specifications/audio.md b/content/hardware-guide/specifications/audio.md new file mode 100644 index 00000000..af3b686c --- /dev/null +++ b/content/hardware-guide/specifications/audio.md @@ -0,0 +1,17 @@ +--- +title: "Audio specifications" +description: "Audio system specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 500 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/general.md b/content/hardware-guide/specifications/general.md new file mode 100644 index 00000000..fff9b431 --- /dev/null +++ b/content/hardware-guide/specifications/general.md @@ -0,0 +1,17 @@ +--- +title: "General specifications" +description: "General specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 300 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/grippers.md b/content/hardware-guide/specifications/grippers.md new file mode 100644 index 00000000..564e9552 --- /dev/null +++ b/content/hardware-guide/specifications/grippers.md @@ -0,0 +1,17 @@ +--- +title: "Grippers specifications" +description: "Grippers specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 800 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/mobile-base.md b/content/hardware-guide/specifications/mobile-base.md new file mode 100644 index 00000000..a1f93078 --- /dev/null +++ b/content/hardware-guide/specifications/mobile-base.md @@ -0,0 +1,17 @@ +--- +title: "Mobile base specifications" +description: "Mobile base specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 700 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/motors-actuators.md b/content/hardware-guide/specifications/motors-actuators.md new file mode 100644 index 00000000..effa5a0b --- /dev/null +++ b/content/hardware-guide/specifications/motors-actuators.md @@ -0,0 +1,17 @@ +--- +title: "Motors & Actuators specifications" +description: "Audio system specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 600 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/hardware-guide/specifications/vision.md b/content/hardware-guide/specifications/vision.md new file mode 100644 index 00000000..43c98f15 --- /dev/null +++ b/content/hardware-guide/specifications/vision.md @@ -0,0 +1,17 @@ +--- +title: "Vision specifications" +description: "Vision system specifications of Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + hardware-guide: + parent: "Specifications" +weight: 300 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/help/contact-support/_index.md b/content/help/contact-support/_index.md new file mode 100644 index 00000000..1fb775d5 --- /dev/null +++ b/content/help/contact-support/_index.md @@ -0,0 +1,10 @@ +--- +title: "Contact support" +description: "Links to contact Pollen support team and get assistance" +date: 2023-08-21T16:18:47+02:00 +lastmod: 2023-08-21T16:18:47+02:00 +draft: false +images: [] +weight: 100 +type: docs +--- diff --git a/content/help/contact-support/need-somebody.md b/content/help/contact-support/need-somebody.md new file mode 100644 index 00000000..471f3022 --- /dev/null +++ b/content/help/contact-support/need-somebody.md @@ -0,0 +1,54 @@ +--- +title : "I need somebody" +description: "Get assistance from the community or Pollen support team" +lead: "Get assistance from the community or Pollen support team" +date: 2023-07-26T08:44:51+02:00 +lastmod: 2023-07-26T08:44:51+02:00 +draft: false +images: [] +type: docs +menu: + help: + parent: "Contact support" +toc: true +weight: 20 +--- + +## Problem with the motors + +The motors are managed by the reachy2-core service. +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` + +## Problem with the cameras or sound + +### With teleoperation application + +During teleoperation, the cameras and sound are managed by the webrtc service. +This service is automatically launched when you start Reachy 2 computer. + +> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: +>- that any running client to the sdk has been disconnected +>- that the speaker has been plugged back +>- that the webrtc services has been restarted + +Check all logs of the service with: + +```bash +journalctl -b -u webrtc +``` + +### With the Python SDK + +If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. + +> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) + +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` diff --git a/content/help/debug/_index.md b/content/help/debug/_index.md new file mode 100644 index 00000000..6afbb655 --- /dev/null +++ b/content/help/debug/_index.md @@ -0,0 +1,10 @@ +--- +title: "Debug" +description: "Learn how you can debug Reachy." +date: 2023-08-21T16:18:47+02:00 +lastmod: 2023-08-21T16:18:47+02:00 +draft: false +images: [] +weight: 100 +type: docs +--- diff --git a/content/help/debug/debug-checklist.md b/content/help/debug/debug-checklist.md new file mode 100644 index 00000000..82211697 --- /dev/null +++ b/content/help/debug/debug-checklist.md @@ -0,0 +1,54 @@ +--- +title : "Quick debug checklist" +description: "Debug" +lead: "Easy steps to debug yourself common issues" +date: 2023-07-26T08:44:51+02:00 +lastmod: 2023-07-26T08:44:51+02:00 +draft: false +images: [] +type: docs +menu: + help: + parent: "Debug" +toc: true +weight: 20 +--- + +## Problem with the motors + +The motors are managed by the reachy2-core service. +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` + +## Problem with the cameras or sound + +### With teleoperation application + +During teleoperation, the cameras and sound are managed by the webrtc service. +This service is automatically launched when you start Reachy 2 computer. + +> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: +>- that any running client to the sdk has been disconnected +>- that the speaker has been plugged back +>- that the webrtc services has been restarted + +Check all logs of the service with: + +```bash +journalctl -b -u webrtc +``` + +### With the Python SDK + +If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. + +> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) + +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` diff --git a/content/help/faq/_index.md b/content/help/faq/_index.md new file mode 100644 index 00000000..119d6df2 --- /dev/null +++ b/content/help/faq/_index.md @@ -0,0 +1,10 @@ +--- +title: "FAQ" +description: "Frequently asked questions" +date: 2023-08-21T16:18:47+02:00 +lastmod: 2023-08-21T16:18:47+02:00 +draft: false +images: [] +weight: 100 +type: docs +--- diff --git a/content/help/faq/robot-faq.md b/content/help/faq/robot-faq.md new file mode 100644 index 00000000..dacaa15d --- /dev/null +++ b/content/help/faq/robot-faq.md @@ -0,0 +1,54 @@ +--- +title : "Robot" +description: "Robot FAQ" +lead: "Frequently asked questions on the robot" +date: 2023-07-26T08:44:51+02:00 +lastmod: 2023-07-26T08:44:51+02:00 +draft: false +images: [] +type: docs +menu: + help: + parent: "FAQ" +toc: true +weight: 20 +--- + +## Problem with the motors + +The motors are managed by the reachy2-core service. +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` + +## Problem with the cameras or sound + +### With teleoperation application + +During teleoperation, the cameras and sound are managed by the webrtc service. +This service is automatically launched when you start Reachy 2 computer. + +> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: +>- that any running client to the sdk has been disconnected +>- that the speaker has been plugged back +>- that the webrtc services has been restarted + +Check all logs of the service with: + +```bash +journalctl -b -u webrtc +``` + +### With the Python SDK + +If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. + +> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) + +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` diff --git a/content/help/faq/sdk-faq.md b/content/help/faq/sdk-faq.md new file mode 100644 index 00000000..57c0baa2 --- /dev/null +++ b/content/help/faq/sdk-faq.md @@ -0,0 +1,54 @@ +--- +title : "Python SDK" +description: "Python SDK FAQ" +lead: "Frequently asked questions on the Python SDK for Reachy 2" +date: 2023-07-26T08:44:51+02:00 +lastmod: 2023-07-26T08:44:51+02:00 +draft: false +images: [] +type: docs +menu: + help: + parent: "FAQ" +toc: true +weight: 20 +--- + +## Problem with the motors + +The motors are managed by the reachy2-core service. +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` + +## Problem with the cameras or sound + +### With teleoperation application + +During teleoperation, the cameras and sound are managed by the webrtc service. +This service is automatically launched when you start Reachy 2 computer. + +> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: +>- that any running client to the sdk has been disconnected +>- that the speaker has been plugged back +>- that the webrtc services has been restarted + +Check all logs of the service with: + +```bash +journalctl -b -u webrtc +``` + +### With the Python SDK + +If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. + +> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) + +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` diff --git a/content/help/faq/teleoperation-faq.md b/content/help/faq/teleoperation-faq.md new file mode 100644 index 00000000..88299853 --- /dev/null +++ b/content/help/faq/teleoperation-faq.md @@ -0,0 +1,54 @@ +--- +title : "Teleoperation" +description: "VR teleoperation application FAQ" +lead: "Frequently asked questions on VR teleoperation application" +date: 2023-07-26T08:44:51+02:00 +lastmod: 2023-07-26T08:44:51+02:00 +draft: false +images: [] +type: docs +menu: + help: + parent: "FAQ" +toc: true +weight: 20 +--- + +## Problem with the motors + +The motors are managed by the reachy2-core service. +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` + +## Problem with the cameras or sound + +### With teleoperation application + +During teleoperation, the cameras and sound are managed by the webrtc service. +This service is automatically launched when you start Reachy 2 computer. + +> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: +>- that any running client to the sdk has been disconnected +>- that the speaker has been plugged back +>- that the webrtc services has been restarted + +Check all logs of the service with: + +```bash +journalctl -b -u webrtc +``` + +### With the Python SDK + +If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. + +> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) + +Check all logs of the service with: + +```bash +journalctl -b -u reachy2-core +``` diff --git a/content/teleoperation/_index.md b/content/teleoperation/_index.md new file mode 100644 index 00000000..48652df5 --- /dev/null +++ b/content/teleoperation/_index.md @@ -0,0 +1,10 @@ +--- +title: "Teleoperation" +description: "Use the VR teleoperation app." +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/teleoperation/compatibility-specs/_index.md b/content/teleoperation/compatibility-specs/_index.md new file mode 100644 index 00000000..ee86eec8 --- /dev/null +++ b/content/teleoperation/compatibility-specs/_index.md @@ -0,0 +1,10 @@ +--- +title: "Compatibility & Specifications" +description: "Find compatible VR headsets and get minimal computer specifications for teleoperation" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/teleoperation/compatibility-specs/compatible-devices.md b/content/teleoperation/compatibility-specs/compatible-devices.md new file mode 100644 index 00000000..1495ec3e --- /dev/null +++ b/content/teleoperation/compatibility-specs/compatible-devices.md @@ -0,0 +1,17 @@ +--- +title: "Compatible devices" +description: "Find compatible VR headsets and get minimal computer specifications for teleoperation" +lead: "Compatible VR headsets and minimal computer specifications for VR teleoperation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Compatibility & Specifications" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/compatibility-specs/latency-network.md b/content/teleoperation/compatibility-specs/latency-network.md new file mode 100644 index 00000000..821434be --- /dev/null +++ b/content/teleoperation/compatibility-specs/latency-network.md @@ -0,0 +1,17 @@ +--- +title: "Latency and network insights" +description: "Get expected latency" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Compatibility & Specifications" +weight: 300 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/getting-started-teleoperation/_index.md b/content/teleoperation/getting-started-teleoperation/_index.md new file mode 100644 index 00000000..fec04ceb --- /dev/null +++ b/content/teleoperation/getting-started-teleoperation/_index.md @@ -0,0 +1,10 @@ +--- +title: "Getting started with teleoperation" +description: "Find out how to start with the VR application for teleoperation" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/teleoperation/getting-started-teleoperation/best-practice.md b/content/teleoperation/getting-started-teleoperation/best-practice.md new file mode 100644 index 00000000..2817439c --- /dev/null +++ b/content/teleoperation/getting-started-teleoperation/best-practice.md @@ -0,0 +1,17 @@ +--- +title: "Best practice" +description: "Safety guidelines and other best practice for a safe teleoperation" +lead: "Safety guidelines and other best practice for a safe teleoperation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Getting started with teleoperation" +weight: 400 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/getting-started-teleoperation/connect-reachy2.md b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md new file mode 100644 index 00000000..ef884212 --- /dev/null +++ b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md @@ -0,0 +1,17 @@ +--- +title: "Connect to Reachy 2" +description: "Establish connection with the robot form the VR teleoperation application" +lead: "Establish connection with the robot form the VR teleoperation application" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Getting started with teleoperation" +weight: 300 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/getting-started-teleoperation/installation.md b/content/teleoperation/getting-started-teleoperation/installation.md new file mode 100644 index 00000000..6c6cc955 --- /dev/null +++ b/content/teleoperation/getting-started-teleoperation/installation.md @@ -0,0 +1,17 @@ +--- +title: "Installation" +description: "Download and install the latest VR teleoperation application" +lead: "Download and install the latest VR teleoperation application" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Getting started with teleoperation" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/_index.md b/content/teleoperation/using-application/_index.md new file mode 100644 index 00000000..edc0a6c6 --- /dev/null +++ b/content/teleoperation/using-application/_index.md @@ -0,0 +1,10 @@ +--- +title: "Using Reachy2Teleoperation application" +description: "Find out how to use Reachy2Teleoperation VR application for teleoperation" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/teleoperation/using-application/control-mobile-base.md b/content/teleoperation/using-application/control-mobile-base.md new file mode 100644 index 00000000..42408fab --- /dev/null +++ b/content/teleoperation/using-application/control-mobile-base.md @@ -0,0 +1,17 @@ +--- +title: "Control the mobile base" +description: "Use the mobile base in teleoperation" +lead: "Use the mobile base in teleoperation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/controllers-inputs.md b/content/teleoperation/using-application/controllers-inputs.md new file mode 100644 index 00000000..3dcc40a3 --- /dev/null +++ b/content/teleoperation/using-application/controllers-inputs.md @@ -0,0 +1,17 @@ +--- +title: "Controllers inputs" +description: "Mapping between controllers and teleoperation features" +lead: "Mapping between controllers and teleoperation features" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/customize-teleop-session.md b/content/teleoperation/using-application/customize-teleop-session.md new file mode 100644 index 00000000..cffb785e --- /dev/null +++ b/content/teleoperation/using-application/customize-teleop-session.md @@ -0,0 +1,17 @@ +--- +title: "Customize your teleop session" +description: "Customize motion sickness effects and other user prefs" +lead: "Customize motion sickness effects and other user prefs" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/emergency-stop.md b/content/teleoperation/using-application/emergency-stop.md new file mode 100644 index 00000000..aadefd5c --- /dev/null +++ b/content/teleoperation/using-application/emergency-stop.md @@ -0,0 +1,17 @@ +--- +title: "Emergency stop" +description: "Quickly stop robot movements in teleoperation" +lead: "Quickly stop robot movements in teleoperation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 300 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/step-by-step.md b/content/teleoperation/using-application/step-by-step.md new file mode 100644 index 00000000..32bc448c --- /dev/null +++ b/content/teleoperation/using-application/step-by-step.md @@ -0,0 +1,17 @@ +--- +title: "Step-by-step starting" +description: "Start and stop teleoperation" +lead: "Start and stop teleoperation" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file diff --git a/content/teleoperation/using-application/teleoperation-messages.md b/content/teleoperation/using-application/teleoperation-messages.md new file mode 100644 index 00000000..19284fff --- /dev/null +++ b/content/teleoperation/using-application/teleoperation-messages.md @@ -0,0 +1,17 @@ +--- +title: "Teleoperation messages" +description: "Understand displayed information during teleoperation sessions" +lead: "Understand displayed information during teleoperation sessions" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + teleoperation: + parent: "Using Reachy2Teleoperation application" +weight: 200 +toc: true +--- + +This is how you assemble your robot \ No newline at end of file From 4c81bbc23a6b11d619ec31fabe003a0241b75db0 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 03:51:29 +0100 Subject: [PATCH 2/8] Update first page content --- content/_index.md | 2 +- layouts/index.html | 64 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/content/_index.md b/content/_index.md index 0eaef33b..fe5ba615 100644 --- a/content/_index.md +++ b/content/_index.md @@ -1,5 +1,5 @@ --- -title : "Reachy 2 (beta) Documentation" +title : "Reachy 2 Documentation" description: "Reachy 2 Documentation" lead: "Covers everything you need to know from the physical installation of Reachy 2 to advanced uses like VR teleoperation." date: 2020-10-06T08:47:36+00:00 diff --git a/layouts/index.html b/layouts/index.html index 99e43e5b..7e34b01c 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -18,31 +18,67 @@

{{ .Title }}

-
-

Setup Reachy 2

-

Just got your Reachy kit? Check how to install your robot and start having fun with it.

+

Getting Started

+

+

+

-

Python SDK

-

Easy control of a Reachy robot in Python: read sensor information (eg. camera, joint position, force) and send actuator commands.

+

Hardware guide

+

+

+

+
+
-

VR teleoperation

-

Control the robot remotely using Reachy's VR teleoperation application.

+

Developing with Reachy 2

+

+

+

-

Dashboard

-

Use Reachy's dashboard to easily debug and do basic control.

+

Teleoperation

+

+

+

-

FAQ/Support

-

Can't solve your problem? Ask for help!

+

AI with Reachy 2

+

+

+

From f5a284fb2447b5b55e0fc04c90e0fe26bc6d190c Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 04:04:41 +0100 Subject: [PATCH 3/8] Add buttons --- layouts/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/layouts/index.html b/layouts/index.html index 7e34b01c..f2b3cf54 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -6,6 +6,8 @@

{{ .Title }}

{{ .Params.lead | safeHTML }}

+ Getting started + Safety guidelines
From 133c8e5872a080433cce772cd80e22b6b771b13b Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 11:44:34 +0100 Subject: [PATCH 4/8] Sort content correctly --- content/developing/advanced-tutos/_index.md | 5 ++++- content/developing/advanced-tutos/reachy-awakening.md | 2 +- content/developing/advanced-tutos/reachy-the-greengrocer.md | 2 +- content/developing/advanced-tutos/reachy-the-mime.md | 2 +- content/developing/basics/1-hello-world.md | 2 +- content/developing/basics/2-understand-moves.md | 2 +- content/developing/basics/3-basic-arm-control.md | 2 +- content/developing/basics/4-use-arm-kinematics.md | 2 +- content/developing/basics/5-control-head.md | 2 +- content/developing/basics/6-get-images-from-cameras.md | 2 +- content/developing/basics/7-record-replay-trajectories.md | 2 +- content/developing/basics/8-use-mobile-base.md | 2 +- content/developing/basics/_index.md | 3 +++ content/developing/getting-started-sdk/_index.md | 3 +++ content/developing/getting-started-sdk/connect-reachy2.md | 2 +- .../developing/getting-started-sdk/visualize-fake-robot.md | 2 +- content/developing/simulation/_index.md | 3 +++ content/developing/simulation/simulation-installation.md | 2 +- content/getting-started/dashboard/_index.md | 4 +++- content/getting-started/dashboard/discover.md | 2 +- content/getting-started/safety-first/_index.md | 4 ++++ content/getting-started/setup-reachy2/_index.md | 3 +++ content/getting-started/setup-reachy2/connect-reachy2.md | 2 +- content/getting-started/setup-reachy2/start-reachy2.md | 2 +- content/getting-started/setup-reachy2/stop-reachy2.md | 2 +- content/getting-started/update-reachy2/_index.md | 3 +++ content/getting-started/update-reachy2/update-software.md | 2 +- content/hardware-guide/makers/_index.md | 3 +++ content/hardware-guide/makers/cad-files.md | 2 +- content/hardware-guide/specifications/_index.md | 3 +++ content/hardware-guide/specifications/audio.md | 2 +- content/hardware-guide/specifications/general.md | 2 +- content/hardware-guide/specifications/grippers.md | 2 +- content/hardware-guide/specifications/mobile-base.md | 2 +- content/hardware-guide/specifications/motors-actuators.md | 2 +- content/hardware-guide/specifications/vision.md | 2 +- content/help/contact-support/_index.md | 3 +++ content/help/contact-support/need-somebody.md | 2 +- content/help/debug/_index.md | 3 +++ content/help/debug/debug-checklist.md | 2 +- content/help/faq/_index.md | 3 +++ content/help/faq/robot-faq.md | 2 +- content/help/faq/sdk-faq.md | 2 +- content/help/faq/teleoperation-faq.md | 2 +- content/teleoperation/compatibility-specs/_index.md | 3 +++ .../teleoperation/compatibility-specs/compatible-devices.md | 2 +- content/teleoperation/compatibility-specs/latency-network.md | 2 +- .../teleoperation/getting-started-teleoperation/_index.md | 3 +++ .../getting-started-teleoperation/best-practice.md | 2 +- .../getting-started-teleoperation/connect-reachy2.md | 2 +- content/teleoperation/using-application/_index.md | 3 +++ .../teleoperation/using-application/control-mobile-base.md | 2 +- .../teleoperation/using-application/controllers-inputs.md | 2 +- .../using-application/customize-teleop-session.md | 2 +- content/teleoperation/using-application/emergency-stop.md | 2 +- content/teleoperation/using-application/step-by-step.md | 2 +- .../using-application/teleoperation-messages.md | 2 +- 57 files changed, 91 insertions(+), 43 deletions(-) diff --git a/content/developing/advanced-tutos/_index.md b/content/developing/advanced-tutos/_index.md index 1d759032..fe03e69d 100644 --- a/content/developing/advanced-tutos/_index.md +++ b/content/developing/advanced-tutos/_index.md @@ -1,5 +1,5 @@ --- -title: "Advanced tutos" +title: "Advanced tutorials" description: "Practice the use of the SDK with advanced tutorials" lead: "" date: 2023-07-25T15:34:02+02:00 @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + developing: +weight: 30 --- diff --git a/content/developing/advanced-tutos/reachy-awakening.md b/content/developing/advanced-tutos/reachy-awakening.md index daf008f3..fd3d9477 100644 --- a/content/developing/advanced-tutos/reachy-awakening.md +++ b/content/developing/advanced-tutos/reachy-awakening.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Advanced tutorials" -weight: 100 +weight: 300 toc: true --- diff --git a/content/developing/advanced-tutos/reachy-the-greengrocer.md b/content/developing/advanced-tutos/reachy-the-greengrocer.md index c1e5c832..393c0134 100644 --- a/content/developing/advanced-tutos/reachy-the-greengrocer.md +++ b/content/developing/advanced-tutos/reachy-the-greengrocer.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Advanced tutorials" -weight: 100 +weight: 320 toc: true --- diff --git a/content/developing/advanced-tutos/reachy-the-mime.md b/content/developing/advanced-tutos/reachy-the-mime.md index 55f6e33c..395c7bed 100644 --- a/content/developing/advanced-tutos/reachy-the-mime.md +++ b/content/developing/advanced-tutos/reachy-the-mime.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Advanced tutorials" -weight: 100 +weight: 310 toc: true --- diff --git a/content/developing/basics/1-hello-world.md b/content/developing/basics/1-hello-world.md index 0ddbc8e4..1aa444f3 100644 --- a/content/developing/basics/1-hello-world.md +++ b/content/developing/basics/1-hello-world.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 200 toc: true --- diff --git a/content/developing/basics/2-understand-moves.md b/content/developing/basics/2-understand-moves.md index 53a67763..7ceb4c30 100644 --- a/content/developing/basics/2-understand-moves.md +++ b/content/developing/basics/2-understand-moves.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 210 toc: true --- diff --git a/content/developing/basics/3-basic-arm-control.md b/content/developing/basics/3-basic-arm-control.md index 57eb4297..b5c1bfc3 100644 --- a/content/developing/basics/3-basic-arm-control.md +++ b/content/developing/basics/3-basic-arm-control.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 220 toc: true --- diff --git a/content/developing/basics/4-use-arm-kinematics.md b/content/developing/basics/4-use-arm-kinematics.md index bfb730f7..1276712c 100644 --- a/content/developing/basics/4-use-arm-kinematics.md +++ b/content/developing/basics/4-use-arm-kinematics.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 230 toc: true --- diff --git a/content/developing/basics/5-control-head.md b/content/developing/basics/5-control-head.md index 1571b09d..96681d45 100644 --- a/content/developing/basics/5-control-head.md +++ b/content/developing/basics/5-control-head.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 240 toc: true --- diff --git a/content/developing/basics/6-get-images-from-cameras.md b/content/developing/basics/6-get-images-from-cameras.md index 6b0e1b6c..2e7cb13b 100644 --- a/content/developing/basics/6-get-images-from-cameras.md +++ b/content/developing/basics/6-get-images-from-cameras.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 250 toc: true --- diff --git a/content/developing/basics/7-record-replay-trajectories.md b/content/developing/basics/7-record-replay-trajectories.md index 78cc797b..13f117c5 100644 --- a/content/developing/basics/7-record-replay-trajectories.md +++ b/content/developing/basics/7-record-replay-trajectories.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 260 toc: true --- diff --git a/content/developing/basics/8-use-mobile-base.md b/content/developing/basics/8-use-mobile-base.md index f19c1e60..8838070f 100644 --- a/content/developing/basics/8-use-mobile-base.md +++ b/content/developing/basics/8-use-mobile-base.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "SDK basics" -weight: 100 +weight: 270 toc: true --- diff --git a/content/developing/basics/_index.md b/content/developing/basics/_index.md index db5a7434..70a28837 100644 --- a/content/developing/basics/_index.md +++ b/content/developing/basics/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + developing: +weight: 20 --- diff --git a/content/developing/getting-started-sdk/_index.md b/content/developing/getting-started-sdk/_index.md index b9d4914c..fd436830 100644 --- a/content/developing/getting-started-sdk/_index.md +++ b/content/developing/getting-started-sdk/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + developing: +weight: 10 --- diff --git a/content/developing/getting-started-sdk/connect-reachy2.md b/content/developing/getting-started-sdk/connect-reachy2.md index 76b8a5f2..20d68d1d 100644 --- a/content/developing/getting-started-sdk/connect-reachy2.md +++ b/content/developing/getting-started-sdk/connect-reachy2.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Getting started with the SDK" -weight: 100 +weight: 110 toc: true --- diff --git a/content/developing/getting-started-sdk/visualize-fake-robot.md b/content/developing/getting-started-sdk/visualize-fake-robot.md index e56dc96e..504bfa54 100644 --- a/content/developing/getting-started-sdk/visualize-fake-robot.md +++ b/content/developing/getting-started-sdk/visualize-fake-robot.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Getting started with the SDK" -weight: 100 +weight: 120 toc: true --- diff --git a/content/developing/simulation/_index.md b/content/developing/simulation/_index.md index 8a62daff..8eab7fcb 100644 --- a/content/developing/simulation/_index.md +++ b/content/developing/simulation/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + developing: +weight: 40 --- diff --git a/content/developing/simulation/simulation-installation.md b/content/developing/simulation/simulation-installation.md index 9ae55a02..47a64eb0 100644 --- a/content/developing/simulation/simulation-installation.md +++ b/content/developing/simulation/simulation-installation.md @@ -10,7 +10,7 @@ type: docs menu: developing: parent: "Simulation" -weight: 100 +weight: 400 toc: true --- diff --git a/content/getting-started/dashboard/_index.md b/content/getting-started/dashboard/_index.md index 1fba4e97..78ba1f00 100644 --- a/content/getting-started/dashboard/_index.md +++ b/content/getting-started/dashboard/_index.md @@ -7,5 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs -weigth: 1000 +menu: + getting-started: +weigth: 40 --- diff --git a/content/getting-started/dashboard/discover.md b/content/getting-started/dashboard/discover.md index 6c13ade7..95cee889 100644 --- a/content/getting-started/dashboard/discover.md +++ b/content/getting-started/dashboard/discover.md @@ -10,7 +10,7 @@ type: docs menu: getting-started: parent: "Dashboard" -weight: 1000 +weight: 400 toc: true --- diff --git a/content/getting-started/safety-first/_index.md b/content/getting-started/safety-first/_index.md index 7d72640e..f5fb33bb 100644 --- a/content/getting-started/safety-first/_index.md +++ b/content/getting-started/safety-first/_index.md @@ -6,4 +6,8 @@ lastmod: 2023-07-25T15:34:19+02:00 draft: false images: [] type: docs +menu: + getting-started: +weight: 10 +toc: true --- diff --git a/content/getting-started/setup-reachy2/_index.md b/content/getting-started/setup-reachy2/_index.md index a8c4f89f..2f4c4583 100644 --- a/content/getting-started/setup-reachy2/_index.md +++ b/content/getting-started/setup-reachy2/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + getting-started: +weight: 20 --- diff --git a/content/getting-started/setup-reachy2/connect-reachy2.md b/content/getting-started/setup-reachy2/connect-reachy2.md index 9efcd0c3..155fbf20 100644 --- a/content/getting-started/setup-reachy2/connect-reachy2.md +++ b/content/getting-started/setup-reachy2/connect-reachy2.md @@ -10,7 +10,7 @@ type: docs menu: getting-started: parent: "Setup Reachy 2" -weight: 400 +weight: 220 toc: true --- diff --git a/content/getting-started/setup-reachy2/start-reachy2.md b/content/getting-started/setup-reachy2/start-reachy2.md index f1e59a70..5ae89a9e 100644 --- a/content/getting-started/setup-reachy2/start-reachy2.md +++ b/content/getting-started/setup-reachy2/start-reachy2.md @@ -10,7 +10,7 @@ type: docs menu: getting-started: parent: "Setup Reachy 2" -weight: 300 +weight: 210 toc: true --- diff --git a/content/getting-started/setup-reachy2/stop-reachy2.md b/content/getting-started/setup-reachy2/stop-reachy2.md index a8ff99f9..da5dcef9 100644 --- a/content/getting-started/setup-reachy2/stop-reachy2.md +++ b/content/getting-started/setup-reachy2/stop-reachy2.md @@ -10,7 +10,7 @@ type: docs menu: getting-started: parent: "Setup Reachy 2" -weight: 500 +weight: 230 toc: true --- diff --git a/content/getting-started/update-reachy2/_index.md b/content/getting-started/update-reachy2/_index.md index ab6f6805..89793449 100644 --- a/content/getting-started/update-reachy2/_index.md +++ b/content/getting-started/update-reachy2/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + getting-started: +weight: 30 --- diff --git a/content/getting-started/update-reachy2/update-software.md b/content/getting-started/update-reachy2/update-software.md index 1eb47e41..1725f80c 100644 --- a/content/getting-started/update-reachy2/update-software.md +++ b/content/getting-started/update-reachy2/update-software.md @@ -10,7 +10,7 @@ type: docs menu: getting-started: parent: "Update Reachy 2" -weight: 200 +weight: 300 toc: true --- diff --git a/content/hardware-guide/makers/_index.md b/content/hardware-guide/makers/_index.md index 3e0c001e..66c29962 100644 --- a/content/hardware-guide/makers/_index.md +++ b/content/hardware-guide/makers/_index.md @@ -6,5 +6,8 @@ date: 2023-07-25T15:34:02+02:00 lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] +menu: + hardware-guide: +weight: 20 type: docs --- diff --git a/content/hardware-guide/makers/cad-files.md b/content/hardware-guide/makers/cad-files.md index 5a90be9d..96f49c1d 100644 --- a/content/hardware-guide/makers/cad-files.md +++ b/content/hardware-guide/makers/cad-files.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Makers" -weight: 500 +weight: 200 toc: true --- diff --git a/content/hardware-guide/specifications/_index.md b/content/hardware-guide/specifications/_index.md index 0704196c..d749f208 100644 --- a/content/hardware-guide/specifications/_index.md +++ b/content/hardware-guide/specifications/_index.md @@ -6,5 +6,8 @@ date: 2023-07-25T15:34:02+02:00 lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] +menu: + hardware-guide: +weight: 10 type: docs --- diff --git a/content/hardware-guide/specifications/audio.md b/content/hardware-guide/specifications/audio.md index af3b686c..daa7b7ff 100644 --- a/content/hardware-guide/specifications/audio.md +++ b/content/hardware-guide/specifications/audio.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 500 +weight: 120 toc: true --- diff --git a/content/hardware-guide/specifications/general.md b/content/hardware-guide/specifications/general.md index fff9b431..a7d5f26a 100644 --- a/content/hardware-guide/specifications/general.md +++ b/content/hardware-guide/specifications/general.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 300 +weight: 100 toc: true --- diff --git a/content/hardware-guide/specifications/grippers.md b/content/hardware-guide/specifications/grippers.md index 564e9552..a9372c36 100644 --- a/content/hardware-guide/specifications/grippers.md +++ b/content/hardware-guide/specifications/grippers.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 800 +weight: 140 toc: true --- diff --git a/content/hardware-guide/specifications/mobile-base.md b/content/hardware-guide/specifications/mobile-base.md index a1f93078..5101df32 100644 --- a/content/hardware-guide/specifications/mobile-base.md +++ b/content/hardware-guide/specifications/mobile-base.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 700 +weight: 150 toc: true --- diff --git a/content/hardware-guide/specifications/motors-actuators.md b/content/hardware-guide/specifications/motors-actuators.md index effa5a0b..073a8610 100644 --- a/content/hardware-guide/specifications/motors-actuators.md +++ b/content/hardware-guide/specifications/motors-actuators.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 600 +weight: 130 toc: true --- diff --git a/content/hardware-guide/specifications/vision.md b/content/hardware-guide/specifications/vision.md index 43c98f15..40e23feb 100644 --- a/content/hardware-guide/specifications/vision.md +++ b/content/hardware-guide/specifications/vision.md @@ -10,7 +10,7 @@ type: docs menu: hardware-guide: parent: "Specifications" -weight: 300 +weight: 110 toc: true --- diff --git a/content/help/contact-support/_index.md b/content/help/contact-support/_index.md index 1fb775d5..77fb27ef 100644 --- a/content/help/contact-support/_index.md +++ b/content/help/contact-support/_index.md @@ -7,4 +7,7 @@ draft: false images: [] weight: 100 type: docs +menu: + help: +weight: 30 --- diff --git a/content/help/contact-support/need-somebody.md b/content/help/contact-support/need-somebody.md index 471f3022..f50af685 100644 --- a/content/help/contact-support/need-somebody.md +++ b/content/help/contact-support/need-somebody.md @@ -11,7 +11,7 @@ menu: help: parent: "Contact support" toc: true -weight: 20 +weight: 300 --- ## Problem with the motors diff --git a/content/help/debug/_index.md b/content/help/debug/_index.md index 6afbb655..2ce19de8 100644 --- a/content/help/debug/_index.md +++ b/content/help/debug/_index.md @@ -7,4 +7,7 @@ draft: false images: [] weight: 100 type: docs +menu: + help: +weight: 10 --- diff --git a/content/help/debug/debug-checklist.md b/content/help/debug/debug-checklist.md index 82211697..3568e3a0 100644 --- a/content/help/debug/debug-checklist.md +++ b/content/help/debug/debug-checklist.md @@ -11,7 +11,7 @@ menu: help: parent: "Debug" toc: true -weight: 20 +weight: 100 --- ## Problem with the motors diff --git a/content/help/faq/_index.md b/content/help/faq/_index.md index 119d6df2..aba79044 100644 --- a/content/help/faq/_index.md +++ b/content/help/faq/_index.md @@ -7,4 +7,7 @@ draft: false images: [] weight: 100 type: docs +menu: + help: +weight: 20 --- diff --git a/content/help/faq/robot-faq.md b/content/help/faq/robot-faq.md index dacaa15d..d831d669 100644 --- a/content/help/faq/robot-faq.md +++ b/content/help/faq/robot-faq.md @@ -11,7 +11,7 @@ menu: help: parent: "FAQ" toc: true -weight: 20 +weight: 200 --- ## Problem with the motors diff --git a/content/help/faq/sdk-faq.md b/content/help/faq/sdk-faq.md index 57c0baa2..39d40b27 100644 --- a/content/help/faq/sdk-faq.md +++ b/content/help/faq/sdk-faq.md @@ -11,7 +11,7 @@ menu: help: parent: "FAQ" toc: true -weight: 20 +weight: 210 --- ## Problem with the motors diff --git a/content/help/faq/teleoperation-faq.md b/content/help/faq/teleoperation-faq.md index 88299853..06d5f1b2 100644 --- a/content/help/faq/teleoperation-faq.md +++ b/content/help/faq/teleoperation-faq.md @@ -11,7 +11,7 @@ menu: help: parent: "FAQ" toc: true -weight: 20 +weight: 230 --- ## Problem with the motors diff --git a/content/teleoperation/compatibility-specs/_index.md b/content/teleoperation/compatibility-specs/_index.md index ee86eec8..34653ffc 100644 --- a/content/teleoperation/compatibility-specs/_index.md +++ b/content/teleoperation/compatibility-specs/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + teleoperation: +weight: 10 --- diff --git a/content/teleoperation/compatibility-specs/compatible-devices.md b/content/teleoperation/compatibility-specs/compatible-devices.md index 1495ec3e..53286f0e 100644 --- a/content/teleoperation/compatibility-specs/compatible-devices.md +++ b/content/teleoperation/compatibility-specs/compatible-devices.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Compatibility & Specifications" -weight: 200 +weight: 100 toc: true --- diff --git a/content/teleoperation/compatibility-specs/latency-network.md b/content/teleoperation/compatibility-specs/latency-network.md index 821434be..9b202d36 100644 --- a/content/teleoperation/compatibility-specs/latency-network.md +++ b/content/teleoperation/compatibility-specs/latency-network.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Compatibility & Specifications" -weight: 300 +weight: 110 toc: true --- diff --git a/content/teleoperation/getting-started-teleoperation/_index.md b/content/teleoperation/getting-started-teleoperation/_index.md index fec04ceb..ef722308 100644 --- a/content/teleoperation/getting-started-teleoperation/_index.md +++ b/content/teleoperation/getting-started-teleoperation/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + teleoperation: +weight: 20 --- diff --git a/content/teleoperation/getting-started-teleoperation/best-practice.md b/content/teleoperation/getting-started-teleoperation/best-practice.md index 2817439c..74b3cacb 100644 --- a/content/teleoperation/getting-started-teleoperation/best-practice.md +++ b/content/teleoperation/getting-started-teleoperation/best-practice.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Getting started with teleoperation" -weight: 400 +weight: 220 toc: true --- diff --git a/content/teleoperation/getting-started-teleoperation/connect-reachy2.md b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md index ef884212..761c88cf 100644 --- a/content/teleoperation/getting-started-teleoperation/connect-reachy2.md +++ b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Getting started with teleoperation" -weight: 300 +weight: 210 toc: true --- diff --git a/content/teleoperation/using-application/_index.md b/content/teleoperation/using-application/_index.md index edc0a6c6..8e45abc2 100644 --- a/content/teleoperation/using-application/_index.md +++ b/content/teleoperation/using-application/_index.md @@ -7,4 +7,7 @@ lastmod: 2023-07-25T15:34:02+02:00 draft: false images: [] type: docs +menu: + teleoperation: +weight: 30 --- diff --git a/content/teleoperation/using-application/control-mobile-base.md b/content/teleoperation/using-application/control-mobile-base.md index 42408fab..4cb59533 100644 --- a/content/teleoperation/using-application/control-mobile-base.md +++ b/content/teleoperation/using-application/control-mobile-base.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 200 +weight: 320 toc: true --- diff --git a/content/teleoperation/using-application/controllers-inputs.md b/content/teleoperation/using-application/controllers-inputs.md index 3dcc40a3..bb5a3870 100644 --- a/content/teleoperation/using-application/controllers-inputs.md +++ b/content/teleoperation/using-application/controllers-inputs.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 200 +weight: 330 toc: true --- diff --git a/content/teleoperation/using-application/customize-teleop-session.md b/content/teleoperation/using-application/customize-teleop-session.md index cffb785e..661a6ecb 100644 --- a/content/teleoperation/using-application/customize-teleop-session.md +++ b/content/teleoperation/using-application/customize-teleop-session.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 200 +weight: 340 toc: true --- diff --git a/content/teleoperation/using-application/emergency-stop.md b/content/teleoperation/using-application/emergency-stop.md index aadefd5c..7bef7397 100644 --- a/content/teleoperation/using-application/emergency-stop.md +++ b/content/teleoperation/using-application/emergency-stop.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 300 +weight: 310 toc: true --- diff --git a/content/teleoperation/using-application/step-by-step.md b/content/teleoperation/using-application/step-by-step.md index 32bc448c..c0a35dd9 100644 --- a/content/teleoperation/using-application/step-by-step.md +++ b/content/teleoperation/using-application/step-by-step.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 200 +weight: 300 toc: true --- diff --git a/content/teleoperation/using-application/teleoperation-messages.md b/content/teleoperation/using-application/teleoperation-messages.md index 19284fff..0414f8f4 100644 --- a/content/teleoperation/using-application/teleoperation-messages.md +++ b/content/teleoperation/using-application/teleoperation-messages.md @@ -10,7 +10,7 @@ type: docs menu: teleoperation: parent: "Using Reachy2Teleoperation application" -weight: 200 +weight: 350 toc: true --- From 0e6f2b4d5c4cf7f70c0f044c092323c4f346c895 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 13:01:51 +0100 Subject: [PATCH 5/8] Finalize first page of documentation --- config/_default/menus/menus.en.toml | 4 +- config/_default/params.toml | 2 +- content/ai-with-reachy-2/_index.md | 10 +++ .../autonomous-behaviors/_index.md | 13 ++++ .../record-data-learning-models.md | 17 +++++ content/ai-with-reachy-2/perception/_index.md | 13 ++++ .../perception/use-pollen-vision.md | 17 +++++ .../_index.md | 0 .../advanced-tutos/_index.md | 2 +- .../advanced-tutos/reachy-awakening.md | 2 +- .../advanced-tutos/reachy-the-greengrocer.md | 2 +- .../advanced-tutos/reachy-the-mime.md | 2 +- .../basics/1-hello-world.md | 2 +- .../basics/2-understand-moves.md | 2 +- .../basics/3-basic-arm-control.md | 2 +- .../basics/4-use-arm-kinematics.md | 2 +- .../basics/5-control-head.md | 2 +- .../basics/6-get-images-from-cameras.md | 2 +- .../basics/7-record-replay-trajectories.md | 2 +- .../basics/8-use-mobile-base.md | 2 +- .../basics/_index.md | 2 +- .../getting-started-sdk/_index.md | 2 +- .../getting-started-sdk/connect-reachy2.md | 2 +- .../getting-started-sdk/installation.md | 2 +- .../visualize-fake-robot.md | 2 +- .../simulation/_index.md | 2 +- .../simulation/simulation-installation.md | 2 +- layouts/index.html | 66 +++++++++---------- 28 files changed, 125 insertions(+), 55 deletions(-) create mode 100644 content/ai-with-reachy-2/_index.md create mode 100644 content/ai-with-reachy-2/autonomous-behaviors/_index.md create mode 100644 content/ai-with-reachy-2/autonomous-behaviors/record-data-learning-models.md create mode 100644 content/ai-with-reachy-2/perception/_index.md create mode 100644 content/ai-with-reachy-2/perception/use-pollen-vision.md rename content/{developing => developing-with-reachy-2}/_index.md (100%) rename content/{developing => developing-with-reachy-2}/advanced-tutos/_index.md (89%) rename content/{developing => developing-with-reachy-2}/advanced-tutos/reachy-awakening.md (91%) rename content/{developing => developing-with-reachy-2}/advanced-tutos/reachy-the-greengrocer.md (92%) rename content/{developing => developing-with-reachy-2}/advanced-tutos/reachy-the-mime.md (91%) rename content/{developing => developing-with-reachy-2}/basics/1-hello-world.md (90%) rename content/{developing => developing-with-reachy-2}/basics/2-understand-moves.md (91%) rename content/{developing => developing-with-reachy-2}/basics/3-basic-arm-control.md (92%) rename content/{developing => developing-with-reachy-2}/basics/4-use-arm-kinematics.md (92%) rename content/{developing => developing-with-reachy-2}/basics/5-control-head.md (91%) rename content/{developing => developing-with-reachy-2}/basics/6-get-images-from-cameras.md (91%) rename content/{developing => developing-with-reachy-2}/basics/7-record-replay-trajectories.md (92%) rename content/{developing => developing-with-reachy-2}/basics/8-use-mobile-base.md (91%) rename content/{developing => developing-with-reachy-2}/basics/_index.md (88%) rename content/{developing => developing-with-reachy-2}/getting-started-sdk/_index.md (88%) rename content/{developing => developing-with-reachy-2}/getting-started-sdk/connect-reachy2.md (92%) rename content/{developing => developing-with-reachy-2}/getting-started-sdk/installation.md (91%) rename content/{developing => developing-with-reachy-2}/getting-started-sdk/visualize-fake-robot.md (93%) rename content/{developing => developing-with-reachy-2}/simulation/_index.md (87%) rename content/{developing => developing-with-reachy-2}/simulation/simulation-installation.md (90%) diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 7bf777bf..2b24f9d9 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -13,8 +13,8 @@ weight = 20 [[main]] - name = "Developing with Reachy 2" - url = "/developing/getting-started-sdk/installation/" + name = "Developing with reachy 2" + url = "/developing-with-reachy-2/getting-started-sdk/installation/" weight = 30 [[main]] diff --git a/config/_default/params.toml b/config/_default/params.toml index fbc4b597..7835048e 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -92,7 +92,7 @@ lastMod = false instantPage = true flexSearch = true searchSectionsShow = [] - searchSectionsIndex = ["getting-started", "hardware-guide", "developing-with", "teleoperation", "help"] + searchSectionsIndex = ["getting-started", "hardware-guide", "developing-with-reachy-2", "teleoperation", "help"] darkMode = true bootStrapJs = true breadCrumb = false diff --git a/content/ai-with-reachy-2/_index.md b/content/ai-with-reachy-2/_index.md new file mode 100644 index 00000000..82eb7268 --- /dev/null +++ b/content/ai-with-reachy-2/_index.md @@ -0,0 +1,10 @@ +--- +title: "AI with Reachy 2" +description: "Begin AI with robotics using Reachy 2" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +--- diff --git a/content/ai-with-reachy-2/autonomous-behaviors/_index.md b/content/ai-with-reachy-2/autonomous-behaviors/_index.md new file mode 100644 index 00000000..d0f6b95d --- /dev/null +++ b/content/ai-with-reachy-2/autonomous-behaviors/_index.md @@ -0,0 +1,13 @@ +--- +title: "Autonomous behaviors" +description: "Teach the robot how to execute simple tasks" +lead: "Teach the robot how to execute simple tasks" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +menu: + ai-with-reachy-2: +weight: 20 +--- diff --git a/content/ai-with-reachy-2/autonomous-behaviors/record-data-learning-models.md b/content/ai-with-reachy-2/autonomous-behaviors/record-data-learning-models.md new file mode 100644 index 00000000..05c89da9 --- /dev/null +++ b/content/ai-with-reachy-2/autonomous-behaviors/record-data-learning-models.md @@ -0,0 +1,17 @@ +--- +title: "Record data for learning models" +description: "Record robot data during task execution to train learning models" +lead: "Record robot data during task execution to train learning models" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + ai-with-reachy-2: + parent: "Autonomous behaviors" +weight: 200 +toc: true +--- + +This is how to update the robot \ No newline at end of file diff --git a/content/ai-with-reachy-2/perception/_index.md b/content/ai-with-reachy-2/perception/_index.md new file mode 100644 index 00000000..c9947ac7 --- /dev/null +++ b/content/ai-with-reachy-2/perception/_index.md @@ -0,0 +1,13 @@ +--- +title: "Perception" +description: "Vision models with Reachy 2" +lead: "" +date: 2023-07-25T15:34:02+02:00 +lastmod: 2023-07-25T15:34:02+02:00 +draft: false +images: [] +type: docs +menu: + ai-with-reachy-2: +weight: 10 +--- diff --git a/content/ai-with-reachy-2/perception/use-pollen-vision.md b/content/ai-with-reachy-2/perception/use-pollen-vision.md new file mode 100644 index 00000000..5ae9abd6 --- /dev/null +++ b/content/ai-with-reachy-2/perception/use-pollen-vision.md @@ -0,0 +1,17 @@ +--- +title: "Use vision models with Reachy 2" +description: "Use vision models with Reachy 2" +lead: "" +date: 2023-07-26T08:05:23+02:00 +lastmod: 2023-07-26T08:05:23+02:00 +draft: false +images: [] +type: docs +menu: + ai-with-reachy-2: + parent: "Perception" +weight: 100 +toc: true +--- + +This is how to update the robot \ No newline at end of file diff --git a/content/developing/_index.md b/content/developing-with-reachy-2/_index.md similarity index 100% rename from content/developing/_index.md rename to content/developing-with-reachy-2/_index.md diff --git a/content/developing/advanced-tutos/_index.md b/content/developing-with-reachy-2/advanced-tutos/_index.md similarity index 89% rename from content/developing/advanced-tutos/_index.md rename to content/developing-with-reachy-2/advanced-tutos/_index.md index fe03e69d..bf8ad40e 100644 --- a/content/developing/advanced-tutos/_index.md +++ b/content/developing-with-reachy-2/advanced-tutos/_index.md @@ -8,6 +8,6 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: weight: 30 --- diff --git a/content/developing/advanced-tutos/reachy-awakening.md b/content/developing-with-reachy-2/advanced-tutos/reachy-awakening.md similarity index 91% rename from content/developing/advanced-tutos/reachy-awakening.md rename to content/developing-with-reachy-2/advanced-tutos/reachy-awakening.md index fd3d9477..fc17eb5f 100644 --- a/content/developing/advanced-tutos/reachy-awakening.md +++ b/content/developing-with-reachy-2/advanced-tutos/reachy-awakening.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Advanced tutorials" weight: 300 toc: true diff --git a/content/developing/advanced-tutos/reachy-the-greengrocer.md b/content/developing-with-reachy-2/advanced-tutos/reachy-the-greengrocer.md similarity index 92% rename from content/developing/advanced-tutos/reachy-the-greengrocer.md rename to content/developing-with-reachy-2/advanced-tutos/reachy-the-greengrocer.md index 393c0134..bebd279b 100644 --- a/content/developing/advanced-tutos/reachy-the-greengrocer.md +++ b/content/developing-with-reachy-2/advanced-tutos/reachy-the-greengrocer.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Advanced tutorials" weight: 320 toc: true diff --git a/content/developing/advanced-tutos/reachy-the-mime.md b/content/developing-with-reachy-2/advanced-tutos/reachy-the-mime.md similarity index 91% rename from content/developing/advanced-tutos/reachy-the-mime.md rename to content/developing-with-reachy-2/advanced-tutos/reachy-the-mime.md index 395c7bed..9c8513a4 100644 --- a/content/developing/advanced-tutos/reachy-the-mime.md +++ b/content/developing-with-reachy-2/advanced-tutos/reachy-the-mime.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Advanced tutorials" weight: 310 toc: true diff --git a/content/developing/basics/1-hello-world.md b/content/developing-with-reachy-2/basics/1-hello-world.md similarity index 90% rename from content/developing/basics/1-hello-world.md rename to content/developing-with-reachy-2/basics/1-hello-world.md index 1aa444f3..1d911764 100644 --- a/content/developing/basics/1-hello-world.md +++ b/content/developing-with-reachy-2/basics/1-hello-world.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 200 toc: true diff --git a/content/developing/basics/2-understand-moves.md b/content/developing-with-reachy-2/basics/2-understand-moves.md similarity index 91% rename from content/developing/basics/2-understand-moves.md rename to content/developing-with-reachy-2/basics/2-understand-moves.md index 7ceb4c30..e196ec93 100644 --- a/content/developing/basics/2-understand-moves.md +++ b/content/developing-with-reachy-2/basics/2-understand-moves.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 210 toc: true diff --git a/content/developing/basics/3-basic-arm-control.md b/content/developing-with-reachy-2/basics/3-basic-arm-control.md similarity index 92% rename from content/developing/basics/3-basic-arm-control.md rename to content/developing-with-reachy-2/basics/3-basic-arm-control.md index b5c1bfc3..b0897886 100644 --- a/content/developing/basics/3-basic-arm-control.md +++ b/content/developing-with-reachy-2/basics/3-basic-arm-control.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 220 toc: true diff --git a/content/developing/basics/4-use-arm-kinematics.md b/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md similarity index 92% rename from content/developing/basics/4-use-arm-kinematics.md rename to content/developing-with-reachy-2/basics/4-use-arm-kinematics.md index 1276712c..6cee37dc 100644 --- a/content/developing/basics/4-use-arm-kinematics.md +++ b/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 230 toc: true diff --git a/content/developing/basics/5-control-head.md b/content/developing-with-reachy-2/basics/5-control-head.md similarity index 91% rename from content/developing/basics/5-control-head.md rename to content/developing-with-reachy-2/basics/5-control-head.md index 96681d45..d7ba2937 100644 --- a/content/developing/basics/5-control-head.md +++ b/content/developing-with-reachy-2/basics/5-control-head.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 240 toc: true diff --git a/content/developing/basics/6-get-images-from-cameras.md b/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md similarity index 91% rename from content/developing/basics/6-get-images-from-cameras.md rename to content/developing-with-reachy-2/basics/6-get-images-from-cameras.md index 2e7cb13b..b0b228bd 100644 --- a/content/developing/basics/6-get-images-from-cameras.md +++ b/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 250 toc: true diff --git a/content/developing/basics/7-record-replay-trajectories.md b/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md similarity index 92% rename from content/developing/basics/7-record-replay-trajectories.md rename to content/developing-with-reachy-2/basics/7-record-replay-trajectories.md index 13f117c5..645f770e 100644 --- a/content/developing/basics/7-record-replay-trajectories.md +++ b/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 260 toc: true diff --git a/content/developing/basics/8-use-mobile-base.md b/content/developing-with-reachy-2/basics/8-use-mobile-base.md similarity index 91% rename from content/developing/basics/8-use-mobile-base.md rename to content/developing-with-reachy-2/basics/8-use-mobile-base.md index 8838070f..92cc4a07 100644 --- a/content/developing/basics/8-use-mobile-base.md +++ b/content/developing-with-reachy-2/basics/8-use-mobile-base.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "SDK basics" weight: 270 toc: true diff --git a/content/developing/basics/_index.md b/content/developing-with-reachy-2/basics/_index.md similarity index 88% rename from content/developing/basics/_index.md rename to content/developing-with-reachy-2/basics/_index.md index 70a28837..a88285ce 100644 --- a/content/developing/basics/_index.md +++ b/content/developing-with-reachy-2/basics/_index.md @@ -8,6 +8,6 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: weight: 20 --- diff --git a/content/developing/getting-started-sdk/_index.md b/content/developing-with-reachy-2/getting-started-sdk/_index.md similarity index 88% rename from content/developing/getting-started-sdk/_index.md rename to content/developing-with-reachy-2/getting-started-sdk/_index.md index fd436830..dbfbe699 100644 --- a/content/developing/getting-started-sdk/_index.md +++ b/content/developing-with-reachy-2/getting-started-sdk/_index.md @@ -8,6 +8,6 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: weight: 10 --- diff --git a/content/developing/getting-started-sdk/connect-reachy2.md b/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md similarity index 92% rename from content/developing/getting-started-sdk/connect-reachy2.md rename to content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md index 20d68d1d..25f81860 100644 --- a/content/developing/getting-started-sdk/connect-reachy2.md +++ b/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Getting started with the SDK" weight: 110 toc: true diff --git a/content/developing/getting-started-sdk/installation.md b/content/developing-with-reachy-2/getting-started-sdk/installation.md similarity index 91% rename from content/developing/getting-started-sdk/installation.md rename to content/developing-with-reachy-2/getting-started-sdk/installation.md index 8fcc3b69..ea94adfd 100644 --- a/content/developing/getting-started-sdk/installation.md +++ b/content/developing-with-reachy-2/getting-started-sdk/installation.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Getting started with the SDK" weight: 100 toc: true diff --git a/content/developing/getting-started-sdk/visualize-fake-robot.md b/content/developing-with-reachy-2/getting-started-sdk/visualize-fake-robot.md similarity index 93% rename from content/developing/getting-started-sdk/visualize-fake-robot.md rename to content/developing-with-reachy-2/getting-started-sdk/visualize-fake-robot.md index 504bfa54..cedaf280 100644 --- a/content/developing/getting-started-sdk/visualize-fake-robot.md +++ b/content/developing-with-reachy-2/getting-started-sdk/visualize-fake-robot.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Getting started with the SDK" weight: 120 toc: true diff --git a/content/developing/simulation/_index.md b/content/developing-with-reachy-2/simulation/_index.md similarity index 87% rename from content/developing/simulation/_index.md rename to content/developing-with-reachy-2/simulation/_index.md index 8eab7fcb..8ee8dddf 100644 --- a/content/developing/simulation/_index.md +++ b/content/developing-with-reachy-2/simulation/_index.md @@ -8,6 +8,6 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: weight: 40 --- diff --git a/content/developing/simulation/simulation-installation.md b/content/developing-with-reachy-2/simulation/simulation-installation.md similarity index 90% rename from content/developing/simulation/simulation-installation.md rename to content/developing-with-reachy-2/simulation/simulation-installation.md index 47a64eb0..75d0a1ae 100644 --- a/content/developing/simulation/simulation-installation.md +++ b/content/developing-with-reachy-2/simulation/simulation-installation.md @@ -8,7 +8,7 @@ draft: false images: [] type: docs menu: - developing: + developing-with-reachy-2: parent: "Simulation" weight: 400 toc: true diff --git a/layouts/index.html b/layouts/index.html index f2b3cf54..5c319a98 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -4,10 +4,10 @@

{{ .Title }}

-
+

{{ .Params.lead | safeHTML }}

Getting started - Safety guidelines + Safety guidelines
From 27c6f237e90ad27f06ac76f114af06128b503430 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 13:14:33 +0100 Subject: [PATCH 6/8] Fix typos --- .../getting-started/safety-first/safety-guidelines.md | 2 +- layouts/index.html | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/content/getting-started/safety-first/safety-guidelines.md b/content/getting-started/safety-first/safety-guidelines.md index 9e3b8799..d9afd552 100644 --- a/content/getting-started/safety-first/safety-guidelines.md +++ b/content/getting-started/safety-first/safety-guidelines.md @@ -1,7 +1,7 @@ --- title: "Safety guidelines" description: "Safety guidelines as mandatory reading" -lead: "Everything you must know before using Reachyh 2 for a safe experience with the robot" +lead: "Everything you must know before using Reachy 2 for a safe experience with the robot" date: 2023-07-26T08:05:23+02:00 lastmod: 2023-07-26T08:05:23+02:00 draft: false diff --git a/layouts/index.html b/layouts/index.html index 5c319a98..384c0008 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -36,19 +36,19 @@

@@ -83,6 +83,11 @@

+
{{ end }} From 5fe42417b3592f1ff5a64295d6fa267a42b80523 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 16:17:03 +0100 Subject: [PATCH 7/8] Update content --- .../simulation/simulation-installation.md | 41 +++- .../safety-first/safety-guidelines.md | 137 ++++++++++++- .../setup-reachy2/assemble-and-plug.md | 60 +++++- .../setup-reachy2/connect-reachy2.md | 26 ++- .../setup-reachy2/connect-wifi.md | 48 +++++ .../setup-reachy2/start-reachy2.md | 36 +++- .../setup-reachy2/stop-reachy2.md | 31 ++- .../update-reachy2/update-software.md | 45 ++++- content/help/faq/robot-faq.md | 190 ++++++++++++++++-- content/help/faq/sdk-faq.md | 27 --- content/help/faq/teleoperation-faq.md | 23 +-- ...ae17cf1693_91849_1270x740_resize_box_2.png | Bin 0 -> 122071 bytes ...91849_3f6b16ffca8f553b211127d347977ca0.png | Bin 0 -> 647 bytes 13 files changed, 589 insertions(+), 75 deletions(-) create mode 100644 content/getting-started/setup-reachy2/connect-wifi.md create mode 100644 resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_1270x740_resize_box_2.png create mode 100644 resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_3f6b16ffca8f553b211127d347977ca0.png diff --git a/content/developing-with-reachy-2/simulation/simulation-installation.md b/content/developing-with-reachy-2/simulation/simulation-installation.md index 75d0a1ae..8f4f3b45 100644 --- a/content/developing-with-reachy-2/simulation/simulation-installation.md +++ b/content/developing-with-reachy-2/simulation/simulation-installation.md @@ -14,4 +14,43 @@ weight: 400 toc: true --- -Ohlala it's safe now \ No newline at end of file +If you want to try movements on the robot without using the real robot, you can install a simulated Reachy 2 on your computer, and run it the same way the real robot is run. The easiest way is using a docker image. We will thus assume that you already have docker installed and setup. + +Clone the sources of our docker, and pull the sources: +```python +git clone git@github.com:pollen-robotics/docker_reachy2_core.git +cd docker_reachy2_core +./pull_sources.sh beta +``` + +Then download the configuration files: +```python +git clone git@github.com:pollen-robotics/reachy_config_example.git +cp -r reachy_config_example/.reachy_config ~/ +``` + +In your docker_reachy2_core folder, compose a container with: +```python +docker compose -f dev.yaml up -d core +``` +> This can take a few minutes to compose. + +Build: +```python +cbuilds +``` + + +In a first terminal, launch the robot server: +```python +# terminal 1 +docker exec -it core bash +ros2 launch reachy_bringup reachy.launch.py fake:=true start_sdk_server:=true start_rviz:=true +``` +Keep this terminal open, and in a second terminal: +```python +# terminal 2 +docker exec -it core bash +python3 ../dev/reachy2-sdk/src/example/test_goto.py +``` +> If you have the Python SDK installed on your computer, you can launch the example outside the container. diff --git a/content/getting-started/safety-first/safety-guidelines.md b/content/getting-started/safety-first/safety-guidelines.md index d9afd552..e8ea5d6a 100644 --- a/content/getting-started/safety-first/safety-guidelines.md +++ b/content/getting-started/safety-first/safety-guidelines.md @@ -14,4 +14,139 @@ weight: 100 toc: true --- -Ohlala it's safe now \ No newline at end of file + +{{< warning icon="👉🏾" text="Reachy 2 is much more powerful than the previous version. To avoid any accident, please follow carefully the safety guidelines!" >}} + +> There is currently **no automatic collision security** on the robot: it won't stop if hitting anything or anyone, even itself. Remain constantly watchful when using it. + +## Users + +### Attention and reaction + +Users must be in **full possession of their physical and mental powers at all times** when using the robot. Reachy 2 must never be used by someone having consumed substances that could affect their reactions, such as medication, drugs or alcohol. + +Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the [emergency stop button]({{< ref "/sdk/getting-started/safety#emergency-stop-button" >}}). + +### Qualified users + +The robot must not be used if no qualified user is present. + +People using the robot or interacting with it must all be aware of the risks and be explicitly informed of the robot capabilities, limitations and restrictions. They must all be able to act with the appropriate behavior using the robot. + +{{< alert icon="👉" text="No one should use the robot without knowing the safety guidelines." >}} + +## Emergency stop button + +The robot is delivered with an emergency stop button. + +Pressing the emergency stop button will **immediately power off all motors**, from the arms to the mobile base wheels. Nevertheless it won't power off the computer, which means you won't lose anything running on the computer. + +> If you feel like you are losing control of the robot's movements or notice an unexpected behavior at anytime, **never hesitate to press the emergency stop button**. + +Someone must be holding the emergency stop button at any time when using the robot, being ready to press the button if needed, and keep its attention focused on the robot. + +{{< alert icon="👉" text="Objects may fall out of the grippers when pressing the emergency stop button. Make sure they cannot cause injuries." >}} + +## Don't harm yourself... + +Reachy 2 is a powerful robot that may hurt you if it is misused. + +If you do not respect the safety guidelines, you expose yourself to the following risks: +- pinching +- crushing +- punches +- electrical hazard + +### Alertness + +People interacting with the robot or present near its workspace must always look at the robot. + +If the robot is being teleoperated with its mobile base, people in the surroundings must be informed of the robot presence, and the operator must never make the robot pop by surprise near a person or come close to a person, making the person reachable by the arms. + +### Appropriate position + +Do not expose yourself to dangerous punches! + +People must never place their head, or any other body parts, in between or underneath segments of the robot when the robot is in use. Their head should never be reachable by the robots' arms if the robot is in use. + +If people are near the workspace of the robot, they must always stay in a position that allow them to quickly retract or recoil. + +> When the robot is in use, no one should enter or stay in the robot workspace. + +### Free space for retracting + +If people are standing near the robot workspace, make sure they have **sufficient space to retract or recoil**, and that this space is free of obstacles. + +People must never be blocked between the robot and a wall or furniture. + +### Objects manipulation with Reachy 2 + +Be careful with the objects you manipulate with the robot. Sharp and pointed object manipulation is dangerous, do not get close to the robot if it manipulates such objects. + +For all manipulation tasks, users are responsible for assessing the hazards and risks relative to the objects they manipulated with the robot. + +### Manipulate the robot + +When the robot is in use, never manipulate robot parts at the same time. + +Users must be careful if putting their fingers in the actuators or between robot parts to avoid pinching or crushing. +:warning: They must never put their fingers in the actuators or between robot parts if the robot is in use. + +### Hardware intervention + +Never make any hardware intervention on the robot, such as screwing on unscrewing something, if it is powered on. + +### Robot toppling risk + +The following section ["...and don't harm Reachy 2!"]({{< ref "/sdk/getting-started/safety#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. +**All events of the following section can lead to users injuries**, so read them as users safety guidelines as well. + +## ...and don't harm Reachy 2! + +There are a few things you need to know to make sure that your Reachy doesn't get damaged when using it. + +### Carrying heavy objects + +Be careful of the position of the arms when lifting heavy objects with the robot. +Avoid carrying the object to far from the robot torso, mainly to avoid risk of front toppling. + +Do not try to lift objects over 3kg (6.6lb). + +### Pulling/pushing + +Do not try to pull or push elements that are too heavy or oppositing too much! + +This may result in a robot toppling. + +### Obstacles + +Be aware of obstacles! + +When you are sending movements instructions to Reachy, be careful to obstacles the robot can meet. The robot will try to reach the positions you asked for as hard as it can, whether or not there is something on its way. + +Because of the force of the robot, and depending on the weigh or fragility of the object, two things may occur: +- make the object fall and/or break it +- make Reachy 2 tumble + +### Self-collision + +When you are moving both arms simultaneously, there are no safety measures implemented to prevent them from hitting each other. +Nothing will neither prevent Reachy's arms from hitting its chest if you ask them to. + +If situations like these happen, do not hesitate to turn off the motors so that Reachy's motors will stop trying to reach a position they can't get to. + +### Mobile base + +#### Surface + +The mobile robot is made to be used on **flat surfaces**. +Never use the robot on slopes, this may result in a robot toppling. + +#### Speed and movements + +Speed and commands are limited when using the Python SDK, nevertheless you can still generate behaviors that may be dangerous. Do not ask for high speeds and strong stops, or suddent changes of directions. +Provoking oscillations of the robot may lead to a robot toppling. + +### Anti-collision LIDAR safety + +:warning: The anti-collision LIDAR safety has been deactivated. diff --git a/content/getting-started/setup-reachy2/assemble-and-plug.md b/content/getting-started/setup-reachy2/assemble-and-plug.md index ef15e467..e5db8d99 100644 --- a/content/getting-started/setup-reachy2/assemble-and-plug.md +++ b/content/getting-started/setup-reachy2/assemble-and-plug.md @@ -14,4 +14,62 @@ weight: 200 toc: true --- -This is how you assemble your robot \ No newline at end of file + +## Your robot is nearly already assembled! + +{{< alert icon="👉" text="The robot weigh is around 50kg (110lb). You will need to be at least 3 to carry the robot out of the box.
Wear suitable personal protective equipment (e.g. safety shoes) when unpacking the robot. When lifting Reachy 2, pay attention to lift correctly using with your legs, to avoid back injury. Be also aware of your fingers position on the robot." >}} + +Unpack your robot, you just have a few things to plug to finish assembling it. +Check your box contains, in addition to the robot, the following elements: +- a battery charger +- a calibration board +- wifi antennas +- a mini USB cable +- an emergency stop button +- robot antennas screws + +{{< alert icon="👉" text="Make a visual check of all the robot to check nothing seems damage after the travel, especially the cables. In case of doubt on any element, please contact us.
Do not use the robot if something is damaged." >}} + +## Adjust robot size + +Reachy 2 is mounted on its mobile base with a tripod for stability. + +This tripod is **adjustable in height**: choose a suitable height before starting using the robot. + +{{< alert icon="👉" text="Be careful, Reachy 2 is heavy. Ask for help to adjust robot size." >}} + +To do so, maintain the mobile base and ask for someone to maintain the robot's torso. Then unscrew all pods (do not unscrew them too much!), and raise the robot's torso. + +> The button on the cranks are here to modify their positions without unscrewing them. + +## Assemble the last elements + +### Screw the robot antennas + +Stick the antennas in the support on the head, then use the provided screws to fix them, preferably from the back hole. There is one screw by antenna. + +{{< img-center "images/docs/getting-started/antennas.jpg" 400x "Antennas support" >}} + + +### Plug the WiFi antennas + +Plug the wifi antennas on the robot computer, on port 1 and 3. + +{{< img-center "images/docs/getting-started/plug-antennas.jpg" 300x "Wifi antennas emplacement" >}} + +Make sure to place them correctly so that the robot's arms cannot touch them: + +{{< img-center "images/docs/getting-started/wifi-antennas.png" 400x "Wifi antennas position" >}} + +### Plug the emergency stop button + +To plug the emergency state button, you will find a little black connector on the mobile base. Simply connect the button cable to it. + +{{< img-center "images/docs/getting-started/bau-connection.png" 300x "Connect the emergency stop button" >}} + +### Connect the battery + +First make sure the emergency stop button is pressed. +Then plug the yellow connector of the mobile base so the robot will be powered when the emergency stop button will be unpressed. + +{{< img-center "images/docs/getting-started/yellow-connector.png" 300x "Power your robot" >}} diff --git a/content/getting-started/setup-reachy2/connect-reachy2.md b/content/getting-started/setup-reachy2/connect-reachy2.md index 155fbf20..99d63712 100644 --- a/content/getting-started/setup-reachy2/connect-reachy2.md +++ b/content/getting-started/setup-reachy2/connect-reachy2.md @@ -14,4 +14,28 @@ weight: 220 toc: true --- -This is how you connect your robot \ No newline at end of file +> On the **first connection, connect Reachy 2 to your network using an ethernet cable**. You will then be able to choose another network using the dashboard. + +## Hard-wired connection + +Use an **ethernet cable** to connect your robot to the network. + +Ethernet plugs are available at position (c) of the robot's computer interface. +Reachy 2's computer is configured to use DHCP. It should thus be directly accessible on your network. + +{{< img-center "images/docs/network/hardware-interface.png" 400x "hardware-interface" >}} + +To easily find the IP address of the robot, read the little LCD screen plugged in the back of the robot. Wait for the IP address to appear, it may take a few minutes. + +{{< img-center "images/vr/getting-started/lcd-display.png" 200x "lcd-display" >}} + +> Every 10 seconds, the screen switches between WiFi and Ethernet information. + + +## WiFi + +After your first connection with an ethernet connection, simply use the **dashboard** to connect Reachy to WiFi. + + +> **If you cannot use an ethernet connection for your first connection:** + diff --git a/content/getting-started/setup-reachy2/connect-wifi.md b/content/getting-started/setup-reachy2/connect-wifi.md new file mode 100644 index 00000000..e3a26896 --- /dev/null +++ b/content/getting-started/setup-reachy2/connect-wifi.md @@ -0,0 +1,48 @@ +--- +title: "Connect your robot to the WiFi" +description: "How to connect your robot to the WiFi without using the dashboard." +lead: "How to connect Reachy 2 to WiFi without the dashboard" +date: 2023-08-09T14:43:31+02:00 +lastmod: 2023-08-09T14:43:31+02:00 +draft: false +images: [] +toc: true +hidden: true +--- +## WiFi + +On your first connection to a network, the simpliest is to connect your robot with an ethernet cable. + +If you cannot do this: + +Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. + +{{< img-center "images/docs/getting-started/serial-connection.png" 400x "Serial connection port" >}} + +We use `tio`for the serial connection. If you haven't installed it yet on your computer: +`apt install tio` + +{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER
Then reboot your computer for the new group to be effective." >}} + +Then, in a terminal on your computer, get access to the robot with: + +```python +tio /dev/ttyUSB0 +``` + +> Note that the connection could be on another USB port. Check all ports with `ls /dev/ttyUSB*` + +{{< img-center "images/docs/getting-started/tio-terminal.png" 400x "tio connection terminal" >}} + +{{< alert icon="👉" text="Login: bedrock
Password: root" >}} + + +Manually connect the robot to a WiFi with: +```bash +nmcli device wifi connect password +``` + +> For example, with the wifi *POLLEN-WIFI*, with password *superstrongpassword*: +> `nmcli device wifi connect POLLEN-WIFI password superstrongpassword` + +{{< my-button link="/getting-started/setup-reachy2/connect-reachy2/" label="< Back to network connection" >}} \ No newline at end of file diff --git a/content/getting-started/setup-reachy2/start-reachy2.md b/content/getting-started/setup-reachy2/start-reachy2.md index 5ae89a9e..9d4ed837 100644 --- a/content/getting-started/setup-reachy2/start-reachy2.md +++ b/content/getting-started/setup-reachy2/start-reachy2.md @@ -14,4 +14,38 @@ weight: 210 toc: true --- -This is how you start your robot \ No newline at end of file + +## Power up your robot +To start your robot: +1. Press the mobile base button (next to the mobile base's LCD screen). The mobile base's screen should turn on, indicating the current state of the battery (remaining battery percentage, current flow, etc). + +2. **Automatic calibration process** + +Put the robot in a environment with no obstacle, and make sure its arms or grippers are not touching the tripod. + +{{< alert icon="👉" text="The robot is going to slightly move during the calibration. Do not touch the robot during the calibration, and make sure the arms will not meet any obstacle during their movements." >}} + +Press and turn clockwise the emergency stop button to raise it. The automatic calibration process will start. + +> Do not move the robot until the services running on the computer are ready for use. + +

+ {{< video "videos/docs/getting-started/calibration-process.mp4" "40%" >}} +
+ Automatic calibration process +

+ +3. Turn on the robot's computer: +- plug the green connector to the computer. The computer should automatically turn on. + +- if the computer was already plugged, use the (a) button to turn it on. +{{< img-center "images/docs/getting-started/a-button.png" 400x "drawing" >}} + +> We advise to unplug the computer after each use for power saving, because the USB ports are still consuming current when the computer is off. + + +

+ {{< video "videos/docs/getting-started/turn-on-reachy.mp4" "40%" >}} +
+ Full turn on process in video +

diff --git a/content/getting-started/setup-reachy2/stop-reachy2.md b/content/getting-started/setup-reachy2/stop-reachy2.md index da5dcef9..61d24bc2 100644 --- a/content/getting-started/setup-reachy2/stop-reachy2.md +++ b/content/getting-started/setup-reachy2/stop-reachy2.md @@ -14,4 +14,33 @@ weight: 230 toc: true --- -This is how you stop your robot \ No newline at end of file +## Power off your robot + +Power off your robot in the exact opposite order you turned it on! + +To stop your robot: + +1. From the dashboard, click on the Power Off button in the footer. +2. Press the emergency stop button. +3. Press the mobile base button. +4. Wait for the led of the computer to turn off, then unplug the green port from the robot's computer. + + +## Understanding the power buttons and battery life good practices +The mobile base uses the 24V battery to power the wheels directly. DC-DC converters are used to generate 5V (emergency button power, USB HUB power and relay logic) and 12V for the upper body. +The 5V converter draws almost 100mA when idle and is necessary for the emergency button logic. + +The emergency button and the mobile base button both need to be ON to turn on the power relay that shares the 24V with the rest of the robot. However, the mobile base button is the only one that, when turned OFF, shuts down the 5V converter. + + +> :warning: **WARNING!** :warning: When turning off the robot, always turn off the mobile base button to minimize the idle current consumption. If you turn off the robot with the emergency button and didn't press the mobile base button before storing your robot, the battery will deplate faster. + +:bulb: Even with the mobile base button OFF, the battery screen will be powered (low consumption at around ~1mA). If you plan to store the robot for more than a month, we recommend unplugging one of the wires of the battery (like when you received the robot). + + +| Configuration | Storage time before depleting a full battery | +| :-----------------------------------------: | :------------------------------------------: | +| Mobile base button ON, emergency button OFF | A few days | +| Mobile base button OFF | A few months | +| Unplugging the battery | A few years | + diff --git a/content/getting-started/update-reachy2/update-software.md b/content/getting-started/update-reachy2/update-software.md index 1725f80c..d2ec734d 100644 --- a/content/getting-started/update-reachy2/update-software.md +++ b/content/getting-started/update-reachy2/update-software.md @@ -14,4 +14,47 @@ weight: 300 toc: true --- -This is how to update the robot \ No newline at end of file +## Use the dashboard + +The update of the robot can be entirely done with the dashboard. + +From the **Updates** tab, check if updates are available: + +{{< img-center "images/docs/update/dashboard-update-page.png" 600x "" >}} + +> Only advanced update management is working so far + +## Advanced update management + +From the dashboard Update page, click on **Advanced udpate management**: + +{{< img-center "images/docs/update/update.png" 600x "PLUM update" >}} + +> You can directly access the advanced update dashboard from **`http://:5000/`** + +### Fetch updates + +Click **Fetch Updates** to check if there is any available update on one of the robot's services. +Once this is done, you can browse between the 5 services to see if a more recent version is available. + +> For example, an update is available for reachy2-dashboard here: +{{< img-center "images/docs/update/update-available.png" 600x "PLUM update" >}} + +### Install update + +Select the version you want to download for the upgrade, and click on **Pull Container**. +Wait for the message "*service.name* Pulled" to appear in the window. + +{{< img-center "images/docs/update/pull-container.png" 600x "PLUM update" >}} + +When this is done, click on **Generate**. +Wait for the confirmation message to appear. + +{{< img-center "images/docs/update/generate.png" 600x "PLUM Update" >}} + +### Activate the update + +Finish the update installation by clicking on: +1. **Enable**, to activate by default the updated service +2. **Stop**, to stop the current outdated service running +3. **Start**, to launch the updated service diff --git a/content/help/faq/robot-faq.md b/content/help/faq/robot-faq.md index d831d669..d48b3870 100644 --- a/content/help/faq/robot-faq.md +++ b/content/help/faq/robot-faq.md @@ -13,42 +13,194 @@ menu: toc: true weight: 200 --- +## WiFi -## Problem with the motors +On your first connection to a network, the simpliest is to connect your robot with an ethernet cable. -The motors are managed by the reachy2-core service. -Check all logs of the service with: +If you cannot do this: +Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. + +{{< img-center "images/docs/getting-started/serial-connection.png" 400x "Serial connection port" >}} + +We use `tio`for the serial connection. If you haven't installed it yet on your computer: +`apt install tio` + +{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER
Then reboot your computer for the new group to be effective." >}} + +Then, in a terminal on your computer, get access to the robot with: + +```python +tio /dev/ttyUSB0 +``` + +> Note that the connection could be on another USB port. Check all ports with `ls /dev/ttyUSB*` + +{{< img-center "images/docs/getting-started/tio-terminal.png" 400x "tio connection terminal" >}} + +{{< alert icon="👉" text="Login: bedrock
Password: root" >}} + + +Manually connect the robot to a WiFi with: +```bash +nmcli device wifi connect password +``` + +> For example, with the wifi *POLLEN-WIFI*, with password *superstrongpassword*: +> `nmcli device wifi connect POLLEN-WIFI password superstrongpassword` + +There are several ways to connect to your robot. + +## SSH connection +Using the robot's IP address (check [Find Reachy 2's IP]({{< ref "help/system/find-my-ip" >}}) if you don't know it), you can directly connect via ssh to Reachy 2's computer: + +```python +ssh bedrock@ +``` + +> For example, with robot's IP being 192.168.1.42: +> ```python +> ssh bedrock@192.168.1.42 +> ``` + +{{< alert icon="👉" text="Password: root" >}} + +## Hard-wired connection + +Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. + +{{< img-center "images/docs/advanced/serial-connection.png" 500x "Serial connection port" >}} + +We use `tio`for the serial connection. If you haven't installed it yet on your computer: +`apt install tio` + +{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER
Then reboot your computer for the new group to be effective." >}} + +Once connected, open a terminal on your computer and run: +```python +tio /dev/ttyUSB0 +``` +*Note that depending on the elements you connected to the robot, the port could be something else than ttyUSB0. Check other available serial ports with `ls /dev/ttyUSB*`* + +{{< img-center "images/docs/advanced/tio-terminal.png" 500x "Tio connection port" >}} + +{{< alert icon="👉" text="Login: bedrock
Password: root" >}} + +You are then connected to Reachy 2 computer! + +## Avahi connection + +Find the serial number of your robot on its back, connect your computer on the same network as your robot, open a terminal and type: ```bash -journalctl -b -u reachy2-core +ping .local ``` -## Problem with the cameras or sound +>For example, if the serial number is reachy2-beta1: +>```bash +>ping reachy2-beta1.local +>``` + + -### With teleoperation application +{{< alert icon="👉" text="This calibration is for stereovision only. It will only work if the images are clear.

If you want to modify the focus of the cameras because the images are blurred, this requires a hardware intervention on the lenses, which is not covered by the following explanations." >}} -During teleoperation, the cameras and sound are managed by the webrtc service. -This service is automatically launched when you start Reachy 2 computer. +## Repositories installation -> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: ->- that any running client to the sdk has been disconnected ->- that the speaker has been plugged back ->- that the webrtc services has been restarted +The calibration process relies in 2 Pollen Robotics repositories. +The simpliest way is to clone both of these repositories on your computer: -Check all logs of the service with: +- Pollen's `multical` fork. [**Clone the repo**](https://github.com/pollen-robotics/multical), then: +```bash +cd multical +pip install -e . +``` +- `pollen-vision` repo. [**Clone the repo**](https://github.com/pollen-robotics/pollen-vision/tree/develop), then: ```bash -journalctl -b -u webrtc +cd pollen-vision +pip install -e .[depthai_wrapper] ``` -### With the Python SDK +> We recommand to use virtual environments. + +## 1. Charuco calibration board + + + +Go to `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`. + +If you don't have one, generate a charuco board with the following command: + +```console +$ python3 generate_board.py +``` -If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. +Print it on a A4 paper and place it on a flat surface (we use a wooden board). -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) +> You should have received a calibration board with the robot, with the relevant information written behind. -Check all logs of the service with: +Mesure as accurately as possible the size of the squares and the size of the markers and edit the `example_boards/pollen_charuco.yaml` file in the previously cloned `multical` repo to report the values you measured (must be in meters). +## 2. Get some images + +Connect the teleop cameras to your computer. You simply have to disconnect the *teleop cameras* USB connector from the robot's computer and plug it to your computer instead. + +If it is your first calibration, you must add the udev rules with: ```bash -journalctl -b -u reachy2-core +echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="03e7", MODE="0666"' | sudo tee /etc/udev/rules.d/80-movidius.rules +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +Then, still in `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`, run: +```console +$ python3 acquire.py --config CONFIG_IMX296 +``` + +Press `return` to save a pair of images in `./calib_images/` (by default, use `--imagesPath` to change this). + +Try to cover a maximum of the field of view, with the board in a variety of orientations. If the coverage is good, about 30 images is sufficient. +Also, make sure that most of the board is visible by all the cameras for all the saved images pairs. + +Below is an example of good coverage: +{{< img-center "images/docs/advanced/mosaic.png" 500x "Good coverage images" >}} + +## 3. Run multical + +```console +$ cd <...>/multical +$ multical calibrate --image_path --boards example_boards/pollen_charuco.yaml --isFisheye True ``` + +(For some reason, --image_path must be an absolute path, relative paths don't work) + +It will write a `calibration.json` file in ``. + +## 4. Flash the calibration to the EEPROM + +Back in `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`. + +Run: +```console +$ python3 flash.py --config CONFIG_IMX296 --calib_json_file +``` + +A backup file with the current calibration settings stored on the device will be produced in case you need to revert back. + +If needed, run: +```console +$ python3 restore_calibration_backup.py --calib_file CALIBRATION_BACKUP_<...>.json +``` + +## 5. Check the calibration + +Run: +```console +$ python3 check_epilines.py --config CONFIG_IMX296 +``` +And show the aruco board to the cameras. + +An `AVG SLOPE SCORE` below `0.1%` is OK. + +Ideally it could be under `0.05%`. + +The lower, the better. diff --git a/content/help/faq/sdk-faq.md b/content/help/faq/sdk-faq.md index 39d40b27..7b32755a 100644 --- a/content/help/faq/sdk-faq.md +++ b/content/help/faq/sdk-faq.md @@ -14,33 +14,6 @@ toc: true weight: 210 --- -## Problem with the motors - -The motors are managed by the reachy2-core service. -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` - -## Problem with the cameras or sound - -### With teleoperation application - -During teleoperation, the cameras and sound are managed by the webrtc service. -This service is automatically launched when you start Reachy 2 computer. - -> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: ->- that any running client to the sdk has been disconnected ->- that the speaker has been plugged back ->- that the webrtc services has been restarted - -Check all logs of the service with: - -```bash -journalctl -b -u webrtc -``` - ### With the Python SDK If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. diff --git a/content/help/faq/teleoperation-faq.md b/content/help/faq/teleoperation-faq.md index 06d5f1b2..784a1725 100644 --- a/content/help/faq/teleoperation-faq.md +++ b/content/help/faq/teleoperation-faq.md @@ -1,5 +1,5 @@ --- -title : "Teleoperation" +title : "Teleoperation issues" description: "VR teleoperation application FAQ" lead: "Frequently asked questions on VR teleoperation application" date: 2023-07-26T08:44:51+02:00 @@ -14,15 +14,6 @@ toc: true weight: 230 --- -## Problem with the motors - -The motors are managed by the reachy2-core service. -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` - ## Problem with the cameras or sound ### With teleoperation application @@ -40,15 +31,3 @@ Check all logs of the service with: ```bash journalctl -b -u webrtc ``` - -### With the Python SDK - -If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. - -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) - -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` diff --git a/resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_1270x740_resize_box_2.png b/resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_1270x740_resize_box_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c88e78e4704013f0209fdd3ec1b7d02652af13cb GIT binary patch literal 122071 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 XNVrV868!oG_DfYs>uITiS@8b@BD(TM literal 0 HcmV?d00001 diff --git a/resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_3f6b16ffca8f553b211127d347977ca0.png b/resources/_gen/images/logo-pollen_huce698a7cb671e7aa50983aae17cf1693_91849_3f6b16ffca8f553b211127d347977ca0.png new file mode 100644 index 0000000000000000000000000000000000000000..b15dfd0bf6a171d36bd28e0c153c50b14ef144c3 GIT binary patch literal 647 zcmV;20(kw2P)VEAK=c_7!X~!b0I3USXvut z3c4&^h;>md78lZo#Xg`9Gxq&XGIQr#Ng6|STF>gtIp6v5ow-NHf8zF&t^#e1>Le%Y z$L+5+h}sV<_J54WmQG{6|j96tgHuQi`XB-PcFZQ%dE;jd8?$Zx0rj}G*^h<{EYOV|^ z7WvwY5yqR!DkQf+^+P)J{Q@9O~!EUFfT)Bnk~n==RX2FT#$vPbRA?6 zjGEwPgOL^MxtHOLxBdj9rI%orR$xJHx*!GQedm%%m}o7nM#G+Am^rgV2<3r$HKa~N zfO95LGrNHvdm8WDGDrxY!%TQA@ojMuZ_{ZUKd9ltVGXA%f)anuMzz;#OQTh1iPUv~ zt^z2T;371;M=`IAzhG&14L=u#;K)?wa|A#eNX0(AjDE*UZ~o$akAXOLJNNkGYVX0&~7jDEqEKe8=wYm8f#Q5exLH9A$-`qrg8y)YOH4C8%w hcU0~)^E&_l|NrJy^mJ7>Gphgq002ovPDHLkV1kjfD5L-Y literal 0 HcmV?d00001 From 0519242f2e437c2cf7b154794ffe613559c89248 Mon Sep 17 00:00:00 2001 From: glannuzel Date: Thu, 14 Nov 2024 17:29:55 +0100 Subject: [PATCH 8/8] Clean content --- content/advanced/_index.md | 10 - content/advanced/overview/_index.md | 11 - content/advanced/overview/reachy2.md | 20 -- content/advanced/safety/_index.md | 11 - content/advanced/safety/correct-use.md | 75 ---- content/advanced/safety/mobile-base.md | 55 --- content/advanced/services/_index.md | 11 - content/advanced/services/available.md | 61 ---- content/advanced/services/manage-services.md | 64 ---- content/advanced/software/_index.md | 11 - .../advanced/software/configuration-file.md | 61 ---- content/advanced/software/presentation.md | 103 ------ content/advanced/software/ros2-level.md | 163 --------- content/advanced/specifications/_index.md | 11 - content/advanced/specifications/arm-specs.md | 56 --- .../advanced/specifications/general-specs.md | 23 -- .../advanced/specifications/gripper-specs.md | 24 -- content/advanced/specifications/head-specs.md | 38 -- .../specifications/mobile-base-specs.md | 52 --- .../advanced/specifications/orbita-specs.md | 54 --- .../advanced/specifications/torso-specs.md | 40 --- content/dashboard/_index.md | 10 - content/dashboard/content/_index.md | 9 - content/dashboard/content/dashboard.md | 29 -- content/dashboard/content/network.md | 23 -- content/dashboard/content/services.md | 41 --- content/dashboard/content/updates.md | 62 ---- content/dashboard/content/visualization.md | 25 -- content/dashboard/introduction/_index.md | 9 - content/dashboard/introduction/connection.md | 32 -- .../dashboard/introduction/introduction.md | 40 --- .../basics/1-hello-world.md | 279 ++++++++++++++- .../basics/2-understand-moves.md | 231 +++++++++++- .../basics/3-basic-arm-control.md | 224 +++++++++++- .../basics/4-use-arm-kinematics.md | 317 ++++++++++++++++- .../basics/5-control-head.md | 161 ++++++++- .../basics/6-get-images-from-cameras.md | 129 ++++++- .../basics/7-record-replay-trajectories.md | 109 +++++- .../basics/8-use-mobile-base.md | 81 ++++- .../getting-started-sdk/connect-reachy2.md | 23 +- .../getting-started-sdk/installation.md | 33 +- content/docs/_index.md | 9 - content/docs/advanced/_index.md | 9 - content/docs/advanced/access-computer.md | 61 ---- content/docs/advanced/calibrate-cameras.md | 114 ------ content/docs/getting-started/_index.md | 9 - content/docs/getting-started/dashboard.md | 37 -- content/docs/getting-started/hello-world.md | 62 ---- content/docs/getting-started/network.md | 36 -- content/docs/getting-started/safety.md | 147 -------- content/docs/getting-started/turn-off.md | 41 --- content/docs/getting-started/turn-on.md | 48 --- content/docs/getting-started/unpack.md | 70 ---- content/docs/getting-started/wifi.md | 47 --- content/docs/simulation/_index.md | 9 - .../simulation/simulation-installation.md | 51 --- content/docs/update/_index.md | 9 - content/docs/update/update.md | 56 --- content/getting-started/dashboard/discover.md | 50 ++- .../safety-first/safety-guidelines.md | 4 +- content/help/contact-support/need-somebody.md | 37 +- content/help/debug/debug-checklist.md | 42 +-- content/help/faq/robot-faq.md | 2 +- content/help/faq/sdk-faq.md | 2 - content/help/help/_index.md | 10 - content/help/help/debug.md | 51 --- content/help/help/recovering.md | 2 +- content/help/help/support.md | 24 -- content/help/help/torso.md | 20 -- content/help/safety/VR-use.md | 18 - content/help/safety/_index.md | 9 - content/help/safety/correct-use.md | 147 -------- content/help/system/_index.md | 9 - content/help/system/find-my-ip.md | 70 ---- content/sdk/_index.md | 10 - content/sdk/advanced/_index.md | 10 - content/sdk/advanced/mobile-base.md | 70 ---- content/sdk/first-moves/_index.md | 9 - content/sdk/first-moves/arm.md | 241 ------------- content/sdk/first-moves/cameras.md | 140 -------- content/sdk/first-moves/head.md | 173 --------- content/sdk/first-moves/intro.md | 311 ---------------- content/sdk/first-moves/kinematics.md | 331 ------------------ content/sdk/first-moves/mobile-base.md | 92 ----- content/sdk/first-moves/moves.md | 242 ------------- content/sdk/first-moves/record.md | 120 ------- content/sdk/getting-started/_index.md | 10 - content/sdk/getting-started/connect.md | 33 -- content/sdk/getting-started/hello-world.md | 109 ------ content/sdk/getting-started/install.md | 44 --- content/sdk/getting-started/overview.md | 60 ---- content/sdk/getting-started/safety.md | 148 -------- content/sdk/introduction/_index.md | 10 - content/sdk/introduction/introduction.md | 68 ---- content/sdk/mobile-base/_index.md | 9 - content/sdk/mobile-base/safety.md | 45 --- .../compatibility-specs/compatible-devices.md | 32 +- .../best-practice.md | 132 ++++++- .../connect-reachy2.md | 38 +- .../installation.md | 58 ++- .../using-application/controllers-inputs.md | 35 +- .../customize-teleop-session.md | 49 ++- .../using-application/emergency-stop.md | 18 +- .../using-application/step-by-step.md | 145 +++++++- .../teleoperation-messages.md | 14 +- content/vr/_index.md | 9 - content/vr/compatibility/_index.md | 9 - content/vr/compatibility/headsets.md | 26 -- content/vr/compatibility/pc-requirements.md | 23 -- content/vr/getting-started/_index.md | 9 - content/vr/getting-started/check-robot.md | 34 -- content/vr/getting-started/connect.md | 50 --- content/vr/getting-started/installation.md | 69 ---- content/vr/getting-started/setup.md | 60 ---- content/vr/installation.md | 34 -- content/vr/introduction/_index.md | 9 - content/vr/introduction/introduction.md | 20 -- content/vr/problem/_index.md | 9 - content/vr/problem/debug.md | 70 ---- content/vr/problem/support-vr.md | 22 -- content/vr/use-teleop/_index.md | 9 - content/vr/use-teleop/best-practice.md | 143 -------- content/vr/use-teleop/commands.md | 47 --- content/vr/use-teleop/emergency-stop.md | 29 -- content/vr/use-teleop/messages.md | 25 -- content/vr/use-teleop/mobile-base.md | 39 --- content/vr/use-teleop/motion-sickness.md | 50 --- content/vr/use-teleop/start.md | 156 --------- 128 files changed, 2156 insertions(+), 5734 deletions(-) delete mode 100644 content/advanced/_index.md delete mode 100644 content/advanced/overview/_index.md delete mode 100644 content/advanced/overview/reachy2.md delete mode 100644 content/advanced/safety/_index.md delete mode 100644 content/advanced/safety/correct-use.md delete mode 100644 content/advanced/safety/mobile-base.md delete mode 100644 content/advanced/services/_index.md delete mode 100644 content/advanced/services/available.md delete mode 100644 content/advanced/services/manage-services.md delete mode 100644 content/advanced/software/_index.md delete mode 100644 content/advanced/software/configuration-file.md delete mode 100644 content/advanced/software/presentation.md delete mode 100644 content/advanced/software/ros2-level.md delete mode 100644 content/advanced/specifications/_index.md delete mode 100644 content/advanced/specifications/arm-specs.md delete mode 100644 content/advanced/specifications/general-specs.md delete mode 100644 content/advanced/specifications/gripper-specs.md delete mode 100644 content/advanced/specifications/head-specs.md delete mode 100644 content/advanced/specifications/mobile-base-specs.md delete mode 100644 content/advanced/specifications/orbita-specs.md delete mode 100644 content/advanced/specifications/torso-specs.md delete mode 100644 content/dashboard/_index.md delete mode 100644 content/dashboard/content/_index.md delete mode 100644 content/dashboard/content/dashboard.md delete mode 100644 content/dashboard/content/network.md delete mode 100644 content/dashboard/content/services.md delete mode 100644 content/dashboard/content/updates.md delete mode 100644 content/dashboard/content/visualization.md delete mode 100644 content/dashboard/introduction/_index.md delete mode 100644 content/dashboard/introduction/connection.md delete mode 100644 content/dashboard/introduction/introduction.md delete mode 100644 content/docs/_index.md delete mode 100644 content/docs/advanced/_index.md delete mode 100644 content/docs/advanced/access-computer.md delete mode 100644 content/docs/advanced/calibrate-cameras.md delete mode 100644 content/docs/getting-started/_index.md delete mode 100644 content/docs/getting-started/dashboard.md delete mode 100644 content/docs/getting-started/hello-world.md delete mode 100644 content/docs/getting-started/network.md delete mode 100644 content/docs/getting-started/safety.md delete mode 100644 content/docs/getting-started/turn-off.md delete mode 100644 content/docs/getting-started/turn-on.md delete mode 100644 content/docs/getting-started/unpack.md delete mode 100644 content/docs/getting-started/wifi.md delete mode 100644 content/docs/simulation/_index.md delete mode 100644 content/docs/simulation/simulation-installation.md delete mode 100644 content/docs/update/_index.md delete mode 100644 content/docs/update/update.md delete mode 100644 content/help/help/_index.md delete mode 100644 content/help/help/debug.md delete mode 100644 content/help/help/support.md delete mode 100644 content/help/help/torso.md delete mode 100644 content/help/safety/VR-use.md delete mode 100644 content/help/safety/_index.md delete mode 100644 content/help/safety/correct-use.md delete mode 100644 content/help/system/_index.md delete mode 100644 content/help/system/find-my-ip.md delete mode 100644 content/sdk/_index.md delete mode 100644 content/sdk/advanced/_index.md delete mode 100644 content/sdk/advanced/mobile-base.md delete mode 100644 content/sdk/first-moves/_index.md delete mode 100644 content/sdk/first-moves/arm.md delete mode 100644 content/sdk/first-moves/cameras.md delete mode 100644 content/sdk/first-moves/head.md delete mode 100644 content/sdk/first-moves/intro.md delete mode 100644 content/sdk/first-moves/kinematics.md delete mode 100644 content/sdk/first-moves/mobile-base.md delete mode 100644 content/sdk/first-moves/moves.md delete mode 100644 content/sdk/first-moves/record.md delete mode 100644 content/sdk/getting-started/_index.md delete mode 100644 content/sdk/getting-started/connect.md delete mode 100644 content/sdk/getting-started/hello-world.md delete mode 100644 content/sdk/getting-started/install.md delete mode 100644 content/sdk/getting-started/overview.md delete mode 100644 content/sdk/getting-started/safety.md delete mode 100644 content/sdk/introduction/_index.md delete mode 100644 content/sdk/introduction/introduction.md delete mode 100644 content/sdk/mobile-base/_index.md delete mode 100644 content/sdk/mobile-base/safety.md delete mode 100644 content/vr/_index.md delete mode 100644 content/vr/compatibility/_index.md delete mode 100644 content/vr/compatibility/headsets.md delete mode 100644 content/vr/compatibility/pc-requirements.md delete mode 100644 content/vr/getting-started/_index.md delete mode 100644 content/vr/getting-started/check-robot.md delete mode 100644 content/vr/getting-started/connect.md delete mode 100644 content/vr/getting-started/installation.md delete mode 100644 content/vr/getting-started/setup.md delete mode 100644 content/vr/installation.md delete mode 100644 content/vr/introduction/_index.md delete mode 100644 content/vr/introduction/introduction.md delete mode 100644 content/vr/problem/_index.md delete mode 100644 content/vr/problem/debug.md delete mode 100644 content/vr/problem/support-vr.md delete mode 100644 content/vr/use-teleop/_index.md delete mode 100644 content/vr/use-teleop/best-practice.md delete mode 100644 content/vr/use-teleop/commands.md delete mode 100644 content/vr/use-teleop/emergency-stop.md delete mode 100644 content/vr/use-teleop/messages.md delete mode 100644 content/vr/use-teleop/mobile-base.md delete mode 100644 content/vr/use-teleop/motion-sickness.md delete mode 100644 content/vr/use-teleop/start.md diff --git a/content/advanced/_index.md b/content/advanced/_index.md deleted file mode 100644 index bde837fb..00000000 --- a/content/advanced/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title : "Description" -description: "Reachy's description." -lead: "" -date: 2023-07-26T08:02:25+02:00 -lastmod: 2023-07-26T08:02:25+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/advanced/overview/_index.md b/content/advanced/overview/_index.md deleted file mode 100644 index 7e9a408a..00000000 --- a/content/advanced/overview/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title : "Overview" -description: "A quick overview of Reachy." -lead: "" -date: 2023-07-26T08:02:36+02:00 -lastmod: 2023-07-26T08:02:36+02:00 -draft: false -images: [] -type: docs -weight: 100 ---- diff --git a/content/advanced/overview/reachy2.md b/content/advanced/overview/reachy2.md deleted file mode 100644 index 98f20a46..00000000 --- a/content/advanced/overview/reachy2.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "Reachy 2" -description: "Reachy 2 mobile robot." -date: 2023-07-26T08:04:08+02:00 -lastmod: 2023-07-26T08:04:08+02:00 -draft: false -type: docs -menu: - advanced: - parent: "overview" -weight: 120 -toc: true ---- -Reachy + mobile base is composed of two parts: -* a full kit Reachy robot (i.e. with two arms, torso and a head), -* an omnidirectional mobile base - -{{< img-center "images/advanced/overview/reachy-mobile.png" 500x "Reachy on its mobile base" >}} - -For more info on what is included in the mobile base, check the [mobile base specifications]({{< ref "advanced/specifications/mobile-base-specs">}}). diff --git a/content/advanced/safety/_index.md b/content/advanced/safety/_index.md deleted file mode 100644 index 72b3fa89..00000000 --- a/content/advanced/safety/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title : "Safety first" -description: "Safety measures to take when using Reachy and it smobile base." -lead: "" -date: 2023-07-26T08:03:22+02:00 -lastmod: 2023-07-26T08:03:22+02:00 -draft: false -images: [] -type: docs -weight: 120 ---- diff --git a/content/advanced/safety/correct-use.md b/content/advanced/safety/correct-use.md deleted file mode 100644 index 35234442..00000000 --- a/content/advanced/safety/correct-use.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: "Use Reachy properly" -description: "Safety measures with Reachy to protect the user and prevent the robot from damaging. Following this measures will ensure the longetivity of the robot." -lead: "" -date: 2023-07-26T08:04:56+02:00 -lastmod: 2023-07-26T08:04:56+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "safety" -weight: 300 -toc: true ---- - -## Don't harm yourself... - -Even though there is little chance that you get hurt using Reachy, you might get surprised by its movements, especially the first times. - -We recommend that you move both Reachy's arms with your hands before you start programming it. The goal is that you get a sense of Reachy's working space, the positions it can reach so that you won't get hit when you actually send it commands. - -

- {{< video "videos/advanced/safety/movement_compliant.mp4" "50%" >}} -

- -## and don't harm Reachy! - -There are a few things you need to know to make sure that your Reachy doesn't get damaged when using it. - -### Don't stay in stiff mode if you're not moving the robot - -Each Reachy's motor can be in one of two compliance modes: -* **compliant**: the motor is soft and can be freely turned by hand as in the video above. -It cannot be controlled with code, setting a new target position will have no effect. Yet you can still read the motor position. -* **stiff**: the motor is hard and cannot be moved by hand. It can be controlled by setting new target position. In this mode, the motor use its maximum torque to maintain its present position until a target position is sent. You should hear a small noise coming from a motor in stiff mode, especially if you try to move it with your hands, it's totally normal. - -

- {{< video "videos/advanced/safety/stiff.mp4" "50%" >}} -

- -Check out the [Python SDK section]({{< ref "sdk/first-moves/arm#from-the-joints" >}}) on how to switch between the two modes. - - -> #### :rotating_light: What you need to keep in mind -> **You must be careful not to let the joints in stiff mode when you're not using the robot**. This mode can be really demanding for a motor, letting a motor in stiff mode will damage it after some time. -> -> If an arm is lifted or if the neck is lowered, maintaining the position in stiff mode will be exhausting because the motors would have to compensate the gravity and they could get damaged. -> You can make the analogy with a human. If we ask you to keep stretched out arms, after a certain time it will be painful. So is the case for the joints of the robot. - -### Be aware of obstacles - -When you are sending movements instructions to Reachy, mind the obstacles that could block Reachy during its movements. - -For example, when you are asking to an arm to go between two positions, it will try to do it as hard as it can, whether or not there is something on its way. Also when you are moving both arms simultaneously, there are no safety measures implemented to prevent them from hitting each other. -Nothing will also prevent Reachy's arms from hitting its chest if you ask them to. -If situations like these happen, don't hesitate to use the motor's switch in Reachy's back to **immediately turn off** the motors so that Reachy's motors will stop trying to reach a position they can't get. - -### Check the temperatures - -Reachy's motors will heat when you are using its joints so you should manage the motors temperatures. -The temperatures of each motor can be checked with the [dashboard]({{< ref "dashboard/content/dashboard" >}}) or be accessed using [Reachy's Python SDK]({{< ref "/sdk/first-moves/arm#temperature" >}}). - -There are two important temperature constants you need to know, their values depend on Reachy's part: -* **fan trigger temperature**: temperature at which the motor will start to get hot and the matching fan should be turned on automatically. The fans allow to work longer with hot joints but enventually the temperature will keep rising if the joints keep being sollicitated. The default value is 45°C on Reachy. -* **shutdown temperature**: when this temperature is reached, the motor will normally shutdown and stop working until it has cooled down. This is a precaution measure to protect the motor. The default value is 55°C on Reachy. - -Even though there exists a shutdown temperature, we recommand that when you intend on using the robot for a long period, you let the arms rest and their motors cool down regularly (5 minutes rest every 30 minutes of effort). - -## Good practices -Here is a non-exhaustive list of things to remember when you are using your Reachy, in order to make it last as long as possible. - -- Make sure that the robot is turned off and that the power supply is disconnected when you are not using it. -- Remember not to let the motors in stiff mode if you don't plan to make them move. Even letting the arms on a table and in stiff mode for quite some time might damage them. -- Check that no obstacles will be on Reachy's way when it will try to move. Sending commands to Reachy's arms with an obstacle on the way will make the motors force as much as they can. Being in this kind of situation might happen but when this does, remember to turn off the motors immediately using the switch button in Reachy's back. \ No newline at end of file diff --git a/content/advanced/safety/mobile-base.md b/content/advanced/safety/mobile-base.md deleted file mode 100644 index 431b797f..00000000 --- a/content/advanced/safety/mobile-base.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: "Use the mobile base properly" -description: "Safety measures to follow with Reachy's mobile base." -lead: "" -date: 2023-07-26T08:05:05+02:00 -lastmod: 2023-07-26T08:05:05+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "safety" -weight: 310 -toc: true ---- - -## Basic mouvements - -We recommend that you get a feel for the inertia of the robot by holding on to the metal pole and pushing and pulling it. - - -Block a wheel with your foot and try to gently tilt the robot. - - -Then use the controller to move around the robot as explained in [Moving the mobile base]({{< ref "sdk/first-moves/mobile-base" >}}) - -{{< video "videos/advanced/mobile-base/controller_mouvement.mp4" "100%" >}} - -## Common risks and advice -Even though the mobile base is programmed to move relatively slowly, it is important to try to avoid any potential collisions. The mobile base is designed to be used indoors on a flat surface. - -:bulb: The arms and any grasped objects should ideally be in the vertical projection of the mobile base. The idea here is that the robot should always be able to rotate in place safely. Also, keeping the arms tugged in reduces the risk of tipping. - -A low level collision avoidance safety always runs in the background, but it can only prevent collisions seen by the LIDAR. Read more about it in [Anti-collision safety]({{< ref "sdk/mobile-base/safety" >}}). A non exaustive list of cases where the safety can't work: -* Stairwells. There are no cliff sensors so the robot has no practical way of knowing it's near downward stairs. -* A table. The LIDAR can see the legs but not the table top. -* A large clean bay window migh be invisible to the LIDAR. -* Small obstacles that fit below the LIDAR won't be seen. - -Another risk is the robot tipping. Avoid rapid variations in acceleration. Also, we don't recommend using the robot on a slope above 10°. - - -## Battery management -We chose a high end battery for the mobile base. The Life4PO technology and the overal grade of the equipement (BMS, charger, monitoring system, certified UN 38.3, 5 years warranty), should make this one of the safest choices available on the market. -However, the battery can hold a large amount of energy (832 Wh) and should always be treated carefully. - -:warning: Only use the dedicated charger to charge the battery - -:bulb: When stocking the battery for long periods, aim for at least 60% charge - -:bulb: Use the monitoring system (small screen on the mobile base) to recharge the battery before reaching 0% and relying on the BMS to shutdown the battery. - -## Dynamic capabilities -The wheel motors are **very** potent. In their default configuration, they are used at 20% of their maximum capabilities. -You can, at your own risk, modify this limit in the [configuration of the HAL](https://github.com/pollen-robotics/reachy_2023/blob/master/mobile_base_controller/zuuu_hal/config/params.yaml). diff --git a/content/advanced/services/_index.md b/content/advanced/services/_index.md deleted file mode 100644 index 1e6dc52c..00000000 --- a/content/advanced/services/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title : "Services" -description: "Use systemd services with Reachy." -lead: "" -date: 2023-07-26T08:03:33+02:00 -lastmod: 2023-07-26T08:03:33+02:00 -draft: false -images: [] -type: docs -weight: 140 ---- diff --git a/content/advanced/services/available.md b/content/advanced/services/available.md deleted file mode 100644 index 02c77d66..00000000 --- a/content/advanced/services/available.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: "Available system services" -description: "Core services running on Reachy." -lead: "" -date: 2023-07-26T08:05:23+02:00 -lastmod: 2023-07-26T08:05:23+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "services" -weight: 500 -toc: true ---- - -System services are available on the robot to automatically launch at boot the most commonly used features of the robot. It is useful when you just want to use [our Python SDK]({{< ref "sdk/introduction/introduction" >}}) without having to worry about running by hand [Reachy's core ROS code]({{< ref "advanced/software/presentation#ros" >}}). Nevertheless, you may want to use Reachy differently and deactivate them. - -We use system.d to handle the services. If you are not familiar with this system, you should refer to the [official documentation](https://www.freedesktop.org/wiki/Software/systemd/). - -> :bulb: The services are in user mode and stored in `~/.config/systemd/user`. - -## Services available - -### reachy_sdk_server.service - -For each Reachy's configuration except for the Arm kit (i.e. Full, Starter and Mobile kit), the service `reachy_sdk_server.service` is available and enabled by default. - -You can see how the service is defined on [reachy_sdk_server repository](https://github.com/pollen-robotics/reachy_2023/blob/develop/reachy_sdk_server/launch.bash) but basically what this service does is executing a bash file which itself executes the ROS command: - -```bash -ros2 launch reachy_bringup reachy.launch.py start_sdk_server:=true -``` - -The bringup launch file will start each useful Reachy's ROS node like a node to handle the joints, one for the kinematics, another for the cameras (if Reachy's configuration has a head), ... - -For the complete list of the ROS nodes launched by the service, check [reachy.launch.py file](https://github.com/pollen-robotics/reachy_2023/blob/develop/reachy_bringup/launch/reachy.launch.py). - -### reachy_mobile_base.service - -If your Reachy is equipped with a mobile base, the service `reachy_mobile_base.service` is also available and enabled by default. Having separate services for Reachy and the mobile base allows to work separately with the mobile base or Reachy when you have a Reachy Mobile. - -As `reachy_sdk_server.service`, `reachy_mobile_base.service` is defined in the [mobile_base_sdk_server repository](https://github.com/pollen-robotics/reachy_2023/blob/master/mobile_base_controller/mobile_base_sdk_server/launch_mobile_base.bash). The service executes a bash file which itself executes the ROS command: - -```bash -ros2 launch mobile_base_sdk_server run_mobile_base_sdk_server_and_hal.launch.py -``` - -if a mobile base version is specified in Reachy's configuration file. - -The launch file launched will start the ROS nodes for the HAL of the mobile base and the node to start the gRPC SDK server to use the [mobile base Python SDK](https://github.com/pollen-robotics/mobile-base-sdk). - -For the complete list of the ROS nodes launched by the service, check [run_mobile_base_sdk_server_and_hal.launch.py](https://github.com/pollen-robotics/mobile_base_sdk_server/blob/main/launch/run_mobile_base_sdk_server_and_hal.launch.py). - -### reachy_dashboard.service - -The `reachy_dashboard.service` is also available and enabled by default on each Reachy. This service makes sure that the [dashboard]({{< ref "dashboard/introduction/introduction" >}}) is started when the robot boots and that you can check its IP address on the LCD screen installed in its back. - -## What if I don't want to use services - -If you don't want to use the default services, you can simply [disable them]({{< ref "advanced/services/manage-services#enable-or-disable-a-service" >}}) so that they won't start when booting the robot and launch [Reachy's ROS launch files]({{< ref "advanced/software/ros2-level" >}}) by hand. diff --git a/content/advanced/services/manage-services.md b/content/advanced/services/manage-services.md deleted file mode 100644 index 219c65aa..00000000 --- a/content/advanced/services/manage-services.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: "Manage Reachy's services" -description: "Manage Reachy's core services." -lead: "" -date: 2023-07-26T08:05:33+02:00 -lastmod: 2023-07-26T08:05:33+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "services" -weight: 510 -toc: true ---- -## Use the dashboard! - -Each Reachy's service appear in the [services page of the dashboard]({{< ref "/dashboard/content/services">}}). A card is created for each service with three buttons: **restart** (to restart the service), **stop** (to stop it) and **show logs** (to have acces to the status of the service and check what is happening, useful for debug). Using the dashboard is the easiest way to manage Reachy's services. - -:bulb: A card will be created for one of Reachy's services **only if the service is enabled**. - -## Manage the services by hand - -It is of course possible to manage the services using CLI. The following commands are taken from [systemd documentation](https://www.freedesktop.org/wiki/Software/systemd/). For more details, don't hesitate to check the documentation directly. - -### Start, restart or stop a service -Eachy Reachy's services can be started, stopped or restarted by hand. It can be useful for situations where for example you turned Reachy's computer on but forgot to turn on its motors. By restarting *reachy_sdk_server.service*, you would not have to reboot Reachy's computer. - -To start a specific service like [*reachy_sdk_server.service*]({{< ref "/advanced/services/available#reachy_sdk_serverservice" >}}), type the following command in a terminal: -```bash -systemctl --user start reachy_sdk_server.service -``` - -Similarly, you can stop or restart a specific service by replacing the start keyword by either stop or restart. -For example, to restart reachy_sdk_server.service, the command is: -```bash -systemctl --user restart reachy_sdk_server.service -``` - -> Note: if you stop a service, it will start again automatically at the next boot of Reachy's computer. If you would prefer to always have the service stopped, you will have to [disable]({{< ref "/advanced/services/manage-services#enable-or-disable-a-service" >}}) it. - -### Get a service status -Having a service's status can be really useful for debugging. With it you can know whether the service is active or not and especially, you can have access to the latest logs of the service. For example if you can't connect to your Reachy or the mobile base with the Python SDK, there is probably a message in the service explaining why the code has crashed. - -To get the status of a service like *reachy_sdk_server.service*, use - -```bash -systemctl --user status reachy_sdk_server.service -``` - -### Enable or disable a service -There are situations when you would prefer to disable a service completely so that it is never started when Reachy's computer is booting. It might be for example because you would prefer to start Reachy's ROS code by hand to have a finer control on it. - -If that is the case, you can disable a service like *reachy_sdk_server.service* with - -```bash -systemctl --user disable reachy_sdk_server.service -``` - -At any time, if you prefer to work with the service again, you can enable it. - -```bash -systemctl --user enable reachy_sdk_server.service -``` diff --git a/content/advanced/software/_index.md b/content/advanced/software/_index.md deleted file mode 100644 index 0890eda3..00000000 --- a/content/advanced/software/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title : "Reachy's software" -description: "Description of Reachy's software architecture." -lead: "" -date: 2023-07-26T08:03:42+02:00 -lastmod: 2023-07-26T08:03:42+02:00 -draft: false -images: [] -type: docs -weight: 130 ---- diff --git a/content/advanced/software/configuration-file.md b/content/advanced/software/configuration-file.md deleted file mode 100644 index 413bf17d..00000000 --- a/content/advanced/software/configuration-file.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: "Reachy's configuration file" -description: "Reachy's configuration file is used to indicate which Reachy's configuration your robot has and whether a mobile base is connected to the robot or not." -lead: "" -date: 2023-07-26T08:05:52+02:00 -lastmod: 2023-07-26T08:05:52+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "software" -weight: 420 -toc: true ---- -We created a custom yaml file (***~/.reachy.yaml***) to indicate which Reachy's configuration your robot has and whether a mobile base is connected to the robot or not. Having this file is useful to start only the necessary code required by the Reachy version you are using. - -This file is read when [Reachy's main services]({{< ref "/advanced/services/available" >}}) are launched at boot or by the bringup launch file. - -The configuration file has multiple entries: -- **model**: model of your Reachy (if it is a full kit, a starter kit, ...). When [reachy_sdk_server.service]({{< ref "/advanced/services/available#reachy_sdk_serverservice" >}}) starts, it will look at this entry to choose what code it has to run depending on the model of the robot. -- **zuuu_model**: is at None if no mobile base is attached with the robot, else the mobile base version is indicated (current mobile base version is 1.2). When [reachy_mobile_base.service]({{< ref "/advanced/services/available#reachy_mobile_baseservice" >}}) starts, if *zuuu_model* is not None, the mobile base code is launched. -- **neck_zero_hardware**: hardware position of the three disks. You should not need to change those values unless you changed Orbita. -- **fan_trigger_temperature**: temperature used to determine whether or not Reachy's fans need to be turned on to cool the motors off. The default value is 45°C. - - -Typically, *~/.reachy.yaml* looks like this: - -```yaml -generation: 2023 -model: full_kit -zuuu_version: 1.2 -neck_orbita_zero: - top: 0.0 - middle: 0.0 - bottom: 0.0 -fan_trigger_temperature: 45 -camera_parameters: - left: - fx: 0.0 - fy: 0.0 - cx: 0.0 - cy: 0.0 - k1: 0.0 - k2: 0.0 - k3: 0.0 - p1: 0.0 - p2: 0.0 - right: - fx: 0.0 - fy: 0.0 - cx: 0.0 - cy: 0.0 - k1: 0.0 - k2: 0.0 - k3: 0.0 - p1: 0.0 - p2: 0.0 -``` - -You can find a template [here](https://github.com/pollen-robotics/reachy_2023/blob/develop/reachy_utils/reachy_utils/files/.reachy.yaml). diff --git a/content/advanced/software/presentation.md b/content/advanced/software/presentation.md deleted file mode 100644 index 9d96d557..00000000 --- a/content/advanced/software/presentation.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: "Overall presentation" -description: "Presentation of the different components of Reachy's software and how they interact." -lead: "" -date: 2023-07-26T08:06:01+02:00 -lastmod: 2023-07-26T08:06:01+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "software" -weight: 400 -toc: true ---- - -Reachy's software is composed of three main parts: - -- **a HAL** (Hardware Abstraction Layer) handling the communication with Reachy's sensors i.e. the Dynamixel motors in the arms, fans, force sensors and Orbita actuator. -- **ROS packages:** this is the core of the software. We are using ROS (Robotics Operating System), more precisely the **ROS2 Humble distribution**, and interact with the HAL via [ros2 control](https://control.ros.org/master/index.html). ROS packages are used to compute the kinematics for Reachy's arms and Orbita, to get the camera feed and to manage the autofocus on Reachy's motorised zooms. -Another ROS package is also used, along with gRPC, to create a server interacting with the different ROS nodes and services made for Reachy and allowing remote control on the robot without being physically connected to it. - -- **gRPC client:** the strength of using the gRPC framework is that we can have a remote control to the robot and create clients in any programming language (Python, C++, C#, ...). So knowing how to use ROS is not needed to work with Reachy. - -## Packages - -The packages developed for Reachy 2023 are divided into two categories: the ROS packages and non-ROS packages. - -### ROS - -(installed in ~/reachy_ws folder of Reachy's computer) - -The main package is [**reachy_2023**](https://github.com/pollen-robotics/reachy_2023). It contains multiple sub-packages: - -- [**reachy_description**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_description): publishes the robot's URDF and control tag, needed by the kinematics package and by the different ROS simulation tools (rviz, gazebo, ...) - -- [**reachy_kdl_kinematics**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_kdl_kinematics): computes the forward / inverse kinematics of Reachy's arms and the forward / inverse kinematics of Orbita. - -- [**reachy_controllers**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_controllers): communicates with the HAL through [ROS control hardware interface](https://control.ros.org/master/doc/ros2_control/hardware_interface/doc/hardware_components_userdoc.html). -- [**camera_controllers**](https://github.com/pollen-robotics/reachy_2023/tree/master/camera_controllers): communicates with the camera using v4l2 and zoom. -- [**gripper_safe_controller**](https://github.com/pollen-robotics/reachy_2023/tree/master/gripper_safe_controller): Smart gripper controller that automatically adjusts target position to avoid forcing. - -- [**reachy_msgs**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_msgs): specific ROS messages for Reachy -- [**reachy_bringup**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_bringup): bringup launch file (can launch real, fake or gazebo reachy with or without RViz, etc.) - -- [**reachy_sdk_server**](https://github.com/pollen-robotics/reachy_2023/tree/master/reachy_sdk_server): creates two gRPC servers, *camera_server* to get the camera's images and control the motorised zooms and *reachy_sdk_server* for the joints, load sensors, fans and Orbita. - -{{< img-center "images/advanced/software/reachy-rviz.jpg" 800x "Reachy's visualised with Rviz" >}} - -##### Mobile base -The following package is only needed if you have a Reachy with mobile base: - -- [**mobile_base_controller**](https://github.com/pollen-robotics/reachy_2023/tree/master/mobile_base_controller) - -with the following sub-packages: - -- [**zuuu_hal**](https://github.com/pollen-robotics/reachy_2023/tree/master/mobile_base_controller/zuuu_hal): HAL dedicated to the mobile base -- [**zuuu_interfaces**](https://github.com/pollen-robotics/reachy_2023/tree/master/mobile_base_controller/zuuu_interfaces): custom ROS services for the mobile base -- [**mobile_base_sdk_server**](https://github.com/pollen-robotics/reachy_2023/tree/master/mobile_base_controller/mobile_base_sdk_server): creates a gRPC server to control the mobile base - -:bulb: **Zuuu** is the internal name of the mobile base. It's a french onomatopoeia that evokes swift mouvements :) - - -### Non-ROS - -(installed in ~/dev folder of Reachy's computer) - -The main library you will use: -- [**reachy_sdk**](https://github.com/pollen-robotics/reachy-sdk): SDK Python to control Reachy and develop applications - -Other dependencies for more specific use cases: -- [**reachy_sdk_api**](https://github.com/pollen-robotics/reachy-sdk-api): protobuf services and messages definition for the gRPC servers -- [**zoom_kurokesu**](https://github.com/pollen-robotics/zoom_kurokesu): Python library to control Reachy's motorized zooms - -##### Mobile base -The following package is only needed if you have a Reachy with mobile base: - -- [**mobile_base_sdk**](https://github.com/pollen-robotics/mobile-base-sdk): SDK Python to control Reachy's mobile base without necessarily having a Reachy robot connected. Controling the mobile base using [**reachy_sdk**](https://github.com/pollen-robotics/reachy-sdk) actually uses the [**mobile_base_sdk**](https://github.com/pollen-robotics/mobile-base-sdk) but hides it. - - -## gRPC clients - -As explained, the gRPC clients permits the communication with the gRPC server through a network and without being physically connected on the robot. The gRPC clients can be installed on another machine and have few requisites, there is no need for the machine to have ROS installed on it. - -gRPC clients can be in different programming languages. Currently, you can remotely control your robot using: - -- [**reachy_sdk**](https://github.com/pollen-robotics/reachy-sdk): as described above, SDK Python to control Reachy's arm, head, gripper. This is the library that we use when we want to develop an app on Reachy or test a new robot, -- [**mobile_base_sdk**](https://github.com/pollen-robotics/mobile-base-sdk): SDK Python to control Reachy's mobile base. It can work on the mobile base alone and with this, you don't have to worry about whether or not Reachy's motors are on or if Reachy's main service is running. - -
- -:bulb: **To learn more on the packages content and usage, please refer to README.md files of each directory.** - -
- -{{< alert icon="👉" text="Want to get the latest software updates?
Check how to do it here!" >}} - -## Sum up - -The diagram below sums up what has been described in this page. - -{{< img-center "images/advanced/software/software-archi.png" 750x "Reachy's software architecture" >}} - diff --git a/content/advanced/software/ros2-level.md b/content/advanced/software/ros2-level.md deleted file mode 100644 index 532c5c5e..00000000 --- a/content/advanced/software/ros2-level.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: "Working with ROS2 Humble" -description: "Working at the ROS level of the robot. What are the different nodes available." -lead: "Working at the ROS level for low-level control." -date: 2023-07-26T08:06:11+02:00 -lastmod: 2023-07-26T08:06:11+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "software" -weight: 410 -toc: true ---- - -Even if [gRPC clients]({{< ref "/advanced/software/presentation#grpc-clients" >}}) are available to control Reachy without knowing how to use ROS, you may want to work at the ROS level to implement new things for Reachy or use the tools provided by ROS. In this page, we will describe how to use the specfic ROS2 packages for Reachy. - -Reachy runs natively on [ROS2 Humble](https://docs.ros.org/en/humble/index.html). ROS stands for Robotic Operating System, it offers a huge variety of compatible algorithms and hardware drivers. - -{{< img-center "images/advanced/software/reachy-rviz.jpg" 800x "Reachy's visualised with Rviz" >}} - - -The embedded NUC computer comes with ROS2 and Reachy specific packages already installed and running. They provide full access to Reachy. You can: -- get the */joint_states* and */dynamic_joint_states* -- use *Rviz* to visualize your robot (either real or simulated) -- subscribe to various sensor topic (camera, force sensor, etc) -- publish position, torque, pid, etc commands using forward controller -- access client for IK/FK - -{{< alert icon="💡" text="At this level, joints angles are handled in radians." >}} - - -> NOTE: If you don't know how to use ROS but still want to do it on Reachy, you should check the [official ROS documentation](https://docs.ros.org/en/humble/index.html), espcecially the [tutorials](https://docs.ros.org/en/humble/Tutorials.html) showing examples and presenting the different key notions introduced by ROS. - -## What is runnning by default - -If you have a **Full kit** or a **Starter kit**, `reachy_sdk_server.service` is enabled by default, meaninig that all Reachy ROS2 packages presented in the [Overall presentation]({{< ref "/advanced/software/presentation" >}}) are automatically launched when you start the robot. - -If you have a **Reachy mobile**, `reachy_mobile_base.service` is enabled along with `reachy_sdk_server.service`. - -See section [Using services]({{< ref "/advanced/services/available" >}}) for more information on the services. - -You can check all ROS2 topics/services running on Reachy with: -```bash -ros2 topic list -``` -and -```bash -ros2 service list -``` - -## Using launch files directly - -The following presents what launch files can be launched, if you don't whant to use the service. -If you want to learn more about what is run by each launch file, check the README of the corresponding package. - -## Bringup - -The launch file [***reachy.launch.py***](https://github.com/pollen-robotics/reachy_2023/blob/master/reachy_bringup/launch/reachy.launch.py) is the main entry point. It is reponsible for launching everything you need to use your Reachy. It can either connect to a real Reachy or simulate a fake one. You can run the sdk server or not, etc. - -To connect to your robot and run everything needed to control it via ROS you can simply run: - -```bash -ros2 launch reachy_bringup reachy.launch.py -``` - -If you want to control it using the SDK (that is what is done by default by Reachy's main service [reachy_sdk_server.service]({{< ref "/advanced/services/available#reachy_sdk_serverservice" >}})): - -```bash -ros2 launch reachy_bringup reachy.launch.py start_sdk_server:=true -``` - -Similarly, if you want to control a fake Reachy using the SDK, you can run (we also launch RViz so you can see what's going on): - -```bash -ros2 launch reachy_bringup fake:=true start_sdk_server:=true start_rviz:=true -``` - -Other options are available and can be seen below: - -```bash -ros2 launch reachy_bringup reachy.launch.py --show-args -Arguments (pass arguments as ':='): - - 'start_rviz': - Start RViz2 automatically with this launch file. Valid choices are: ['true', 'false'] - (default: 'false') - - 'fake': - Start on fake_reachy mode with this launch file. Valid choices are: ['true', 'false'] - (default: 'false') - - 'gazebo': - Start a fake_hardware with gazebo as simulation tool. Valid choices are: ['true', 'false'] - (default: 'false') - - 'start_sdk_server': - Start sdk_server along with reachy nodes with this launch file. Valid choices are: ['true', 'false'] - (default: 'false') -``` - -This launch file actually runs many other launch files. If you want to have your custom launch file, the better way is probably to directly have a look at what's inside. - -## Cameras nodes - -*Cameras nodes are available for full/starter kit only:* - -To run the **camera view** node ROS services: -```bash -ros2 run camera_controllers camera_publisher -``` -To launch the **camera zoom** node ROS services: -```bash -ros2 run camera_controllers camera_zoom_service -``` -To launch the **camera focus** node ROS services: -```bash -ros2 run camera_controllers camera_focus -``` - -## Kinematics nodes - -The Kinematics services are available to provide inverse and forward kinematics services for the arms, as well as inverse kinematics for the neck. They are launched automatically by the bringup launch file. - -If you need to run them separately: - -```bash -ros2 run reachy_kdl_kinematics reachy_kdl_kinematics -``` - -It requires the *robot_state_publisher* to be running. - -## Mobile base - -To launch the mobile base Hardware Abstraction Layer node: -```bash -ros2 launch zuuu_hal hal.launch.py -``` -Many parameters on the mobile base like the maximum velocity can only be tuned at the ROS level. Check the [mobile base's HAL README](https://github.com/pollen-robotics/reachy_2023/tree/master/mobile_base_controller/zuuu_hal) to learn about what you can do with the mobile base at the ROS level. - -## SDK server nodes - -A layer above ROS, you can interact with **Reachy SDK API**. The Python SDK offers a gRPC (Remote Procedure Call) interface to communicate with the server. -To communicate with Reachy through the SDK, you need to launch server nodes that handle gRPC services. The easiest way is to use the special flag `start_sdk_server:=true` in the bringup launch file. But if you want to run it independently: - -To launch the node for the **joints, fans and kinematics** gRPC services: -```bash -ros2 run reachy_sdk_server reachy_sdk_server -``` - -To launch the node for the **cameras view and zoom** gRPC services *(full/starter kit only)*: -```bash -ros2 run reachy_sdk_server camera_server -``` - -> Note: For the servers to work, the required ROS services must be already launched. The easiest way is via the bringup launch file. - - -To launch the node for the **mobile base** gRPC services *(mobile kit only)*: -```bash -ros2 launch mobile_base_sdk_server mobile_base_sdk_server.launch.py -``` diff --git a/content/advanced/specifications/_index.md b/content/advanced/specifications/_index.md deleted file mode 100644 index 21e4119a..00000000 --- a/content/advanced/specifications/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title : "Specifications" -description: "A quick overview of Reachy." -lead: "" -date: 2023-07-26T08:03:52+02:00 -lastmod: 2023-07-26T08:03:52+02:00 -draft: false -images: [] -type: docs -weight: 110 ---- diff --git a/content/advanced/specifications/arm-specs.md b/content/advanced/specifications/arm-specs.md deleted file mode 100644 index 80243722..00000000 --- a/content/advanced/specifications/arm-specs.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: "Arm specifications" -description: "Reachy's 2023 arm specifications: material used for pieces, power consumption, dimensions, weight, payload, degrees of freedom." -lead: "Reachy 2023 arm specifications." -date: 2023-07-26T08:06:36+02:00 -lastmod: 2023-07-26T08:06:36+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 210 -toc: true ---- - -**Construction:** 3D printed MJF Painted- 3 axial needle roller bearings -**Power consumption:** 51W -**Dimensions:** 662x88x73mm - -## Weight repartition -Overall Arm: 1670g -Shoulder: 240g -Upper arm: 610g -Forearm: 590g -Gripper: 230g - -**Maximum payload: 500g** -*(this may vary depending on the holding and duration configuration)* - -{{< img-center "images/advanced/specifications/right-arm-scheme.png" 600x "Reachy's right arm schematic" >}} - -## Degrees of freedom -Reachy's arm offers 7 degrees of movement + 1 for the gripper - -|Right arm| | | |Left arm| | | -|-------|-------------|----------|-------|-------|-------------|----------| -| **Motor name** | **Angle limits** | **Motor ID** | | **Motor name** | **Angle limits** | **Motor ID** | -|shoulder_pitch|-150, 90|10| |shoulder_pitch|-150, 90|20| -|shoulder_roll|-180, 10|11| |shoulder_roll|-10, 180|21| -|arm_yaw|-90, 90|12| |arm_yaw|-90, 90|22| -|elbow_pitch|-125, 0|13| |elbow_pitch|-125, 0|23| -|forearm_yaw|-100, 100|14| |forearm_yaw|-100, 100|24| -|wrist_pitch|-45, 45|15| |wrist_pitch|-45, 45|25| -|wrist_roll|-55, 35|16| |wrist_roll|-35, 55|26| -|gripper|-50, 25|17| |gripper|-25, 50|27| - -| Motors| -|---------| -|3 Dynamixel MX-106T| -|1 Dynamixel MX-64AT| -|4 Dynamixel MX-28AT| - - -## Fans -3 fans (shoulder, elbow and wrist) diff --git a/content/advanced/specifications/general-specs.md b/content/advanced/specifications/general-specs.md deleted file mode 100644 index 75900828..00000000 --- a/content/advanced/specifications/general-specs.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "General specifications" -description: "Reachy's full/starter kit general specifications: material used for pieces, power consumption, dimensions, weight." -lead: "Reachy 2023 general specifications (full/starter kit only)." -date: 2023-07-26T08:06:45+02:00 -lastmod: 2023-07-26T08:06:45+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 200 -toc: true ---- - -**Construction:** 3D printed MJF Painted - Flexible PU molded - Aluminium -**Max Power consumption:** 180W -**Full Kit Dimensions:** 670x450x200mm (670x1800x200mm with arms outstretched) -**Starter Kit Dimensions:** 670x380x200mm (670x1008x200mm with arms outstretched) -**Weight:** 6.2kg without metal fixation - -{{< img-center "images/advanced/specifications/reachy_schematic.png" 600x "Reachy's full kit dimensions" >}} diff --git a/content/advanced/specifications/gripper-specs.md b/content/advanced/specifications/gripper-specs.md deleted file mode 100644 index ccc0b2ab..00000000 --- a/content/advanced/specifications/gripper-specs.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "Gripper specifications" -description: "Reachy's 2023 gripper specifications: material used for pieces, power consumption, dimensions, weight." -lead: "Reachy 2023 gripper specifications." -date: 2023-07-26T08:06:53+02:00 -lastmod: 2023-07-26T08:06:53+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 220 -toc: true ---- - -Animated by 1 Dynamixel MX-28AT. -Includes a **micro load cell** 0.78 Kg - -**Construction:** 3D printed MJF Painted - Flexible PU molded -**Power consumption:** 5.3W -**Dimensions:** 117.3x84x51.4mm -**Weight:** 0.3Kg - diff --git a/content/advanced/specifications/head-specs.md b/content/advanced/specifications/head-specs.md deleted file mode 100644 index 0d6e2e6f..00000000 --- a/content/advanced/specifications/head-specs.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "Head specifications" -description: "Reachy's 2023 head specifications: material used for pieces, power consumption, dimensions, weight, cameras, description of neck joint and antennas." -lead: "Reachy 2023 head specifications (full/starter kit only)." -date: 2023-07-26T08:06:59+02:00 -lastmod: 2023-07-26T08:06:59+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 230 -toc: true ---- - -**Construction:** 3D printed MJF Painted. -**Power consumption:** 15W. -**Dimensions:** 175x253x108mm. -**Weight:** 0.675Kg. - -Reachy’s head features **two motorized high quality wide angle cameras**, to observe its environment as well as being able to focus on the task of manipulating. The head is animated by **Orbita**, a unique technology developed by Pollen Robotics’ R&D team. This ball joint actuator allows unpreceded dynamic and multi-directional movement. With **animated antennas**, Reachy can convey many emotions to his audience. - -See the head in action in this video: - -{{< youtube X9dgsLX_u9I >}} - -## Cameras -Dual 1080p@30fps [camera with motorized zoom](https://www.kurokesu.com/shop/cameras/C2_USBC) (FOV 65° to 125°), associated with 2 optical lenses. - -## Orbita neck joint -Ball joint actuator that is composed of a parallel mechanism motorized by 3 brushless Maxon motors. The control of each motor is done with a magnetic absolute encoder included on the electronic board on top of Orbita. - -## Antennas -Antennas are animated by a Dynamixel motor and are removable. -A system of 3 magnets allow the attachment of the antennas to the rotation axis. - - diff --git a/content/advanced/specifications/mobile-base-specs.md b/content/advanced/specifications/mobile-base-specs.md deleted file mode 100644 index 7e9c2109..00000000 --- a/content/advanced/specifications/mobile-base-specs.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: "Mobile Base specifications" -description: "Reachy's mobile base specifications: material used for pieces, power consumption, dimensions, weight, description of sensors, wheels and battery." -lead: "Reachy's mobile base specifications." -date: 2023-07-26T08:07:06+02:00 -lastmod: 2023-07-26T08:07:06+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 260 -toc: true ---- - -## Specifications - -**Construction:** -- Cylinder shape -- Aluminium, MJF 3D printed plastic parts, Steel - -{{< img-center "images/advanced/specifications/mobile_base.png" 600x "" >}} - -**Dimension:** 50*25cm -**Weight:** 25kg -**Payload:** 80kg - -{{< img-center "images/advanced/specifications/mobile_base_drawing.png" 600x "Mobile base schematic" >}} - -**Sensors:** -- Hall Sensors and IMU on each wheel -- RP Lidar S2 (30m radius distance, 32k measurments/s, 0.12° angle resolution, resistance to sunlight…) - -**Wheels:** -- 3x Omnidirectional wheels -- 300W Max power -- No-load speed: 210 rpm -- Stall Torque: 13Nm - 13A -- Rated load, speed and current : 5Nm, 115rpm, 5A - -**Battery OlenBox M:** -- 24V, 35Ah -- 19.5 x 17.2 x 13.4cm, 6.5kg -- 5 years warranty -- Equipped with a BMS for safety -- Battery state indicator - -**Emergency Stop:** The emergency stop can be placed on the robot or in the users hands. -The E-stop instantly shuts down the entire robot. - - diff --git a/content/advanced/specifications/orbita-specs.md b/content/advanced/specifications/orbita-specs.md deleted file mode 100644 index 821b15ae..00000000 --- a/content/advanced/specifications/orbita-specs.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: "Orbita specifications" -description: "Orbita spherical joint specifications: material used for pieces, power consumption, dimensions, weight, gearbox, degrees of freedom and limit angles." -lead: "Orbita spherical joint specifications." -date: 2023-07-26T08:07:15+02:00 -lastmod: 2023-07-26T08:07:15+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 250 -toc: true ---- - -## Specifications - -**Construction:** Aluminium machined and SLS printed parts - Custom steel gears - metal bearings and axes. - -**Power consumption:** 8W -**Voltage:** 12V -**No-load speed:** 25rpm -**Max Continous torque:** 1.7Nm -**Gear reduction ratio:** 4.2666 - -**Diameter:** 70mm -**height:** 170mm -**Weight:** 850g - -## Motor + Gearbox specifications - -**Power consumption:** 8W -**Voltage:** 12V -**No-load speed:** 105 rpm -**Max Continous torque:** 0.4 Nm -**Gear reduction ratio:** 35:1 - -**Diameter:** 22mm -**Height:** 75mm - -Motor's full specification here - - -## Degrees of freedom -Orbita has 3 degrees of freedom actuated by three motors described above. -They correspond to three rotation at the same point like Roll Pitch Yaw rotations. - -{{< img-center "images/advanced/specifications/rpy-orbita.jpg" 300x "" >}} - -**Angle limits** -Roll: -46° to 46° -Pitch: -46° to 46° -Yaw: 360° full rotation diff --git a/content/advanced/specifications/torso-specs.md b/content/advanced/specifications/torso-specs.md deleted file mode 100644 index 2adfea4d..00000000 --- a/content/advanced/specifications/torso-specs.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: "Torso specifications" -description: "Reachy's 2023 torso specifications: material used for pieces, dimensions, weight and description of each hardware installed in it (computer, microphone, TPU, speaker, amplifier, power supply)." -lead: "Reachy 2023 torso specifications (full/starter kit only)." -date: 2023-07-26T08:07:22+02:00 -lastmod: 2023-07-26T08:07:22+02:00 -draft: false -images: [] -type: docs -menu: - advanced: - parent: "specifications" -weight: 240 -toc: true ---- - -**Construction:** 3D printed MJF Painted - Aluminium -**Power consumption:** 36W -**Dimensions:** 300x350x150mm -**Weight:** 1.7Kg - -Reachy's torso area includes the following elements: - -## Computer -Powerful internal computer NUC intel i5 quad-core 1.6Ghz with 16Go DDR4 and 256Go SSD (NUC8v5PN) - -## Microphone -Seeed Studio - ReSpeaker Mic Array v2.0: Microphone array for NLU (ReSpeaker) and a 3.5mm jack audio output - -## TPU -Embedded TPU Google Coral G950-01456-01 for running ML models inference at high speed locally - -## Speaker -2x 12W - 4Ohm Tectonic TEBM36S12 Speakers allowing stereo sound. - -## Amplifier -Drocking PAM8620 12V audio amplifier - -## Power supply -Mean Well - GST220A12-R7B180W - output 12V 15 A (input 85~264VAC - 120~370VDC) diff --git a/content/dashboard/_index.md b/content/dashboard/_index.md deleted file mode 100644 index a992677b..00000000 --- a/content/dashboard/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "Dashboard" -description: "Use the dashboard to check Reachy's status, debug Reachy's issues and start applications." -lead: "" -date: 2023-07-25T15:34:02+02:00 -lastmod: 2023-07-25T15:34:02+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/dashboard/content/_index.md b/content/dashboard/content/_index.md deleted file mode 100644 index ff21b5a6..00000000 --- a/content/dashboard/content/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Content" -description: "What you can find in Reachy's dashboard." -date: 2023-07-25T15:34:19+02:00 -lastmod: 2023-07-25T15:34:19+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/dashboard/content/dashboard.md b/content/dashboard/content/dashboard.md deleted file mode 100644 index 7c7a4650..00000000 --- a/content/dashboard/content/dashboard.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: "Reachy control" -description: "Monitor Reachy from Reachy control dashboard page. Send compliance and goal positions commands, and read errors." -lead: "Reachy quick monitoring through the dashboard" -date: 2023-07-25T15:46:33+02:00 -lastmod: 2023-07-25T15:46:33+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "50" ---- - -{{< alert icon="👉" text="No available yet" >}} - - -The Reachy Control page is a monitoring page where you can both: -- read **errors** from the robot -- send high level commands, such as goal positions and compliance. - -{{< img-center "images/dashboard/content/control.png" 600x "Control tab" >}} - -Try to turn on or off parts of the robot, or the whole robot. - -You can also send commands to make the part moves. Give joints goal positions, express **in degrees** in Reachy 2 coordinate system. - -> Have a look to the [Arms kinematics page]({{< ref "sdk/first-moves/kinematics" >}}) to know the sign of the angles to send to the joints. - -Enter the value you want to send, then click **Go to** to reach the position. diff --git a/content/dashboard/content/network.md b/content/dashboard/content/network.md deleted file mode 100644 index 6b9d36e4..00000000 --- a/content/dashboard/content/network.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "Network" -description: "Dashboard page to manage Reachy 2's network connection." -lead: "Manage Reachy 2's network connection" -date: 2023-07-25T15:46:07+02:00 -lastmod: 2023-07-25T15:46:07+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "20" ---- -The wifi tab of the dashboard lets you handle the network connection of the robot. -You can get the IP address and choose the network you want to connect the robot to. - -It looks like the following: - -{{< img-center "images/dashboard/content/network.png" 600x "Wifi page" >}} - -There are 2 main elements on this page: -1. **Network status card**: this card will display the current network connections of the robot and its IP addresses. You may have two IP addresses if your robot is both connected to wifi and ethernet, - -2. **Update wifi card**: this card will help you connect Reachy to a wifi network. The dropdown will list each wifi network detected. Select the network you want to connect to and enter your wifi password in the corresponding box. diff --git a/content/dashboard/content/services.md b/content/dashboard/content/services.md deleted file mode 100644 index 29076cee..00000000 --- a/content/dashboard/content/services.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: "Services" -description: "Dashboard page to control Reachy's services." -lead: "The services tab is dedicated to the services setup for Reachy 2" -date: 2023-07-25T15:46:23+02:00 -lastmod: 2023-07-25T15:46:23+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "10" ---- - -Working with services has the advantage of having the code running automatically at boot, whithout needing to connect to the robot and start it yourself. However using the services can make debugging the robot more difficult because the code running for Reachy is "hidden", that is why we made this page. - -This page is mainly useful to restart the service in order to [recover from a problem]({{< ref "/help/help/recovering" >}}). - -## Content - -In this page, one card is created for each robot's service. It looks like the following: - -{{< img-center "images/dashboard/content/services.png" 500x "Services page" >}} - -The available services are: -- **reachy2-core**: manages the motors and the server for the Python SDK -- **webrtc**: manages the server for teleoperation. *Requires reachy2-core* -- **plum**: manages the updates service -- **display**: manages the visualization tool -- **reachy2-dashboard**: manages the dashboard - -## Actions on services - -For each service, three buttons are available: -{{< img-center "images/dashboard/content/service.png" 150x "Service card" >}} - -* **Restart**: restarts the service, -* **Stop**: stops the service, -* **Show logs**: displays the logs of the service *(only display the service status at the moment)* - -> Restarting reachy2-dashboard will made your dashboard unavailable for a few seconds. - \ No newline at end of file diff --git a/content/dashboard/content/updates.md b/content/dashboard/content/updates.md deleted file mode 100644 index d2da0b23..00000000 --- a/content/dashboard/content/updates.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: "Updates" -description: "Dashboard page to update Reachy 2 core software." -lead: "Update Reachy 2 core software" -date: 2023-07-25T15:46:41+02:00 -lastmod: 2023-07-25T15:46:41+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "30" ---- - -## Updates availability - -From the **Updates** tab, check if updates are available: -The update tab enables you to get the last updates of the core software robot. - -If your robot already has the last versions for all the services, the page will indicate the robot is up to date: - -{{< img-center "images/dashboard/content/updates.png" 600x "Updates page" >}} - -In case some services have updates available, the page will indicate you don't have the last versions: - -{{< img-center "images/docs/update/dashboard-update-page.png" 600x "" >}} - -> Only advanced update management is working so far - -## Advanced update management - -From the dashboard Update page, click on **Advanced udpate management**: - -{{< img-center "images/docs/update/update.png" 600x "PLUM update" >}} - -> You can directly access the advanced update dashboard from **`http://:5000/`** - -### Fetch updates - -Click **Fetch Updates** to check if there is any available update on one of the robot's services. -Once this is done, you can browse between the 5 services to see if a more recent version is available. - -> For example, an update is available for reachy2-dashboard here: -{{< img-center "images/docs/update/update-available.png" 600x "PLUM update" >}} - -### Install update - -Select the version you want to download for the upgrade, and click on **Pull Container**. -Wait for the message "*service.name* Pulled" to appear in the window. - -{{< img-center "images/docs/update/pull-container.png" 600x "PLUM update" >}} - -When this is done, click on **Generate**. -Wait for the confirmation message to appear. - -{{< img-center "images/docs/update/generate.png" 600x "PLUM Update" >}} - -### Activate the update - -Finish the update installation by clicking on: -1. **Enable**, to activate by default the updated service -2. **Stop**, to stop the current outdated service running -3. **Start**, to launch the updated service diff --git a/content/dashboard/content/visualization.md b/content/dashboard/content/visualization.md deleted file mode 100644 index 043a36c5..00000000 --- a/content/dashboard/content/visualization.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Visualization tools" -description: "Dashboard page to access visualization tools for the robot (Foxglove and VNC)." -lead: "Foxglove and VNC easy access" -date: 2023-07-25T15:46:30+02:00 -lastmod: 2023-07-25T15:46:30+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "40" ---- - -{{< img-center "images/dashboard/content/visu.png" 600x "Visualization page" >}} - -## Foxglove - -Open a [Foxglove](https://foxglove.dev/) window to visualize data of the robot. -It specially enables to visualize ROS data from the robot. - -## VNC - -Open a window to visualize graphical elements running on the robot. - -As [RViz](http://wiki.ros.org/rviz) is launched by default with the [reachy2-core service]({{< ref "/dashboard/content/services" >}}), you can see the Rviz window showing a simplified robot moving. \ No newline at end of file diff --git a/content/dashboard/introduction/_index.md b/content/dashboard/introduction/_index.md deleted file mode 100644 index f5b93cc4..00000000 --- a/content/dashboard/introduction/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Introduction" -description: "Introduction to Reachy's dashboard." -date: 2023-07-25T15:34:49+02:00 -lastmod: 2023-07-25T15:34:49+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/dashboard/introduction/connection.md b/content/dashboard/introduction/connection.md deleted file mode 100644 index b54052d5..00000000 --- a/content/dashboard/introduction/connection.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: "Connection" -description: "" -lead: "" -date: 2023-07-25T16:34:00+02:00 -lastmod: 2023-07-25T16:34:00+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "20" ---- - -## 1. Find Reachy 2's IP address - -After you connected the robot to the network, it should have an IP address. The LCD screen connected in Reachy's back should be diplaying its IP address. - -{{< img-center "images/vr/getting-started/lcd-display.png" 400x "" >}} - -If the LCD screen is not working or is unplugged, check out the page [Find my IP section]({{< ref "help/system/find-my-ip" >}}) to learn other ways to get the IP address. -> Note the LCD screen will not work if you plug it after having turned on the computer. - -## 2. Connect from the navigator - -From your computer, on the same network, open a navigator and go to: -**`http://:8000/`** - -> For example, if the screen indicates `192.168.1.42`, connect to `http://192.168.1.42:8000/` - -You should arrive on a services page: - -{{< img-center "images/docs/getting-started/dashboard.png" 600x "dashboard" >}} \ No newline at end of file diff --git a/content/dashboard/introduction/introduction.md b/content/dashboard/introduction/introduction.md deleted file mode 100644 index 33940cbc..00000000 --- a/content/dashboard/introduction/introduction.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: "Introduction" -description: "What is the dashboard?" -lead: "What is the dashboard?" -date: 2023-07-25T16:34:27+02:00 -lastmod: 2023-07-25T16:34:27+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "10" ---- - -This tool has been thought to help you **start easier with the robot** and **facilitate quick debugging**. - -The dashboard is here to give you an overview of the robot's state as well as giving you the possiblity to access quickly some features (changing a robot's part compliance for example). - -## Features Overview - -What does the dashboard provide? - -* **Access the services** - [**Services page**]({{< ref "/dashboard/content/services" >}})
-Stop or restart the robot's services, see robot logs *(coming soon)*. - -* **Manage network connection** - [**Network page**]({{< ref "/dashboard/content/network" >}})
-Choose a wifi network to connect the robot to. - -* **Update robot software** - [**Updates page**]({{< ref "/dashboard/content/updates" >}})
-Get the last software versions of the robot, and choose the services you want to update. - -* **Visualize robot state** - [**Visualization tools page**]({{< ref "/dashboard/content/visualization" >}})
-Get RViz visualization or even display live data from ROS topics with Foxglove. - -* **Send robot commands** - [**Reachy control page**]({{< ref "/dashboard/content/dashboard" >}})
-*Coming soon* - - -On each page, the **serial number** of your robot is also displayed. - -More information is available for each page in the content section. \ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/1-hello-world.md b/content/developing-with-reachy-2/basics/1-hello-world.md index 1d911764..92c2da71 100644 --- a/content/developing-with-reachy-2/basics/1-hello-world.md +++ b/content/developing-with-reachy-2/basics/1-hello-world.md @@ -14,4 +14,281 @@ weight: 200 toc: true --- -Ohlala it's safe now \ No newline at end of file + +## Be ready to move + +### 1. Connect to the robot + +If you followed the instructions from ["Connect to Reachy 2"]({{< ref "developing-with-reachy-2/getting-started-sdk/" >}}), you know how to get Reachy's IP address and how to connect to the robot with the command: + +```python +from reachy2_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP +``` + +### 2. Turn on motors + +When starting, your robot is in compliant mode, which means you can move its parts by manipulating manually the robot. In this mode, the robot won't respond to any command you send to it. + +At each use, you will have to turn on your robot's motors doing: +```python +reachy.turn_on() +``` + +At the end of your session or program, switch off the motors to send them back to compliant mode doing: +```python +reachy.turn_off() +``` + +This will act on all parts of your robot, including the mobile base. +If you want to turn on or off a single part, access directly the relevant part and turn it on or off, for example for the left arm: + +```python +reachy.l_arm.turn_on() +reachy.l_arm.turn_off() +``` + +All parts are detailed below in [ReachySDK attributes]({{< ref "developing-with-reachy-2/basics/1-hello-world#attributes" >}}). + +At any time, you can check the state of your robot using the `is_on()` or `is_off()` method. Note that it will return True only if **all parts** are in the requested state. This means both methods can return False if the right arm is on but not the left one for example. + +```python +# Turn on all parts +reachy.turn_on() +# Check robot state +reachy.is_on() +>>> True +reachy.is_off() +>>> False + +# Turn off only the left arm +reachy.l_arm.turn_off() +# Check robot state +reachy.is_on() # reachy is not on, as left arm is off +>>> False +reachy.is_off() # but reachy is not fully off neither +>>> False +# Check parts state +reachy.r_arm.is_on() # right arm is still on +>>> True +reachy.l_arm.is_off() # left arm is off +>>> True +``` + +### 3. Start from a standard position (optional) + +2 standard positions are accessible and can be called easily to setup your starting position: +- the **zero** pose, with all joints set at 0 degree +- the **elbow_90** pose, with the elbow pitch set at -90 degrees and all other joints at 0 degree + +To start at the zero position, use the `set_pose()` function: +```python +reachy.set_pose('zero') +``` + +By default, this movement is made in 2 seconds. You can choose to specify a custom duration. For example, to reach the elbow_90 pose in 5 seconds: +```python +reachy.set_pose('elbow_90', duration=5) +``` + +## Check connection + +At any time, you can check the connection between your SDK and the robot is still open with: +```python +reachy.is_connected() +>>> True +``` + +If the connection has been lost, and the problem has been resolved, you can reconnect to the robot with the `connect()`method: +```python +reachy.connect() +``` + +{{< alert icon="💡" text="You cannot use this method to connect to another IP address. It will automatically reconnect to the initial instantiated robot." >}} + +## ReachySDK object + +The *reachy* object instanciated from the ReachySDK class above is the root access to get all incoming information from Reachy 2 (joints or cameras) and to control each part of the robot (left/right arm, head, mobile base). + +The *reachy* object has 7 attributes and ?? methods that we will quickly present here, more detailed information are given in the dedicated pages after this one. + +{{< alert icon="💡" text="Note that you can only instantiate one ReachySDK in a session." >}} + +{{< img-center "images/sdk/first-moves/reachy_attributes.png" 400x "" >}} + +### Attributes + +The *reachy* attributes detailed give to access to info, parts and sensors of the robot. + +#### List of attributes +[reachy.cameras]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachycameras" >}}) +[reachy.head]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyhead" >}}) +[reachy.info]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyinfo" >}}) +[reachy.joints]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyjoints" >}}) +[reachy.l_arm]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyl_arm" >}}) +[reachy.mobile_base]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachymobile_base" >}}) +[reachy.r_arm]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyr_arm" >}}) + +#### reachy.cameras + +[Camera object](https://pollen-robotics.github.io/reachy-sdk/api/camera.html). It is used to recover the last image captured by the left camera and also to control the motorized zoom attached to the camera. + +```python +reachy.left_camera +>>> +``` + +#### reachy.head + +[Head object](https://pollen-robotics.github.io/reachy-sdk/api/head.html). +Contains the three joints composing the Orbita actuator along with methods for its kinematics or to control it. + +```python +reachy.head +>>> + + + + +>> +``` + +#### reachy.info + +[Camera object](https://pollen-robotics.github.io/reachy-sdk/api/camera.html). It is used to recover the last image captured by the right camera and also to control the motorized zoom attached to the camera. + +```python +reachy.right_camera +>>> +``` + +#### reachy.joints + +[Joint object](https://pollen-robotics.github.io/reachy-sdk/api/joint.html) containing every joint of the robot, from its arms to its head and antennas. This is useful when you want to get information, like the position, from all joints at once. + +```python +reachy.joints +>>> + + + + + + + + + + + + + + + + + + + + +> +``` + +#### reachy.l_arm + +[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the left arm along with its kinematics methods. + +```python +reachy.l_arm +>>> + + + + + + + +>> +``` + +#### reachy.mobile_base + +[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the right arm along with its kinematics methods. + +```python +reachy.r_arm +>>> + + + + + + + +>> +``` + +#### reachy.r_arm + +[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the right arm along with its kinematics methods. + +```python +reachy.r_arm +>>> + + + + + + + +>> +``` + +### Basic methods + +The *reachy* object has ?? methods, 8 of them being basic methods useful to start using the robot. The other methods are related to robot movements, and will be detailed in a more advanced section. + +#### List of basic methods + +[reachy.connect()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyconnect" >}}) +[reachy.disconnect()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachydisconnect" >}}) +[reachy.is_connected()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyis_connected" >}}) +[reachy.is_off()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyis_off" >}}) +[reachy.is_on()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyis_on" >}}) +[reachy.turn_off()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyturn_off" >}}) +[reachy.turn_on()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyturn_on" >}}) +[reachy.set_pose()]({{< ref "developing-with-reachy-2/basics/1-hello-world#reachyset_pose" >}}) + + +#### reachy.connect() + +#### reachy.disconnect() + +#### reachy.is_connected() + +#### reachy.is_off() + +#### reachy.is_on() + +#### reachy.turn_off() + +Method to turn off the whole robot. Turning off the robot means putting all parts of the robot in compliant mode, including the mobile base if there is one. See next section for more information on what the compliant mode is for a motor. + +```python +reachy.turn_off() +``` + +#### reachy.turn_on() + +Method to turn on the whole robot. Turning on the robot means putting all the parts of the robot in stiff mode, including the mobile base if there is one. See next section for more information on what the stiff mode is for a motor. + +```python +reachy.turn_on() +``` + +#### reachy.set_pose() diff --git a/content/developing-with-reachy-2/basics/2-understand-moves.md b/content/developing-with-reachy-2/basics/2-understand-moves.md index e196ec93..cb4f5629 100644 --- a/content/developing-with-reachy-2/basics/2-understand-moves.md +++ b/content/developing-with-reachy-2/basics/2-understand-moves.md @@ -14,4 +14,233 @@ weight: 210 toc: true --- -Ohlala it's safe now \ No newline at end of file + +## Moves methods + +ReachySDK for Reachy 2 offers you methods to make movements with the arms and head, controlling the target position in several way, choosing the duration of the movement, or even the interpolation mode. + +Those methods work the same way on the left and right arms and on the head, **but not on the mobile base**. + + +The methods to use in order to control the robot are: + +- for the arms: + - **`goto_joints()`**: you control directly the goal position of each joint of the arm, in degrees + - **`goto_from_matrix()`**: you control the target pose of the end effector in the robot's coordinate system, from a 4x4 homogeneous matrix +- for the head: + - **`look_at()`**: you control the head by giving a point in the robot coordinate system the head will look at + - **`rotate_to()`**: you control directly the roll, pitch and yaw goal positions of the neck, in degrees + - **`orient()`**: you control the head orientation with a quaternion + +## Moves properties + +### Moves IDs + +The previous methods all return an id, that you can use to get information on this movements or to cancel this movement. Store this id in a variable to be able to use it further. + +```python +move_1 = reachy.r_arm.goto_joints([10, -10, 0, -90, 0, 0, 0]) + +print(move_1) +>>> ?? +``` + +### Moves execution + +Move commands can only be sent on parts: +- reachy.l_arm +- reachy.r_arm +- reachy.head + +#### Moves are non-blocking for other parts +It means you can send a move command on different parts, it won't wait for the movement to be executed on the first part to execute the other one, but will follow the timing of your code. + +Let's take an example with the following sequence: +```python +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) +time.sleep(1) +reachy.r_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 2) +``` +This sequence will take 3 seconds to execute, as the right arm will start its movement 1 second after the left arm has started its own movement. They will finish at the same time. + +#### Moves are blocking and stacked for a part +It means that you can send several move commands on a part one after another without any delay, they will be played in this order, but will wait for the previous move to be finished. + +Let's take an example with the following sequence: +```python +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) +``` +This sequence will take 8 seconds to execute, as each movement on the left arm will wait for the previous before starting. + +Nevertheless, you can still send move commands to other parts. +For example: +```python +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) #1 +time.sleep(1) +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) #2 +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) #3 +reachy.r_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 2) #4 +``` + +This sequence will still take 8 seconds to execute: +- commands #1, #2 and #3 are sent to the left arm. They will be stacked on the left arm, and the `time.sleep(1)` won't have any effect . When received, command #2 will simply wait 2 seconds rather than 3 secondes in the previous example. +- commands #4 is sent on the right arm, where no movement is progress. It will then start 1 second after command #1 has started, and will then be over approximatively at the same time. + +The sequence execution order is #1, #4, #2, #3 + +### Part execution state +As the sequence can become complex, you can get information for each part on its current status, to now which movementis being played and know which others are waiting to be played. +For each part, the following methods are available: +- **`get_move_playing()`**: will return the id of the currently playing move on the part +- **`get_moves_queue()`**: will return the ids of all stacked move commands waiting to be played on the part + +Those methods are called at the part level, to get info on the state of the part. +For example: +```python +# Write a sequence for the left arm +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) # id=1 +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) # id=2 +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) # id=3 + +# Move #1 is currently playing +current_move = reachy.l_arm.get_move_playing() +print(current_move) +>>> ?? + +# 2 move commands, #2 and #3, are waiting to be played +print(len(reachy.l_arm.get_moves_queue())) +>>> 2 +``` + +### Moves state + +For a specific move, you may want to know its current state. You can get information on the moves given its id with 3 methods available at reachy's level: +- **`is_move_playing()`**: return True if the movement is currently being played +- **`is_move_finished()`**: return True if the movement is over, but also if it won't be played because it has been cancelled for example +- **`get_move_joints_request()`**: will return the joints goal positions sent to the part by the corresponding move command + +Let's take an example: +```python +move_1 = reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) + +time.sleep(1) + +# Move is currently being played +reachy.is_move_playing(move_1) +>>> True +reachy.is_move_finished(move_1) +>>> False + +time.sleep(3) + +# Move is now over +reachy.is_move_playing(move_1) +>>> False +reachy.is_move_finished(move_1) +>>> True + +# Get joint goal position of the move +reachy.get_move_joints_request(move_1) +>>> ?? +``` + +### Cancel moves + +If you want to modify the queue of move commands on a part, or interrupt the movement being played, you can cancel move commands at any time. + +#### Single move cancellation + +To cancel a single movement, currently playing or stacked in a part's queue, use its id and call `cancel_move_by_id()` from reachy. + +```python +move_1 = reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) + +time.sleep(1) +reachy.cancel_move_by_id(move_1) +``` + +#### Cancel all moves at once + +To cancel all moves at once, you can call the `cancel_all_moves()` methods. +This method can be called at the level you want to act, which can be either **reachy** or a **specific part**. + +##### All robot moves + +For example, if you want to cancel all moves on all parts: +```python +# Send a sequence of moves +reachy.head.rotate_to(20, 30, -10, duration=3) +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) + +# Cancel all moves +reachy.cancel_all_moves() +``` + +All movements are cancelled, even the movement stacked in the left arm queue which will never be played. + +##### All part moves + +If you only want to cancel movement on the left arm: +```python +# Send a sequence of moves +reachy.head.rotate_to(20, 30, -10, duration=3) +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) + +# Cancel moves on left arm only +reachy.l_arm.cancel_all_moves() +``` + +The movement on the head will continue, but all the movements of the left will be stopped and the left arm queue cleaned. + + +## Moves duration + +For each methods mentioned in [Moves methods]({{< ref "developing-with-reachy-2/basics/2-understand-moves#moves-methods" >}}), you can give a custom duration for the execution of the movements. + +Simply specify the **`duration`** argument **in seconds** when calling the method, as shown in the move examples above: +```python +reachy.head.rotate_to(20, 30, -10, duration=3) +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 5) + + +# Doing: +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0]) +# will lead to the same result as: +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) +``` + +> Default duration is 2 seconds. + +You **cannot set a duration to 0 second**. This will raise an exception in your code: +?? + + +## Moves interpolation mode + +The moves methods generates a trajectory between the present position and the goal position. This trajectory is then interpolated at a predefined frequency (100Hz) to compute all intermediary target positions that should be followed before reaching the final goal position. Depending on the interpolation mode chosen, you can have a better control over speed and acceleration. + +Two interpolation modes are available when sending a move command: +- the **linear** interpolation mode +- the **minimum-jerk** interpolation mode + +{{< img-center "images/sdk/first-moves/interpolation.png" 400x "" >}} + +Both trajectories start and finish at the same point but don't follow the same intermediate positions. The minimum jerk will slowly accelerate at the begining and slowly decelerate at the end. This makes the movements more natural. + +You can specify the interpolation mode by setting the **`interpolation_mode`** argument when calling the method: +```python +reachy.head.rotate_to(20, 30, -10, interpolation_mode='linear') +reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], interpolation_mode='linear') + + +# Doing: +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0]) +# will lead to the same result as: +reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], interpolation_mode='minimum_jerk') +``` + +> Default interpolation mode is minimum-jerk. \ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/3-basic-arm-control.md b/content/developing-with-reachy-2/basics/3-basic-arm-control.md index b0897886..474114f9 100644 --- a/content/developing-with-reachy-2/basics/3-basic-arm-control.md +++ b/content/developing-with-reachy-2/basics/3-basic-arm-control.md @@ -14,4 +14,226 @@ weight: 220 toc: true --- -Ohlala it's safe now \ No newline at end of file +## Arm presentation + +Reachy's arm offers 7 degrees of freedom. It also gives access to one joint for the gripper. +The **arm** is divided as follow: +- **shoulder**, composed of 2 joints (pitch and roll) +- **elbow**, composed of 2 joints (yaw and pitch) +- **wrist**, composed of 3 joints (roll, pitch and yaw) + +We refer to the shoulder, elbow and wrist as **actuators**. +For some actions, such as changing the compliance, is the the lowest level of control you will have. + +### The actuators + +Each actuator has a unique name and uid. To access a specific actuator, you can use the attribute under the part you are using. We don't not provide a direct access to all actuators. For the arms, the following actuators are available: + +```python +from reachy2_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.r_arm._actuators +>>> +``` + +Because they are parallel actuators, it often doesn't have sense to control one motor of an actuator without controlling the other motors of the same actuator. + +This is why actuators are for several cases the lowest degree of control we give. At the actuator level, you can then: +- modify the actuator compliance +- modify torques +- modify speed + + +### The joints + +Each joint has a unique name and uid. To access a specific joint, you can either use *reachy.joints* which has each joint of the robot as attribute or access it via the actuators it belongs to. For example, to access the right arm shoulder roll : *reachy.r_arm.shoulder.roll*. + +First, connect to your Reachy. + +```python +from reachy_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.r_arm.shoulder.roll +>>> +``` +The name and the id are attributes of the returned Joint object. + +```python +reachy.r_arm.r_shoulder_pitch.name +>>> 'r_shoulder_pitch' +reachy.r_arm.r_shoulder_pitch.uid +>>> 8 +``` + +Joints in Reachy are abstract elements that do not have a physical element. A joint is controlled by several motors of the actuators. The only thing you can do at joint level is reading the **present_position** and send **goal_position**. + +#### present_position + +You can get the present position of each joint with this attribute. + +```python +reachy.r_arm.r_shoulder_pitch.present_position +>>> 22.4 +``` + +> present_position is returned in **degrees**. + +#### goal_position + +The *goal_position* attribute of a joint can be used to set a new joint's target position to make it move. However, we recommend using the [**goto_joints() method**]({{< ref "developing-with-reachy-2/basics/3-basic-arm-control#goto_joints" >}}) to move the motors which provides better control on the joint's trajectories. + +Using goal_position will make the motor move **as fast as it can**, so be careful when using it. +```python +reachy.r_arm.r_elbow_pitch.goal_position = -90 +``` + +> goal_position must be written in **degrees**. + +### The gripper + +## Arm moves methods +### goto_joints() + +The **`goto_joints()`** method takes a seven-elements-long list, with the angles in this order: +- r_arm.shoulder.pitch +- r_arm.shoulder.roll +- r_arm.elbow.yaw +- r_arm.elbow.pitch +- r_arm.wrist.roll +- r_arm.wrist.pitch +- r_arm.wrist.yaw + +Let's see an example of how to use it. + +You will use the `goto_joints()` methods to place the right arm at a right-angled position. First, make sure that the Reachy's right arm is placed on a cleared table and that there will not be obstacles during its movement. + +The setup should look like this: + +{{< img-center "images/sdk/first-moves/base_pos.jpg" 500x "" >}} + +Let's define a list with **reachy.r_arm.elbow.pitch** at -90 degrees to the set a right-angled position for the right arm: + +```python +right_angled_pose = [0, 0, 0, -90, 0, 0, 0] +``` + +Then send the `goto_joints()` commands to the right arm: +Set the right arm motors in stiff mode. + +```python +reachy.r_arm.turn_on() # don't forget to turn the arm on + +reachy.r_arm.goto_joints(right_angled_pose) +``` + +You can use the + + +The result should look like this: + +

+ {{< video "videos/sdk/goto.mp4" "80%" >}} +

+ +Don't forget to put the right arm's joints back to the compliant mode. Place your hand below the right arm's gripper to prevent the arm from falling hard on the table. + +```python +reachy.r_arm.turn_off() +``` + +> To find out whether you have to send positive or negative angles, read next section on the arm kinematics. + +### goto_matrix() + +The **`goto_matrix()`** method takes a 4x4 matrix expressing the target pose of Reachy 2's end effector in Reachy 2 coordinate system. + +> Read next section on [Use arm kinematics]({{< ref "developing-with-reachy-2/basics/4-use-arm-kinematics" >}}) to better understand the use of the `goto_matrix()` method. + +## Gripper control + +### open() + +To **open the grippers**, call the **`open()`** method on the wanted gripper. +It will open it entirely: +```python +reachy.r_arm.gripper.open() +``` + +### close() + +To **close the grippers**, call the **`close()`** method on the wanted gripper. +It will close the gripper with the appropriate value, which means it will be entirely closed if there is no object to grasp, or set a suitable value if an object has been detected in the gripper during the closing: +```python +reachy.r_arm.gripper.close() +``` + +### opening + +The opening value corresponds to a **percentage of opening**, which means: +- 0 is close +- 100 is open + +You can read the opening of the gripper through the opening attribute: +```python +reachy.r_arm.gripper.opening +>>> 20 # almost closed +``` + +You can also control the opening of the gripper, using the **`set_opening()`** method. + +Send your custom opening value, still between 0 and 100, to the gripper with: +```python +reachy.r_arm.gripper.set_opening(50) # half-opened +``` + +> Note that there is an smart gripper control that will avoid the gripper from reaching the opening position if an object has been detected while closing the gripper. + + +## Read arm position + +### get_joints_position() + +You can retrieve the values from each **arm joints** using the **`get_joints_position()`** method. + +This method returns a seven-elements-long list, with the angles in this order: +- r_arm.shoulder.pitch +- r_arm.shoulder.roll +- r_arm.elbow.yaw +- r_arm.elbow.pitch +- r_arm.wrist.roll +- r_arm.wrist.pitch +- r_arm.wrist.yaw + +> Angles are returned in **degrees** by default. + +```python +reachy.l_arm.rotate_to(20, 30, -10) + +reachy.head.get_joints_position() +>>> [7, 10, 4, -50, 4, 5, 7] + +# r_arm.shoulder.pitch=7, +# r_arm.shoulder.roll=10, +# r_arm.elbow.yaw=4, +# r_arm.elbow.pitch=-50, +# r_arm.wrist.roll=4, +# r_arm.wrist.pitch=5, +# r_arm.wrist.yaw=7, +``` + + +### End effector position + +You can get the end effector position of Reachy 2 in Reachy 2 coordinate system using forward kinematics. + +Call: +```python +reachy.l_arm.forward_kinematics() +``` +to get the position of the left gripper in cartesian space. + +> Read next section on [Use arm kinematics]({{< ref "developing-with-reachy-2/basics/4-use-arm-kinematics" >}}) to better understand the use of the `forward_kinematics()` method. diff --git a/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md b/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md index 6cee37dc..9e5c4383 100644 --- a/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md +++ b/content/developing-with-reachy-2/basics/4-use-arm-kinematics.md @@ -14,4 +14,319 @@ weight: 230 toc: true --- -Ohlala it's safe now \ No newline at end of file +## Arm coordinate system + +### Joint coordinates + +If you remember the [`goto_joint()` function]({{< ref "developing-with-reachy-2/basics/3-basic-arm-control#goto_joints" >}}), to generate a trajectory for the arm, you need to pass a list of joints with the requested position as argument. + +For example, to place the right arm in a right angled position, we defined the following list: + +```python +right_angled_position = [0, 0, 0, -90, 0, 0, 0] +``` + +and then call the function with is: + +```python +reachy.r_arm.goto_joints(right_angled_position) +``` + +In this basic arm control, we used what is called **joint coordinates** to move Reachy. This means that we controlled each joint separately. + +Controlling a robot in joint coordinates can be hard and is often far from what we actually do as humans. When we want to grasp an object in front of us, we think of where we should put our hand, not how to flex each individual muscle to reach this position. This approach relies on the cartesian coordinates: the 3D position and orientation in space, this is where the **kinematic model** comes into play. + +### Kinematic model + +The **kinematic model** describes the motion of a robot in mathematical form without considering the forces and torque affecting it. It only focuses on the geometric relationship between elements. + +We have defined the whole kinematic model of the arm. This means the translation and rotation required to go from one joint to the next one. On a right arm equipped with a gripper this actually look like this: + +|Motor|Translation|Rotation| +|-----|-----------|--------| +|r_arm.shoulder.pitch|(0, -0.019, 0)|(0, 1, 0) +|r_arm.shoulder.roll|(0, 0, 0)|(1, 0, 0) +|r_arm.elbow.yaw|(0, 0, -0.280)|(0, 0, 1) +|r_arm.elbow.pitch|(0, 0, 0)|(0, 1, 0) +|r_arm.wrist.roll|(0, 0, -0.120)|(0, 0, 1) +|r_arm.wrist.pitch|(0, 0, 0)|(0, 1, 0) +|r_arm.wrist.yaw|(0, 0, 0)|(1, 0, 0) +|r_gripper|(0, ??, ??)|(0, 0, 0) + + +To use and understand the kinematic model, you need to know how Reachy coordinate system is defined (from Reachy's perspective), see below: + +{{< img-center "images/sdk/first-moves/arm_axis.png" 400x "" >}} + +* the X axis corresponds to the forward arrow, +* the Y axis corresponds to the right to left arrow, +* the Z axis corresponds to the up arrow. + +The origin of this coordinate system is located in the upper part of the robot trunk, inside Reachy. + Basically, if you imagine a segment going from the left shoulder to the right shoulder of the robot, the origin is the middle of this segment, which corresponds to behind the center of Pollen's logo on Reachy's torso. + +{{< img-center "images/sdk/first-moves/reachy_frame.jpg" 400x "" >}} + +> Units in this coordinate system are **meters**. So the point (0.3, -0.2, 0) is 30cm in front of the origin, 20cm to the right and at the same height. + + +### End effector location + +We consider the end-effector to be in a virtual joint located in the gripper and referred as *'right_tip'* or *'left_tip'* in the [urdf file](https://github.com/pollen-robotics/reachy_kinematics/blob/master/reachy.URDF), as shown below. + +{{< img-center "images/sdk/first-moves/eef.png" 400x "" >}} + +The red dot corresponds to the *'right_tip'*. + +You can see the right and left end-effectors animated below. + +

+ {{< video "videos/sdk/eef.mp4" "80%" >}} +

+ +### Switching between joint and cartesian coordinates + +Forward and inverse kinematics are a way to go from one coordinates system to the other: + +* **forward kinematics: joint coordinates –> cartesian coordinates**, +* **inverse kinematics: cartesian coordinates –> joint coordinates**. + +## Forward kinematics + +Using the kinematic model defined above, we can compute the 3D position and orientation of the right or left end-effector with the **`forward_kinematics()`** method. + +### forward_kinematics() + +Each arm has a **`forward_kinematics()`** method. To use it, you first need to connect to your Reachy. + +```python +from reachy_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.r_arm.forward_kinematics() +>>> array([[ 0.04622308, -0.03799621, -0.99820825, 0.31144822], + [ 0.10976691, 0.99341829, -0.03273101, -0.19427524], + [ 0.99288199, -0.1080573 , 0.05008958, -0.4255104 ], + [ 0. , 0. , 0. , 1. ]]) +``` + +The method returns a 4x4 matrix indicating the position and orientation of the end effector in Reachy 2's coordinate system. + +> By specifying no argument, it will give the current 3D position and orientation of the end effector. + +You can compute the forward kinematics of the arm for other joints positions, by giving as an argument a seven-element-long list, as for the `goto_joints()`method. The arm will not move, but you can get the target position and orientation of the arm in this configuration. + +For example, for the right arm right angled position: +```python +reachy.r_arm.forward_kinematics([0, 0, 0, -90, 0, 0, 0]) +>>> array([[ 0.04622308, -0.03799621, -0.99820825, 0.31144822], + [ 0.10976691, 0.99341829, -0.03273101, -0.19427524], + [ 0.99288199, -0.1080573 , 0.05008958, -0.4255104 ], + [ 0. , 0. , 0. , 1. ]]) +``` + +### Understand the result +The 4x4 matrix returned by the **`forward_kinematics()`** method is what is often called a **pose**. It actually encodes both the 3D translation (as a 3D vector) and the 3D rotation (as a 3x3 matrix) into one single representation. + +$$\begin{bmatrix} +R_{11} & R_{12} & R_{13} & T_x\\\\\\ +R_{21} & R_{22} & R_{23} & T_y\\\\\\ +R_{31} & R_{32} & R_{33} & T_z\\\\\\ +0 & 0 & 0 & 1 +\end{bmatrix}$$ + +The instruction + +```python +reachy.r_arm.forward_kinematics() +``` + +returns the current pose of the right end-effector, based on the present position of every joint in the right arm. + +You can also compute the pose for a given joints position, to do that just pass the list of position as argument of forward_kinematics. Be careful to respect the order of the position you give and to give all the joints in the arm kinematic chain (i.e. from *shoulder_pitch* to *wrist_roll*). + +For example, we can compute the forward kinematics for the right-angle position we defined earlier. + +```python +reachy.r_arm.forward_kinematics(right_angle_position) +>>> array([[ 0. , 0. , -1. , 0.3675], + [ 0. , 1. , 0. , -0.202 ], + [ 1. , 0. , 0. , -0.28 ], + [ 0. , 0. , 0. , 1. ]]) +``` + +With this result, we can tell that when the right arm is in the right angle position, the right end-effector is 37cm in front of the origin, 20cm to the left and 28cm below the origin. + +As of the rotation matrix, the identity matrix corresponds to the zero position of the robot which is when the hand is facing toward the bottom. + +Here we obtained the rotation matrix + +$$\begin{bmatrix} +0 & 0 & -1\\\\\\ +0 & 1 & 0 \\\\\\ +1 & 0 & 0 +\end{bmatrix}$$ + +We can use scipy to understand what this matrix represents. + +```python +from scipy.spatial.transform import Rotation as R +import numpy as np + +R.from_matrix([ + [0, 0, -1], + [0, 1, 0], + [1, 0, 0], +]).as_euler('xyz', degrees=True) +>>> array([ 0. , -89.99999879, 0. ]) +``` +So scipy tells us that a rotation of -90° along the y axis has been made to get this matrix, which is coherent with the result because having the hand facing forward corresponds to this rotation according to Reachy's xyz axis that we saw above. + +## Inverse kinematics + +The inverse kinematics is the exact opposite of the forward kinematics. From a 4x4 pose in Reachy 2 coordinate system, it gives you a list of joints positions to reach this target. + +Knowing where you arm is located in the 3D space can be useful but most of the time what you want is to move the arm in cartesian coordinates. You want to have the possibility to say: “move your hand to [x, y, z] with a 90° rotation around the Y axis”. This is what **`goto_matrix()`** + +### inverse_kinematics() + +Each arm has an **`inverse_kinematics()`** method. To use it, you first need to connect to your Reachy. +You need to specify as an argument a target pose in Reachy coordinate system. + +Let's for example ask for the inverse kinematics of the current pose, using the forward kinematics. + +```python +from reachy_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.r_arm.inverse_kinematics(reachy.r_arm.forward_kinematics()) +>>> [0, 0, 0, -90, 0, 0, 0] ?? +``` + +The method returns a seven-element-long list indicating the position of each arm joint, in the usual order: +- r_arm.shoulder.pitch +- r_arm.shoulder.roll +- r_arm.elbow.yaw +- r_arm.elbow.pitch +- r_arm.wrist.roll +- r_arm.wrist.pitch +- r_arm.wrist.yaw + +Contrary to the forward kinematics which has a unique answer (giving all joints values will always put the end effector at the same target position), inverse kinematics can have an infinite number of answers (for a target position of the end effector, several combinations of joints angles are possible). + +#### Using a q0 value +The inverse kinematics returns one solution, but you may want to custom the position from which the computation is done to get another result. +To do so, specify a **q0** value when calling the `inverse_kinematics()` method. The **`q0`** argument must be a seven-element-long list as well: +```python +reachy.r_arm.inverse_kinematics( + reachy.r_arm.forward_kinematics(), + q0=[0, 0, 0, 0, 0, 0, 0]) +>>> [0, 0, 0, -90, 0, 0, 0] ?? +``` + + +### Example: square movement with goto_matrix() + +#### Defining the poses + +To make this more concrete, let's first try with a simple example. We will make the right hand draw a square in 3D space. To draw it, we will define the four corners of a square and Reachy's right hand will go to each of them. + +The virtual corner is represented below. + +{{< img-center "images/sdk/first-moves/square_setup.jpg" 400x "" >}} + +For our starting corner A, let's imagine a point in front of the robot, on its right and below its base. With Reachy coordinate system, we can define such a point with the following coordinates: + +$$A = \begin{pmatrix}0.3 & -0.4 & -0.3\end{pmatrix}$$ + +The coordinates of B should match A except the z component wich should be higher. Hence + +$$B = \begin{pmatrix}0.3 & -0.4 & 0.0\end{pmatrix}$$ + +For the corner C, we want a point on the same z level as B in the inner space of Reachy and in the same plane as A and B so we only need to change the y component of B. We can take for example + +$$C = \begin{pmatrix}0.3 & -0.1 & 0.0\end{pmatrix}$$ + +And to complete our corners we can deduce D from A and C. D coordinates should match C except its z component which must the same as A. Hence + +$$D = \begin{pmatrix}0.3 & -0.1 & -0.3\end{pmatrix}$$ + +> **Remember that you always have to provide poses to the inverse kinematics that are actually reachable by the robot.** If you're not sure whether the 3D point that you defined is reachable by Reachy, you can move the arm with your hand in compliant mode, ask the forward kinematics and check the 3D translation component of the returned pose. + +But having the 3D position is not enough to design a pose. You also need to provide the 3D orientation via a rotation matrix. The rotation matrix is often the tricky part when building a target pose matrix. + +Keep in mind that the identity rotation matrix corresponds to the zero position of the robot which is when the hand is facing toward the bottom. So if we want the hand facing forward when drawing our virtual square, we need to rotate it from -90° around the y axis, as we saw in the forward kinematics part. + +We know from before which rotation matrix corresponds to this rotation, but we can use scipy again to generate the rotation matrix for given rotations. + +```python +print(np.around(R.from_euler('y', np.deg2rad(-90)).as_matrix(), 3)) +>>> [[ 0. -0. -1.] + [ 0. 1. -0.] + [ 1. 0. 0.]] +``` + +We got the rotation matrix that we expected! + +As mentionned, building the pose matrix can be hard, so don't hesitate to use scipy to build your rotation matrix. You can also move the arm with your hand where you want it to be and use the forward kinematics to get an approximation of the target pose matrix you would give to the inverse kinematics. + +Here, having the rotation matrix and the 3D positions for our points A and B, we can build both target pose matrices. + +```python +A = np.array([ + [0, 0, -1, 0.3], + [0, 1, 0, -0.4], + [1, 0, 0, -0.3], + [0, 0, 0, 1], +]) + +B = np.array([ + [0, 0, -1, 0.3], + [0, 1, 0, -0.4], + [1, 0, 0, 0.0], + [0, 0, 0, 1], +]) + +C = np.array([ + [0, 0, -1, 0.3], + [0, 1, 0, -0.1], + [1, 0, 0, 0.0], + [0, 0, 0, 1], +]) + +D = np.array([ + [0, 0, -1, 0.3], + [0, 1, 0, -0.1], + [1, 0, 0, -0.3], + [0, 0, 0, 1], +]) +``` + +#### Sending the movements commands + +As before, we use the **`goto_matrix()`** to send moving instructions to the arm. + + +```python +import time +# put the joints in stiff mode +reachy.r_arm.turn_on() + +# use the goto_matrix() method +reachy.r_arm.goto_matrix(A) +reachy.r_arm.goto_matrix(B) +reachy.r_arm.goto_matrix(C) +reachy.r_arm.goto_matrix(D) + +# put the joints back to compliant mode +# use turn_off_smoothly to prevent the arm from falling hard +reachy.r_arm.turn_off() +``` + +The result should look like this: + +

+ {{< video "videos/sdk/goto_ik.mp4" "80%" >}} +

\ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/5-control-head.md b/content/developing-with-reachy-2/basics/5-control-head.md index d7ba2937..b83720a0 100644 --- a/content/developing-with-reachy-2/basics/5-control-head.md +++ b/content/developing-with-reachy-2/basics/5-control-head.md @@ -14,4 +14,163 @@ weight: 240 toc: true --- -Ohlala it's safe now \ No newline at end of file + +## Head presentation + +Reachy 2's head is mounted on an Orbita3D actuator, referred to as the **neck** actuator, giving 3 degrees of freedom to control the head orientation. +> Note : the antennas are not motorized for the moment + +

+ {{< video "videos/sdk/orbita.mp4" "80%" >}} +

+ + +Before starting to control it, connect to your Reachy and turn it on. As in the other pages: + +```python +from reachy2_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.head +>>> + +reachy.head.turn_on() # we turn on only the head +``` + +You could of course turn on the whole robot by calling `reachy.turn_on()` directly. + +There are several ways to control the head movements: +- using the `look_at()`, `rotate_to()` and `orient()` methods, called directly at the **head** level. These methods works as [move commands described previously]({{< ref "developing-with-reachy-2/basics/2-understand-moves" >}}). +- controlling the joints goal positions, namely **reachy.head.neck.roll**, **reachy.head.neck.pitch** and **reachy.head.neck.yaw**. + +## Head moves methods + +### look_at() + +You can use the `look_at()` function to make the head look at a specific point in space. This point must be given in Reachy 2's coordinate system in **meters**. The coordinate system is the one we have seen previously: + +* the X axis corresponds to the foward arrow, +* the Y axis corresponds to the right to left arrow, +* the Z axis corresponds to the up arrow. + +The origin of this coordinate system is located in the upper part of the robot trunk. + +{{< img-center "images/sdk/first-moves/reachy_frame.jpg" 400x "" >}} + +If you want Reachy to look forward you can send it the following. + +```python +reachy.head.turn_on() # Don't forget to put the hand in stiff mode +reachy.head.look_at(x=0.5, y=0, z=0.2, duration=1.0) +``` + +You can use multiple *look_at* to chain head movements, or even chain them with the `rotate_to()` and `orient()` functions described below. As seen in the [Understand moves in Reachy 2 section]({{< ref "developing-with-reachy-2/basics/2-understand-moves" >}}), the commands on the head will be stacked. + +

+ {{< video "videos/sdk/look.mp4" "80%" >}} +

+ +Here is the code to reproduce this. + +```python +import time + +look_right = reachy.head.look_at(x=0.5, y=-0.5, z=0.1, duration=1.0) +look_down = reachy.head.look_at(x=0.5, y=0, z=-0.4, duration=1.0) +look_left = reachy.head.look_at(x=0.5, y=0.3, z=-0.3, duration=1.0) +look_front = reachy.head.look_at(x=0.5, y=0, z=0, duration=1.0) +``` + +The best way to understand how to use the *look_at* is to play with it. Picture a position you would like Reachy's head to be in, guess a point which could match for the *look_at* and check if you got it right! + +Another cool thing is that we can combine Reachy's kinematics with the *look_at* so that Reachy's head follows its hand! + +

+ {{< video "videos/sdk/look_at_hand.mp4" "80%" >}} +

+ +```python +reachy.turn_on('head') + +x, y, z = reachy.r_arm.forward_kinematics()[:3, -1] +reachy.head.look_at(x=x, y=y, z=z, duration=1.0) + +time.sleep(0.5) + +while True: + x, y, z = reachy.r_arm.forward_kinematics()[:3, -1] + reachy.head.look_at(x=x, y=y, z=z, duration=0.1) +``` + +What the code says is that we compute the [forward kinematics of Reachy's right arm]({{< ref "developing-with-reachy-2/basics/5-control-head#forward-kinematics" >}}), and the x, y, z of Reachy's right end-effector in the Reachy's coordinates system will be the coordinates of the point used by the *look_at*. + +### rotate_to() + +The `rotate_to()` function is another way to control the head. You directly control the joint of the neck, giving the roll, pitch and yaw angles in degrees. The rotation is made in the order: roll, pitch, yaw, in the Orbita3D coordinate system. + +{{< img-center "images/sdk/first-moves/orbita_rpy.png" 400x "" >}} + +To make the robot looks a little down: +```python +reachy.head.turn_on() # Don't forget to put the hand in stiff mode +reachy.head.rotate_to(roll=0, pitch=-10, yaw=0, duration=1.0) +``` + +### orient() + +The last method to control the head is the `orient()` method. You can control the head with a quaternion. + +You can use [pyquaternion library](https://kieranwynn.github.io/pyquaternion/) to create suitable quaternion for this method. + +```python +from pyquaternion import Quaternion + +q = Quaternion(axis=[1, 0, 0], angle=3.14159265) +reachy.head.turn_on() +reachy.head.orient(q) +``` + +## Joint's goal_position + + +## Read head position + +You can read the head orientation in two different ways: + +- using the `get_orientation()` method, which returns a quaternion +- using the `get_joints_positions()` method, which the neck's roll, pitch and yaw present_position. + +### get_orientation() + +```python +q = reachy.head.get_orientation() +print(q) +>>> ?? +``` + +### get_joints_positions() + +In case you feel more comfortable using roll, pitch, yaw angles rather than working with quaternions, you can retrieve those values from the **neck joints**. + +```python +reachy.head.rotate_to(20, 30, -10) +time.sleep(2) +reachy.head.get_joints_positions() +>>> [20, 30, -10] # roll=20, pitch=30, yaw=-10 +``` + +Be careful that contrary to the quaternion that offers a unique representation of a rotation, it is not the case of the euler angles. Several angles combination can lead to the same orientation in space. For example: + +```python +reachy.head.rotate_to(70, -100, 80) # roll=70, pitch=-100, yaw=80 +time.sleep(2) +reachy.head.get_joints_positions() +>>> [-110, -80, -100] # roll=-110, pitch=-80, yaw=-100 +``` + +The values are different, nevertheless it is the same final orientation. You can convince yourself doing: +```python +reachy.head.rotate_to(-110, -80, -100) +``` +The head won't move. \ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md b/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md index b0b228bd..85ae7030 100644 --- a/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md +++ b/content/developing-with-reachy-2/basics/6-get-images-from-cameras.md @@ -14,4 +14,131 @@ weight: 250 toc: true --- -Ohlala it's safe now \ No newline at end of file +This section assumes that you went through the [Hello World]({{< ref "developing-with-reachy-2/getting-started-sdk/connect-reachy2" >}}) so that you know how to connect to the robot. + +Reachy 2 has 2 types of camera: +- the **teleop** cameras, with a right and left cameras, located in Reachy 2's head and used for the teleoperation +- the **SR** camera, which is a depth camera, located in Reachy 2's torso and mainly useful for manipulation tasks + +Each camera can be accessed separately through *reachy.cameras*. They both have a right and left view, with the left and right sides considered from Reachy point of view. To be able to specify the view you want to get a frame from, you will need to import CameraView: + +```python +from reachy2_sdk.media.camera import CameraView +``` + +## Enable teleop cameras for the SDK + +### SR camera +The SR camera is unplugged by default. +If you want to use it, plug the SR camera on the robot's computer remaining USB port (2). + +{{< img-center "images/sdk/first-moves/plugged-sr.png" 400x "" >}} + +> Make sure to unplug it if you want to use the teleoperation. + +### Teleop cameras +The teleop cameras are shared between the teleop service and the SDK server, and can only be used by one at the same time. +In order to be able to use the teleop cameras with the SDK: +1. Go to the dashboard +2. Stop webrtc service in the services tab of the dashboard + +{{< img-center "images/sdk/first-moves/stop-webrtc-service.png" 600x "" >}} + +## Get images + +First, connect to your Reachy. + +```python +from reachy_sdk import ReachySDK + +reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP + +reachy.cameras +>>> ?? +``` + +The list of initialized cameras should contain both the teleop and SR camera. + +For each camera, namely the teleop and the SR ones, you must call the `capture()`function each time you want to get an image. This captures an image from both view of the given camera at the same time. You can then access one of the image with the `get_frame()` method. + +### Teleop camera + +To get both views of the robot teleop cameras: +```python +from reachy2_sdk import ReachySDK +from reachy2_sdk.media.camera import CameraView + +reachy = ReachySDK(host='192.168.0.42') + +reachy.cameras.teleop.capture() +l_frame = reachy.cameras.teleop.get_frame(CameraView.LEFT) +r_frame = reachy.cameras.teleop.get_frame(CameraView.RIGHT) +``` + +Let's display the captured frame with opencv: +```python +import cv2 + +cv2.imshow("left", l_frame) +cv2.imshow("right", r_frame) +cv.waitKey(0) +cv.destroyAllWindows() +``` + +### SR camera +The SR camera works exactly the same as the teleop camera, but you have more elements captured. In fact, it a RGBD camera, so you have both access to the RGB images and depth information. + +#### RGB images +Getting RGB images from the SR camera looks the same as from the teleop one: after having called `capture()`, use `get_frame()` specifying the CameraView you want to get. +```python +from reachy_sdk import ReachySDK +from reachy2_sdk.media.camera import CameraView + +reachy = ReachySDK(host='192.168.0.42') + +reachy.cameras.SR.capture() +l_frame = reachy.cameras.SR.get_frame(CameraView.LEFT) +r_frame = reachy.cameras.SR.get_frame(CameraView.RIGHT) +``` + +Let's display them with opencv: +```python +import cv2 + +cv2.imshow("left", l_frame) +cv2.imshow("right", r_frame) +cv.waitKey(0) +cv.destroyAllWindows() +``` + +#### Depth information + +The SR camera is a depth camera, you can then diplay a left or right **depth frame** using `get_depth_frame()`, but also the **depthmap** and the **disparity**. + +You first have to capture all, then you can read the frame and get the information you want: +```python +from reachy_sdk import ReachySDK +from reachy2_sdk.media.camera import CameraView + +reachy = ReachySDK(host='192.168.0.42') + +reachy.cameras.SR.capture() +l_depth_frame = reachy.cameras.SR.get_depth_frame(CameraView.LEFT) +r_depth_frame = reachy.cameras.SR.get_depth_frame(CameraView.RIGHT) +depth = reachy.cameras.SR.get_depthmap() +disparity = reachy.cameras.SR.get_disparity() +``` + +Let's display them with opencv: +```python +import cv2 + +cv2.imshow("sr_depthNode_left", l_depth_frame) +cv2.imshow("sr_depthNode_right", r_depth_frame) +cv2.imshow("depth", depth) +cv2.imshow("disparity", disparity) +cv.waitKey(0) +cv.destroyAllWindows() +``` + +> Note that when you call `capture()` on the SR camera, both RGB images and depth information are captured at the same time. \ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md b/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md index 645f770e..a6eb4572 100644 --- a/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md +++ b/content/developing-with-reachy-2/basics/7-record-replay-trajectories.md @@ -14,4 +14,111 @@ weight: 260 toc: true --- -Ohlala it's safe now \ No newline at end of file + +You can easily record joint trajectories directly on Reachy, store and replay them later. This page will show you how to implement such mechanisms. + +All examples given below will show trajectories record on each of the robot joints. The position of each motor will be stored at a predefined frequency (typically 100Hz). Similarly, the replay will set new target position using the same frequency. Those basics examples does not perform any kind of filtering or modification of the data. + +In the following examples, we will assume that you are already connected to your robot and know how to control individual motors. + +## Recording a trajectory + +To record a trajectory, we will simply get the current position of individual motors at a predefiend frequency. We will first define a list of motors that we want to record. In this example, we will only record the joints from the right arm, but you can similarly record a single motor, or all motors of the robot at once. + +```python +# assuming we run something like this before: +# reachy = ReachySDK(host='192.168.0.42') + +recorded_joints = [ + reachy.r_arm.r_shoulder_pitch, + reachy.r_arm.r_shoulder_roll, + reachy.r_arm.r_arm_yaw, + reachy.r_arm.r_elbow_pitch, + reachy.r_arm.r_forearm_yaw, + reachy.r_arm.r_wrist_pitch, + reachy.r_arm.r_wrist_roll, +] +``` + +Now let's define our frequency and record duration: + +```python +sampling_frequency = 100 # in Hz +record_duration = 5 # in sec. +``` + +Our record loop can then be defined as such: + +```python +import time + +trajectories = [] + +start = time.time() +while (time.time() - start) < record_duration: + # We here get the present position for all of recorded joints + current_point = [joint.present_position for joint in recorded_joints] + # Add this point to the already recorded trajectories + trajectories.append(current_point) + + time.sleep(1 / sampling_frequency) +``` +If you want to record a demonstration on the robot, first make sure the robot is compliant. Then, put it in the starting position. Run the code, and start moving the robot. After 5 seconds, the loop will stop and the movements you have made on Reachy will be recorded. + +Depending on your uses, you can define another duration. You can also choose not to use a specify duration but maybe use start and stop event to record. In such case, the easy way is probably to run the loop within a thread or an asynchronous fonction, so it can run in background. + +## Visualise your recordings + +The trajectories you recorded can be converted to numpy array for more complex processings: + +```python +import numpy as np + +traj_array = np.array(trajectories) +``` + +If you are familiar with matplotlib, you can also plot it via: + +```python +from matplotlib import pyplot as plt + +plt.figure() +plt.plot(trajectories) +``` + +## Replay a recorded trajectory + +Replaying the recorded trajectory basically uses the same loop but set the goal position instead of reading the present position. + +But before actually replaying the trajectory, there are a few key points that you should take care of: + +- First, make sure the joints you are going to move are stiff. +- Then, if the arm is not in the same position than the one you use as a start position of your recording, the beginning of the replay will be really brutal. It will try to go to the starting position as fast as possible. + +To avoid that, you can use the goto function to first go to the first point of your trajectories: + +```python +from reachy_sdk.trajectory import goto + +# Set all used joint stiff +for joint in recorded_joints: + joint.compliant = False + +# Create a dict associating a joint to its first recorded position +first_point = dict(zip(recorded_joints, trajectories[0])) + +# Goes to the start of the trajectory in 3s +goto(first_point, duration=3.0) +``` + +Now that we are in position, we can actually play the trajectory. To do that, we simply loop over our recordings and set the goal position of each joints at the same frequency: + +```python +import time + +for joints_positions in trajectories: + for joint, pos in zip(recorded_joints, joints_positions): + joint.goal_position = pos + + time.sleep(1 / sampling_frequency) +``` \ No newline at end of file diff --git a/content/developing-with-reachy-2/basics/8-use-mobile-base.md b/content/developing-with-reachy-2/basics/8-use-mobile-base.md index 92cc4a07..d4f0223f 100644 --- a/content/developing-with-reachy-2/basics/8-use-mobile-base.md +++ b/content/developing-with-reachy-2/basics/8-use-mobile-base.md @@ -14,4 +14,83 @@ weight: 270 toc: true --- -Ohlala it's safe now \ No newline at end of file + +## What is accessible on the mobile base +The following elements are accessible with *reachy.mobile_base*: +* mobile base version, +* battery level, +* odometry of the base, +* control and drive modes, +* goto and set_speed methods to make the mobile base move. + +## Frames + +### Robot frame +The robot frame or egocentric frame or base_link frame is **rigidly attached to the robot**. Its (0, 0) point is the projection on the floor of the center of the mobile base. +**X in front, Y to the left, Theta positive counterclockwise.** + +{{< img-center "images/sdk/mobile-base/robot_frame.png" 400x "" >}} + +*It follows ROS' conventions described in [REP 105 “Coordinate Frames for Mobile Platforms”](https://www.ros.org/reps/rep-0105.html)* + +### Odom frame +The odom frame is a **world-fixed frame**. The position (x, y, theta) of the robot in the odom frame is continuously updated by the HAL through odometry calculations. These calculations currently only use the measurements from the wheels to estimate the movement of the robot. While the position of the robot is continuous, **it should never be relied upon for long-term reference as it will always drift.** + +{{< img-center "images/sdk/mobile-base/odom_frame.png" 400x "" >}} + +The initial position of the odom frame matches the position of the robot when the HAL was started. The odom frame can also be reset to the current position of the robot using: + ```python + reachy_mobile.mobile_base.reset_odometry() + ``` + +## Moving the mobile base + +### Using the goto method +The `goto()` method expects a goal position in the [odom frame]({{< ref "/developing-with-reachy-2/basics/8-use-mobile-base#odom-frame" >}}), composed of 3 elements: x in meters, y in meters and theta in degrees. + +:warning: The most important thing to get used to, is the fact that the odom frame is world-fixed and that the position of the robot is always updated as long as the HAL is running (the HAL is automatically started during the robot boot-up). So by default, **if you ask for a ```goto(0, 0, 0)``` the robot will try to comeback to the position it was at boot-up.** + +To perform a goto relative to the current position of the robot, use the method ```reset_odometry()```. For example, create an instance of reachy with: + +```python +from reachy2_sdk import ReachySDK + +reachy = ReachySDK(host='your-reachy-ip') +``` + +Reset the odometry frame, and ask the robot to move 50cm in front of it: +```python +reachy.mobile_base.reset_odometry() +reachy.mobile_base.goto(x=0.5, y=0.0, theta=0.0) +``` +Now, ask for a goto(0,0,0). The robot should go back to its previous position: +```python +reachy_mobile.mobile_base.goto(x=0.0, y=0.0, theta=0.0) +``` + +We recommend taking the time to play around with this concept. + +> Note the **goto() method of the mobile base does not work like [moves methods explained previously]({{< ref "/developing-with-reachy-2/basics/8-use-mobile-base">}})** + + +By default, the robot will always try to reach the goal position, meaning that even if the robot did reach its position and you push it, it will try to come back to the goal position again. + +However, you can define two types of stop conditions through optional parameters. + +- A timeout, expressed in seconds. The robot stops the goto when the elapsed time since the start of the command is superior to the timeout. There is a **default timeout that scales with the distance asked by the goto**. + +- A spatial tolerance, expressed with 4 values: delta_x (the error in m along the X axis), delta_y (the error in m along the Y axis), delta_theta (the angle error in deg) and distance (the l2 distance between the current position and the goal position in m). The robot stops the goto when it is close enough to satisfy all 4 conditions simultaneously. + +### Using the set_speed method +Since the mobile base is holonomic, the `set_speed()` method expects 3 speed commands expressed in the robot frame: +- x_vel, in m/s. The instantaneous speed positive in front of the robot. +- y_vel, in m/s. The instantaneous speed positive to the left of the robot. +- rot_vel, in deg/s. The instantaneous rotational speed positive counterclockwise. + +See the [joy_controller code](https://github.com/pollen-robotics/mobile-base-sdk/blob/main/mobile_base_sdk/examples/scripts/joy_controller.py) for a working example. + +:bulb: As a safety measure, the HAL will stop the wheels if it didn't receive a new goal speed in the last 200ms. + +:bulb: The way this is implemented in the HAL is simply to listen to the /cmd_vel topic, apply some smoothing, perform the kinematic calculations and send the speed commands to the wheels. This makes it very easy to create control interfaces using ROS, see the [keyboard example](https://github.com/pollen-robotics/zuuu_hal/blob/main/examples/zuuu_teleop_keyboard.py) or the [joy controller example](https://github.com/pollen-robotics/zuuu_hal/blob/main/examples/zuuu_teleop_joy.py). + +*Note: the HAL has a drive mode to set speed commands for variable amounts of time. Instead of relying on a topic, it creates a service. The niche usage didn't warrant the added complexity, so the interface with the SDK was not made. But if needed, it exists!* diff --git a/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md b/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md index 25f81860..843d112c 100644 --- a/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md +++ b/content/developing-with-reachy-2/getting-started-sdk/connect-reachy2.md @@ -14,4 +14,25 @@ weight: 110 toc: true --- -Ohlala it's safe now \ No newline at end of file + +The last required step before being able to use your Reachy 2 is to find its IP address. + +> Note: if you haven't connected Reachy to a network yet, please first follow the instructions ??? + +## Using the LCD screen + +If you haven't unplugged it, the LCD screen connected in Reachy's back should be diplaying its IP address. + +{{< img-center "images/sdk/getting-started/lcd-display.png" 400x "" >}} + +If the LCD screen is not working or is unplugged, check out the page Find my IP section to learn other ways to get the IP address. + + +You can check that everything is working as expected by running the following Python code: + +```python +from reachy_sdk import ReachySDK + +# Replace with the actual IP you've found. +reachy = ReachySDK(host='the.reachy.ip.found.') +``` diff --git a/content/developing-with-reachy-2/getting-started-sdk/installation.md b/content/developing-with-reachy-2/getting-started-sdk/installation.md index ea94adfd..c63948d1 100644 --- a/content/developing-with-reachy-2/getting-started-sdk/installation.md +++ b/content/developing-with-reachy-2/getting-started-sdk/installation.md @@ -14,4 +14,35 @@ weight: 100 toc: true --- -Ohlala it's safe now \ No newline at end of file + +## How to install the Python SDK + +The Python SDK is a pure Python library. The installation should thus be rather straightforward. + +It supports Python >= 3.10 (older versions will not work because of typing syntax). It works on Windows/Mac/Linux. + +We recommend to use [virtual environment](https://docs.python.org/3/tutorial/venv.html) for your development. They make the installation simple and avoid compatibility issues. They also come with their [pip](https://pip.pypa.io/en/stable/) command. + +### From PyPi + +```bash +pip install reachy2-sdk +``` + +### From the source + +```bash +git clone https://github.com/pollen-robotics/reachy2-sdk +cd reachy2-sdk +pip install -e reachy2-sdk +``` + +## Dependencies + +The SDK relies on a few third-party Python packages, such as: + +* [numpy](https://numpy.org) - mostly for trajectory computation +* [opencv](https://opencv.org) - for camera frame access +* [grpc](https://grpc.io) - to connect to the robot + +They will be **installed automatically** when you install the SDK. diff --git a/content/docs/_index.md b/content/docs/_index.md deleted file mode 100644 index 8d6f4a8b..00000000 --- a/content/docs/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title : "Docs" -description: "Learn how to install and get started with Reachy." -lead: "" -date: 2020-10-06T08:48:23+00:00 -lastmod: 2020-10-06T08:48:23+00:00 -draft: false -images: [] ---- diff --git a/content/docs/advanced/_index.md b/content/docs/advanced/_index.md deleted file mode 100644 index f5ab8a7f..00000000 --- a/content/docs/advanced/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title : "Advanced usage" -description: "Advanced usage with Reachy 2." -lead: "" -date: 2023-07-25T14:29:14+02:00 -lastmod: 2023-07-25T14:29:14+02:00 -draft: false -images: [] ---- diff --git a/content/docs/advanced/access-computer.md b/content/docs/advanced/access-computer.md deleted file mode 100644 index 832d335b..00000000 --- a/content/docs/advanced/access-computer.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: "Access Reachy 2 computer" -description: "How to connect to the robot's embedded computer" -lead: "How to connect to the robot's embedded computer" -date: 2023-08-09T14:43:24+02:00 -lastmod: 2023-08-09T14:43:24+02:00 -draft: false -images: [] -toc: true -weight: "90" ---- -There are several ways to connect to your robot. - -## SSH connection -Using the robot's IP address (check [Find Reachy 2's IP]({{< ref "help/system/find-my-ip" >}}) if you don't know it), you can directly connect via ssh to Reachy 2's computer: - -```python -ssh bedrock@ -``` - -> For example, with robot's IP being 192.168.1.42: -> ```python -> ssh bedrock@192.168.1.42 -> ``` - -{{< alert icon="👉" text="Password: root" >}} - -## Hard-wired connection - -Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. - -{{< img-center "images/docs/advanced/serial-connection.png" 500x "Serial connection port" >}} - -We use `tio`for the serial connection. If you haven't installed it yet on your computer: -`apt install tio` - -{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER
Then reboot your computer for the new group to be effective." >}} - -Once connected, open a terminal on your computer and run: -```python -tio /dev/ttyUSB0 -``` -*Note that depending on the elements you connected to the robot, the port could be something else than ttyUSB0. Check other available serial ports with `ls /dev/ttyUSB*`* - -{{< img-center "images/docs/advanced/tio-terminal.png" 500x "Tio connection port" >}} - -{{< alert icon="👉" text="Login: bedrock
Password: root" >}} - -You are then connected to Reachy 2 computer! - -## Avahi connection - -Find the serial number of your robot on its back, connect your computer on the same network as your robot, open a terminal and type: -```bash -ping .local -``` - ->For example, if the serial number is reachy2-beta1: ->```bash ->ping reachy2-beta1.local ->``` \ No newline at end of file diff --git a/content/docs/advanced/calibrate-cameras.md b/content/docs/advanced/calibrate-cameras.md deleted file mode 100644 index c6fe36ed..00000000 --- a/content/docs/advanced/calibrate-cameras.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: "Calibrate teleop cameras" -description: "How to calibrate the stereovision for the teleop cameras" -lead: "How to calibrate stereovision on the teleop cameras" -date: 2023-08-09T14:43:31+02:00 -lastmod: 2023-08-09T14:43:31+02:00 -draft: false -images: [] -toc: true -weight: "100" ---- - -{{< alert icon="👉" text="This calibration is for stereovision only. It will only work if the images are clear.

If you want to modify the focus of the cameras because the images are blurred, this requires a hardware intervention on the lenses, which is not covered by the following explanations." >}} - -## Repositories installation - -The calibration process relies in 2 Pollen Robotics repositories. -The simpliest way is to clone both of these repositories on your computer: - -- Pollen's `multical` fork. [**Clone the repo**](https://github.com/pollen-robotics/multical), then: -```bash -cd multical -pip install -e . -``` - -- `pollen-vision` repo. [**Clone the repo**](https://github.com/pollen-robotics/pollen-vision/tree/develop), then: -```bash -cd pollen-vision -pip install -e .[depthai_wrapper] -``` - -> We recommand to use virtual environments. - -## 1. Charuco calibration board - - - -Go to `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`. - -If you don't have one, generate a charuco board with the following command: - -```console -$ python3 generate_board.py -``` - -Print it on a A4 paper and place it on a flat surface (we use a wooden board). - -> You should have received a calibration board with the robot, with the relevant information written behind. - -Mesure as accurately as possible the size of the squares and the size of the markers and edit the `example_boards/pollen_charuco.yaml` file in the previously cloned `multical` repo to report the values you measured (must be in meters). - -## 2. Get some images - -Connect the teleop cameras to your computer. You simply have to disconnect the *teleop cameras* USB connector from the robot's computer and plug it to your computer instead. - -If it is your first calibration, you must add the udev rules with: -```bash -echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="03e7", MODE="0666"' | sudo tee /etc/udev/rules.d/80-movidius.rules -sudo udevadm control --reload-rules && sudo udevadm trigger -``` - -Then, still in `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`, run: -```console -$ python3 acquire.py --config CONFIG_IMX296 -``` - -Press `return` to save a pair of images in `./calib_images/` (by default, use `--imagesPath` to change this). - -Try to cover a maximum of the field of view, with the board in a variety of orientations. If the coverage is good, about 30 images is sufficient. -Also, make sure that most of the board is visible by all the cameras for all the saved images pairs. - -Below is an example of good coverage: -{{< img-center "images/docs/advanced/mosaic.png" 500x "Good coverage images" >}} - -## 3. Run multical - -```console -$ cd <...>/multical -$ multical calibrate --image_path --boards example_boards/pollen_charuco.yaml --isFisheye True -``` - -(For some reason, --image_path must be an absolute path, relative paths don't work) - -It will write a `calibration.json` file in ``. - -## 4. Flash the calibration to the EEPROM - -Back in `pollen-vision/pollen_vision/pollen_vision/camera_wrappers/depthai/calibration`. - -Run: -```console -$ python3 flash.py --config CONFIG_IMX296 --calib_json_file -``` - -A backup file with the current calibration settings stored on the device will be produced in case you need to revert back. - -If needed, run: -```console -$ python3 restore_calibration_backup.py --calib_file CALIBRATION_BACKUP_<...>.json -``` - -## 5. Check the calibration - -Run: -```console -$ python3 check_epilines.py --config CONFIG_IMX296 -``` -And show the aruco board to the cameras. - -An `AVG SLOPE SCORE` below `0.1%` is OK. - -Ideally it could be under `0.05%`. - -The lower, the better. diff --git a/content/docs/getting-started/_index.md b/content/docs/getting-started/_index.md deleted file mode 100644 index 31e6155a..00000000 --- a/content/docs/getting-started/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Getting Started" -description: "On first start." -lead: "" -date: 2023-07-25T14:15:43+02:00 -lastmod: 2023-07-25T14:15:43+02:00 -draft: false -images: [] ---- diff --git a/content/docs/getting-started/dashboard.md b/content/docs/getting-started/dashboard.md deleted file mode 100644 index 356d60d6..00000000 --- a/content/docs/getting-started/dashboard.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: "Connect to the dashboard" -description: "" -lead: "" -date: 2023-08-09T14:43:48+02:00 -lastmod: 2023-08-09T14:43:48+02:00 -draft: false -images: [] -toc: true -weight: "50" ---- -The dashboard is here to give you an overview of the robot's state (what services are running, is there an error on a motor,...) and give you the possibility to access quickly some features (changing a robot's part compliance for example). - -This tool has been thought to help you **start easier with the robot** and **facilitate quick debugging**. - -## 1. Find Reachy 2's IP address - -The LCD screen connected in Reachy's back should be diplaying its IP address. - -{{< img-center "images/vr/getting-started/lcd-display.png" 400x "" >}} - -If the LCD screen is not working or is unplugged, check out the page [Find my IP section]({{< ref "help/system/find-my-ip" >}}) to learn other ways to get the IP address. - -> Note the LCD screen will not work if you plug it after having turned on the computer. - -## 2. Connect from the navigator - -From your computer, on the same network, open a navigator and go to: -**`http://:8000/`** - -> For example, if the screen indicates `192.168.1.42`, connect to `http://192.168.1.42:8000/` - -You should arrive on a services page: - -{{< img-center "images/docs/getting-started/dashboard.png" 600x "dashboard" >}} - -Usage of the dashboard is detailed in the next sections. diff --git a/content/docs/getting-started/hello-world.md b/content/docs/getting-started/hello-world.md deleted file mode 100644 index cad309e2..00000000 --- a/content/docs/getting-started/hello-world.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: "Hello World" -description: "First robot use." -lead: "Is everything working fine?" -date: 2023-08-09T14:44:11+02:00 -lastmod: 2023-08-09T14:44:11+02:00 -draft: false -images: [] -toc: true -weight: "60" ---- -## 1. Check services are running - -All elements of the robots should have started automatically. -Check this is the case on [the dashboard]({{< ref "/docs/getting-started/dashboard" >}}) - -2 services must be launched: -- **reachy2-core** -- **reachy2-webrtc** - -Click on **Logs** for both services to check they have correctly started. -You should see content appearing under the services tab: - -{{< img-center "images/docs/getting-started/dashboard-services.png" 600x "services" >}} - -> If you see any error, click on **Restart** to restart them. - -## 2. Try sending commands - -(Temporary checkup) - -To check everything is working fine, you can use the examples of the Python SDK. - -### Clone reachy2-sdk - -Clone reachy2-sdk repository from Github on your computer. - -### Try the jupyter notebook examples - -Then go to `reachy2-sdk/src/examples/`, and try the two first jupyter notebooks: -- 1_getting_started -- 2_moves_introduction - -Check you manage to connect, to get data from the robot and to make it move. - -> We do not test the cameras from the Python SDK so far, because they can be accessed only by one service at the same time, and the webrtc service is already running by default. - - diff --git a/content/docs/getting-started/network.md b/content/docs/getting-started/network.md deleted file mode 100644 index 91146fa8..00000000 --- a/content/docs/getting-started/network.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: "Connect your robot to the network" -description: "How to connect your robot to the network." -lead: "How to connect Reachy 2 to the network" -date: 2023-08-09T14:44:05+02:00 -lastmod: 2023-08-09T14:44:05+02:00 -draft: false -images: [] -toc: true -weight: "40" ---- -> On the **first connection, connect Reachy 2 to your network using an ethernet cable**. You will then be able to choose another network using the dashboard. - -## Hard-wired connection - -Use an **ethernet cable** to connect your robot to the network. - -Ethernet plugs are available at position (c) of the robot's computer interface. -Reachy 2's computer is configured to use DHCP. It should thus be directly accessible on your network. - -{{< img-center "images/docs/network/hardware-interface.png" 400x "hardware-interface" >}} - -To easily find the IP address of the robot, read the little LCD screen plugged in the back of the robot. Wait for the IP address to appear, it may take a few minutes. - -{{< img-center "images/vr/getting-started/lcd-display.png" 200x "lcd-display" >}} - -> Every 10 seconds, the screen switches between WiFi and Ethernet information. - - -## WiFi - -After your first connection with an ethernet connection, simply use the **dashboard** to connect Reachy to WiFi. - - -> **If you cannot use an ethernet connection for your first connection:** -> {{< my-button link="/docs/getting-started/wifi/" label="How to connect to WiFi without using the dashboard?" >}} \ No newline at end of file diff --git a/content/docs/getting-started/safety.md b/content/docs/getting-started/safety.md deleted file mode 100644 index e0ddd3ac..00000000 --- a/content/docs/getting-started/safety.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: "Safety guidelines" -description: "Use Reachy 2 properly." -lead: "Compulsory reading before using the robot" -date: 2023-08-09T14:44:05+02:00 -lastmod: 2023-08-09T14:44:05+02:00 -draft: false -images: [] -toc: true -weight: "20" ---- - -{{< warning icon="👉🏾" text="Reachy 2 is much more powerful than the previous version. To avoid any accident, please follow carefully the safety guidelines!" >}} - -> There is currently **no automatic collision security** on the robot: it won't stop if hitting anything or anyone, even itself. Remain constantly watchful when using it. - -## Users - -### Attention and reaction - -Users must be in **full possession of their physical and mental powers at all times** when using the robot. Reachy 2 must never be used by someone having consumed substances that could affect their reactions, such as medication, drugs or alcohol. - -Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the [emergency stop button]({{< ref "/sdk/getting-started/safety#emergency-stop-button" >}}). - -### Qualified users - -The robot must not be used if no qualified user is present. - -People using the robot or interacting with it must all be aware of the risks and be explicitly informed of the robot capabilities, limitations and restrictions. They must all be able to act with the appropriate behavior using the robot. - -{{< alert icon="👉" text="No one should use the robot without knowing the safety guidelines." >}} - -## Emergency stop button - -The robot is delivered with an emergency stop button. - -Pressing the emergency stop button will **immediately power off all motors**, from the arms to the mobile base wheels. Nevertheless it won't power off the computer, which means you won't lose anything running on the computer. - -> If you feel like you are losing control of the robot's movements or notice an unexpected behavior at anytime, **never hesitate to press the emergency stop button**. - -Someone must be holding the emergency stop button at any time when using the robot, being ready to press the button if needed, and keep its attention focused on the robot. - -{{< alert icon="👉" text="Objects may fall out of the grippers when pressing the emergency stop button. Make sure they cannot cause injuries." >}} - -## Don't harm yourself... - -Reachy 2 is a powerful robot that may hurt you if it is misused. - -If you do not respect the safety guidelines, you expose yourself to the following risks: -- pinching -- crushing -- punches -- electrical hazard - -### Alertness - -People interacting with the robot or present near its workspace must always look at the robot. - -If the robot is being teleoperated with its mobile base, people in the surroundings must be informed of the robot presence, and the operator must never make the robot pop by surprise near a person or come close to a person, making the person reachable by the arms. - -### Appropriate position - -Do not expose yourself to dangerous punches! - -People must never place their head, or any other body parts, in between or underneath segments of the robot when the robot is in use. Their head should never be reachable by the robots' arms if the robot is in use. - -If people are near the workspace of the robot, they must always stay in a position that allow them to quickly retract or recoil. - -> When the robot is in use, no one should enter or stay in the robot workspace. - -### Free space for retracting - -If people are standing near the robot workspace, make sure they have **sufficient space to retract or recoil**, and that this space is free of obstacles. - -People must never be blocked between the robot and a wall or furniture. - -### Objects manipulation with Reachy 2 - -Be careful with the objects you manipulate with the robot. Sharp and pointed object manipulation is dangerous, do not get close to the robot if it manipulates such objects. - -For all manipulation tasks, users are responsible for assessing the hazards and risks relative to the objects they manipulated with the robot. - -### Manipulate the robot - -When the robot is in use, never manipulate robot parts at the same time. - -Users must be careful if putting their fingers in the actuators or between robot parts to avoid pinching or crushing. -:warning: They must never put their fingers in the actuators or between robot parts if the robot is in use. - -### Hardware intervention - -Never make any hardware intervention on the robot, such as screwing on unscrewing something, if it is powered on. - -### Robot toppling risk - -The following section ["...and don't harm Reachy 2!"]({{< ref "/sdk/getting-started/safety#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. -**All events of the following section can lead to users injuries**, so read them as users safety guidelines as well. - -## ...and don't harm Reachy 2! - -There are a few things you need to know to make sure that your Reachy doesn't get damaged when using it. - -### Carrying heavy objects - -Be careful of the position of the arms when lifting heavy objects with the robot. -Avoid carrying the object to far from the robot torso, mainly to avoid risk of front toppling. - -Do not try to lift objects over 3kg (6.6lb). - -### Pulling/pushing - -Do not try to pull or push elements that are too heavy or oppositing too much! - -This may result in a robot toppling. - -### Obstacles - -Be aware of obstacles! - -When you are sending movements instructions to Reachy, be careful to obstacles the robot can meet. The robot will try to reach the positions you asked for as hard as it can, whether or not there is something on its way. - -Because of the force of the robot, and depending on the weigh or fragility of the object, two things may occur: -- make the object fall and/or break it -- make Reachy 2 tumble - -### Self-collision - -When you are moving both arms simultaneously, there are no safety measures implemented to prevent them from hitting each other. -Nothing will neither prevent Reachy's arms from hitting its chest if you ask them to. - -If situations like these happen, do not hesitate to turn off the motors so that Reachy's motors will stop trying to reach a position they can't get to. - -### Mobile base - -#### Surface - -The mobile robot is made to be used on **flat surfaces**. -Never use the robot on slopes, this may result in a robot toppling. - -#### Speed and movements - -Speed and commands are limited when using the Python SDK, nevertheless you can still generate behaviors that may be dangerous. Do not ask for high speeds and strong stops, or suddent changes of directions. -Provoking oscillations of the robot may lead to a robot toppling. - -### Anti-collision LIDAR safety - -:warning: The anti-collision LIDAR safety has been deactivated. diff --git a/content/docs/getting-started/turn-off.md b/content/docs/getting-started/turn-off.md deleted file mode 100644 index 80dda0d3..00000000 --- a/content/docs/getting-started/turn-off.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: "Stop your robot" -description: "How to switch off your robot." -lead: "How to switch off your robot." -date: 2023-08-09T14:44:11+02:00 -lastmod: 2023-08-09T14:44:11+02:00 -draft: false -images: [] -toc: true -weight: "70" ---- -## Power off your robot - -Power off your robot in the exact opposite order you turned it on! - -To stop your robot: - -1. From the dashboard, click on the Power Off button in the footer. -2. Press the emergency stop button. -3. Press the mobile base button. -4. Wait for the led of the computer to turn off, then unplug the green port from the robot's computer. - - -## Understanding the power buttons and battery life good practices -The mobile base uses the 24V battery to power the wheels directly. DC-DC converters are used to generate 5V (emergency button power, USB HUB power and relay logic) and 12V for the upper body. -The 5V converter draws almost 100mA when idle and is necessary for the emergency button logic. - -The emergency button and the mobile base button both need to be ON to turn on the power relay that shares the 24V with the rest of the robot. However, the mobile base button is the only one that, when turned OFF, shuts down the 5V converter. - - -> :warning: **WARNING!** :warning: When turning off the robot, always turn off the mobile base button to minimize the idle current consumption. If you turn off the robot with the emergency button and didn't press the mobile base button before storing your robot, the battery will deplate faster. - -:bulb: Even with the mobile base button OFF, the battery screen will be powered (low consumption at around ~1mA). If you plan to store the robot for more than a month, we recommend unplugging one of the wires of the battery (like when you received the robot). - - -| Configuration | Storage time before depleting a full battery | -| :-----------------------------------------: | :------------------------------------------: | -| Mobile base button ON, emergency button OFF | A few days | -| Mobile base button OFF | A few months | -| Unplugging the battery | A few years | - diff --git a/content/docs/getting-started/turn-on.md b/content/docs/getting-started/turn-on.md deleted file mode 100644 index 53f19968..00000000 --- a/content/docs/getting-started/turn-on.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: "Start your robot" -description: "How to switch on your robot." -lead: "How to switch on your robot." -date: 2023-08-09T14:44:11+02:00 -lastmod: 2023-08-09T14:44:11+02:00 -draft: false -images: [] -toc: true -weight: "30" ---- - - -## Power up your robot -To start your robot: -1. Press the mobile base button (next to the mobile base's LCD screen). The mobile base's screen should turn on, indicating the current state of the battery (remaining battery percentage, current flow, etc). - -2. **Automatic calibration process** - -Put the robot in a environment with no obstacle, and make sure its arms or grippers are not touching the tripod. - -{{< alert icon="👉" text="The robot is going to slightly move during the calibration. Do not touch the robot during the calibration, and make sure the arms will not meet any obstacle during their movements." >}} - -Press and turn clockwise the emergency stop button to raise it. The automatic calibration process will start. - -> Do not move the robot until the services running on the computer are ready for use. - -

- {{< video "videos/docs/getting-started/calibration-process.mp4" "40%" >}} -
- Automatic calibration process -

- -3. Turn on the robot's computer: -- plug the green connector to the computer. The computer should automatically turn on. - -- if the computer was already plugged, use the (a) button to turn it on. -{{< img-center "images/docs/getting-started/a-button.png" 400x "drawing" >}} - -> We advise to unplug the computer after each use for power saving, because the USB ports are still consuming current when the computer is off. - - -

- {{< video "videos/docs/getting-started/turn-on-reachy.mp4" "40%" >}} -
- Full turn on process in video -

diff --git a/content/docs/getting-started/unpack.md b/content/docs/getting-started/unpack.md deleted file mode 100644 index 512d7bba..00000000 --- a/content/docs/getting-started/unpack.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "Unpack Reachy 2" -description: "Unpack your robot to start with Reachy 2." -lead: "How to unpack and start with Reachy 2" -date: 2023-08-09T14:43:24+02:00 -lastmod: 2023-08-09T14:43:24+02:00 -draft: false -images: [] -toc: true -weight: "10" ---- - -## Your robot is nearly already assembled! - -{{< alert icon="👉" text="The robot weigh is around 50kg (110lb). You will need to be at least 3 to carry the robot out of the box.
Wear suitable personal protective equipment (e.g. safety shoes) when unpacking the robot. When lifting Reachy 2, pay attention to lift correctly using with your legs, to avoid back injury. Be also aware of your fingers position on the robot." >}} - -Unpack your robot, you just have a few things to plug to finish assembling it. -Check your box contains, in addition to the robot, the following elements: -- a battery charger -- a calibration board -- wifi antennas -- a mini USB cable -- an emergency stop button -- robot antennas screws - -{{< alert icon="👉" text="Make a visual check of all the robot to check nothing seems damage after the travel, especially the cables. In case of doubt on any element, please contact us.
Do not use the robot if something is damaged." >}} - -## Adjust robot size - -Reachy 2 is mounted on its mobile base with a tripod for stability. - -This tripod is **adjustable in height**: choose a suitable height before starting using the robot. - -{{< alert icon="👉" text="Be careful, Reachy 2 is heavy. Ask for help to adjust robot size." >}} - -To do so, maintain the mobile base and ask for someone to maintain the robot's torso. Then unscrew all pods (do not unscrew them too much!), and raise the robot's torso. - -> The button on the cranks are here to modify their positions without unscrewing them. - -## Assemble the last elements - -### Screw the robot antennas - -Stick the antennas in the support on the head, then use the provided screws to fix them, preferably from the back hole. There is one screw by antenna. - -{{< img-center "images/docs/getting-started/antennas.jpg" 400x "Antennas support" >}} - - -### Plug the WiFi antennas - -Plug the wifi antennas on the robot computer, on port 1 and 3. - -{{< img-center "images/docs/getting-started/plug-antennas.jpg" 300x "Wifi antennas emplacement" >}} - -Make sure to place them correctly so that the robot's arms cannot touch them: - -{{< img-center "images/docs/getting-started/wifi-antennas.png" 400x "Wifi antennas position" >}} - -### Plug the emergency stop button - -To plug the emergency state button, you will find a little black connector on the mobile base. Simply connect the button cable to it. - -{{< img-center "images/docs/getting-started/bau-connection.png" 300x "Connect the emergency stop button" >}} - -### Connect the battery - -First make sure the emergency stop button is pressed. -Then plug the yellow connector of the mobile base so the robot will be powered when the emergency stop button will be unpressed. - -{{< img-center "images/docs/getting-started/yellow-connector.png" 300x "Power your robot" >}} diff --git a/content/docs/getting-started/wifi.md b/content/docs/getting-started/wifi.md deleted file mode 100644 index ac906043..00000000 --- a/content/docs/getting-started/wifi.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: "Connect your robot to the WiFi" -description: "How to connect your robot to the WiFi without using the dashboard." -lead: "How to connect Reachy 2 to WiFi without the dashboard" -date: 2023-08-09T14:43:31+02:00 -lastmod: 2023-08-09T14:43:31+02:00 -draft: false -images: [] -toc: true ---- -## WiFi - -On your first connection to a network, the simpliest is to connect your robot with an ethernet cable. - -If you cannot do this: - -Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. - -{{< img-center "images/docs/getting-started/serial-connection.png" 400x "Serial connection port" >}} - -We use `tio`for the serial connection. If you haven't installed it yet on your computer: -`apt install tio` - -{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER
Then reboot your computer for the new group to be effective." >}} - -Then, in a terminal on your computer, get access to the robot with: - -```python -tio /dev/ttyUSB0 -``` - -> Note that the connection could be on another USB port. Check all ports with `ls /dev/ttyUSB*` - -{{< img-center "images/docs/getting-started/tio-terminal.png" 400x "tio connection terminal" >}} - -{{< alert icon="👉" text="Login: bedrock
Password: root" >}} - - -Manually connect the robot to a WiFi with: -```bash -nmcli device wifi connect password -``` - -> For example, with the wifi *POLLEN-WIFI*, with password *superstrongpassword*: -> `nmcli device wifi connect POLLEN-WIFI password superstrongpassword` - -{{< my-button link="/docs/getting-started/network/" label="< Back to network connection" >}} \ No newline at end of file diff --git a/content/docs/simulation/_index.md b/content/docs/simulation/_index.md deleted file mode 100644 index f600f2fc..00000000 --- a/content/docs/simulation/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Simluation installation" -description: "Simulation installation process." -lead: "" -date: 2023-07-25T15:04:00+02:00 -lastmod: 2023-07-25T15:04:00+02:00 -draft: false -images: [] ---- diff --git a/content/docs/simulation/simulation-installation.md b/content/docs/simulation/simulation-installation.md deleted file mode 100644 index 67252890..00000000 --- a/content/docs/simulation/simulation-installation.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "Simulation installation" -description: "Simulation installation process." -lead: "How to install a simulated Reachy 2 on your computer." -date: 2023-08-09T14:45:14+02:00 -lastmod: 2023-08-09T14:45:14+02:00 -draft: false -images: [] -toc: true -weight: "70" ---- -If you want to try movements on the robot without using the real robot, you can install a simulated Reachy 2 on your computer, and run it the same way the real robot is run. The easiest way is using a docker image. We will thus assume that you already have docker installed and setup. - -Clone the sources of our docker, and pull the sources: -```python -git clone git@github.com:pollen-robotics/docker_reachy2_core.git -cd docker_reachy2_core -./pull_sources.sh beta -``` - -Then download the configuration files: -```python -git clone git@github.com:pollen-robotics/reachy_config_example.git -cp -r reachy_config_example/.reachy_config ~/ -``` - -In your docker_reachy2_core folder, compose a container with: -```python -docker compose -f dev.yaml up -d core -``` -> This can take a few minutes to compose. - -Build: -```python -cbuilds -``` - - -In a first terminal, launch the robot server: -```python -# terminal 1 -docker exec -it core bash -ros2 launch reachy_bringup reachy.launch.py fake:=true start_sdk_server:=true start_rviz:=true -``` -Keep this terminal open, and in a second terminal: -```python -# terminal 2 -docker exec -it core bash -python3 ../dev/reachy2-sdk/src/example/test_goto.py -``` -> If you have the Python SDK installed on your computer, you can launch the example outside the container. diff --git a/content/docs/update/_index.md b/content/docs/update/_index.md deleted file mode 100644 index 18e80c39..00000000 --- a/content/docs/update/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Update Reachy" -description: "Learn how to update Reachy's software." -lead: "" -date: 2023-07-25T15:19:04+02:00 -lastmod: 2023-07-25T15:19:04+02:00 -draft: false -images: [] ---- diff --git a/content/docs/update/update.md b/content/docs/update/update.md deleted file mode 100644 index 658a7b61..00000000 --- a/content/docs/update/update.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title : "Update Reachy 2 software" -description: "Update Reachy" -lead: "Get latest version of Reachy software" -date: 2023-07-25T15:15:22+02:00 -lastmod: 2023-07-25T15:15:22+02:00 -draft: false -images: [] -toc: true -weight: "80" ---- - -## Use the dashboard - -The update of the robot can be entirely done with the dashboard. - -From the **Updates** tab, check if updates are available: - -{{< img-center "images/docs/update/dashboard-update-page.png" 600x "" >}} - -> Only advanced update management is working so far - -## Advanced update management - -From the dashboard Update page, click on **Advanced udpate management**: - -{{< img-center "images/docs/update/update.png" 600x "PLUM update" >}} - -> You can directly access the advanced update dashboard from **`http://:5000/`** - -### Fetch updates - -Click **Fetch Updates** to check if there is any available update on one of the robot's services. -Once this is done, you can browse between the 5 services to see if a more recent version is available. - -> For example, an update is available for reachy2-dashboard here: -{{< img-center "images/docs/update/update-available.png" 600x "PLUM update" >}} - -### Install update - -Select the version you want to download for the upgrade, and click on **Pull Container**. -Wait for the message "*service.name* Pulled" to appear in the window. - -{{< img-center "images/docs/update/pull-container.png" 600x "PLUM update" >}} - -When this is done, click on **Generate**. -Wait for the confirmation message to appear. - -{{< img-center "images/docs/update/generate.png" 600x "PLUM Update" >}} - -### Activate the update - -Finish the update installation by clicking on: -1. **Enable**, to activate by default the updated service -2. **Stop**, to stop the current outdated service running -3. **Start**, to launch the updated service \ No newline at end of file diff --git a/content/getting-started/dashboard/discover.md b/content/getting-started/dashboard/discover.md index 95cee889..e5f81ed9 100644 --- a/content/getting-started/dashboard/discover.md +++ b/content/getting-started/dashboard/discover.md @@ -14,4 +14,52 @@ weight: 400 toc: true --- -This is the dashboard \ No newline at end of file + +## 1. Find Reachy 2's IP address + +After you connected the robot to the network, it should have an IP address. The LCD screen connected in Reachy's back should be diplaying its IP address. + +{{< img-center "images/vr/getting-started/lcd-display.png" 400x "" >}} + +If the LCD screen is not working or is unplugged, check out the page Find my IP section to learn other ways to get the IP address. +> Note the LCD screen will not work if you plug it after having turned on the computer. + +## 2. Connect from the navigator + +From your computer, on the same network, open a navigator and go to: +**`http://:8000/`** + +> For example, if the screen indicates `192.168.1.42`, connect to `http://192.168.1.42:8000/` + +You should arrive on a services page: + +{{< img-center "images/docs/getting-started/dashboard.png" 600x "dashboard" >}} + + +This tool has been thought to help you **start easier with the robot** and **facilitate quick debugging**. + +The dashboard is here to give you an overview of the robot's state as well as giving you the possiblity to access quickly some features (changing a robot's part compliance for example). + +## Features Overview + +What does the dashboard provide? + +* **Access the services** - **Services page**
+Stop or restart the robot's services, see robot logs *(coming soon)*. + +* **Manage network connection** - **Network page**
+Choose a wifi network to connect the robot to. + +* **Update robot software** - **Updates page**
+Get the last software versions of the robot, and choose the services you want to update. + +* **Visualize robot state** - **Visualization tools page**
+Get RViz visualization or even display live data from ROS topics with Foxglove. + +* **Send robot commands** - **Reachy control page**
+*Coming soon* + + +On each page, the **serial number** of your robot is also displayed. + +More information is available for each page in the content section. \ No newline at end of file diff --git a/content/getting-started/safety-first/safety-guidelines.md b/content/getting-started/safety-first/safety-guidelines.md index e8ea5d6a..42035a02 100644 --- a/content/getting-started/safety-first/safety-guidelines.md +++ b/content/getting-started/safety-first/safety-guidelines.md @@ -25,7 +25,7 @@ toc: true Users must be in **full possession of their physical and mental powers at all times** when using the robot. Reachy 2 must never be used by someone having consumed substances that could affect their reactions, such as medication, drugs or alcohol. -Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the [emergency stop button]({{< ref "/sdk/getting-started/safety#emergency-stop-button" >}}). +Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the emergency stop button. ### Qualified users @@ -98,7 +98,7 @@ Never make any hardware intervention on the robot, such as screwing on unscrewin ### Robot toppling risk -The following section ["...and don't harm Reachy 2!"]({{< ref "/sdk/getting-started/safety#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. +The following section ["...and don't harm Reachy 2!"]({{< ref "/getting-started/safety-first/safety-guidelines#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. **All events of the following section can lead to users injuries**, so read them as users safety guidelines as well. ## ...and don't harm Reachy 2! diff --git a/content/help/contact-support/need-somebody.md b/content/help/contact-support/need-somebody.md index f50af685..1d005988 100644 --- a/content/help/contact-support/need-somebody.md +++ b/content/help/contact-support/need-somebody.md @@ -14,41 +14,14 @@ toc: true weight: 300 --- -## Problem with the motors +## Forum -The motors are managed by the reachy2-core service. -Check all logs of the service with: +Join **[our forum](https://forum.pollen-robotics.com/)** if you have any questions or simply want to take a look at others topics! -```bash -journalctl -b -u reachy2-core -``` +{{< alert icon="👉" text="Any questions relative to your development with Reachy?
Go to Pollen Community" >}} -## Problem with the cameras or sound -### With teleoperation application +## Pollen Robotics support -During teleoperation, the cameras and sound are managed by the webrtc service. -This service is automatically launched when you start Reachy 2 computer. +For any specific questions concerning your robot or if you meet problems with the product, please contact us at [support@pollen-robotics.com](mailto:support@pollen-robotics.com). -> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: ->- that any running client to the sdk has been disconnected ->- that the speaker has been plugged back ->- that the webrtc services has been restarted - -Check all logs of the service with: - -```bash -journalctl -b -u webrtc -``` - -### With the Python SDK - -If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. - -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) - -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` diff --git a/content/help/debug/debug-checklist.md b/content/help/debug/debug-checklist.md index 3568e3a0..860e34e6 100644 --- a/content/help/debug/debug-checklist.md +++ b/content/help/debug/debug-checklist.md @@ -14,41 +14,17 @@ toc: true weight: 100 --- -## Problem with the motors -The motors are managed by the reachy2-core service. -Check all logs of the service with: +## Fast recovering -```bash -journalctl -b -u reachy2-core -``` +The simpliest way to recover from an error (for example an arm not responding anymore) is to **power cycle the motors and restart the services**. -## Problem with the cameras or sound +It as a fast recovery procedure that may cover 80% of unexpected behavior. -### With teleoperation application +To do so: +1. Suspend your current use of the robot +2. Press the emergency stop button +3. Make sure to put the arms and head in a suitable position before restarting the motors +4. Press and turn clockwise the emergency stop button to raise it +5. Go to the dashboard and click on *Restart* for `reachy2-core` then `webrtc` -During teleoperation, the cameras and sound are managed by the webrtc service. -This service is automatically launched when you start Reachy 2 computer. - -> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: ->- that any running client to the sdk has been disconnected ->- that the speaker has been plugged back ->- that the webrtc services has been restarted - -Check all logs of the service with: - -```bash -journalctl -b -u webrtc -``` - -### With the Python SDK - -If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. - -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) - -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` diff --git a/content/help/faq/robot-faq.md b/content/help/faq/robot-faq.md index d48b3870..5004ec56 100644 --- a/content/help/faq/robot-faq.md +++ b/content/help/faq/robot-faq.md @@ -52,7 +52,7 @@ nmcli device wifi connect password There are several ways to connect to your robot. ## SSH connection -Using the robot's IP address (check [Find Reachy 2's IP]({{< ref "help/system/find-my-ip" >}}) if you don't know it), you can directly connect via ssh to Reachy 2's computer: +Using the robot's IP address (check Find Reachy 2's IP if you don't know it), you can directly connect via ssh to Reachy 2's computer: ```python ssh bedrock@ diff --git a/content/help/faq/sdk-faq.md b/content/help/faq/sdk-faq.md index 7b32755a..0c38b61a 100644 --- a/content/help/faq/sdk-faq.md +++ b/content/help/faq/sdk-faq.md @@ -18,8 +18,6 @@ weight: 210 If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) - Check all logs of the service with: ```bash diff --git a/content/help/help/_index.md b/content/help/help/_index.md deleted file mode 100644 index 43720ad7..00000000 --- a/content/help/help/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "Debug" -description: "Learn how you can debug Reachy." -date: 2023-08-21T16:18:47+02:00 -lastmod: 2023-08-21T16:18:47+02:00 -draft: false -images: [] -weight: 100 -type: docs ---- diff --git a/content/help/help/debug.md b/content/help/help/debug.md deleted file mode 100644 index 1c951d6b..00000000 --- a/content/help/help/debug.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title : "Debug" -description: "Debug" -lead: "Use journalctl on the services to look for errors" -date: 2023-07-26T08:44:51+02:00 -lastmod: 2023-07-26T08:44:51+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "20" ---- - -## Problem with the motors - -The motors are managed by the reachy2-core service. -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` - -## Problem with the cameras or sound - -### With teleoperation application - -During teleoperation, the cameras and sound are managed by the webrtc service. -This service is automatically launched when you start Reachy 2 computer. - -> If you have switched between the Python SDK and the teleoperation application without robot rebooting, first make sure: ->- that any running client to the sdk has been disconnected ->- that the speaker has been plugged back ->- that the webrtc services has been restarted - -Check all logs of the service with: - -```bash -journalctl -b -u webrtc -``` - -### With the Python SDK - -If you are using the cameras with the Python SDK, the cameras are then managed by the reachy2-core service. - -> First make sure you have enabled correctly the [cameras for the SDK]({{< ref "sdk/first-moves/cameras#enable-teleop-cameras-for-the-sdk">}}) - -Check all logs of the service with: - -```bash -journalctl -b -u reachy2-core -``` diff --git a/content/help/help/recovering.md b/content/help/help/recovering.md index 5357d940..2caa4792 100644 --- a/content/help/help/recovering.md +++ b/content/help/help/recovering.md @@ -22,5 +22,5 @@ To do so: 2. Press the emergency stop button 3. Make sure to put the arms and head in a suitable position before restarting the motors 4. Press and turn clockwise the emergency stop button to raise it -5. [Go to the dashboard]({{< ref "/dashboard/introduction/connection" >}}) and click on *Restart* for `reachy2-core` then `webrtc` +5. Go to the dashboard and click on *Restart* for `reachy2-core` then `webrtc` diff --git a/content/help/help/support.md b/content/help/help/support.md deleted file mode 100644 index 79fdccca..00000000 --- a/content/help/help/support.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title : "Support" -description: "Get support for your Reachy robot." -lead: "Can't solve your problem? Ask for help!" -date: 2023-07-26T08:45:50+02:00 -lastmod: 2023-07-26T08:45:50+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "40" ---- - -## Forum - -Join **[our forum](https://forum.pollen-robotics.com/)** if you have any questions or simply want to take a look at others topics! - -{{< alert icon="👉" text="Any questions relative to your development with Reachy?
Go to Pollen Community" >}} - - -## Pollen Robotics support - -For any specific questions concerning your robot or if you meet problems with the product, please contact us at [support@pollen-robotics.com](mailto:support@pollen-robotics.com). - diff --git a/content/help/help/torso.md b/content/help/help/torso.md deleted file mode 100644 index e6192312..00000000 --- a/content/help/help/torso.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title : "Hardware intervention" -description: "Hardware debug in the robot's torso" -lead: "Open the torso to access hardware inside Reachy 2" -date: 2023-07-26T08:44:51+02:00 -lastmod: 2023-07-26T08:44:51+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "30" ---- - -## Remove the torso case - -Simply unscrew the 4 little screws maintaining the case in place. There are 2 on each side of the robot: - -{{< img-center "images/help/torso/torso-case.png" 200x "torso-case" >}} - -> The case is slightly flexible, you will have to flex it a little to set it back in place. \ No newline at end of file diff --git a/content/help/safety/VR-use.md b/content/help/safety/VR-use.md deleted file mode 100644 index d29551ee..00000000 --- a/content/help/safety/VR-use.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Use VR teleoperation" -description: "Guidelines to use the VR teleoperation app safely, for you, the robot and the surrounding people" -date: 2023-07-26T08:45:40+02:00 -lastmod: 2023-07-26T08:45:40+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "70" ---- - -## Watch all guidelines in video! -Watch this quick video to have an overview of the main guidelines to use teleoperation: - -{{< youtube bK7th6zY8Rg >}} - -
diff --git a/content/help/safety/_index.md b/content/help/safety/_index.md deleted file mode 100644 index b1e7d65c..00000000 --- a/content/help/safety/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Safety" -description: "Use the robot safely in any situation" -date: 2023-07-26T08:45:24+02:00 -lastmod: 2023-07-26T08:45:24+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/help/safety/correct-use.md b/content/help/safety/correct-use.md deleted file mode 100644 index 6de1c11f..00000000 --- a/content/help/safety/correct-use.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: "Use Reachy 2 properly" -description: "Guidelines to use Reachy 2 safely, for you and the robot" -date: 2023-07-26T08:45:34+02:00 -lastmod: 2023-07-26T08:45:34+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "60" ---- - -{{< warning icon="👉🏾" text="Reachy 2 is much more powerful than the previous version. To avoid any accident, please follow carefully the safety guidelines!" >}} - -> There is currently **no automatic collision security** on the robot: it won't stop if hitting anything or anyone, even itself. Remain constantly watchful when using it. - -## Users - -### Attention and reaction - -Users must be in **full possession of their physical and mental powers at all times** when using the robot. Reachy 2 must never be used by someone having consumed substances that could affect their reactions, such as medication, drugs or alcohol. - -Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the [emergency stop button]({{< ref "/sdk/getting-started/safety#emergency-stop-button" >}}). - -### Qualified users - -The robot must not be used if no qualified user is present. - -People using the robot or interacting with it must all be aware of the risks and be explicitly informed of the robot capabilities, limitations and restrictions. They must all be able to act with the appropriate behavior using the robot. - -{{< alert icon="👉" text="No one should use the robot without knowing the safety guidelines." >}} - -## Emergency stop button - -The robot is delivered with an emergency stop button. - -Pressing the emergency stop button will **immediately power off all motors**, from the arms to the mobile base wheels. Nevertheless it won't power off the computer, which means you won't lose anything running on the computer. - -> If you feel like you are losing control of the robot's movements or notice an unexpected behavior at anytime, **never hesitate to press the emergency stop button**. - -Someone must be holding the emergency stop button at any time when using the robot, being ready to press the button if needed, and keep its attention focused on the robot. - -{{< alert icon="👉" text="Objects may fall out of the grippers when pressing the emergency stop button. Make sure they cannot cause injuries." >}} - -## Don't harm yourself... - -Reachy 2 is a powerful robot that may hurt you if it is misused. - -If you do not respect the safety guidelines, you expose yourself to the following risks: -- pinching -- crushing -- punches -- electrical hazard - -### Alertness - -People interacting with the robot or present near its workspace must always look at the robot. - -If the robot is being teleoperated with its mobile base, people in the surroundings must be informed of the robot presence, and the operator must never make the robot pop by surprise near a person or come close to a person, making the person reachable by the arms. - -### Appropriate position - -Do not expose yourself to dangerous punches! - -People must never place their head, or any other body parts, in between or underneath segments of the robot when the robot is in use. Their head should never be reachable by the robots' arms if the robot is in use. - -If people are near the workspace of the robot, they must always stay in a position that allow them to quickly retract or recoil. - -> When the robot is in use, no one should enter or stay in the robot workspace. - -### Free space for retracting - -If people are standing near the robot workspace, make sure they have **sufficient space to retract or recoil**, and that this space is free of obstacles. - -People must never be blocked between the robot and a wall or furniture. - -### Objects manipulation with Reachy 2 - -Be careful with the objects you manipulate with the robot. Sharp and pointed object manipulation is dangerous, do not get close to the robot if it manipulates such objects. - -For all manipulation tasks, users are responsible for assessing the hazards and risks relative to the objects they manipulated with the robot. - -### Manipulate the robot - -When the robot is in use, never manipulate robot parts at the same time. - -Users must be careful if putting their fingers in the actuators or between robot parts to avoid pinching or crushing. -:warning: They must never put their fingers in the actuators or between robot parts if the robot is in use. - -### Hardware intervention - -Never make any hardware intervention on the robot, such as screwing on unscrewing something, if it is powered on. - -### Robot toppling risk - -The following section ["...and don't harm Reachy 2!"]({{< ref "/sdk/getting-started/safety#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. -**All events of the following section can lead to users injuries**, so read them as users safety guidelines as well. - -## ...and don't harm Reachy 2! - -There are a few things you need to know to make sure that your Reachy doesn't get damaged when using it. - -### Carrying heavy objects - -Be careful of the position of the arms when lifting heavy objects with the robot. -Avoid carrying the object to far from the robot torso, mainly to avoid risk of front toppling. - -Do not try to lift objects over 3kg (6.6lb). - -### Pulling/pushing - -Do not try to pull or push elements that are too heavy or oppositing too much! - -This may result in a robot toppling. - -### Obstacles - -Be aware of obstacles! - -When you are sending movements instructions to Reachy, be careful to obstacles the robot can meet. The robot will try to reach the positions you asked for as hard as it can, whether or not there is something on its way. - -Because of the force of the robot, and depending on the weigh or fragility of the object, two things may occur: -- make the object fall and/or break it -- make Reachy 2 tumble - -### Self-collision - -When you are moving both arms simultaneously, there are no safety measures implemented to prevent them from hitting each other. -Nothing will neither prevent Reachy's arms from hitting its chest if you ask them to. - -If situations like these happen, do not hesitate to turn off the motors so that Reachy's motors will stop trying to reach a position they can't get to. - -### Mobile base - -#### Surface - -The mobile robot is made to be used on **flat surfaces**. -Never use the robot on slopes, this may result in a robot toppling. - -#### Speed and movements - -Speed and commands are limited when using the Python SDK, nevertheless you can still generate behaviors that may be dangerous. Do not ask for high speeds and strong stops, or suddent changes of directions. -Provoking oscillations of the robot may lead to a robot toppling. - -### Anti-collision LIDAR safety - -:warning: The anti-collision LIDAR safety has been deactivated. diff --git a/content/help/system/_index.md b/content/help/system/_index.md deleted file mode 100644 index 2deb5429..00000000 --- a/content/help/system/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "System" -description: "Resolve most common difficulties and problems with the robot" -date: 2023-07-26T08:46:02+02:00 -lastmod: 2023-07-26T08:46:02+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/help/system/find-my-ip.md b/content/help/system/find-my-ip.md deleted file mode 100644 index 475b8928..00000000 --- a/content/help/system/find-my-ip.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "Find Reachy 2's IP" -description: "How to find Reachy 2 IP address" -lead: "How to find your robot's IP address." -date: 2023-07-26T08:46:47+02:00 -lastmod: 2023-07-26T08:46:47+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "50" ---- - -Here are 4 different options to find out the IP address of your robot. -> Make sure your robot has already been connected to a network before trying to get its IP address. - - -## LCD display screen - -If you haven't unplugged it, the LCD screen connected in Reachy's back should be diplaying its IP address. - -{{< img-center "images/help/system/lcd-display.png" 400x "LCD display for IP" >}} - -## Hard-wired connection - -Use the appropriate cable and connect your computer directly to Reachy 2's computer. The cable has to be plugged in port (b) of Reachy 2's hardware interface. - -{{< img-center "images/help/system/serial-connection.png" 400x "serial connection port" >}} - -We use `tio`for the serial connection. If you haven't installed it yet on your computer: -`apt install tio` - -{{< alert icon="👉" text="Make sure dialout is in your groups, otherwise add it to your groups. To check it:
>>> groups
If it doesn't appear in the list, add it with:
>>> sudo usermod -aG dialout $USER" >}} - -Once connected, open a terminal on your computer and run: -```python -tio /dev/ttyUSB0 -``` -*Note that depending on the elements you connected to the robot, the port could be something else than ttyUSB0. Check other available serial ports with `ls /dev/ttyUSB*`* - -{{< img-center "images/help/system/tio-terminal.png" 400x "tio connection terminal" >}} - -{{< alert icon="👉" text="Login: bedrock
Password: root" >}} - -You should then be connected to Reachy's computer via serial port. -You can find the IP address with: -```python -ifconfig -``` - -{{< img "images/help/system/ifconfig.png" 400x "Square">}} -> In our case, Reachy 2's IP is *"192.168.86.56"*. - -## Using the serial number - -Find the serial number of your robot on its back, connect your computer on the same network as your robot, open a terminal and type: -```bash -ping .local -``` - ->For example, if the serial number is reachy2-beta1: ->```bash ->ping reachy2-beta1.local ->``` - -## Using a smartphone - -The **[Fing app](https://www.fing.com/products/fing-app)** let you scan IPs directly from your smartphone. - -To use it, install the app on your smartphone and connect your smartphone on the **same network** as the robot, then run an analysis of the network to find out the IPs connected. Reachy 2 must be one of them! diff --git a/content/sdk/_index.md b/content/sdk/_index.md deleted file mode 100644 index 21954d9e..00000000 --- a/content/sdk/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "Docs" -description: "Discover the Python SDK for Reachy and its mobile base." -lead: "" -date: 2022-01-25T14:40:56+01:00 -lastmod: 2022-01-25T14:40:56+01:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/advanced/_index.md b/content/sdk/advanced/_index.md deleted file mode 100644 index 59631e7c..00000000 --- a/content/sdk/advanced/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title : "Advanced Python SDK features" -description: "Use Reachy 2 Python SDK, advanced features." -lead: "" -date: 2023-07-25T17:37:16+02:00 -lastmod: 2023-07-25T17:37:16+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/advanced/mobile-base.md b/content/sdk/advanced/mobile-base.md deleted file mode 100644 index 912b896c..00000000 --- a/content/sdk/advanced/mobile-base.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "Mobile base drive and control modes" -description: "Drive modes and control modes description for the mobile base." -date: 2023-07-26T08:32:17+02:00 -lastmod: 2023-07-26T08:32:17+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "160" ---- -## Drive modes -### Overview -The drive mode impacts the way the mobile base accepts commands. We could say it's the current state of the mobile base. - -In most cases, there is no need to think about these modes or to handle them in your code. Below are the most common use cases. -* If you want to use the set_speed method to spam speed commands (e.g. pilot the robot with a controller), the mode has to be manually changed to 'cmd_vel': - ```python - reachy_mobile.mobile_base.drive_mode = 'cmd_vel' - ``` -* If you want to push the robot easily, this will set the wheels in a compliancy state: - ```python - reachy_mobile.mobile_base.drive_mode = 'free_wheel' - ``` -* On the contrary, if you want the robot to apply a passive resistance to movement, use: - ```python - reachy_mobile.mobile_base.drive_mode = 'brake' - ``` - -You can use this [Jupyter Notebook](https://github.com/pollen-robotics/mobile-base-sdk/blob/main/mobile_base_sdk/examples/notebooks/drive-modes.ipynb) to explore the drive modes with your mobile base. - -### Detailed behaviour -This section is only useful if you intend to interact directly with the Hardware Abstraction Layer (HAL). - -Six drive modes are available for the mobile base: -* **cmd_vel**: in this mode, speed instructions can be spammed to the wheels controllers. This mode is used for the *set_speed* method. -* **brake**: in this mode, the wheels will be stiff. -* **free_wheel**: in this mode, the wheels will be as compliant as possible. -* **emergency_stop**: in this mode, the wheels will stop receiving mobility commands. Switching to this mode will also stop the mobile base hal code. This is a safety mode. -* **speed**: another mode to send speed instructions, but less frequently than with the cmd_vel mode. This mode is actually not used at this level (python SDK level), but is implemented at the ROS level, in case one might need it. -* **goto**: this mode is used for the *goto* method. - -*note: the 'speed' and 'goto' modes can't be changed by hand. The drive mode is handled automagically when requesting a set_speed or a goto.* - -The code for the [HAL can be found here](https://github.com/pollen-robotics/zuuu_hal) - -## Control modes -### Overview -The control mode dictates the low level control strategy used by the mobile bases's HAL. - -Two control modes are possible: -* ***open_loop*** (default mode): in this mode, the wheels are compliant and the control is smoother. - ```python - reachy_mobile.mobile_base.control_mode = 'open_loop' - ``` - -* ***pid***: in this mode, the wheels are stiff and the control is more precise. - ```python - reachy_mobile.mobile_base.control_mode = 'pid' - ``` -:bulb: We recommend that you run the following [Jupyter Notebook](https://github.com/pollen-robotics/mobile-base-sdk/blob/main/mobile_base_sdk/examples/notebooks/control-modes.ipynb) to get a feel of what the control mode does. - -### Detailed behaviour -Regardless of how the mobile base is piloted (goto, set_speed, controller), the HAL always ends up calculating a goal rotational speed for each wheel. -The control mode only changes the used strategy to reach that rotational speed. -* In the open_loop mode, a simple affine model was identified to match a PWM to a goal rotational speed. The VESC controllers then apply the PWM directly to the motors of the wheels, without any other low level control. The measures can be found [here](https://github.com/pollen-robotics/zuuu_hal/tree/main/measures). While the model is simple, it does account for the static friction and the experimental data shows a good fit when the mobile base is on a flat surface. - -{{< img-center "images/sdk/mobile-base/affine_pwm_model.png" 400x "" >}} - -* In the pid mode, the HAL gives the goal rotational speeds directly to the VESC controllers of each wheel. The VESC will use a PID controller to control the speeds. \ No newline at end of file diff --git a/content/sdk/first-moves/_index.md b/content/sdk/first-moves/_index.md deleted file mode 100644 index 095d2ec0..00000000 --- a/content/sdk/first-moves/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "First Moves" -description: "Basic steps to get started with the SDK. Learn how to control each part of Reachy." -date: 2023-07-25T17:38:17+02:00 -lastmod: 2023-07-25T17:38:17+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/first-moves/arm.md b/content/sdk/first-moves/arm.md deleted file mode 100644 index c69030b1..00000000 --- a/content/sdk/first-moves/arm.md +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: "3. Basic arm control" -description: "What are the joints in Reachy's arms, what information are available and how to control them." -lead: "Learn how to control Reachy 2 arms and send commands in the joints space." -date: 2023-07-25T17:38:27+02:00 -lastmod: 2023-07-25T17:38:27+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "90" ---- -> Note : Make sure you checked the [safety page]({{< ref "sdk/getting-started/safety" >}}) before controlling the arm. - -## Arm presentation - -Reachy's arm offers 7 degrees of freedom. It also gives access to one joint for the gripper. -The **arm** is divided as follow: -- **shoulder**, composed of 2 joints (pitch and roll) -- **elbow**, composed of 2 joints (yaw and pitch) -- **wrist**, composed of 3 joints (roll, pitch and yaw) - -We refer to the shoulder, elbow and wrist as **actuators**. -For some actions, such as changing the compliance, is the the lowest level of control you will have. - -The arm's mechanical specifications are given [here]({{< ref "advanced/specifications/arm-specs" >}}) but as a reminder, the arm schematic is given below: - -{{< img-center "images/sdk/first-moves/arm_schematic.png" 400x "" >}} - -### The actuators - -Each actuator has a unique name and uid. To access a specific actuator, you can use the attribute under the part you are using. We don't not provide a direct access to all actuators. For the arms, the following actuators are available: - -```python -from reachy2_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.r_arm._actuators ->>> -``` - -Because they are parallel actuators, it often doesn't have sense to control one motor of an actuator without controlling the other motors of the same actuator. - -This is why actuators are for several cases the lowest degree of control we give. At the actuator level, you can then: -- modify the actuator compliance -- modify torques -- modify speed - - -### The joints - -Each joint has a unique name and uid. To access a specific joint, you can either use *reachy.joints* which has each joint of the robot as attribute or access it via the actuators it belongs to. For example, to access the right arm shoulder roll : *reachy.r_arm.shoulder.roll*. - -First, connect to your Reachy. - -```python -from reachy_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.r_arm.shoulder.roll ->>> -``` -The name and the id are attributes of the returned Joint object. - -```python -reachy.r_arm.r_shoulder_pitch.name ->>> 'r_shoulder_pitch' -reachy.r_arm.r_shoulder_pitch.uid ->>> 8 -``` - -Joints in Reachy are abstract elements that do not have a physical element. A joint is controlled by several motors of the actuators. The only thing you can do at joint level is reading the **present_position** and send **goal_position**. - -#### present_position - -You can get the present position of each joint with this attribute. - -```python -reachy.r_arm.r_shoulder_pitch.present_position ->>> 22.4 -``` - -> present_position is returned in **degrees**. - -#### goal_position - -The *goal_position* attribute of a joint can be used to set a new joint's target position to make it move. However, we recommend using the [**goto_joints() method**]({{< ref "sdk/first-moves/arm#goto_joints" >}}) to move the motors which provides better control on the joint's trajectories. - -Using goal_position will make the motor move **as fast as it can**, so be careful when using it. -```python -reachy.r_arm.r_elbow_pitch.goal_position = -90 -``` - -> goal_position must be written in **degrees**. - -### The gripper - -## Arm moves methods -### goto_joints() - -The **`goto_joints()`** method takes a seven-elements-long list, with the angles in this order: -- r_arm.shoulder.pitch -- r_arm.shoulder.roll -- r_arm.elbow.yaw -- r_arm.elbow.pitch -- r_arm.wrist.roll -- r_arm.wrist.pitch -- r_arm.wrist.yaw - -Let's see an example of how to use it. - -You will use the `goto_joints()` methods to place the right arm at a right-angled position. First, make sure that the Reachy's right arm is placed on a cleared table and that there will not be obstacles during its movement. - -The setup should look like this: - -{{< img-center "images/sdk/first-moves/base_pos.jpg" 500x "" >}} - -Let's define a list with **reachy.r_arm.elbow.pitch** at -90 degrees to the set a right-angled position for the right arm: - -```python -right_angled_pose = [0, 0, 0, -90, 0, 0, 0] -``` - -Then send the `goto_joints()` commands to the right arm: -Set the right arm motors in stiff mode. - -```python -reachy.r_arm.turn_on() # don't forget to turn the arm on - -reachy.r_arm.goto_joints(right_angled_pose) -``` - -You can use the - - -The result should look like this: - -

- {{< video "videos/sdk/goto.mp4" "80%" >}} -

- -Don't forget to put the right arm's joints back to the compliant mode. Place your hand below the right arm's gripper to prevent the arm from falling hard on the table. - -```python -reachy.r_arm.turn_off() -``` - -> To find out whether you have to send positive or negative angles, read next section on the arm kinematics. - -### goto_matrix() - -The **`goto_matrix()`** method takes a 4x4 matrix expressing the target pose of Reachy 2's end effector in Reachy 2 coordinate system. - -> Read next section on [Use arm kinematics]({{< ref "sdk/first-moves/kinematics" >}}) to better understand the use of the `goto_matrix()` method. - -## Gripper control - -### open() - -To **open the grippers**, call the **`open()`** method on the wanted gripper. -It will open it entirely: -```python -reachy.r_arm.gripper.open() -``` - -### close() - -To **close the grippers**, call the **`close()`** method on the wanted gripper. -It will close the gripper with the appropriate value, which means it will be entirely closed if there is no object to grasp, or set a suitable value if an object has been detected in the gripper during the closing: -```python -reachy.r_arm.gripper.close() -``` - -### opening - -The opening value corresponds to a **percentage of opening**, which means: -- 0 is close -- 100 is open - -You can read the opening of the gripper through the opening attribute: -```python -reachy.r_arm.gripper.opening ->>> 20 # almost closed -``` - -You can also control the opening of the gripper, using the **`set_opening()`** method. - -Send your custom opening value, still between 0 and 100, to the gripper with: -```python -reachy.r_arm.gripper.set_opening(50) # half-opened -``` - -> Note that there is an smart gripper control that will avoid the gripper from reaching the opening position if an object has been detected while closing the gripper. - - -## Read arm position - -### get_joints_position() - -You can retrieve the values from each **arm joints** using the **`get_joints_position()`** method. - -This method returns a seven-elements-long list, with the angles in this order: -- r_arm.shoulder.pitch -- r_arm.shoulder.roll -- r_arm.elbow.yaw -- r_arm.elbow.pitch -- r_arm.wrist.roll -- r_arm.wrist.pitch -- r_arm.wrist.yaw - -> Angles are returned in **degrees** by default. - -```python -reachy.l_arm.rotate_to(20, 30, -10) - -reachy.head.get_joints_position() ->>> [7, 10, 4, -50, 4, 5, 7] - -# r_arm.shoulder.pitch=7, -# r_arm.shoulder.roll=10, -# r_arm.elbow.yaw=4, -# r_arm.elbow.pitch=-50, -# r_arm.wrist.roll=4, -# r_arm.wrist.pitch=5, -# r_arm.wrist.yaw=7, -``` - - -### End effector position - -You can get the end effector position of Reachy 2 in Reachy 2 coordinate system using forward kinematics. - -Call: -```python -reachy.l_arm.forward_kinematics() -``` -to get the position of the left gripper in cartesian space. - -> Read next section on [Use arm kinematics]({{< ref "sdk/first-moves/kinematics" >}}) to better understand the use of the `forward_kinematics()` method. diff --git a/content/sdk/first-moves/cameras.md b/content/sdk/first-moves/cameras.md deleted file mode 100644 index 5de47ef7..00000000 --- a/content/sdk/first-moves/cameras.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: "6. Get images from cameras" -description: "How to get the images from Reachy 2's cameras." -lead: "" -date: 2023-07-25T17:38:34+02:00 -lastmod: 2023-07-25T17:38:34+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "120" ---- -This section assumes that you went through the [Hello World]({{< ref "sdk/getting-started/hello-world" >}}) so that you know how to connect to the robot. - -Reachy 2 has 2 types of camera: -- the **teleop** cameras, with a right and left cameras, located in Reachy 2's head and used for the teleoperation -- the **SR** camera, which is a depth camera, located in Reachy 2's torso and mainly useful for manipulation tasks - -Each camera can be accessed separately through *reachy.cameras*. They both have a right and left view, with the left and right sides considered from Reachy point of view. To be able to specify the view you want to get a frame from, you will need to import CameraView: - -```python -from reachy2_sdk.media.camera import CameraView -``` - -## Enable teleop cameras for the SDK - -### SR camera -The SR camera is unplugged by default. -If you want to use it, plug the SR camera on the robot's computer remaining USB port (2). - -{{< img-center "images/sdk/first-moves/plugged-sr.png" 400x "" >}} - -> Make sure to unplug it if you want to use the teleoperation. - -### Teleop cameras -The teleop cameras are shared between the teleop service and the SDK server, and can only be used by one at the same time. -In order to be able to use the teleop cameras with the SDK: -1. Go to the dashboard -2. Stop [webrtc service in the services tab]({{< ref "/dashboard/content/services" >}}) - -{{< img-center "images/sdk/first-moves/stop-webrtc-service.png" 600x "" >}} - -## Get images - -First, connect to your Reachy. - -```python -from reachy_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.cameras ->>> ?? -``` - -The list of initialized cameras should contain both the teleop and SR camera. - -For each camera, namely the teleop and the SR ones, you must call the `capture()`function each time you want to get an image. This captures an image from both view of the given camera at the same time. You can then access one of the image with the `get_frame()` method. - -### Teleop camera - -To get both views of the robot teleop cameras: -```python -from reachy2_sdk import ReachySDK -from reachy2_sdk.media.camera import CameraView - -reachy = ReachySDK(host='192.168.0.42') - -reachy.cameras.teleop.capture() -l_frame = reachy.cameras.teleop.get_frame(CameraView.LEFT) -r_frame = reachy.cameras.teleop.get_frame(CameraView.RIGHT) -``` - -Let's display the captured frame with opencv: -```python -import cv2 - -cv2.imshow("left", l_frame) -cv2.imshow("right", r_frame) -cv.waitKey(0) -cv.destroyAllWindows() -``` - -### SR camera -The SR camera works exactly the same as the teleop camera, but you have more elements captured. In fact, it a RGBD camera, so you have both access to the RGB images and depth information. - -#### RGB images -Getting RGB images from the SR camera looks the same as from the teleop one: after having called `capture()`, use `get_frame()` specifying the CameraView you want to get. -```python -from reachy_sdk import ReachySDK -from reachy2_sdk.media.camera import CameraView - -reachy = ReachySDK(host='192.168.0.42') - -reachy.cameras.SR.capture() -l_frame = reachy.cameras.SR.get_frame(CameraView.LEFT) -r_frame = reachy.cameras.SR.get_frame(CameraView.RIGHT) -``` - -Let's display them with opencv: -```python -import cv2 - -cv2.imshow("left", l_frame) -cv2.imshow("right", r_frame) -cv.waitKey(0) -cv.destroyAllWindows() -``` - -#### Depth information - -The SR camera is a depth camera, you can then diplay a left or right **depth frame** using `get_depth_frame()`, but also the **depthmap** and the **disparity**. - -You first have to capture all, then you can read the frame and get the information you want: -```python -from reachy_sdk import ReachySDK -from reachy2_sdk.media.camera import CameraView - -reachy = ReachySDK(host='192.168.0.42') - -reachy.cameras.SR.capture() -l_depth_frame = reachy.cameras.SR.get_depth_frame(CameraView.LEFT) -r_depth_frame = reachy.cameras.SR.get_depth_frame(CameraView.RIGHT) -depth = reachy.cameras.SR.get_depthmap() -disparity = reachy.cameras.SR.get_disparity() -``` - -Let's display them with opencv: -```python -import cv2 - -cv2.imshow("sr_depthNode_left", l_depth_frame) -cv2.imshow("sr_depthNode_right", r_depth_frame) -cv2.imshow("depth", depth) -cv2.imshow("disparity", disparity) -cv.waitKey(0) -cv.destroyAllWindows() -``` - -> Note that when you call `capture()` on the SR camera, both RGB images and depth information are captured at the same time. \ No newline at end of file diff --git a/content/sdk/first-moves/head.md b/content/sdk/first-moves/head.md deleted file mode 100644 index 5d3558d5..00000000 --- a/content/sdk/first-moves/head.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: "5. Control the head" -description: "Control the head" -lead: "" -date: 2023-07-25T17:38:48+02:00 -lastmod: 2023-07-25T17:38:48+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "110" ---- - -## Head presentation - -Reachy 2's head is mounted on an Orbita3D actuator, referred to as the **neck** actuator, giving 3 degrees of freedom to control the head orientation. -> Note : the antennas are not motorized for the moment - -

- {{< video "videos/sdk/orbita.mp4" "80%" >}} -

- -The complete head's specifications are given [here]({{< ref "advanced/specifications/head-specs" >}}). - -Before starting to control it, connect to your Reachy and turn it on. As in the other pages: - -```python -from reachy2_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.head ->>> - -reachy.head.turn_on() # we turn on only the head -``` - -You could of course turn on the whole robot by calling `reachy.turn_on()` directly. - -There are several ways to control the head movements: -- using the `look_at()`, `rotate_to()` and `orient()` methods, called directly at the **head** level. These methods works as [move commands described previously]({{< ref "sdk/first-moves/moves" >}}). -- controlling the joints goal positions, namely **reachy.head.neck.roll**, **reachy.head.neck.pitch** and **reachy.head.neck.yaw**. - -## Head moves methods - -### look_at() - -You can use the `look_at()` function to make the head look at a specific point in space. This point must be given in Reachy 2's coordinate system in **meters**. The coordinate system is the one we have seen previously: - -* the X axis corresponds to the foward arrow, -* the Y axis corresponds to the right to left arrow, -* the Z axis corresponds to the up arrow. - -The origin of this coordinate system is located in the upper part of the robot trunk. - -{{< img-center "images/sdk/first-moves/reachy_frame.jpg" 400x "" >}} - -If you want Reachy to look forward you can send it the following. - -```python -reachy.head.turn_on() # Don't forget to put the hand in stiff mode -reachy.head.look_at(x=0.5, y=0, z=0.2, duration=1.0) -``` - -You can use multiple *look_at* to chain head movements, or even chain them with the `rotate_to()` and `orient()` functions described below. As seen in the [Understand moves in Reachy 2 section]({{< ref "sdk/first-moves/moves" >}}), the commands on the head will be stacked. - -

- {{< video "videos/sdk/look.mp4" "80%" >}} -

- -Here is the code to reproduce this. - -```python -import time - -look_right = reachy.head.look_at(x=0.5, y=-0.5, z=0.1, duration=1.0) -look_down = reachy.head.look_at(x=0.5, y=0, z=-0.4, duration=1.0) -look_left = reachy.head.look_at(x=0.5, y=0.3, z=-0.3, duration=1.0) -look_front = reachy.head.look_at(x=0.5, y=0, z=0, duration=1.0) -``` - -The best way to understand how to use the *look_at* is to play with it. Picture a position you would like Reachy's head to be in, guess a point which could match for the *look_at* and check if you got it right! - -Another cool thing is that we can combine Reachy's kinematics with the *look_at* so that Reachy's head follows its hand! - -

- {{< video "videos/sdk/look_at_hand.mp4" "80%" >}} -

- -```python -reachy.turn_on('head') - -x, y, z = reachy.r_arm.forward_kinematics()[:3, -1] -reachy.head.look_at(x=x, y=y, z=z, duration=1.0) - -time.sleep(0.5) - -while True: - x, y, z = reachy.r_arm.forward_kinematics()[:3, -1] - reachy.head.look_at(x=x, y=y, z=z, duration=0.1) -``` - -What the code says is that we compute the [forward kinematics of Reachy's right arm]({{< ref "sdk/first-moves/kinematics#forward-kinematics" >}}), and the x, y, z of Reachy's right end-effector in the Reachy's coordinates system will be the coordinates of the point used by the *look_at*. - -### rotate_to() - -The `rotate_to()` function is another way to control the head. You directly control the joint of the neck, giving the roll, pitch and yaw angles in degrees. The rotation is made in the order: roll, pitch, yaw, in the Orbita3D coordinate system. - -{{< img-center "images/sdk/first-moves/orbita_rpy.png" 400x "" >}} - -To make the robot looks a little down: -```python -reachy.head.turn_on() # Don't forget to put the hand in stiff mode -reachy.head.rotate_to(roll=0, pitch=-10, yaw=0, duration=1.0) -``` - -### orient() - -The last method to control the head is the `orient()` method. You can control the head with a quaternion. - -You can use [pyquaternion library](https://kieranwynn.github.io/pyquaternion/) to create suitable quaternion for this method. - -```python -from pyquaternion import Quaternion - -q = Quaternion(axis=[1, 0, 0], angle=3.14159265) -reachy.head.turn_on() -reachy.head.orient(q) -``` - -## Joint's goal_position - - -## Read head position - -You can read the head orientation in two different ways: - -- using the `get_orientation()` method, which returns a quaternion -- using the `get_joints_positions()` method, which the neck's roll, pitch and yaw present_position. - -### get_orientation() - -```python -q = reachy.head.get_orientation() -print(q) ->>> ?? -``` - -### get_joints_positions() - -In case you feel more comfortable using roll, pitch, yaw angles rather than working with quaternions, you can retrieve those values from the **neck joints**. - -```python -reachy.head.rotate_to(20, 30, -10) -time.sleep(2) -reachy.head.get_joints_positions() ->>> [20, 30, -10] # roll=20, pitch=30, yaw=-10 -``` - -Be careful that contrary to the quaternion that offers a unique representation of a rotation, it is not the case of the euler angles. Several angles combination can lead to the same orientation in space. For example: - -```python -reachy.head.rotate_to(70, -100, 80) # roll=70, pitch=-100, yaw=80 -time.sleep(2) -reachy.head.get_joints_positions() ->>> [-110, -80, -100] # roll=-110, pitch=-80, yaw=-100 -``` - -The values are different, nevertheless it is the same final orientation. You can convince yourself doing: -```python -reachy.head.rotate_to(-110, -80, -100) -``` -The head won't move. \ No newline at end of file diff --git a/content/sdk/first-moves/intro.md b/content/sdk/first-moves/intro.md deleted file mode 100644 index f89d590b..00000000 --- a/content/sdk/first-moves/intro.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: "1. Start with Reachy 2" -description: "Quick overview of how to use the robot once connected." -lead: "What can you do once connected to Reachy 2?" -date: 2023-07-25T17:38:52+02:00 -lastmod: 2023-07-25T17:38:52+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "70" ---- - -## Enable teleop cameras for the SDK - - -### SR camera -The SR camera is unplugged by default. -If you want to use it, plug the SR camera on the robot's computer remaining USB port (2). - -{{< img-center "images/sdk/first-moves/plugged-sr.png" 400x "" >}} - -> Make sure to unplug it if you want to use the teleoperation. - -### Teleop cameras -The teleop cameras are shared between the teleop service and the SDK server, and can only be used by one at the same time. -In order to be able to use the teleop cameras with the SDK: -1. Go to the dashboard -2. Stop [webrtc service in the services tab]({{< ref "/dashboard/content/services" >}}) - -{{< img-center "images/sdk/first-moves/stop-webrtc-service.png" 400x "" >}} - -## Be ready to move - -### 1. Connect to the robot - -If you followed the instructions from ["Connect to Reachy 2"]({{< ref "sdk/getting-started/connect" >}}), you know how to get Reachy's IP address and how to connect to the robot with the command: - -```python -from reachy2_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP -``` - -### 2. Turn on motors - -When starting, your robot is in compliant mode, which means you can move its parts by manipulating manually the robot. In this mode, the robot won't respond to any command you send to it. - -At each use, you will have to turn on your robot's motors doing: -```python -reachy.turn_on() -``` - -At the end of your session or program, switch off the motors to send them back to compliant mode doing: -```python -reachy.turn_off() -``` - -This will act on all parts of your robot, including the mobile base. -If you want to turn on or off a single part, access directly the relevant part and turn it on or off, for example for the left arm: - -```python -reachy.l_arm.turn_on() -reachy.l_arm.turn_off() -``` - -All parts are detailed below in [ReachySDK attributes]({{< ref "sdk/first-moves/intro#attributes" >}}). - -At any time, you can check the state of your robot using the `is_on()` or `is_off()` method. Note that it will return True only if **all parts** are in the requested state. This means both methods can return False if the right arm is on but not the left one for example. - -```python -# Turn on all parts -reachy.turn_on() -# Check robot state -reachy.is_on() ->>> True -reachy.is_off() ->>> False - -# Turn off only the left arm -reachy.l_arm.turn_off() -# Check robot state -reachy.is_on() # reachy is not on, as left arm is off ->>> False -reachy.is_off() # but reachy is not fully off neither ->>> False -# Check parts state -reachy.r_arm.is_on() # right arm is still on ->>> True -reachy.l_arm.is_off() # left arm is off ->>> True -``` - -### 3. Start from a standard position (optional) - -2 standard positions are accessible and can be called easily to setup your starting position: -- the **zero** pose, with all joints set at 0 degree -- the **elbow_90** pose, with the elbow pitch set at -90 degrees and all other joints at 0 degree - -To start at the zero position, use the `set_pose()` function: -```python -reachy.set_pose('zero') -``` - -By default, this movement is made in 2 seconds. You can choose to specify a custom duration. For example, to reach the elbow_90 pose in 5 seconds: -```python -reachy.set_pose('elbow_90', duration=5) -``` - -## Check connection - -At any time, you can check the connection between your SDK and the robot is still open with: -```python -reachy.is_connected() ->>> True -``` - -If the connection has been lost, and the problem has been resolved, you can reconnect to the robot with the `connect()`method: -```python -reachy.connect() -``` - -{{< alert icon="💡" text="You cannot use this method to connect to another IP address. It will automatically reconnect to the initial instantiated robot." >}} - -## ReachySDK object - -The *reachy* object instanciated from the ReachySDK class above is the root access to get all incoming information from Reachy 2 (joints or cameras) and to control each part of the robot (left/right arm, head, mobile base). - -The *reachy* object has 7 attributes and ?? methods that we will quickly present here, more detailed information are given in the dedicated pages after this one. - -{{< alert icon="💡" text="Note that you can only instantiate one ReachySDK in a session." >}} - -{{< img-center "images/sdk/first-moves/reachy_attributes.png" 400x "" >}} - -### Attributes - -The *reachy* attributes detailed give to access to info, parts and sensors of the robot. - -#### List of attributes -[reachy.cameras]({{< ref "sdk/first-moves/intro#reachycameras" >}}) -[reachy.head]({{< ref "sdk/first-moves/intro#reachyhead" >}}) -[reachy.info]({{< ref "sdk/first-moves/intro#reachyinfo" >}}) -[reachy.joints]({{< ref "sdk/first-moves/intro#reachyjoints" >}}) -[reachy.l_arm]({{< ref "sdk/first-moves/intro#reachyl_arm" >}}) -[reachy.mobile_base]({{< ref "sdk/first-moves/intro#reachymobile_base" >}}) -[reachy.r_arm]({{< ref "sdk/first-moves/intro#reachyr_arm" >}}) - -#### reachy.cameras - -[Camera object](https://pollen-robotics.github.io/reachy-sdk/api/camera.html). It is used to recover the last image captured by the left camera and also to control the motorized zoom attached to the camera. - -```python -reachy.left_camera ->>> -``` - -#### reachy.head - -[Head object](https://pollen-robotics.github.io/reachy-sdk/api/head.html). -Contains the three joints composing the Orbita actuator along with methods for its kinematics or to control it. - -```python -reachy.head ->>> - - - - ->> -``` - -#### reachy.info - -[Camera object](https://pollen-robotics.github.io/reachy-sdk/api/camera.html). It is used to recover the last image captured by the right camera and also to control the motorized zoom attached to the camera. - -```python -reachy.right_camera ->>> -``` - -#### reachy.joints - -[Joint object](https://pollen-robotics.github.io/reachy-sdk/api/joint.html) containing every joint of the robot, from its arms to its head and antennas. This is useful when you want to get information, like the position, from all joints at once. - -```python -reachy.joints ->>> - - - - - - - - - - - - - - - - - - - - -> -``` - -#### reachy.l_arm - -[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the left arm along with its kinematics methods. - -```python -reachy.l_arm ->>> - - - - - - - ->> -``` - -#### reachy.mobile_base - -[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the right arm along with its kinematics methods. - -```python -reachy.r_arm ->>> - - - - - - - ->> -``` - -#### reachy.r_arm - -[Arm object](https://pollen-robotics.github.io/reachy-sdk/api/arm.html) containing every joint in the right arm along with its kinematics methods. - -```python -reachy.r_arm ->>> - - - - - - - ->> -``` - -### Basic methods - -The *reachy* object has ?? methods, 8 of them being basic methods useful to start using the robot. The other methods are related to robot movements, and will be detailed in a more advanced section. - -#### List of basic methods - -[reachy.connect()]({{< ref "sdk/first-moves/intro#reachyconnect" >}}) -[reachy.disconnect()]({{< ref "sdk/first-moves/intro#reachydisconnect" >}}) -[reachy.is_connected()]({{< ref "sdk/first-moves/intro#reachyis_connected" >}}) -[reachy.is_off()]({{< ref "sdk/first-moves/intro#reachyis_off" >}}) -[reachy.is_on()]({{< ref "sdk/first-moves/intro#reachyis_on" >}}) -[reachy.turn_off()]({{< ref "sdk/first-moves/intro#reachyturn_off" >}}) -[reachy.turn_on()]({{< ref "sdk/first-moves/intro#reachyturn_on" >}}) -[reachy.set_pose()]({{< ref "sdk/first-moves/intro#reachyset_pose" >}}) - - -#### reachy.connect() - -#### reachy.disconnect() - -#### reachy.is_connected() - -#### reachy.is_off() - -#### reachy.is_on() - -#### reachy.turn_off() - -Method to turn off the whole robot. Turning off the robot means putting all parts of the robot in compliant mode, including the mobile base if there is one. See next section for more information on what the compliant mode is for a motor. - -```python -reachy.turn_off() -``` - -#### reachy.turn_on() - -Method to turn on the whole robot. Turning on the robot means putting all the parts of the robot in stiff mode, including the mobile base if there is one. See next section for more information on what the stiff mode is for a motor. - -```python -reachy.turn_on() -``` - -#### reachy.set_pose() - - diff --git a/content/sdk/first-moves/kinematics.md b/content/sdk/first-moves/kinematics.md deleted file mode 100644 index d3bb5015..00000000 --- a/content/sdk/first-moves/kinematics.md +++ /dev/null @@ -1,331 +0,0 @@ ---- -title: "4. Use arms kinematics" -description: "Presentation of Reachy's forward and inverse kinematics." -lead: "" -date: 2023-07-25T17:39:00+02:00 -lastmod: 2023-07-25T17:39:00+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "100" ---- - -> Note : Make sure you checked the [safety page]({{< ref "sdk/getting-started/safety" >}}) before controlling the arm. - -## Arm coordinate system - -### Joint coordinates - -If you remember the [`goto_joint()` function]({{< ref "sdk/first-moves/arm#goto_joints" >}}), to generate a trajectory for the arm, you need to pass a list of joints with the requested position as argument. - -For example, to place the right arm in a right angled position, we defined the following list: - -```python -right_angled_position = [0, 0, 0, -90, 0, 0, 0] -``` - -and then call the function with is: - -```python -reachy.r_arm.goto_joints(right_angled_position) -``` - -In this basic arm control, we used what is called **joint coordinates** to move Reachy. This means that we controlled each joint separately. - -Controlling a robot in joint coordinates can be hard and is often far from what we actually do as humans. When we want to grasp an object in front of us, we think of where we should put our hand, not how to flex each individual muscle to reach this position. This approach relies on the cartesian coordinates: the 3D position and orientation in space, this is where the **kinematic model** comes into play. - -### Kinematic model - -The **kinematic model** describes the motion of a robot in mathematical form without considering the forces and torque affecting it. It only focuses on the geometric relationship between elements. - -We have defined the whole kinematic model of the arm. This means the translation and rotation required to go from one joint to the next one. On a right arm equipped with a gripper this actually look like this: - -|Motor|Translation|Rotation| -|-----|-----------|--------| -|r_arm.shoulder.pitch|(0, -0.019, 0)|(0, 1, 0) -|r_arm.shoulder.roll|(0, 0, 0)|(1, 0, 0) -|r_arm.elbow.yaw|(0, 0, -0.280)|(0, 0, 1) -|r_arm.elbow.pitch|(0, 0, 0)|(0, 1, 0) -|r_arm.wrist.roll|(0, 0, -0.120)|(0, 0, 1) -|r_arm.wrist.pitch|(0, 0, 0)|(0, 1, 0) -|r_arm.wrist.yaw|(0, 0, 0)|(1, 0, 0) -|r_gripper|(0, ??, ??)|(0, 0, 0) - - -To use and understand the kinematic model, you need to know how Reachy coordinate system is defined (from Reachy's perspective), see below: - -{{< img-center "images/sdk/first-moves/arm_axis.png" 400x "" >}} - -* the X axis corresponds to the forward arrow, -* the Y axis corresponds to the right to left arrow, -* the Z axis corresponds to the up arrow. - -The origin of this coordinate system is located in the upper part of the robot trunk, inside Reachy. - Basically, if you imagine a segment going from the left shoulder to the right shoulder of the robot, the origin is the middle of this segment, which corresponds to behind the center of Pollen's logo on Reachy's torso. - -{{< img-center "images/sdk/first-moves/reachy_frame.jpg" 400x "" >}} - -> Units in this coordinate system are **meters**. So the point (0.3, -0.2, 0) is 30cm in front of the origin, 20cm to the right and at the same height. - - -### End effector location - -We consider the end-effector to be in a virtual joint located in the gripper and referred as *'right_tip'* or *'left_tip'* in the [urdf file](https://github.com/pollen-robotics/reachy_kinematics/blob/master/reachy.URDF), as shown below. - -{{< img-center "images/sdk/first-moves/eef.png" 400x "" >}} - -The red dot corresponds to the *'right_tip'*. - -You can see the right and left end-effectors animated below. - -

- {{< video "videos/sdk/eef.mp4" "80%" >}} -

- -### Switching between joint and cartesian coordinates - -Forward and inverse kinematics are a way to go from one coordinates system to the other: - -* **forward kinematics: joint coordinates –> cartesian coordinates**, -* **inverse kinematics: cartesian coordinates –> joint coordinates**. - -## Forward kinematics - -Using the kinematic model defined above, we can compute the 3D position and orientation of the right or left end-effector with the **`forward_kinematics()`** method. - -### forward_kinematics() - -Each arm has a **`forward_kinematics()`** method. To use it, you first need to connect to your Reachy. - -```python -from reachy_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.r_arm.forward_kinematics() ->>> array([[ 0.04622308, -0.03799621, -0.99820825, 0.31144822], - [ 0.10976691, 0.99341829, -0.03273101, -0.19427524], - [ 0.99288199, -0.1080573 , 0.05008958, -0.4255104 ], - [ 0. , 0. , 0. , 1. ]]) -``` - -The method returns a 4x4 matrix indicating the position and orientation of the end effector in Reachy 2's coordinate system. - -> By specifying no argument, it will give the current 3D position and orientation of the end effector. - -You can compute the forward kinematics of the arm for other joints positions, by giving as an argument a seven-element-long list, as for the `goto_joints()`method. The arm will not move, but you can get the target position and orientation of the arm in this configuration. - -For example, for the right arm right angled position: -```python -reachy.r_arm.forward_kinematics([0, 0, 0, -90, 0, 0, 0]) ->>> array([[ 0.04622308, -0.03799621, -0.99820825, 0.31144822], - [ 0.10976691, 0.99341829, -0.03273101, -0.19427524], - [ 0.99288199, -0.1080573 , 0.05008958, -0.4255104 ], - [ 0. , 0. , 0. , 1. ]]) -``` - -### Understand the result -The 4x4 matrix returned by the **`forward_kinematics()`** method is what is often called a **pose**. It actually encodes both the 3D translation (as a 3D vector) and the 3D rotation (as a 3x3 matrix) into one single representation. - -$$\begin{bmatrix} -R_{11} & R_{12} & R_{13} & T_x\\\\\\ -R_{21} & R_{22} & R_{23} & T_y\\\\\\ -R_{31} & R_{32} & R_{33} & T_z\\\\\\ -0 & 0 & 0 & 1 -\end{bmatrix}$$ - -The instruction - -```python -reachy.r_arm.forward_kinematics() -``` - -returns the current pose of the right end-effector, based on the present position of every joint in the right arm. - -You can also compute the pose for a given joints position, to do that just pass the list of position as argument of forward_kinematics. Be careful to respect the order of the position you give and to give all the joints in the arm kinematic chain (i.e. from *shoulder_pitch* to *wrist_roll*). - -For example, we can compute the forward kinematics for the right-angle position we defined earlier. - -```python -reachy.r_arm.forward_kinematics(right_angle_position) ->>> array([[ 0. , 0. , -1. , 0.3675], - [ 0. , 1. , 0. , -0.202 ], - [ 1. , 0. , 0. , -0.28 ], - [ 0. , 0. , 0. , 1. ]]) -``` - -With this result, we can tell that when the right arm is in the right angle position, the right end-effector is 37cm in front of the origin, 20cm to the left and 28cm below the origin. - -As of the rotation matrix, the identity matrix corresponds to the zero position of the robot which is when the hand is facing toward the bottom. - -Here we obtained the rotation matrix - -$$\begin{bmatrix} -0 & 0 & -1\\\\\\ -0 & 1 & 0 \\\\\\ -1 & 0 & 0 -\end{bmatrix}$$ - -We can use scipy to understand what this matrix represents. - -```python -from scipy.spatial.transform import Rotation as R -import numpy as np - -R.from_matrix([ - [0, 0, -1], - [0, 1, 0], - [1, 0, 0], -]).as_euler('xyz', degrees=True) ->>> array([ 0. , -89.99999879, 0. ]) -``` -So scipy tells us that a rotation of -90° along the y axis has been made to get this matrix, which is coherent with the result because having the hand facing forward corresponds to this rotation according to Reachy's xyz axis that we saw above. - -## Inverse kinematics - -The inverse kinematics is the exact opposite of the forward kinematics. From a 4x4 pose in Reachy 2 coordinate system, it gives you a list of joints positions to reach this target. - -Knowing where you arm is located in the 3D space can be useful but most of the time what you want is to move the arm in cartesian coordinates. You want to have the possibility to say: “move your hand to [x, y, z] with a 90° rotation around the Y axis”. This is what **`goto_matrix()`** - -### inverse_kinematics() - -Each arm has an **`inverse_kinematics()`** method. To use it, you first need to connect to your Reachy. -You need to specify as an argument a target pose in Reachy coordinate system. - -Let's for example ask for the inverse kinematics of the current pose, using the forward kinematics. - -```python -from reachy_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -reachy.r_arm.inverse_kinematics(reachy.r_arm.forward_kinematics()) ->>> [0, 0, 0, -90, 0, 0, 0] ?? -``` - -The method returns a seven-element-long list indicating the position of each arm joint, in the usual order: -- r_arm.shoulder.pitch -- r_arm.shoulder.roll -- r_arm.elbow.yaw -- r_arm.elbow.pitch -- r_arm.wrist.roll -- r_arm.wrist.pitch -- r_arm.wrist.yaw - -Contrary to the forward kinematics which has a unique answer (giving all joints values will always put the end effector at the same target position), inverse kinematics can have an infinite number of answers (for a target position of the end effector, several combinations of joints angles are possible). - -#### Using a q0 value -The inverse kinematics returns one solution, but you may want to custom the position from which the computation is done to get another result. -To do so, specify a **q0** value when calling the `inverse_kinematics()` method. The **`q0`** argument must be a seven-element-long list as well: -```python -reachy.r_arm.inverse_kinematics( - reachy.r_arm.forward_kinematics(), - q0=[0, 0, 0, 0, 0, 0, 0]) ->>> [0, 0, 0, -90, 0, 0, 0] ?? -``` - - -### Example: square movement with goto_matrix() - -#### Defining the poses - -To make this more concrete, let's first try with a simple example. We will make the right hand draw a square in 3D space. To draw it, we will define the four corners of a square and Reachy's right hand will go to each of them. - -The virtual corner is represented below. - -{{< img-center "images/sdk/first-moves/square_setup.jpg" 400x "" >}} - -For our starting corner A, let's imagine a point in front of the robot, on its right and below its base. With Reachy coordinate system, we can define such a point with the following coordinates: - -$$A = \begin{pmatrix}0.3 & -0.4 & -0.3\end{pmatrix}$$ - -The coordinates of B should match A except the z component wich should be higher. Hence - -$$B = \begin{pmatrix}0.3 & -0.4 & 0.0\end{pmatrix}$$ - -For the corner C, we want a point on the same z level as B in the inner space of Reachy and in the same plane as A and B so we only need to change the y component of B. We can take for example - -$$C = \begin{pmatrix}0.3 & -0.1 & 0.0\end{pmatrix}$$ - -And to complete our corners we can deduce D from A and C. D coordinates should match C except its z component which must the same as A. Hence - -$$D = \begin{pmatrix}0.3 & -0.1 & -0.3\end{pmatrix}$$ - -> **Remember that you always have to provide poses to the inverse kinematics that are actually reachable by the robot.** If you're not sure whether the 3D point that you defined is reachable by Reachy, you can move the arm with your hand in compliant mode, ask the forward kinematics and check the 3D translation component of the returned pose. - -But having the 3D position is not enough to design a pose. You also need to provide the 3D orientation via a rotation matrix. The rotation matrix is often the tricky part when building a target pose matrix. - -Keep in mind that the identity rotation matrix corresponds to the zero position of the robot which is when the hand is facing toward the bottom. So if we want the hand facing forward when drawing our virtual square, we need to rotate it from -90° around the y axis, as we saw in the forward kinematics part. - -We know from before which rotation matrix corresponds to this rotation, but we can use scipy again to generate the rotation matrix for given rotations. - -```python -print(np.around(R.from_euler('y', np.deg2rad(-90)).as_matrix(), 3)) ->>> [[ 0. -0. -1.] - [ 0. 1. -0.] - [ 1. 0. 0.]] -``` - -We got the rotation matrix that we expected! - -As mentionned, building the pose matrix can be hard, so don't hesitate to use scipy to build your rotation matrix. You can also move the arm with your hand where you want it to be and use the forward kinematics to get an approximation of the target pose matrix you would give to the inverse kinematics. - -Here, having the rotation matrix and the 3D positions for our points A and B, we can build both target pose matrices. - -```python -A = np.array([ - [0, 0, -1, 0.3], - [0, 1, 0, -0.4], - [1, 0, 0, -0.3], - [0, 0, 0, 1], -]) - -B = np.array([ - [0, 0, -1, 0.3], - [0, 1, 0, -0.4], - [1, 0, 0, 0.0], - [0, 0, 0, 1], -]) - -C = np.array([ - [0, 0, -1, 0.3], - [0, 1, 0, -0.1], - [1, 0, 0, 0.0], - [0, 0, 0, 1], -]) - -D = np.array([ - [0, 0, -1, 0.3], - [0, 1, 0, -0.1], - [1, 0, 0, -0.3], - [0, 0, 0, 1], -]) -``` - -#### Sending the movements commands - -As before, we use the **`goto_matrix()`** to send moving instructions to the arm. - - -```python -import time -# put the joints in stiff mode -reachy.r_arm.turn_on() - -# use the goto_matrix() method -reachy.r_arm.goto_matrix(A) -reachy.r_arm.goto_matrix(B) -reachy.r_arm.goto_matrix(C) -reachy.r_arm.goto_matrix(D) - -# put the joints back to compliant mode -# use turn_off_smoothly to prevent the arm from falling hard -reachy.r_arm.turn_off() -``` - -The result should look like this: - -

- {{< video "videos/sdk/goto_ik.mp4" "80%" >}} -

\ No newline at end of file diff --git a/content/sdk/first-moves/mobile-base.md b/content/sdk/first-moves/mobile-base.md deleted file mode 100644 index 7b600d06..00000000 --- a/content/sdk/first-moves/mobile-base.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: "8. Use the mobile base" -description: "How to use the mobile base." -lead: "" -date: 2023-07-25T17:38:34+02:00 -lastmod: 2023-07-25T17:38:34+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "140" ---- - -## What is accessible on the mobile base -The following elements are accessible with *reachy.mobile_base*: -* mobile base version, -* battery level, -* odometry of the base, -* control and drive modes, -* goto and set_speed methods to make the mobile base move. - -## Frames - -### Robot frame -The robot frame or egocentric frame or base_link frame is **rigidly attached to the robot**. Its (0, 0) point is the projection on the floor of the center of the mobile base. -**X in front, Y to the left, Theta positive counterclockwise.** - -{{< img-center "images/sdk/mobile-base/robot_frame.png" 400x "" >}} - -*It follows ROS' conventions described in [REP 105 “Coordinate Frames for Mobile Platforms”](https://www.ros.org/reps/rep-0105.html)* - -### Odom frame -The odom frame is a **world-fixed frame**. The position (x, y, theta) of the robot in the odom frame is continuously updated by the HAL through odometry calculations. These calculations currently only use the measurements from the wheels to estimate the movement of the robot. While the position of the robot is continuous, **it should never be relied upon for long-term reference as it will always drift.** - -{{< img-center "images/sdk/mobile-base/odom_frame.png" 400x "" >}} - -The initial position of the odom frame matches the position of the robot when the HAL was started. The odom frame can also be reset to the current position of the robot using: - ```python - reachy_mobile.mobile_base.reset_odometry() - ``` - -## Moving the mobile base - -### Using the goto method -The `goto()` method expects a goal position in the [odom frame]({{< ref "/sdk/first-moves/mobile-base#odom-frame" >}}), composed of 3 elements: x in meters, y in meters and theta in degrees. - -:warning: The most important thing to get used to, is the fact that the odom frame is world-fixed and that the position of the robot is always updated as long as the HAL is running (the HAL is automatically started during the robot boot-up). So by default, **if you ask for a ```goto(0, 0, 0)``` the robot will try to comeback to the position it was at boot-up.** - -To perform a goto relative to the current position of the robot, use the method ```reset_odometry()```. For example, create an instance of reachy with: - -```python -from reachy2_sdk import ReachySDK - -reachy = ReachySDK(host='your-reachy-ip') -``` - -Reset the odometry frame, and ask the robot to move 50cm in front of it: -```python -reachy.mobile_base.reset_odometry() -reachy.mobile_base.goto(x=0.5, y=0.0, theta=0.0) -``` -Now, ask for a goto(0,0,0). The robot should go back to its previous position: -```python -reachy_mobile.mobile_base.goto(x=0.0, y=0.0, theta=0.0) -``` - -We recommend taking the time to play around with this concept. - -> Note the **goto() method of the mobile base does not work like [moves methods explained previously]({{< ref "/sdk/first-moves/moves">}})** - - -By default, the robot will always try to reach the goal position, meaning that even if the robot did reach its position and you push it, it will try to come back to the goal position again. - -However, you can define two types of stop conditions through optional parameters. - -- A timeout, expressed in seconds. The robot stops the goto when the elapsed time since the start of the command is superior to the timeout. There is a **default timeout that scales with the distance asked by the goto**. - -- A spatial tolerance, expressed with 4 values: delta_x (the error in m along the X axis), delta_y (the error in m along the Y axis), delta_theta (the angle error in deg) and distance (the l2 distance between the current position and the goal position in m). The robot stops the goto when it is close enough to satisfy all 4 conditions simultaneously. - -### Using the set_speed method -Since the mobile base is holonomic, the `set_speed()` method expects 3 speed commands expressed in the robot frame: -- x_vel, in m/s. The instantaneous speed positive in front of the robot. -- y_vel, in m/s. The instantaneous speed positive to the left of the robot. -- rot_vel, in deg/s. The instantaneous rotational speed positive counterclockwise. - -See the [joy_controller code](https://github.com/pollen-robotics/mobile-base-sdk/blob/main/mobile_base_sdk/examples/scripts/joy_controller.py) for a working example. - -:bulb: As a safety measure, the HAL will stop the wheels if it didn't receive a new goal speed in the last 200ms. - -:bulb: The way this is implemented in the HAL is simply to listen to the /cmd_vel topic, apply some smoothing, perform the kinematic calculations and send the speed commands to the wheels. This makes it very easy to create control interfaces using ROS, see the [keyboard example](https://github.com/pollen-robotics/zuuu_hal/blob/main/examples/zuuu_teleop_keyboard.py) or the [joy controller example](https://github.com/pollen-robotics/zuuu_hal/blob/main/examples/zuuu_teleop_joy.py). - -*Note: the HAL has a drive mode to set speed commands for variable amounts of time. Instead of relying on a topic, it creates a service. The niche usage didn't warrant the added complexity, so the interface with the SDK was not made. But if needed, it exists!* diff --git a/content/sdk/first-moves/moves.md b/content/sdk/first-moves/moves.md deleted file mode 100644 index d9e1773f..00000000 --- a/content/sdk/first-moves/moves.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -title: "2. Understand moves in Reachy 2" -description: "How do moves work on Reachy 2." -lead: "Learn how to use moves to control Reachy 2's arms and head." -date: 2023-07-25T17:39:13+02:00 -lastmod: 2023-07-25T17:39:13+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "80" ---- - -## Moves methods - -ReachySDK for Reachy 2 offers you methods to make movements with the arms and head, controlling the target position in several way, choosing the duration of the movement, or even the interpolation mode. - -Those methods work the same way on the left and right arms and on the head, **but not on the mobile base**. - - -The methods to use in order to control the robot are: - -- for the arms: - - **`goto_joints()`**: you control directly the goal position of each joint of the arm, in degrees - - **`goto_from_matrix()`**: you control the target pose of the end effector in the robot's coordinate system, from a 4x4 homogeneous matrix -- for the head: - - **`look_at()`**: you control the head by giving a point in the robot coordinate system the head will look at - - **`rotate_to()`**: you control directly the roll, pitch and yaw goal positions of the neck, in degrees - - **`orient()`**: you control the head orientation with a quaternion - -## Moves properties - -### Moves IDs - -The previous methods all return an id, that you can use to get information on this movements or to cancel this movement. Store this id in a variable to be able to use it further. - -```python -move_1 = reachy.r_arm.goto_joints([10, -10, 0, -90, 0, 0, 0]) - -print(move_1) ->>> ?? -``` - -### Moves execution - -Move commands can only be sent on parts: -- reachy.l_arm -- reachy.r_arm -- reachy.head - -#### Moves are non-blocking for other parts -It means you can send a move command on different parts, it won't wait for the movement to be executed on the first part to execute the other one, but will follow the timing of your code. - -Let's take an example with the following sequence: -```python -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) -time.sleep(1) -reachy.r_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 2) -``` -This sequence will take 3 seconds to execute, as the right arm will start its movement 1 second after the left arm has started its own movement. They will finish at the same time. - -#### Moves are blocking and stacked for a part -It means that you can send several move commands on a part one after another without any delay, they will be played in this order, but will wait for the previous move to be finished. - -Let's take an example with the following sequence: -```python -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) -``` -This sequence will take 8 seconds to execute, as each movement on the left arm will wait for the previous before starting. - -Nevertheless, you can still send move commands to other parts. -For example: -```python -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) #1 -time.sleep(1) -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) #2 -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) #3 -reachy.r_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 2) #4 -``` - -This sequence will still take 8 seconds to execute: -- commands #1, #2 and #3 are sent to the left arm. They will be stacked on the left arm, and the `time.sleep(1)` won't have any effect . When received, command #2 will simply wait 2 seconds rather than 3 secondes in the previous example. -- commands #4 is sent on the right arm, where no movement is progress. It will then start 1 second after command #1 has started, and will then be over approximatively at the same time. - -The sequence execution order is #1, #4, #2, #3 - -### Part execution state -As the sequence can become complex, you can get information for each part on its current status, to now which movementis being played and know which others are waiting to be played. -For each part, the following methods are available: -- **`get_move_playing()`**: will return the id of the currently playing move on the part -- **`get_moves_queue()`**: will return the ids of all stacked move commands waiting to be played on the part - -Those methods are called at the part level, to get info on the state of the part. -For example: -```python -# Write a sequence for the left arm -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) # id=1 -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) # id=2 -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) # id=3 - -# Move #1 is currently playing -current_move = reachy.l_arm.get_move_playing() -print(current_move) ->>> ?? - -# 2 move commands, #2 and #3, are waiting to be played -print(len(reachy.l_arm.get_moves_queue())) ->>> 2 -``` - -### Moves state - -For a specific move, you may want to know its current state. You can get information on the moves given its id with 3 methods available at reachy's level: -- **`is_move_playing()`**: return True if the movement is currently being played -- **`is_move_finished()`**: return True if the movement is over, but also if it won't be played because it has been cancelled for example -- **`get_move_joints_request()`**: will return the joints goal positions sent to the part by the corresponding move command - -Let's take an example: -```python -move_1 = reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) - -time.sleep(1) - -# Move is currently being played -reachy.is_move_playing(move_1) ->>> True -reachy.is_move_finished(move_1) ->>> False - -time.sleep(3) - -# Move is now over -reachy.is_move_playing(move_1) ->>> False -reachy.is_move_finished(move_1) ->>> True - -# Get joint goal position of the move -reachy.get_move_joints_request(move_1) ->>> ?? -``` - -### Cancel moves - -If you want to modify the queue of move commands on a part, or interrupt the movement being played, you can cancel move commands at any time. - -#### Single move cancellation - -To cancel a single movement, currently playing or stacked in a part's queue, use its id and call `cancel_move_by_id()` from reachy. - -```python -move_1 = reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) - -time.sleep(1) -reachy.cancel_move_by_id(move_1) -``` - -#### Cancel all moves at once - -To cancel all moves at once, you can call the `cancel_all_moves()` methods. -This method can be called at the level you want to act, which can be either **reachy** or a **specific part**. - -##### All robot moves - -For example, if you want to cancel all moves on all parts: -```python -# Send a sequence of moves -reachy.head.rotate_to(20, 30, -10, duration=3) -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) - -# Cancel all moves -reachy.cancel_all_moves() -``` - -All movements are cancelled, even the movement stacked in the left arm queue which will never be played. - -##### All part moves - -If you only want to cancel movement on the left arm: -```python -# Send a sequence of moves -reachy.head.rotate_to(20, 30, -10, duration=3) -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 3) -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) - -# Cancel moves on left arm only -reachy.l_arm.cancel_all_moves() -``` - -The movement on the head will continue, but all the movements of the left will be stopped and the left arm queue cleaned. - - -## Moves duration - -For each methods mentioned in [Moves methods]({{< ref "sdk/first-moves/moves#moves-methods" >}}), you can give a custom duration for the execution of the movements. - -Simply specify the **`duration`** argument **in seconds** when calling the method, as shown in the move examples above: -```python -reachy.head.rotate_to(20, 30, -10, duration=3) -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], duration = 5) - - -# Doing: -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0]) -# will lead to the same result as: -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], duration = 2) -``` - -> Default duration is 2 seconds. - -You **cannot set a duration to 0 second**. This will raise an exception in your code: -?? - - -## Moves interpolation mode - -The moves methods generates a trajectory between the present position and the goal position. This trajectory is then interpolated at a predefined frequency (100Hz) to compute all intermediary target positions that should be followed before reaching the final goal position. Depending on the interpolation mode chosen, you can have a better control over speed and acceleration. - -Two interpolation modes are available when sending a move command: -- the **linear** interpolation mode -- the **minimum-jerk** interpolation mode - -{{< img-center "images/sdk/first-moves/interpolation.png" 400x "" >}} - -Both trajectories start and finish at the same point but don't follow the same intermediate positions. The minimum jerk will slowly accelerate at the begining and slowly decelerate at the end. This makes the movements more natural. - -You can specify the interpolation mode by setting the **`interpolation_mode`** argument when calling the method: -```python -reachy.head.rotate_to(20, 30, -10, interpolation_mode='linear') -reachy.l_arm.goto_joints([0, 0, 0, -90, 0, 0, 0], interpolation_mode='linear') - - -# Doing: -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0]) -# will lead to the same result as: -reachy.l_arm.goto_joints([0, 0, 0, 0, 0, 0, 0], interpolation_mode='minimum_jerk') -``` - -> Default interpolation mode is minimum-jerk. \ No newline at end of file diff --git a/content/sdk/first-moves/record.md b/content/sdk/first-moves/record.md deleted file mode 100644 index 07ea8249..00000000 --- a/content/sdk/first-moves/record.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: "7. Record and replay trajectories" -description: "" -lead: "" -date: 2023-07-25T17:39:07+02:00 -lastmod: 2023-07-25T17:39:07+02:00 -draft: false -type: docs -images: [] -toc: true -weight: "130" ---- - -You can easily record joint trajectories directly on Reachy, store and replay them later. This page will show you how to implement such mechanisms. - -All examples given below will show trajectories record on each of the robot joints. The position of each motor will be stored at a predefined frequency (typically 100Hz). Similarly, the replay will set new target position using the same frequency. Those basics examples does not perform any kind of filtering or modification of the data. - -In the following examples, we will assume that you are already connected to your robot and know how to control individual motors. - -## Recording a trajectory - -To record a trajectory, we will simply get the current position of individual motors at a predefiend frequency. We will first define a list of motors that we want to record. In this example, we will only record the joints from the right arm, but you can similarly record a single motor, or all motors of the robot at once. - -```python -# assuming we run something like this before: -# reachy = ReachySDK(host='192.168.0.42') - -recorded_joints = [ - reachy.r_arm.r_shoulder_pitch, - reachy.r_arm.r_shoulder_roll, - reachy.r_arm.r_arm_yaw, - reachy.r_arm.r_elbow_pitch, - reachy.r_arm.r_forearm_yaw, - reachy.r_arm.r_wrist_pitch, - reachy.r_arm.r_wrist_roll, -] -``` - -Now let's define our frequency and record duration: - -```python -sampling_frequency = 100 # in Hz -record_duration = 5 # in sec. -``` - -Our record loop can then be defined as such: - -```python -import time - -trajectories = [] - -start = time.time() -while (time.time() - start) < record_duration: - # We here get the present position for all of recorded joints - current_point = [joint.present_position for joint in recorded_joints] - # Add this point to the already recorded trajectories - trajectories.append(current_point) - - time.sleep(1 / sampling_frequency) -``` -If you want to record a demonstration on the robot, first make sure the robot is compliant. Then, put it in the starting position. Run the code, and start moving the robot. After 5 seconds, the loop will stop and the movements you have made on Reachy will be recorded. - -Depending on your uses, you can define another duration. You can also choose not to use a specify duration but maybe use start and stop event to record. In such case, the easy way is probably to run the loop within a thread or an asynchronous fonction, so it can run in background. - -## Visualise your recordings - -The trajectories you recorded can be converted to numpy array for more complex processings: - -```python -import numpy as np - -traj_array = np.array(trajectories) -``` - -If you are familiar with matplotlib, you can also plot it via: - -```python -from matplotlib import pyplot as plt - -plt.figure() -plt.plot(trajectories) -``` - -## Replay a recorded trajectory - -Replaying the recorded trajectory basically uses the same loop but set the goal position instead of reading the present position. - -But before actually replaying the trajectory, there are a few key points that you should take care of: - -- First, make sure the joints you are going to move are stiff. -- Then, if the arm is not in the same position than the one you use as a start position of your recording, the beginning of the replay will be really brutal. It will try to go to the starting position as fast as possible. - -To avoid that, you can use the goto function to first go to the first point of your trajectories: - -```python -from reachy_sdk.trajectory import goto - -# Set all used joint stiff -for joint in recorded_joints: - joint.compliant = False - -# Create a dict associating a joint to its first recorded position -first_point = dict(zip(recorded_joints, trajectories[0])) - -# Goes to the start of the trajectory in 3s -goto(first_point, duration=3.0) -``` - -Now that we are in position, we can actually play the trajectory. To do that, we simply loop over our recordings and set the goal position of each joints at the same frequency: - -```python -import time - -for joints_positions in trajectories: - for joint, pos in zip(recorded_joints, joints_positions): - joint.goal_position = pos - - time.sleep(1 / sampling_frequency) -``` \ No newline at end of file diff --git a/content/sdk/getting-started/_index.md b/content/sdk/getting-started/_index.md deleted file mode 100644 index 98076fbf..00000000 --- a/content/sdk/getting-started/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title : "Getting Started" -description: "Getting Started with the SDK." -lead: "" -date: 2023-07-25T18:49:17+02:00 -lastmod: 2023-07-25T18:49:17+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/getting-started/connect.md b/content/sdk/getting-started/connect.md deleted file mode 100644 index e1b777b6..00000000 --- a/content/sdk/getting-started/connect.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: "Connect to Reachy 2" -description: "" -date: 2023-07-25T18:49:56+02:00 -lastmod: 2023-07-25T18:49:56+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "30" ---- - -The last required step before being able to use your Reachy 2 is to find its IP address. - -> Note: if you haven't connected Reachy to a network yet, please first follow the instructions ??? - -## Using the LCD screen - -If you haven't unplugged it, the LCD screen connected in Reachy's back should be diplaying its IP address. - -{{< img-center "images/sdk/getting-started/lcd-display.png" 400x "" >}} - -If the LCD screen is not working or is unplugged, check out the page [Find my IP section]({{< ref "help/system/find-my-ip" >}}) to learn other ways to get the IP address. - - -You can check that everything is working as expected by running the following Python code: - -```python -from reachy_sdk import ReachySDK - -# Replace with the actual IP you've found. -reachy = ReachySDK(host='the.reachy.ip.found.') -``` diff --git a/content/sdk/getting-started/hello-world.md b/content/sdk/getting-started/hello-world.md deleted file mode 100644 index b754521e..00000000 --- a/content/sdk/getting-started/hello-world.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "Hello World" -description: "First SDK connection with your Reachy" -date: 2023-07-25T18:50:04+02:00 -lastmod: 2023-07-25T18:50:04+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "40" ---- - -## Enable cameras for the SDK - -### SR camera -The SR camera is unplugged by default. -If you want to use it, plug the SR camera on the robot's computer remaining USB port (2). - -{{< img-center "images/sdk/getting-started/plugged-sr.png" 400x "" >}} - -> Make sure to unplug it if you want to use the teleoperation. - -### Teleop cameras -The teleop cameras are shared between the teleop service and the SDK server, and can only be used by one at the same time. -In order to be able to use the teleop cameras with the SDK: -1. Go to the dashboard -2. Stop [webrtc service in the services tab]({{< ref "/dashboard/content/services" >}}) - -{{< img-center "images/sdk/first-moves/stop-webrtc-service.png" 600x "" >}} - -## Connect to your robot - -Now you should be able to connect to your Reachy 2 and check that everything is ok. As we spoiled in the previous section, to connect to your robot, you simply need to run the following code: - -```python -from reachy2_sdk import ReachySDK - -# Replace with the actual IP you've found. -reachy = ReachySDK(host='the.reachy.ip.found.') -``` - -Before diving into the next chapters that will guide you in the depth of what you can do with the Reachy SDK, here is a quick preview. - -## Getting joints state - -To make sure everything is working fine, let's check the position of its joints. We won't go into details here as we will detail everything later. - -To get the state of a joint, you can access the *joints* attribute that contains all joints and iterate over its content: - -```python -for name, joint in reachy.joints.items(): - print(f'Joint "{name}" is at pos {joint.present_position} degree.') -``` - -Will show something like: -```python -Joint "r_arm.shoulder.pitch" is at pos -3.6 degree. -Joint "r_arm.shoulder.roll" is at pos 1.5 degree. -Joint "r_arm.elbow.yaw" is at pos -3.1 degree. -Joint "r_arm.elbow.pitch" is at pos 2.0 degree. -Joint "r_arm.wrist.roll" is at pos -54.4 degree. -Joint "r_arm.wrist.pitch" is at pos -0.9 degree. -Joint "r_arm.wrist.yaw" is at pos -20.7 degree. -Joint "l_arm.shoulder.pitch" is at pos 43.0 degree. -Joint "l_arm.shoulder.roll" is at pos 0.8 degree. -Joint "l_arm.elbow.yaw" is at pos 0.5 degree. -Joint "l_arm.elbow.pitch" is at pos 1.2 degree. -Joint "l_arm.wrist.roll" is at pos 0.1 degree. -Joint "l_arm.wrist.pitch" is at pos 0.1 degree. -Joint "l_arm.wrist.yaw" is at pos 1.1 degree. -Joint "head.neck.roll" is at pos 4.5 degree. -Joint "head.neck.pitch" is at pos -0.7 degree. -Joint "head.neck.yaw" is at pos -1.9 degree. -``` - -Note that we have accessed the attribute *present_position* to get the joint actual position. You can access the position of a specific joint by using its full name (meaning the part it is attached to plus its name). For instance, to get the position of the 'left shoulder pitch': - -```python ->>> print(reachy.l_arm.shoulder.pitch.present_position) --3.6 -``` - -You can also get a resume of the joint state by doing: -```python ->>> print(reachy.l_arm.shoulder.pitch) - -``` - -If you did not run anything else, your robot should be compliant (meaning you can freely move it). You can try to move it and re-run the code above. You should see that without doing anything specific, the positions are automatically updated. - -## Seeing through Reachy 2's cameras - -Assuming, you are still connected (otherwise, simply reconnect), we will now display what Reachy sees as an [OpenCV window](https://opencv.org). - -```python -import cv2 as cv - -while reachy.cameras.teleop.capture(): - l_frame = reachy.cameras.teleop.get_frame(CameraView.LEFT) - r_frame = reachy.cameras.teleop.get_frame(CameraView.RIGHT) - cv2.imshow("left", l_frame) - cv2.imshow("right", r_frame) - cv2.waitKey(1) -``` - -You should now see what Reachy sees! - -To stop the code, press Ctrl-C. - diff --git a/content/sdk/getting-started/install.md b/content/sdk/getting-started/install.md deleted file mode 100644 index def5ac61..00000000 --- a/content/sdk/getting-started/install.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "Installation" -description: "How to install the Python SDK, either from PyPi or directly from sources." -lead: "" -date: 2023-07-25T18:50:10+02:00 -lastmod: 2023-07-25T18:50:10+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "20" ---- - -## How to install the Python SDK - -The Python SDK is a pure Python library. The installation should thus be rather straightforward. - -It supports Python >= 3.10 (older versions will not work because of typing syntax). It works on Windows/Mac/Linux. - -We recommend to use [virtual environment](https://docs.python.org/3/tutorial/venv.html) for your development. They make the installation simple and avoid compatibility issues. They also come with their [pip](https://pip.pypa.io/en/stable/) command. - -### From PyPi - -```bash -pip install reachy2-sdk -``` - -### From the source - -```bash -git clone https://github.com/pollen-robotics/reachy2-sdk -cd reachy2-sdk -pip install -e reachy2-sdk -``` - -## Dependencies - -The SDK relies on a few third-party Python packages, such as: - -* [numpy](https://numpy.org) - mostly for trajectory computation -* [opencv](https://opencv.org) - for camera frame access -* [grpc](https://grpc.io) - to connect to the robot - -They will be **installed automatically** when you install the SDK. diff --git a/content/sdk/getting-started/overview.md b/content/sdk/getting-started/overview.md deleted file mode 100644 index c6b323c8..00000000 --- a/content/sdk/getting-started/overview.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "SDK Overview" -description: "Understand the structure of the SDK." -lead: "" -date: 2023-07-25T18:49:56+02:00 -lastmod: 2023-07-25T18:49:56+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "50" ---- - -## Understand the SDK structure - -### Reachy - -### Parts - - -### Actuators - -Reachy's arm offers 7 degrees of freedom. It also gives access to one joint for the gripper. -The **arm** is divided as follow: -- **shoulder**, composed of 2 joints (pitch and roll) -- **elbow**, composed of 2 joints (yaw and pitch) -- **wrist**, composed of 3 joints (roll, pitch and yaw) - -We refer to the shoulder, elbow and wrist as **actuators**. -For some actions, such as changing the compliance, is the the lowest level of control you will have. - -### Joints - -Each degree of freedom of Reachy is referred to as a **joint**. Joints are the lowest level of control you can have. -The Orbita2D (used as shoulders and elbows in Reachy 2) offer the control of 2 joints, while Orbita3D (used as wrists and neck) offer the control of 3 joints. -A joint is an angle you can control the position of in order to make movements with Reachy. For each joint, you can read a present position and write a goal position. Those position are given in degrees. - -```python -reachy.r_arm.elbow.pitch.present_position ->>> 0.0 - -reachy.r_arm.elbow.pitch.goal_position = -90 -``` - -### Cameras - -You have 2 different cameras type on Reachy: -- the **teleop** cameras, which are the cameras in Reachy's head. They are mobile cameras which can move the head and with stereovision, that are used for the teleoperation. -- the **SR** cameras, which are the short-range cameras on Reachy's torso. They are fix cameras, with an accessible depth map, mainly useful for manipulation tasks. - -You can access those cameras doing: - -```python -reachy.cameras.teleop ->>> - -reachy.cameras.SR ->>> -``` -{{< alert icon="👉" text="The teleop cameras are shared between the Teleoperation service and the SDK server, and can only be used by one of them at once. Make sure you enabled the access to the teleop cameras for the SDK server before trying to use them through the Python SDK." >}} diff --git a/content/sdk/getting-started/safety.md b/content/sdk/getting-started/safety.md deleted file mode 100644 index 11a53019..00000000 --- a/content/sdk/getting-started/safety.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -title: "Safety first" -description: "What you need to be aware of as a user to prevent Reachy 2 from getting damaged and you from getting hurt." -lead: "Before showing you how to control each part of the robot, let's talk a bit about safety, both for you and the robot." -date: 2023-07-25T18:50:18+02:00 -lastmod: 2023-07-25T18:50:18+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "60" ---- - -{{< warning icon="👉🏾" text="Reachy 2 is much more powerful than the previous version. To avoid any accident, please follow carefully the safety guidelines!" >}} - -> There is currently **no automatic collision security** on the robot: it won't stop if hitting anything or anyone, even itself. Remain constantly watchful when using it. - -## Users - -### Attention and reaction - -Users must be in **full possession of their physical and mental powers at all times** when using the robot. Reachy 2 must never be used by someone having consumed substances that could affect their reactions, such as medication, drugs or alcohol. - -Users must **keep attention focused** on the robot at any time, especially if they are near the robot workspace, and imperatively if they are in its workspace or if they are responsible for the [emergency stop button]({{< ref "/sdk/getting-started/safety#emergency-stop-button" >}}). - -### Qualified users - -The robot must not be used if no qualified user is present. - -People using the robot or interacting with it must all be aware of the risks and be explicitly informed of the robot capabilities, limitations and restrictions. They must all be able to act with the appropriate behavior using the robot. - -{{< alert icon="👉" text="No one should use the robot without knowing the safety guidelines." >}} - -## Emergency stop button - -The robot is delivered with an emergency stop button. - -Pressing the emergency stop button will **immediately power off all motors**, from the arms to the mobile base wheels. Nevertheless it won't power off the computer, which means you won't lose anything running on the computer. - -> If you feel like you are losing control of the robot's movements or notice an unexpected behavior at anytime, **never hesitate to press the emergency stop button**. - -Someone must be holding the emergency stop button at any time when using the robot, being ready to press the button if needed, and keep its attention focused on the robot. - -{{< alert icon="👉" text="Objects may fall out of the grippers when pressing the emergency stop button. Make sure they cannot cause injuries." >}} - -## Don't harm yourself... - -Reachy 2 is a powerful robot that may hurt you if it is misused. - -If you do not respect the safety guidelines, you expose yourself to the following risks: -- pinching -- crushing -- punches -- electrical hazard - -### Alertness - -People interacting with the robot or present near its workspace must always look at the robot. - -If the robot is being teleoperated with its mobile base, people in the surroundings must be informed of the robot presence, and the operator must never make the robot pop by surprise near a person or come close to a person, making the person reachable by the arms. - -### Appropriate position - -Do not expose yourself to dangerous punches! - -People must never place their head, or any other body parts, in between or underneath segments of the robot when the robot is in use. Their head should never be reachable by the robots' arms if the robot is in use. - -If people are near the workspace of the robot, they must always stay in a position that allow them to quickly retract or recoil. - -> When the robot is in use, no one should enter or stay in the robot workspace. - -### Free space for retracting - -If people are standing near the robot workspace, make sure they have **sufficient space to retract or recoil**, and that this space is free of obstacles. - -People must never be blocked between the robot and a wall or furniture. - -### Objects manipulation with Reachy 2 - -Be careful with the objects you manipulate with the robot. Sharp and pointed object manipulation is dangerous, do not get close to the robot if it manipulates such objects. - -For all manipulation tasks, users are responsible for assessing the hazards and risks relative to the objects they manipulated with the robot. - -### Manipulate the robot - -When the robot is in use, never manipulate robot parts at the same time. - -Users must be careful if putting their fingers in the actuators or between robot parts to avoid pinching or crushing. -:warning: They must never put their fingers in the actuators or between robot parts if the robot is in use. - -### Hardware intervention - -Never make any hardware intervention on the robot, such as screwing on unscrewing something, if it is powered on. - -### Robot toppling risk - -The following section ["...and don't harm Reachy 2!"]({{< ref "/sdk/getting-started/safety#and-dont-harm-reachy-2" >}}) mainly describes risks of robot toppling or collision. This may damage the robot, but also harm anyone near to the robot. -**All events of the following section can lead to users injuries**, so read them as users safety guidelines as well. - -## ...and don't harm Reachy 2! - -There are a few things you need to know to make sure that your Reachy doesn't get damaged when using it. - -### Carrying heavy objects - -Be careful of the position of the arms when lifting heavy objects with the robot. -Avoid carrying the object to far from the robot torso, mainly to avoid risk of front toppling. - -Do not try to lift objects over 3kg (6.6lb). - -### Pulling/pushing - -Do not try to pull or push elements that are too heavy or oppositing too much! - -This may result in a robot toppling. - -### Obstacles - -Be aware of obstacles! - -When you are sending movements instructions to Reachy, be careful to obstacles the robot can meet. The robot will try to reach the positions you asked for as hard as it can, whether or not there is something on its way. - -Because of the force of the robot, and depending on the weigh or fragility of the object, two things may occur: -- make the object fall and/or break it -- make Reachy 2 tumble - -### Self-collision - -When you are moving both arms simultaneously, there are no safety measures implemented to prevent them from hitting each other. -Nothing will neither prevent Reachy's arms from hitting its chest if you ask them to. - -If situations like these happen, do not hesitate to turn off the motors so that Reachy's motors will stop trying to reach a position they can't get to. - -### Mobile base - -#### Surface - -The mobile robot is made to be used on **flat surfaces**. -Never use the robot on slopes, this may result in a robot toppling. - -#### Speed and movements - -Speed and commands are limited when using the Python SDK, nevertheless you can still generate behaviors that may be dangerous. Do not ask for high speeds and strong stops, or suddent changes of directions. -Provoking oscillations of the robot may lead to a robot toppling. - -### Anti-collision LIDAR safety - -:warning: The anti-collision LIDAR safety has been deactivated. diff --git a/content/sdk/introduction/_index.md b/content/sdk/introduction/_index.md deleted file mode 100644 index 98076fbf..00000000 --- a/content/sdk/introduction/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title : "Getting Started" -description: "Getting Started with the SDK." -lead: "" -date: 2023-07-25T18:49:17+02:00 -lastmod: 2023-07-25T18:49:17+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/introduction/introduction.md b/content/sdk/introduction/introduction.md deleted file mode 100644 index 5c64b639..00000000 --- a/content/sdk/introduction/introduction.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: "Introduction" -description: "Quick overview of the Python SDK and of the other options available to control the robot." -date: 2023-07-25T18:50:18+02:00 -lastmod: 2023-07-25T18:50:18+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "10" ---- - -## The SDK in a nutshell - -The [Python SDK](https://github.com/pollen-robotics/reachy2-sdk) lets you easily control and program a Reachy robot. It is used to read information (eg. camera image or joint position) and send commands to make the robot move. - -It is designed to: - -* let you start controlling your robot in a few lines of codes, -* allow to focus on your application and not on hardware synchronisation issues, -* facilitate fast prototyping and iteration. - -Connecting to your robot and getting the up-to-date position of all joints is as simple as: -```python -from reachy2_sdk import ReachySDK - -reachy = ReachySDK(host='192.168.0.42') # Replace with the actual IP - -for name, joint in reachy.joints.items(): - print(f'Joint "{name}" position is {joint.present_position} degree.') -``` - -You can use it directly on Reachy's computer or work remotely on another computer, as long as you are connected on the same network. The SDK works on Windows/Mac/Linux and requires Python >= 3.10. It is entirely open-source and released under an [Apache 2.0 License](https://github.com/pollen-robotics/reachy-sdk/blob/main/LICENSE). - -## Is this the right option for me? - -The Python SDK is only one way to control Reachy. There are other options that have different pros and cons. - -To know if the SDK is the right option, the TL;DR here would be something like: - -* You want to **focus on creating an application or behavior on Reachy**. -* You **don't want to dig into the details** on how it can be controlled or run very time constrained code (eg. need more than 100Hz control). -* You have **basic knowledge of Python** (no advanced knowledge is required). -* You do not already have an important code base running on ROS2. - -## The other options - -### Unity VR App - -If you are interested in teleoperation and want to control Reachy via VR controllers, you can directly use our Unity VR App. More information on the [dedicated section]({{< ref "VR/introduction/introduction" >}}). - -### ROS2 Humble packages - -Reachy runs on [ROS2 Humble](https://docs.ros.org/en/humble/index.html). ROS is a Robotic Operating System, it offers a huge variety of compatible algorithms and hardware drivers. Yet, if you are not familiar with ROS, the beginning can be a bit overwhelming. - -The embedded NUC computer comes with ROS2 and Reachy specific packages already installed and running. They provide full access to Reachy (lower-level than the SDK). You can: -- get the *joint states* and *forward position controllers* -- use *Rviz* -- subscribe to various sensor topic (camera, force sensor, etc) -- access client for IK/FK - -For more information, please refer to the [dedicated section]({{< ref "advanced/software/ros2-level" >}}). - -### Custom gRPC client - -If you want to use another language than Python, for instance to integrate Reachy's control within an existing code base, you can write your own [gRPC](https://grpc.io) client. Our API is available [here](https://github.com/pollen-robotics/reachy-sdk-api). - -The API is used both by the Python SDK and the VR App. diff --git a/content/sdk/mobile-base/_index.md b/content/sdk/mobile-base/_index.md deleted file mode 100644 index 40e53140..00000000 --- a/content/sdk/mobile-base/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Mobile Base" -description: "Learn how to use Reachy's mobile base." -date: 2023-07-25T18:49:24+02:00 -lastmod: 2023-07-25T18:49:24+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/sdk/mobile-base/safety.md b/content/sdk/mobile-base/safety.md deleted file mode 100644 index faa56964..00000000 --- a/content/sdk/mobile-base/safety.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: "Anti-collision safety" -description: "LIDAR based anti-collision behaviour for the mobile base." -date: 2023-07-26T08:37:55+02:00 -lastmod: 2023-07-26T08:37:55+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "170" ---- -## Overview -The basic idea is that the LIDAR is used to detect surrounding obstacles and reduce or nullify speed commands that would create a collision with the mobile base. - -

- {{< video "videos/sdk/lidar_safety_human.mp4" "80%" >}} -

- -The safety is active regardless of how you command the mobile base (teleop, controller, goto and set_speed). - -:warning: The safety only works with obstacles that can be seen by the LIDAR. Small obstacles that are below the LIDAR won't be seen. Similarly, the LIDAR will see the legs of a table, but not the table top. - - -## Detailed behaviour -

- {{< video "videos/sdk/lidar_safety_360.mp4" "80%" >}} -

- -- If an obstacle is present inside of the critical distance boundary, then the speed of the mobile base is reduced in all directions, and nullified in the direction that would cause a collision. Rotations are slowed down but are still allowed. -- Otherwise, if an obstacle is present inside of the safety distance boundary, then the speed of the mobile base is reduced only in the directions that would eventually cause a collision. Rotations are unchanged. -- Obstacles that are further away than the safety distance do not trigger the safety in any way - - -:bulb: Reachy's design allows the LIDAR to see close to 360° around it, but not entirely because of the metal bar: this creates a small blind spot. Even if a collision would be very unlikely (you'd have to e.g. drive backwards onto a perfectly aligned pole), any speed command that could create an unseen collision are slowed down. - -:warning: Do not obstruct the LIDAR by placing an objet on top of the mobile base as it will be considered as an obstacle. - -:warning: If the LIDAR disconnects during usage or if its controller crashes, then the mobile base will stop and will reject commands. - -## Advanced tuning - -The mobile base's Hardware Abstraction Layer runs with the anti-collision behaviour active by default. Currently, disabling/enabling the safety is the only configuration you can make using the SDK. If you need to fine tune the behaviour, you'll have to interact with the world of ROS and change the [HAL parameters](https://github.com/pollen-robotics/zuuu_hal/blob/main/config/params.yaml) (you'll have to recompile the package for the changes to take effect). - -The code can be accessed [here.](https://github.com/pollen-robotics/zuuu_hal/blob/main/zuuu_hal/lidar_safety.py) - diff --git a/content/teleoperation/compatibility-specs/compatible-devices.md b/content/teleoperation/compatibility-specs/compatible-devices.md index 53286f0e..58c7daae 100644 --- a/content/teleoperation/compatibility-specs/compatible-devices.md +++ b/content/teleoperation/compatibility-specs/compatible-devices.md @@ -14,4 +14,34 @@ weight: 100 toc: true --- -This is how you assemble your robot \ No newline at end of file +# Compatible VR headsets + +So far, the VR teleoperation application has been tested with the following devices: +* **Meta Quest 2** (with Oculus Link) +* **Meta Quest 3** (with Oculus Link) + +> No native application for Meta Quest headsets has been released at the moment. + + +The application should also support any device compatible with Unity 2022.3 including but not limited to the following devices: +* **Valve Index** +* **HTC Vive** +* **Oculus Rift** + + +Please refer to [Unity documentation](https://docs.unity3d.com/2020.3/Documentation/Manual/VROverview.html) for more information about the compatibility. + +# PC requirements + + +The application is built on Unity 2022.3 LTS for which the requirements can be found [here](https://docs.unity3d.com/2020.3/Documentation/Manual/system-requirements.html). + + +In order to use the desktop version of the teleoperation application, your PC needs to support Virtual Reality. We recommend the computer to run on Windows, to be powerful enough and equipped with a graphic card. + +The computer minimum requirements are the following: +* **Operating System:** Windows 10 (or Windows 7 SP1) +* **Processor:** Intel Core i5-4590/AMD FX 8350 equivalent or better +* **Memory:** 8GB RAM +* **Graphic card:** NVIDIA GeForce GTX 970, AMD Radeon R9 290 equivalent or better +* **Network:** Broadband Internet connection. It is highly recommended for your PC to be **hard-wired** into your router using an **ethernet cable**. diff --git a/content/teleoperation/getting-started-teleoperation/best-practice.md b/content/teleoperation/getting-started-teleoperation/best-practice.md index 74b3cacb..7a412e4b 100644 --- a/content/teleoperation/getting-started-teleoperation/best-practice.md +++ b/content/teleoperation/getting-started-teleoperation/best-practice.md @@ -14,4 +14,134 @@ weight: 220 toc: true --- -This is how you assemble your robot \ No newline at end of file + +{{< warning icon="👉🏾" text="This page contains really important information about the use of the teleoperation app. Please make sure you read it carefully before teleoperating Reachy." >}} + +Using teleoperation application has nothing complicated, but you need to respect a few guidelines to avoid damaging the robot when using it. This page goes through the main elements you need to keep in mind while teleoperating Reachy. The guidelines are not exhaustive, but should give you a good start on how to safely use the application. + +## Ideal use of teleoperation + +The ideal position to start teleoperation may depend on the surrounding of Reachy. Nevertheless, if the robot environment is compatible with it, we advise to start with the elbows at 90 degrees, lightly away from the torso. + +{{< img "images/vr/use-teleop/idealPosFaceReduced.jpg" 300x "ideal position face">}} +{{< img "images/vr/use-teleop/idealPosProfReduced.jpg" 300x "ideal position side">}} + +
+
+Here is a video of movements and positions that are suitable for teleoperation: +
+
+ +{{< video "videos/vr/use-teleop/ChestOk.mp4" "80%" >}} + +
+Follow all the elements described in the next sections to teleoperate Reachy in the best conditions! + +## All guidelines in video +Watch this quick video to have an overview of the main guidelines to use teleoperation: + +{{< youtube bK7th6zY8Rg >}} + +
+The next sections go deeper into each guideline presented in the video and the risks of not following them. + +## Keep the right position +The mapping between your position and the robot is made when holding (A) to start teleoperation. The position and rotation of your headset at this moment are used to calibrate the system. If you move (i.e. change either your body position or orientation), the controllers positions will still be calculated in this coordinate system, and Reachy movements won't look like like yours anymore. For these reasons, you must: + +- Not move your feet when teleoperating Reachy: they must stay static on the floor. + +{{< video "videos/vr/use-teleop/FeetOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/FeetNotOk.mp4" "40%" >}} + + +- Not rotate your torso. +In fact, Reachy's torso won't move, only the arms will try to reach the positions, and this may lead to collision between the Reachy's arms and torso. + +{{< video "videos/vr/use-teleop/ChestOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/ChestNotOk.mp4" "40%" >}} + +## Avoid movements discontinuities +Reachy doesn't have the exact same degrees of freedom as you have, neither the same range for each joints. When a position cannot be reached, either because of the position or the orientation, the inverse kinematics gives the closest arm configuration found. The closest configuration found for the next position may be: + +- the same as the previous one, so the arm won't move and you have the impression Reachy is not following your movements anymore +- quite different from the previous one, which will lead to sudden changes of the arm position + +All this contribute to give movements that seem incontrollable, due to discontinuities in the arm's inverse kinematics. + +**To avoid this situation:** + +- Avoid using extreme joints orientations while teleoperating Reachy +- Avoid unusual arm positions, there are probably above Reachy's joints limits + +{{< video "videos/vr/use-teleop/MovementsOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/MovementsNotOk.mp4" "40%" >}} + +- The most limiting joint is the elbow: avoid working to close to your chest, the elbow will be at the limit of its range of motion + +{{< video "videos/vr/use-teleop/TorsoArmOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/TorsoArmNotOk.mp4" "40%" >}} + +- If the robot seems to stop following your movements, do not continue to move in this direction, you have already reached its workspace limit. Go back to a position you know can be reached. + + +## Avoid damaging motors +Reachy's arms have been designed to manipulate objects at a table level and nearby. +Some positions away from this nominal area can require a lot of effort from the motors to be maintained, and cause them to overheat fast. Moreover, manipulating objects requires more effort from the motors. + +**To avoid damaging motors:** + +- Avoid doing movements above your head +- Avoid keeping your arms straight ahead horizontally to the floor, where the shoulders motors have to carry all the weight of the arms in a static position + +{{< video "videos/vr/use-teleop/AboveHeadOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/AboveHeadNotOk.mp4" "40%" >}} + +- Do not let the motors in stiff mode when you are in the menu if you are not going to teleoperate the robot soon +- Do not try to lift objects that are above Reachy's capabilities. If you try to lift an object and see that Reachy's arm can follow your movement or if you head some crackling noise coming from the motors, it probably means that the object is too heavy for Reachy's arm. + +{{< video "videos/vr/use-teleop/WeightOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/WeightNotOk.mp4" "40%" >}} + +## Avoid damaging 3D parts +Hitting Reachy's arms on objects can break 3D parts of the robot. It may happen even if the arms crash into something at moderate speed. + +**To avoid damaging 3D parts:** +- Check the environment surrounding the robot before starting the teleoperation. Make sure you have enough space around the robot and that there is no object to be hit by the robot (this may also save your object from being broken...) + +{{< video "videos/vr/use-teleop/CheckSpaceRobotOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/CheckSpaceRobotNotOk.mp4" "40%" >}} + +- Stop teleoperation close to the position which will be reached when the motors will be compliant, so that the arms won't fall from high. + +{{< video "videos/vr/use-teleop/StopArmOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/StopArmNotOk.mp4" "40%" >}} + +## Use teleop safely +- Check the environment around you before starting teleoperation. + +{{< video "videos/vr/use-teleop/CheckSpaceOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/CheckSpaceNotOk.mp4" "40%" >}} + +- Stop teleoperation before removing your headset! You must be back in the menu before dropping the controllers and removing your headset, because Reachy will continue following your movements until you stop it. + +{{< video "videos/vr/use-teleop/RemoveHeadsetOk.mp4" "40%" >}} + +{{< video "videos/vr/use-teleop/RemoveHeadsetNotOk.mp4" "40%" >}} + + +## Familiarize yourself with the robot +- Before teleoperating the actual robot, familiarize yourself with its movements, its workspace and its joints limits. The virtual robot in the mirror scene is a good opportunity for that. +- Stay near the robot for your first trials: listen to the motors sounds, be aware of your workspace and field of view in a environment you know, try to manipulate light objects. +- Explore your own workspace with small and quite slow movements to see how the robot reacts and better understand the relation between your movements and its. + + +{{< alert icon="💡" text="You may feel like being in a video game at some point, but never forget that your movements are reproduced in real life!" >}} \ No newline at end of file diff --git a/content/teleoperation/getting-started-teleoperation/connect-reachy2.md b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md index 761c88cf..780a5590 100644 --- a/content/teleoperation/getting-started-teleoperation/connect-reachy2.md +++ b/content/teleoperation/getting-started-teleoperation/connect-reachy2.md @@ -14,4 +14,40 @@ weight: 210 toc: true --- -This is how you assemble your robot \ No newline at end of file +## Launch the app + +Once everything is installed, you can launch the application. +First connect your headset to your computer and make sure it is ready for use. + +> Meta Quest headsets must be used with the link. + +Then run the *Reachy2Teleoperation.exe* file from the previously unzipped folder to start the application. + +## Find Reachy IP address + +The LCD screen connected in Reachy's back should be diplaying its IP address. + +{{< img-center "images/vr/getting-started/lcd-display.png" 400x "" >}} + +If the LCD screen is not working or is unplugged, check out the page Find my IP section to learn other ways to get the IP address. + +## Connect to the robot + +Create a new robot entry in the menu with the IP address you previously found. + +> Note that you must select the input fields with your VR beam and fill them in using your computer keyboard. + +Once the robot is created, select it and click on "**Connect**". +You should then arrive in the *transition room* of the application. + +A message to allow the network access to the app may pop up, in this case **allow access**: + +{{< img-center "images/vr/getting-started/allow-access.png" 400x "" >}} + +Make sure the connection is fine by checking the information displayed at the top of the mirror. +You must see: +- a green text telling you "Connected to Reachy" +- the view of the robot displayed in miniature +- a good network connection indication + +{{< img-center "images/vr/getting-started/mirror-scene.png" 600x "" >}} diff --git a/content/teleoperation/getting-started-teleoperation/installation.md b/content/teleoperation/getting-started-teleoperation/installation.md index 6c6cc955..9bf2360e 100644 --- a/content/teleoperation/getting-started-teleoperation/installation.md +++ b/content/teleoperation/getting-started-teleoperation/installation.md @@ -14,4 +14,60 @@ weight: 200 toc: true --- -This is how you assemble your robot \ No newline at end of file + +> Reachy 2 is already fully compatible with the teleoperation application. You have nothing to install on the robot. + +## On the Windows computer + +### 1. Check VR device installation + +Make sure that your VR device is properly installed and running (please refer to your device documentation). + +### 2. Download application + +Download the zip archive we sent you, and unzip it. + +{{< alert icon="👉" text="No standalone application is available yet for Reachy 2 teleoperation." >}} + +### 3. Install GStreamer + +The project relies on GStreamer. + +- Please install the **[Windows Runtime](https://gstreamer.freedesktop.org/data/pkg/windows/1.24.0/msvc/gstreamer-1.0-msvc-x86_64-1.24.0.msi)**. + +- Choose the **complete installation**: +{{< img-center "images/vr/getting-started/complete-installation.png" 400x "" >}} + +- Add `C:\gstreamer\1.0\msvc_x86_64\bin` to your PATH environment variable. +To do so: + - Access the **Edit the system environment variables** control panel: + {{< img-center "images/vr/getting-started/control-panel.png" 400x "" >}} + + - Open **Environment Variables...**: + {{< img-center "images/vr/getting-started/environment-variables.png" 400x "" >}} + + - Select the **Path** variable and click **Edit...**: + {{< img-center "images/vr/getting-started/user-variables.png" 400x "" >}} + + - Click **New** and **add `C:\gstreamer\1.0\msvc_x86_64\bin`** to the list: + {{< img-center "images/vr/getting-started/new-variable.png" 400x "" >}} + + - Also check you have GSTREAMER_1_0_ROOT_MSVC_X86_64 in your System variables, value being `C:\gstreamer\1.0/msvc_x86_64\`: + {{< img-center "images/vr/getting-started/system-variables.png" 400x "" >}} + +- **Reboot** your computer after the installation. + +### 4. Configure the firewall + +{{< img-center "images/vr/getting-started/firewall.png" 400x "" >}} + +{{< img-center "images/vr/getting-started/allow-app.png" 400x "" >}} + +### 5. Choose your headset refresh rate (optional) + +If you have a Meta Quest headet, we advise you to set the refresh rate at 120 Hz. + +To do so, use the desktop Meta app (the one appearing on your computer when your headset is connected on your computer and the link activated). +In the devices tab, select your headset, and modify the graphics preferences in the advanced section. + +{{< img-center "images/vr/getting-started/refresh-rate.png" 400x "" >}} diff --git a/content/teleoperation/using-application/controllers-inputs.md b/content/teleoperation/using-application/controllers-inputs.md index bb5a3870..b0dc6776 100644 --- a/content/teleoperation/using-application/controllers-inputs.md +++ b/content/teleoperation/using-application/controllers-inputs.md @@ -14,4 +14,37 @@ weight: 330 toc: true --- -This is how you assemble your robot \ No newline at end of file +> A reminder of the controller inputs mapping is available in the **help** section of the *transition room* in the VR teleoperation application: +{{< img "images/vr/use-teleop/help-panel.png" 600x "Help panel in VR transition room">}} + + +## Meta Quest + +### Standard inputs + +{{< img "images/vr/use-teleop/meta-quest-mapping.png" 600x "Meta Quest controller mapping">}} + +|Input|Feature description | +|----|--------------------| +|**A**|**At robot teleoperation start:** Start robot teleoperation| +| |**During teleoperation:** Return to menu| +|**B**|**During teleoperation:** Mobile base boost| +|**X**|**When leaving teleoperation (A pressed):** Lock robot position| +|**Left Thumbstick**|**During teleoperation:** Control mobile base translation| +|**Right Thumbstick**|**During teleoperation:** Control mobile base rotation| +|**Left Index Trigger**|**In menu:** Select button| +| |**During teleoperation:** Control left gripper| +|**Right Index Trigger**|**In menu:** Select button| +| |**During teleoperation:** Control right gripper| +|**Left Controller position / orientation**|**During teleoperation:** Reachy's left arm end effector position / orientation| +|**Right Controller position / orientation**|**During teleoperation:** Reachy's right arm end effector position / orientation| +|**Headset orientation**|**During teleoperation:** Reachy's head orientation| + +### Emergency stop combination + +{{< img "images/vr/use-teleop/meta-quest-emergency-stop.png" 600x "Meta Quest controller emergency stop">}} + +|Input|Feature description | +|----|--------------------| +|**A + right index trigger + right middle finger trigger**|**During teleoperation:** Emergency stop| +|**X + left index trigger + left middle finger trigger**|**During teleoperation:** Emergency stop| diff --git a/content/teleoperation/using-application/customize-teleop-session.md b/content/teleoperation/using-application/customize-teleop-session.md index 661a6ecb..b5b5def3 100644 --- a/content/teleoperation/using-application/customize-teleop-session.md +++ b/content/teleoperation/using-application/customize-teleop-session.md @@ -14,4 +14,51 @@ weight: 340 toc: true --- -This is how you assemble your robot \ No newline at end of file + +## Audio and microphone setup + +To have a better experience within the VR, configure the audio of your headset from your **headset settings**. + +You should be able to speak through the robot and hear from it when you are in the *transition room*. +Check both audio input and output are on, and set them to a correct value. + +> On the Meta Quest 2 headset, we use the following parameters: +> - **audio input**: 100% +> - **audio ouput**: 65% + + +## Motion sickness options + +Once in the *transition room*, you have options you can configure to help you avoid motion sickness. + +On the left of the mirror, open the **Settings** tab, and configure the motion sickness options before starting teleoperating the robot. + +{{< img-center "images/vr/getting-started/vr-settings.png" 600x "" >}} + + +### Reticle +Display a reticle to give a fixed point in the field of view. By default, the reticle only appears when the mobile base is moving. + +*Option:* +- **Always display reticle**: always display the reticle, even if the mobile base is not moving. + +{{< img-center "images/vr/getting-started/reticle.png" 300x "" >}} + + +### Navigation effects + +- **No effect** +- **Tunneling**: when moving the mobile base, a black tunneling will appear in your peripheral vision and reduce your field of view +- **Reduced screen**: when moving the mobile base, the size of the image will be reduced to let you see an artificial horizon behind it. + +*Option:* +- **Activate effect on demande only**: during teleoperation, press one of the joysticks to activate/deactivate the occurence of the selected effect. + + If used with *tunneling*, deactivate the effect will disable the tunneling when moving the mobile base, activate it will let it appear automatically. + + If used with *reduced screen*, activate or deactivate the effect will let you manually reduce the size of the image. + +|Tunneling effect|Reduced screen effect | +|----|--------------------| +|{{< img-center "images/vr/getting-started/tunneling.png" 300x "" >}}|{{< img-center "images/vr/getting-started/reduced-screen.png" 300x "" >}} +| \ No newline at end of file diff --git a/content/teleoperation/using-application/emergency-stop.md b/content/teleoperation/using-application/emergency-stop.md index 7bef7397..4dddebcf 100644 --- a/content/teleoperation/using-application/emergency-stop.md +++ b/content/teleoperation/using-application/emergency-stop.md @@ -14,4 +14,20 @@ weight: 310 toc: true --- -This is how you assemble your robot \ No newline at end of file + +In case you feel like something unexpected is happening with the robot while you are teleoperating it in VR, you can stop immediately teleoperation rather than using the standard exit menu, which requires to wait for a few seconds. + +> The VR application emergency stop does not replace the physical emergency stop button of the robot. + +While pressing either: +- (A) + right index trigger + right middle finger trigger +*or* +- (X) + left index trigger + left middle finger trigger +you will activate the VR emergency stop. +{{< img "images/vr/use-teleop/meta-quest-emergency-stop.png" 400x "Meta Quest controller emergency stop">}} + +The teleoperation application will immediately **stop sending commands** to the robot, **reduce the torque** values of the arms for a few seconds, then turn the robot **compliant**. + +{{< img "images/vr/use-teleop/emergency-stop.png" 600x "Help panel in VR transition room">}}
+ +You will remain in the teleoperation view until you press (A) as usually to go back to the transition room. \ No newline at end of file diff --git a/content/teleoperation/using-application/step-by-step.md b/content/teleoperation/using-application/step-by-step.md index c0a35dd9..0e833fb3 100644 --- a/content/teleoperation/using-application/step-by-step.md +++ b/content/teleoperation/using-application/step-by-step.md @@ -14,4 +14,147 @@ weight: 300 toc: true --- -This is how you assemble your robot \ No newline at end of file + +{{< warning icon="👉🏾" text="Before starting teleoperating Reachy, please make sure you read the Best Practice" >}} + +## In brief + +> The button names used below are for the Meta Quest headsets. Please refer to the Controllers input page to get the corresponding inputs for your device. + +### Start teleoperating Reachy + +1. Make sure the robot is turned on, connected to the network and that all the robot's services are running before launching the teleoperation application. + +2. Select the robot you want to teleoperate (or create a new one), and click on "Connect". + +3. Once in the mirror room, you can configure various settings. Take time to tune the motion sickness effects you want to use in the settings menu. When you are ready to start, press "Ready", then hold (A). + +4. **Look straight ahead, with your body in the same orientation as your head while pressing A** to start the teleoperation. *The initial head position is used to determine the coordinate system giving your VR controllers position.* + +{{< alert icon="👉" text="Warning: you must not move your body anymore after this step. The position of your VR controllers to master the robot arms are calculated depending on the position you had while pressing A." >}} + +{{< warning icon="🚨" text="Important: even if Reachy is bio-inspired, it cannot reproduce exactly all your movements. There are positions that cannot be reached by the robot. Please avoid unusual movements and do not persist in trying to reach a position if you see that the robot is stuck before it." >}} + +5. (NEW) You first have the control of the head and the mobile base, but **not of the arms**. Take a few seconds to check the robot surroundings and go to an appropriate place before starting the full teleoperation. When the environment is safe, **press A** to get the full control. You can also go back to the mirror room pressing the related button with your laser beam. + +6. Come back any time to mirror room by **holding A**. Teleoperation of the robot is automatically paused if the headset is removed. + +{{< alert icon="👉" text="Please stop teleoperation before removing your headset (go back to mirror room or quit the app). If you do not, Reachy will continue following your controllers and headset orientation during a few seconds, and this can cause damages to the robot." >}} + +### Stop teleoperation + +1. Come back to the **mirror room** to pause the teleoperation by **holding A** at any time during teleoperation. + +2. Leave the app by clicking "**Quit**" icons in the mirror room and connection menu. + +The motors are automatically turned into compliant mode when quitting the mirror room. Please make sure the arms are close enough to the lowest position they can reach when coming back to the menu to avoid them falling or hitting something. + + +## Step-by-step starting +1. Make sure that your VR equipement is up and running. Please refer to your device documentation. + +2. Make sure the robot is turned on, connected to the network and that all the robot services are running. *By default, if you haven't modified anything, all services should be automatically launched on start of the **full/starter kit** robots.* + +3. Launch the application *TeleoperateReachy.exe* file if you are using a VR device connected to a Windows computer. For Oculus Quest users, start the app from within the headset if you have installed the *.apk*. + +4. Equip yourself with your headset, make sure you can see both controllers and that the scene around you is moving correctly in accordance with your head movements. + +5. Choose the robot you want to connect to: you can select a robot with its IP address, or add a new one to the list of available robots. + +{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} +{{< img "images/vr/use-teleop/select-robot.png" 600x "Select robot to connect">}} + +6. Press *Connect* to initiate the communication with the robot. + +{{< img "images/vr/use-teleop/connect.png" 600x "Connect to a robot">}}
+ +7. You should be now in the *transition room*, and see yourself controlling a virtual reachy. The actual robot is not in control at that time but the live camera stream is displayed at the top right of the mirror. The info, help and settings menus are available here (they are documented in the next section). Please get familiar with the robot controls and features (emotion, grasping lock). + +{{< img "images/vr/use-teleop/mirror.png" 600x "Mirror scene">}}
+ +8. When you are ready, **face the mirror completely** and click on "Ready". The position of the actual robot appears in a semi-transparent green color. This may be useful when you've left the robot in a certain position that you would like to keep when entering the teleoperation. Hold (A) to start the teleoperation. + +{{< img "images/vr/use-teleop/mirror-ready.png" 600x "Start teleoperation">}}
+ +9. (NEW) You first have the control of the head and the mobile base, but **not of the arms**. Take a few seconds to check the robot surroundings and go to an appropriate place before starting the full teleoperation. When the environment is safe, **press A** to get the full control. You can also go back to the mirror room pressing the related button with your laser beam. + +10. A 3 seconds timer appears while you enter the teleoperation. The motors speeds are reduced during this time to avoid sudden movements of the robot. Full speed is reached at the end of this countdown. + +{{< img "images/vr/use-teleop/timer-start.png" 600x "Validate position before starting">}} + +{{< alert icon="👉" text="Warning: you don't want to move your torso and body anymore after this step. Only your head and arms. The position of your VR controllers to master the robot arms are calculated depending on the position you had while pressing A." >}} + +11. Come back any time to menu by **pressing A**. Teleoperation of the robot is automatically paused if the headset is removed. + + +## Use Reachy's emotions +*Use of the antennas emotion is not available on Reachy 2.* + +## Application features + +### Connection page + +{{% expand "> Add a new robot" %}} +Click on the robot to select to open the panel of all saved robots: +{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} +Then click on "Add new robot +" at the bottom right of the page: +{{< img "images/vr/use-teleop/add-robot-button.png" 600x "Add robot button">}} +Enter a robot name and the IP address of the robot (if the headset is connected on a computer, use the computer keyboard), and save your robot card: +*The IP address is mandatory. If no name is given to the new robot, it will be called @Reachy by default* +{{< img "images/vr/use-teleop/add-robot-card.png" 600x "Add robot panel">}} +{{% /expand %}} + +{{% expand "> Modify an existing robot"%}} +Click on the robot to select to open the panel of all saved robots: +{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} +Then click on the pencil icon of the robot you want to modify: +{{< img "images/vr/use-teleop/modify-robot-button.png" 600x "Modify robot button">}} +Modify the info on the robot card and save the card: +{{< img "images/vr/use-teleop/modify-robot-panel.png" 600x "Modify robot panel">}} +{{% /expand %}} + +{{% expand "> Delete a saved robot"%}} +Click on the robot to select to open the panel of all saved robots: +{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} +Then click on the bin icon of the robot you want to delete: +{{< img "images/vr/use-teleop/delete-robot-button.png" 600x "Delete robot button">}} +Validate the deletion: +{{< img "images/vr/use-teleop/delete-robot-panel.png" 600x "Delete robot panel">}} +{{% /expand %}} + + +### Mirror scene + +{{% expand "> Check robot status"%}} +Open the info menu in the mirror room: +{{< img "images/vr/use-teleop/mirror-info.png" 600x "Info menu">}} +The connection and services status, and motor temperature are reported here. +{{% /expand %}} + +{{% expand "> Controller mapping"%}} +Open the help menu in the mirror room: +{{< img "images/vr/use-teleop/mirror-help.png" 600x "Info menu">}} +The mapping of the controller buttons to the robot actions are displayed here. +{{% /expand %}} + +{{% expand "> Settings menu"%}} +Open the settings menu in the mirror room: +{{< img "images/vr/use-teleop/mirror-settings.png" 600x "Settings menu">}} +Here you can set your size to improve the mapping between your movements and reachy's motion. Individual parts of the robot can be deactivated in the case you don't need the mobile base, a specific arm, etc. +Motion sickness options are available in this panel: choose to display a reticle or not, and select a navigation effect that fit to your robot use. +You can also modify the grasping mode there: with full control you decide at each time the opening of the gripper, while the grasping lock option enables you to close the gripper with on trigger press and open it with another one. Grasping lock option can be turned on/off as well in the emotion menu. +{{% /expand %}} + +{{% expand "> Reset position"%}} +While facing the mirror, your body should be aligned with Reachy's body. This is mandatory to have a consistent control. If this is not the case after having pressed "Ready", face the mirror and click on "Reset position". +{{< img "images/vr/use-teleop/reset_position.png" 600x "Reset position">}} +The "Reset position" button is placed at the bottom of the mirror, under the A loader. +{{% /expand %}} + +### Teleoperation exit + +{{% expand "> Exit and lock position"%}} +While press (A) to exit the teleoperation, you may hold (X) to activate the position lock. A lock is displayed when doing so. +{{< img "images/vr/use-teleop/exit-lock.png" 600x "Exit and lock">}} +The robot will stayed locked while you'll be back in the mirror room. This can be useful to keep a certain position while you need to take a break, change position or remove the headset. The position of the robot will be displayed by the semi-transparent green robot when you will restart the teleoperation. +{{% /expand %}} diff --git a/content/teleoperation/using-application/teleoperation-messages.md b/content/teleoperation/using-application/teleoperation-messages.md index 0414f8f4..64d628f0 100644 --- a/content/teleoperation/using-application/teleoperation-messages.md +++ b/content/teleoperation/using-application/teleoperation-messages.md @@ -14,4 +14,16 @@ weight: 350 toc: true --- -This is how you assemble your robot \ No newline at end of file + +During Reachy teleoperation, several messages can show up in front of view. + +**Warning messages** + +Some messages are just **warnings**, signaling you the quality of teleoperation may be altered or the current state of the robot may evolve into future errors (motors heating up or low battery). These messages are displayed on a **dark grey background**. +When possible, please consider acting to prevent these warnings from becoming errors. + +**Error messages** + +Other messages may signal **errors**, which will lead to a fast dysfunction of the teleoperation. These messages are to take into account quickly, as you may not be controlling the robot properly anymore when they appear. These messages are displayed on a **red background**. + +{{< warning icon="👉🏾" text="When error messages appear, stop teleoperation and act appropriately depending on the error type. " >}} diff --git a/content/vr/_index.md b/content/vr/_index.md deleted file mode 100644 index 04a27924..00000000 --- a/content/vr/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title : "VR app compatibility" -description: "Use systend services with Reachy." -date: 2023-07-26T08:58:44+02:00 -lastmod: 2023-07-26T08:58:44+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/compatibility/_index.md b/content/vr/compatibility/_index.md deleted file mode 100644 index 3cdab028..00000000 --- a/content/vr/compatibility/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Compatibility" -description: "Get compatible VR headsets and minimal PC requirements for the teleoperation app to run" -date: 2023-07-26T08:59:05+02:00 -lastmod: 2023-07-26T08:59:05+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/compatibility/headsets.md b/content/vr/compatibility/headsets.md deleted file mode 100644 index 47b8b1bd..00000000 --- a/content/vr/compatibility/headsets.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Headsets" -description: "Get the list of compatible VR headset to use the VR teleoperation app" -date: 2023-07-26T08:59:13+02:00 -lastmod: 2023-07-26T08:59:13+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "20" ---- - -So far, the VR teleoperation application has been tested with the following devices: -* **Meta Quest 2** (with Oculus Link) -* **Meta Quest 3** (with Oculus Link) - -> No native application for Meta Quest headsets has been released at the moment. - - -The application should also support any device compatible with Unity 2022.3 including but not limited to the following devices: -* **Valve Index** -* **HTC Vive** -* **Oculus Rift** - - -Please refer to [Unity documentation](https://docs.unity3d.com/2020.3/Documentation/Manual/VROverview.html) for more information about the compatibility. \ No newline at end of file diff --git a/content/vr/compatibility/pc-requirements.md b/content/vr/compatibility/pc-requirements.md deleted file mode 100644 index 81585951..00000000 --- a/content/vr/compatibility/pc-requirements.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "PC Requirements" -description: "Get minimal VR requirements for the teleoperation app to run" -date: 2023-07-26T08:59:23+02:00 -lastmod: 2023-07-26T08:59:23+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "30" ---- - -The application is built on Unity 2022.3 LTS for which the requirements can be found [here](https://docs.unity3d.com/2020.3/Documentation/Manual/system-requirements.html). - - -In order to use the desktop version of the teleoperation application, your PC needs to support Virtual Reality. We recommend the computer to run on Windows, to be powerful enough and equipped with a graphic card. - -The computer minimum requirements are the following: -* **Operating System:** Windows 10 (or Windows 7 SP1) -* **Processor:** Intel Core i5-4590/AMD FX 8350 equivalent or better -* **Memory:** 8GB RAM -* **Graphic card:** NVIDIA GeForce GTX 970, AMD Radeon R9 290 equivalent or better -* **Network:** Broadband Internet connection. It is highly recommended for your PC to be **hard-wired** into your router using an **ethernet cable**. diff --git a/content/vr/getting-started/_index.md b/content/vr/getting-started/_index.md deleted file mode 100644 index fb773cad..00000000 --- a/content/vr/getting-started/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "VR Installation" -description: "" -date: 2023-08-21T15:59:42+02:00 -lastmod: 2023-08-21T15:59:42+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/getting-started/check-robot.md b/content/vr/getting-started/check-robot.md deleted file mode 100644 index 5aafba33..00000000 --- a/content/vr/getting-started/check-robot.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "Check robot is ready" -description: "" -lead: "Prepare your robot for teleoperation" -date: 2023-08-21T16:00:11+02:00 -lastmod: 2023-08-21T16:00:11+02:00 -type: docs -draft: false -images: [] -toc: true -weight: "50" ---- - -## Little checks before start - -> When starting the robot, the services required for teleoperation are **automatically launched**. - -### SR camera must be unplugged - -Make sure the **SR camera is unplugged**: it could cause troubles to launch the teleop cameras service. - -{{< img-center "images/vr/getting-started/unplugged-sr.png" 400x "" >}} - -### Have you done anything since the last boot? - -In the following cases: -- you have just unplugged the SR camera, without rebooting the robot -- you have used the Python SDK during your session with the robot - -Then disconnect all running clients (if you used the Python SDK), and **restart the webrtc service** from the dashboard. - -{{< img-center "images/vr/getting-started/restart-webrtc.png" 600x "" >}} - -> A reboot of the robot will also work. \ No newline at end of file diff --git a/content/vr/getting-started/connect.md b/content/vr/getting-started/connect.md deleted file mode 100644 index 684c3126..00000000 --- a/content/vr/getting-started/connect.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Connect to Reachy 2" -description: "" -lead: "How to launch the app and connect to the robot" -date: 2023-08-21T16:00:11+02:00 -lastmod: 2023-08-21T16:00:11+02:00 -type: docs -draft: false -images: [] -toc: true -weight: "60" ---- - -## Launch the app - -Once everything is installed, you can launch the application. -First connect your headset to your computer and make sure it is ready for use. - -> Meta Quest headsets must be used with the link. - -Then run the *Reachy2Teleoperation.exe* file from the previously unzipped folder to start the application. - -## Find Reachy IP address - -The LCD screen connected in Reachy's back should be diplaying its IP address. - -{{< img-center "images/vr/getting-started/lcd-display.png" 400x "" >}} - -If the LCD screen is not working or is unplugged, check out the page [Find my IP section]({{< ref "help/system/find-my-ip" >}}) to learn other ways to get the IP address. - -## Connect to the robot - -Create a new robot entry in the menu with the IP address you previously found. - -> Note that you must select the input fields with your VR beam and fill them in using your computer keyboard. - -Once the robot is created, select it and click on "**Connect**". -You should then arrive in the *transition room* of the application. - -A message to allow the network access to the app may pop up, in this case **allow access**: - -{{< img-center "images/vr/getting-started/allow-access.png" 400x "" >}} - -Make sure the connection is fine by checking the information displayed at the top of the mirror. -You must see: -- a green text telling you "Connected to Reachy" -- the view of the robot displayed in miniature -- a good network connection indication - -{{< img-center "images/vr/getting-started/mirror-scene.png" 600x "" >}} diff --git a/content/vr/getting-started/installation.md b/content/vr/getting-started/installation.md deleted file mode 100644 index 96147698..00000000 --- a/content/vr/getting-started/installation.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: "Installation" -description: "How to install the VR teleoperation application" -lead: "How to install the VR teleoperation application on your computer" -date: 2023-08-21T16:00:11+02:00 -lastmod: 2023-08-21T16:00:11+02:00 -type: docs -draft: false -images: [] -toc: true -weight: "40" ---- - -> Reachy 2 is already fully compatible with the teleoperation application. You have nothing to install on the robot. - -## On the Windows computer - -### 1. Check VR device installation - -Make sure that your VR device is properly installed and running (please refer to your device documentation). - -### 2. Download application - -Download the zip archive we sent you, and unzip it. - -{{< alert icon="👉" text="No standalone application is available yet for Reachy 2 teleoperation." >}} - -### 3. Install GStreamer - -The project relies on GStreamer. - -- Please install the **[Windows Runtime](https://gstreamer.freedesktop.org/data/pkg/windows/1.24.0/msvc/gstreamer-1.0-msvc-x86_64-1.24.0.msi)**. - -- Choose the **complete installation**: -{{< img-center "images/vr/getting-started/complete-installation.png" 400x "" >}} - -- Add `C:\gstreamer\1.0\msvc_x86_64\bin` to your PATH environment variable. -To do so: - - Access the **Edit the system environment variables** control panel: - {{< img-center "images/vr/getting-started/control-panel.png" 400x "" >}} - - - Open **Environment Variables...**: - {{< img-center "images/vr/getting-started/environment-variables.png" 400x "" >}} - - - Select the **Path** variable and click **Edit...**: - {{< img-center "images/vr/getting-started/user-variables.png" 400x "" >}} - - - Click **New** and **add `C:\gstreamer\1.0\msvc_x86_64\bin`** to the list: - {{< img-center "images/vr/getting-started/new-variable.png" 400x "" >}} - - - Also check you have GSTREAMER_1_0_ROOT_MSVC_X86_64 in your System variables, value being `C:\gstreamer\1.0/msvc_x86_64\`: - {{< img-center "images/vr/getting-started/system-variables.png" 400x "" >}} - -- **Reboot** your computer after the installation. - -### 4. Configure the firewall - -{{< img-center "images/vr/getting-started/firewall.png" 400x "" >}} - -{{< img-center "images/vr/getting-started/allow-app.png" 400x "" >}} - -### 5. Choose your headset refresh rate (optional) - -If you have a Meta Quest headet, we advise you to set the refresh rate at 120 Hz. - -To do so, use the desktop Meta app (the one appearing on your computer when your headset is connected on your computer and the link activated). -In the devices tab, select your headset, and modify the graphics preferences in the advanced section. - -{{< img-center "images/vr/getting-started/refresh-rate.png" 400x "" >}} diff --git a/content/vr/getting-started/setup.md b/content/vr/getting-started/setup.md deleted file mode 100644 index 22bb1b95..00000000 --- a/content/vr/getting-started/setup.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Setup your teleop session" -description: "Setup audio and motion sickness options before starting teleoperation" -lead: "How to setup the parameters before starting teleoperation" -date: 2023-08-21T16:00:11+02:00 -lastmod: 2023-08-21T16:00:11+02:00 -type: docs -draft: false -images: [] -toc: true -weight: "70" ---- - -## Audio and microphone setup - -To have a better experience within the VR, configure the audio of your headset from your **headset settings**. - -You should be able to speak through the robot and hear from it when you are in the *transition room*. -Check both audio input and output are on, and set them to a correct value. - -> On the Meta Quest 2 headset, we use the following parameters: -> - **audio input**: 100% -> - **audio ouput**: 65% - - -## Motion sickness options - -Once in the *transition room*, you have options you can configure to help you avoid motion sickness. - -On the left of the mirror, open the **Settings** tab, and configure the motion sickness options before starting teleoperating the robot. - -{{< img-center "images/vr/getting-started/vr-settings.png" 600x "" >}} - - -### Reticle -Display a reticle to give a fixed point in the field of view. By default, the reticle only appears when the mobile base is moving. - -*Option:* -- **Always display reticle**: always display the reticle, even if the mobile base is not moving. - -{{< img-center "images/vr/getting-started/reticle.png" 300x "" >}} - - -### Navigation effects - -- **No effect** -- **Tunneling**: when moving the mobile base, a black tunneling will appear in your peripheral vision and reduce your field of view -- **Reduced screen**: when moving the mobile base, the size of the image will be reduced to let you see an artificial horizon behind it. - -*Option:* -- **Activate effect on demande only**: during teleoperation, press one of the joysticks to activate/deactivate the occurence of the selected effect. - - If used with *tunneling*, deactivate the effect will disable the tunneling when moving the mobile base, activate it will let it appear automatically. - - If used with *reduced screen*, activate or deactivate the effect will let you manually reduce the size of the image. - -|Tunneling effect|Reduced screen effect | -|----|--------------------| -|{{< img-center "images/vr/getting-started/tunneling.png" 300x "" >}}|{{< img-center "images/vr/getting-started/reduced-screen.png" 300x "" >}} -| \ No newline at end of file diff --git a/content/vr/installation.md b/content/vr/installation.md deleted file mode 100644 index e86cbc46..00000000 --- a/content/vr/installation.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "What needs to be installed" -description: "How to install the VR teleoperation application" -lead: "How to install the VR teleoperation application" -date: 2023-07-26T09:00:02+02:00 -lastmod: 2023-07-26T09:00:02+02:00 -draft: false -images: [] -type: docs -toc: true ---- - -{{< alert icon="👉" text="Reachy 2021/2023 is already fully compatible with the teleoperation application. You have nothing to install on the robot." >}} - -{{< alert icon="⬇️" text=" Download the latest version of the app">}} - -## On the Oculus Quest 2 - -There are two options for this device: use it **natively on the headset** or run it on your computer using an **Oculus link**. If you want to use the Oculus Link, please refer to the *On Windows computer* section. -To use it natively, choose one of the following options to install it. - -### From the Quest Store - -Contact us on our [discord channel](https://discord.com/channels/519098054377340948/991321051835404409) to be added to the list of the beta testers. - -### Using the apk - -[Download the apk from our github repo](https://github.com/pollen-robotics/ReachyTeleoperation/releases), and install it to your device with your favorite tool (with the [meta quest developer hub](https://developer.oculus.com/meta-quest-developer-hub/) for instance). - -## On the Windows computer - -Make sure that your VR device is properly installed and running (please refer to your device documentation). - -[Download the zip archive from our github repo](https://github.com/pollen-robotics/ReachyTeleoperation/releases), and unzip it. Simply launch the *TeleopReachy.exe* file to start the application. diff --git a/content/vr/introduction/_index.md b/content/vr/introduction/_index.md deleted file mode 100644 index fbaa98fe..00000000 --- a/content/vr/introduction/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "VR Introduction" -description: "Get quickly introduced to VR teleoperation" -date: 2023-07-26T14:25:40+02:00 -lastmod: 2023-07-26T14:25:40+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/introduction/introduction.md b/content/vr/introduction/introduction.md deleted file mode 100644 index ede050ac..00000000 --- a/content/vr/introduction/introduction.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "Introduction" -description: "What is VR teleoperation application?" -lead: "What is VR teleoperation application?" -date: 2023-07-26T09:00:11+02:00 -lastmod: 2023-07-26T09:00:11+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "10" ---- - -The Virtual Reality (VR) teleoperation application enables you to **control the robot remotely** with VR device. - -By connecting to your robot, the teleoperation application gives you the ability to **move Reachy's arm** with the tracking of the VR controllers, to **rotate Reachy's head** following your own head movements and to **see through Reachy's cameras**. - -You can also **manipulate objects** remotely controlling Reachy's grippers with your controllers' triggers. - -{{< youtube vVIBlbS2zJs >}} \ No newline at end of file diff --git a/content/vr/problem/_index.md b/content/vr/problem/_index.md deleted file mode 100644 index 0eb9f4fa..00000000 --- a/content/vr/problem/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Problem" -description: "Resolve problems you get using VR teleoperation application" -date: 2023-07-26T09:00:36+02:00 -lastmod: 2023-07-26T09:00:36+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/problem/debug.md b/content/vr/problem/debug.md deleted file mode 100644 index f3be68a1..00000000 --- a/content/vr/problem/debug.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "Debug" -description: "Meeting a problem with teleoperation? Find out what can cause this and how to resolve the situation by yourself" -date: 2023-07-26T09:00:50+02:00 -lastmod: 2023-07-26T09:00:50+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "150" ---- - -## Check the info on the app! -Connect to the robot to get more information on the connection status and the status of the robot. Open the "info" menu on the left of the mirror. - -{{< img "images/vr/problem/mirror-info.png" 600x "Mirror Info">}} - -### Connection status -The connection status give you information about the communication with the robot. Existing connection status are the following: -* **Connected to a remote Reachy** *(green)*: everything seems to be working fine -* **Trying to connect** *(blue)*: the app is looking for the connection with the robot -* **Robot connection failed** *(orange)*: you are connected to a remote robot, but either the camera feed or the data stream failed. Teleoperation is not possible -* **Unable to connect to remote server** *(red)*: no robot or service is detected after trying to connect - -### Network connection quality -The status of the network connection can also help you: -* **Good network connection** indicates the application manage to have fast responses from the robot -* **Unable to reach robot** indicates the application doesn't manage to get any answer from the given IP address on the network - -### Services availability - -You can also check which services are available: -* **Camera**: camera service from the cameras. ***Mandatory for teleoperation*** -* **Audio**: service to get sound from the robot to the operator -* **Microphone**: service to send sound of the operator through the robot -* **Motors**: joints services for sending and receiving data from the robot's motors ***Mandatory for teleoperation*** - -## The app doesn't connect to the robot - -If you are not connected to the robot, the reason can be one of the following: -* you are not connected to the right IP address -* the robot is not connected to the network -* the services are not working on the robot (either not launched or crashed) -* your computer is not connected to the network -* the connection is not stable enough for the app to stay connected to the robot - -## Reachy never comes to be ready - -First of all, check that the application managed to connect to the robot. -The connection status with the robot is indicated at the top of the mirror. -Camera view (top right) is not available if the connection failed. - -|Connected to the robot|Unable to connect to the robot| -|----------------------|------------------------------| -|{{< img "images/vr/problem/connected.png" 300x "Connected to Robot">}}| {{< img "images/vr/problem/notconnected.png" 300x "Not connected to Robot">}}| - - -## The robot doesn't move properly -**Reachy movements are shifted from my real movements** -Your head was probably not correctly aligned with your body when you fixed your position, or you moved since the validation step. -Come back to the mirror and validate your choices again to be able to fix a new position. - -**Reachy movements are jerky** -The **connection is not fast enough** between the robot and your computer, or another program may be alterating the reactivity. -A warning message may also be displayed during teleoperation indicated the network is either unstable or has low speed. - -**The movements of the robot seem not correlated anymore with mine** -If a motor is overheating, it may have **stopped working**, which can lead in movements looking very different than yours. In reality, the arm is still trying to move according to yours, but the unmoving joints make the configuration of the arm hard to understand. -In most of the cases, an **error message** should be displayed in the teleoperation, telling that at least 1 motor is in critical error. -Nevertheless it may happen that no error message is displayed, if the motor stopped working before having time to send the information to the teleoperation app: in that case, you received a warning message telling at least 1 motor was heating up previously during teleoperation. Check the **temperature of the motors** in the **Info panel** of the transition room. diff --git a/content/vr/problem/support-vr.md b/content/vr/problem/support-vr.md deleted file mode 100644 index f9d64296..00000000 --- a/content/vr/problem/support-vr.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "Support VR" -description: "Get support from the community or Pollen Robotics if you meet problems with the VR teleoperation app" -date: 2023-07-26T09:00:44+02:00 -lastmod: 2023-07-26T09:00:44+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "160" ---- - -## Discord - -Join **[our Discord](https://discord.gg/vnYD6GAqJR)** if you have any questions, maybe someone has already asked the same question or other people could benefit from the answer! - -{{< alert icon="👉" text="Any questions relative to your development with Reachy?
Join the Pollen Community on Discord" >}} - - -## Pollen Robotics support - -For any specific questions concerning your robot or if you meet problems with the product, please contact us at [support@pollen-robotics.com](mailto:support@pollen-robotics.com). diff --git a/content/vr/use-teleop/_index.md b/content/vr/use-teleop/_index.md deleted file mode 100644 index b596cec3..00000000 --- a/content/vr/use-teleop/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Use Teleop" -description: "How to use the VR application to teleoperate Reachy correctly" -date: 2023-07-26T09:01:14+02:00 -lastmod: 2023-07-26T09:01:14+02:00 -draft: false -images: [] -type: docs ---- diff --git a/content/vr/use-teleop/best-practice.md b/content/vr/use-teleop/best-practice.md deleted file mode 100644 index 226d7b6a..00000000 --- a/content/vr/use-teleop/best-practice.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: "🚨 Best practice" -description: "Simple guidelines to follow for a good usage of the VR teleoperation app" -lead: "Towards a good usage of the VR teleoperation app" -date: 2023-07-26T09:01:27+02:00 -lastmod: 2023-07-26T09:01:27+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "80" ---- - -{{< warning icon="👉🏾" text="This page contains really important information about the use of the teleoperation app. Please make sure you read it carefully before teleoperating Reachy." >}} - -Using teleoperation application has nothing complicated, but you need to respect a few guidelines to avoid damaging the robot when using it. This page goes through the main elements you need to keep in mind while teleoperating Reachy. The guidelines are not exhaustive, but should give you a good start on how to safely use the application. - -## Ideal use of teleoperation - -The ideal position to start teleoperation may depend on the surrounding of Reachy. Nevertheless, if the robot environment is compatible with it, we advise to start with the elbows at 90 degrees, lightly away from the torso. - -{{< img "images/vr/use-teleop/idealPosFaceReduced.jpg" 300x "ideal position face">}} -{{< img "images/vr/use-teleop/idealPosProfReduced.jpg" 300x "ideal position side">}} - -
-
-Here is a video of movements and positions that are suitable for teleoperation: -
-
- -{{< video "videos/vr/use-teleop/ChestOk.mp4" "80%" >}} - -
-Follow all the elements described in the next sections to teleoperate Reachy in the best conditions! - -## All guidelines in video -Watch this quick video to have an overview of the main guidelines to use teleoperation: - -{{< youtube bK7th6zY8Rg >}} - -
-The next sections go deeper into each guideline presented in the video and the risks of not following them. - -## Keep the right position -The mapping between your position and the robot is made when holding (A) to start teleoperation. The position and rotation of your headset at this moment are used to calibrate the system. If you move (i.e. change either your body position or orientation), the controllers positions will still be calculated in this coordinate system, and Reachy movements won't look like like yours anymore. For these reasons, you must: - -- Not move your feet when teleoperating Reachy: they must stay static on the floor. - -{{< video "videos/vr/use-teleop/FeetOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/FeetNotOk.mp4" "40%" >}} - - -- Not rotate your torso. -In fact, Reachy's torso won't move, only the arms will try to reach the positions, and this may lead to collision between the Reachy's arms and torso. - -{{< video "videos/vr/use-teleop/ChestOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/ChestNotOk.mp4" "40%" >}} - -## Avoid movements discontinuities -Reachy doesn't have the exact same degrees of freedom as you have, neither the same range for each joints. When a position cannot be reached, either because of the position or the orientation, the inverse kinematics gives the closest arm configuration found. The closest configuration found for the next position may be: - -- the same as the previous one, so the arm won't move and you have the impression Reachy is not following your movements anymore -- quite different from the previous one, which will lead to sudden changes of the arm position - -All this contribute to give movements that seem incontrollable, due to discontinuities in the arm's inverse kinematics. - -**To avoid this situation:** - -- Avoid using extreme joints orientations while teleoperating Reachy -- Avoid unusual arm positions, there are probably above Reachy's joints limits - -{{< video "videos/vr/use-teleop/MovementsOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/MovementsNotOk.mp4" "40%" >}} - -- The most limiting joint is the elbow: avoid working to close to your chest, the elbow will be at the limit of its range of motion - -{{< video "videos/vr/use-teleop/TorsoArmOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/TorsoArmNotOk.mp4" "40%" >}} - -- If the robot seems to stop following your movements, do not continue to move in this direction, you have already reached its workspace limit. Go back to a position you know can be reached. - - -## Avoid damaging motors -Reachy's arms have been designed to manipulate objects at a table level and nearby. -Some positions away from this nominal area can require a lot of effort from the motors to be maintained, and cause them to overheat fast. Moreover, manipulating objects requires more effort from the motors. - -**To avoid damaging motors:** - -- Avoid doing movements above your head -- Avoid keeping your arms straight ahead horizontally to the floor, where the shoulders motors have to carry all the weight of the arms in a static position - -{{< video "videos/vr/use-teleop/AboveHeadOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/AboveHeadNotOk.mp4" "40%" >}} - -- Do not let the motors in stiff mode when you are in the menu if you are not going to teleoperate the robot soon -- Do not try to lift objects that are above Reachy's capabilities. If you try to lift an object and see that Reachy's arm can follow your movement or if you head some crackling noise coming from the motors, it probably means that the object is too heavy for Reachy's arm. - -{{< video "videos/vr/use-teleop/WeightOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/WeightNotOk.mp4" "40%" >}} - -## Avoid damaging 3D parts -Hitting Reachy's arms on objects can break 3D parts of the robot. It may happen even if the arms crash into something at moderate speed. - -**To avoid damaging 3D parts:** -- Check the environment surrounding the robot before starting the teleoperation. Make sure you have enough space around the robot and that there is no object to be hit by the robot (this may also save your object from being broken...) - -{{< video "videos/vr/use-teleop/CheckSpaceRobotOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/CheckSpaceRobotNotOk.mp4" "40%" >}} - -- Stop teleoperation close to the position which will be reached when the motors will be compliant, so that the arms won't fall from high. - -{{< video "videos/vr/use-teleop/StopArmOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/StopArmNotOk.mp4" "40%" >}} - -## Use teleop safely -- Check the environment around you before starting teleoperation. - -{{< video "videos/vr/use-teleop/CheckSpaceOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/CheckSpaceNotOk.mp4" "40%" >}} - -- Stop teleoperation before removing your headset! You must be back in the menu before dropping the controllers and removing your headset, because Reachy will continue following your movements until you stop it. - -{{< video "videos/vr/use-teleop/RemoveHeadsetOk.mp4" "40%" >}} - -{{< video "videos/vr/use-teleop/RemoveHeadsetNotOk.mp4" "40%" >}} - - -## Familiarize yourself with the robot -- Before teleoperating the actual robot, familiarize yourself with its movements, its workspace and its joints limits. The virtual robot in the mirror scene is a good opportunity for that. -- Stay near the robot for your first trials: listen to the motors sounds, be aware of your workspace and field of view in a environment you know, try to manipulate light objects. -- Explore your own workspace with small and quite slow movements to see how the robot reacts and better understand the relation between your movements and its. - - -{{< alert icon="💡" text="You may feel like being in a video game at some point, but never forget that your movements are reproduced in real life!" >}} \ No newline at end of file diff --git a/content/vr/use-teleop/commands.md b/content/vr/use-teleop/commands.md deleted file mode 100644 index 963a53dc..00000000 --- a/content/vr/use-teleop/commands.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: "Commands" -description: "Controller inputs mapping for VR teleoperation" -date: 2023-07-26T09:01:36+02:00 -lastmod: 2023-07-26T09:01:36+02:00 -draft: false -images: [] -type: docs -toc: true -hidden: true -weight: "90" ---- - -> A reminder of the controller inputs mapping is available in the **help** section of the *transition room* in the VR teleoperation application: -{{< img "images/vr/use-teleop/help-panel.png" 600x "Help panel in VR transition room">}} - - -## Meta Quest - -### Standard inputs - -{{< img "images/vr/use-teleop/meta-quest-mapping.png" 600x "Meta Quest controller mapping">}} - -|Input|Feature description | -|----|--------------------| -|**A**|**At robot teleoperation start:** Start robot teleoperation| -| |**During teleoperation:** Return to menu| -|**B**|**During teleoperation:** Mobile base boost| -|**X**|**When leaving teleoperation (A pressed):** Lock robot position| -|**Left Thumbstick**|**During teleoperation:** Control mobile base translation| -|**Right Thumbstick**|**During teleoperation:** Control mobile base rotation| -|**Left Index Trigger**|**In menu:** Select button| -| |**During teleoperation:** Control left gripper| -|**Right Index Trigger**|**In menu:** Select button| -| |**During teleoperation:** Control right gripper| -|**Left Controller position / orientation**|**During teleoperation:** Reachy's left arm end effector position / orientation| -|**Right Controller position / orientation**|**During teleoperation:** Reachy's right arm end effector position / orientation| -|**Headset orientation**|**During teleoperation:** Reachy's head orientation| - -### Emergency stop combination - -{{< img "images/vr/use-teleop/meta-quest-emergency-stop.png" 600x "Meta Quest controller emergency stop">}} - -|Input|Feature description | -|----|--------------------| -|**A + right index trigger + right middle finger trigger**|**During teleoperation:** Emergency stop| -|**X + left index trigger + left middle finger trigger**|**During teleoperation:** Emergency stop| diff --git a/content/vr/use-teleop/emergency-stop.md b/content/vr/use-teleop/emergency-stop.md deleted file mode 100644 index a5ea04aa..00000000 --- a/content/vr/use-teleop/emergency-stop.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: "Emergency stop" -description: "Stop immediately sending commands to the robot" -lead: "Stop immediately sending commands to the robot" -date: 2023-07-26T09:01:49+02:00 -lastmod: 2023-07-26T09:01:49+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "140" ---- - -In case you feel like something unexpected is happening with the robot while you are teleoperating it in VR, you can stop immediately teleoperation rather than using the standard exit menu, which requires to wait for a few seconds. - -> The VR application emergency stop does not replace the physical emergency stop button of the robot. - -While pressing either: -- (A) + right index trigger + right middle finger trigger -*or* -- (X) + left index trigger + left middle finger trigger -you will activate the VR emergency stop. -{{< img "images/vr/use-teleop/meta-quest-emergency-stop.png" 400x "Meta Quest controller emergency stop">}} - -The teleoperation application will immediately **stop sending commands** to the robot, **reduce the torque** values of the arms for a few seconds, then turn the robot **compliant**. - -{{< img "images/vr/use-teleop/emergency-stop.png" 600x "Help panel in VR transition room">}}
- -You will remain in the teleoperation view until you press (A) as usually to go back to the transition room. \ No newline at end of file diff --git a/content/vr/use-teleop/messages.md b/content/vr/use-teleop/messages.md deleted file mode 100644 index 7f13fee4..00000000 --- a/content/vr/use-teleop/messages.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Teleoperation messages" -description: "Understand warning and error messages in the VR teleoperation app" -lead: "Understand warning and error messages" -date: 2023-07-26T09:01:43+02:00 -lastmod: 2023-07-26T09:01:43+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "130" ---- - -During Reachy teleoperation, several messages can show up in front of view. - -**Warning messages** - -Some messages are just **warnings**, signaling you the quality of teleoperation may be altered or the current state of the robot may evolve into future errors (motors heating up or low battery). These messages are displayed on a **dark grey background**. -When possible, please consider acting to prevent these warnings from becoming errors. - -**Error messages** - -Other messages may signal **errors**, which will lead to a fast dysfunction of the teleoperation. These messages are to take into account quickly, as you may not be controlling the robot properly anymore when they appear. These messages are displayed on a **red background**. - -{{< warning icon="👉🏾" text="When error messages appear, stop teleoperation and act appropriately depending on the error type. " >}} diff --git a/content/vr/use-teleop/mobile-base.md b/content/vr/use-teleop/mobile-base.md deleted file mode 100644 index 0f849ea7..00000000 --- a/content/vr/use-teleop/mobile-base.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Control the mobile base" -description: "Use the mobile in the VR teleoperation application" -lead: "How to use the mobile base in the VR teleoperation application" -date: 2023-07-26T09:01:49+02:00 -lastmod: 2023-07-26T09:01:49+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "110" ---- - -## Control the mobile base -Use the **thumbstick/trackpad** to control the mobile base! -The **left controller controls the translation** of the mobile base, while the **right one controls the rotation**. - -**Is there any security to prevent collision with objects?** - -**Yes!** If you are too close to a wall or object, the LIDAR anti-collision safety unables the mobile base to go closer to the obstacle. The mobile base will therefore not move in this direction, but you can still go in other directions. You will get a warning message when the anti-collision safety is triggered. -[More information on the anti-collision safety](https://docs.pollen-robotics.com/sdk/mobile-base/safety/) - -Nevertheless, this security is for the mobile base and won't prevent the robot's arms to collide with external objects, so be aware while teleoperating the robot. - -*Please note very small objects won't be detected by the LIDAR sensor.* - -**What is the forward direction of Reachy?** - -The forward direction is aligned with the **forward direction of the mobile base**, meaning that giving a forward instruction to the robot will always lead the robot to go physically forward, no matter the direction you are looking to. - -Check the actual direction of your commands using the **indicator** at the bottom: the white arrow shows you the direction command relative to your actual head orientation. If your head is correctly aligned with the mobile base forward direction, this arrow will point forward if giving a forward command with your left controller. -{{< img "images/vr/use-teleop/straight_forward.png" 600x "Forward direction looking straight">}} -{{< img "images/vr/use-teleop/head_on_side_forward.png" 600x "Forward direction looking on the left">}} - -In the above images, the same forward command is sent from the left controller. -On the first image, the user is looking straight (the black arrow is located in the target view), so the white mobility arrow is pointing front. -On the second image, the user is looking on the left side (the target view is on the left of the black arrow), so the forward direction is pointing right, as it is the direction aligned with the mobile base forward direction. - -*Note that these images are only for example, mobility is not available on virtual Reachy.* diff --git a/content/vr/use-teleop/motion-sickness.md b/content/vr/use-teleop/motion-sickness.md deleted file mode 100644 index 0d81f762..00000000 --- a/content/vr/use-teleop/motion-sickness.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Motion sickness options" -description: "Add visual effects to reduce motion sickness while using the teleoperation application" -lead: "Add visual effects to reduce motion sickness while using the teleoperation application" -date: 2023-07-26T09:01:49+02:00 -lastmod: 2023-07-26T09:01:49+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "120" ---- - -Motion sickness may occur using the VR teleoperation application. - -We added a few options you can activate to reduce motion sickness, giving you a fix point in your field of view, or avoid peripheral movements when moving with the robot. - -You have access to these options in the ***transition room***. - -On the left of the mirror, open the **Settings** tab, and configure the motion sickness options before starting teleoperating the robot. - -{{< img-center "images/vr/getting-started/vr-settings.png" 600x "" >}} - - -### Reticle -Display a reticle to give a fixed point in the field of view. By default, the reticle only appears when the mobile base is moving. - -*Option:* -- **Always display reticle**: always display the reticle, even if the mobile base is not moving. - -{{< img-center "images/vr/getting-started/reticle.png" 300x "" >}} - - -### Navigation effects - -- **No effect** -- **Tunneling**: when moving the mobile base, a black tunneling will appear in your peripheral vision and reduce your field of view -- **Reduced screen**: when moving the mobile base, the size of the image will be reduced to let you see an artificial horizon behind it. - -*Option:* -- **Activate effect on demande only**: during teleoperation, press one of the joysticks to activate/deactivate the occurence of the selected effect. - - If used with *tunneling*, deactivate the effect will disable the tunneling when moving the mobile base, activate it will let it appear automatically. - - If used with *reduced screen*, activate or deactivate the effect will let you manually reduce the size of the image. - -|Tunneling effect|Reduced screen effect | -|----|--------------------| -|{{< img-center "images/vr/getting-started/tunneling.png" 300x "" >}}|{{< img-center "images/vr/getting-started/reduced-screen.png" 300x "" >}} -| \ No newline at end of file diff --git a/content/vr/use-teleop/start.md b/content/vr/use-teleop/start.md deleted file mode 100644 index 53540bf5..00000000 --- a/content/vr/use-teleop/start.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: "Teleoperate Reachy" -description: "Start and stop Reachy teleoperation using the VR app" -lead: "How to use the VR teleoperation application" -date: 2023-07-26T09:01:49+02:00 -lastmod: 2023-07-26T09:01:49+02:00 -draft: false -images: [] -type: docs -toc: true -weight: "100" ---- - -{{< warning icon="👉🏾" text="Before starting teleoperating Reachy, please make sure you read the Best Practice" >}} - -## In brief - -> The button names used below are for the Meta Quest headsets. Please refer to the [Controllers input page]({{< ref "/vr/use-teleop/commands">}}) to get the corresponding inputs for your device. - -### Start teleoperating Reachy - -1. Make sure the robot is turned on, connected to the network and that all the robot's services are running before launching the teleoperation application. - -2. Select the robot you want to teleoperate (or create a new one), and click on "Connect". - -3. Once in the mirror room, you can configure various settings. Take time to tune the motion sickness effects you want to use in the settings menu. When you are ready to start, press "Ready", then hold (A). - -4. **Look straight ahead, with your body in the same orientation as your head while pressing A** to start the teleoperation. *The initial head position is used to determine the coordinate system giving your VR controllers position.* - -{{< alert icon="👉" text="Warning: you must not move your body anymore after this step. The position of your VR controllers to master the robot arms are calculated depending on the position you had while pressing A." >}} - -{{< warning icon="🚨" text="Important: even if Reachy is bio-inspired, it cannot reproduce exactly all your movements. There are positions that cannot be reached by the robot. Please avoid unusual movements and do not persist in trying to reach a position if you see that the robot is stuck before it." >}} - -5. (NEW) You first have the control of the head and the mobile base, but **not of the arms**. Take a few seconds to check the robot surroundings and go to an appropriate place before starting the full teleoperation. When the environment is safe, **press A** to get the full control. You can also go back to the mirror room pressing the related button with your laser beam. - -6. Come back any time to mirror room by **holding A**. Teleoperation of the robot is automatically paused if the headset is removed. - -{{< alert icon="👉" text="Please stop teleoperation before removing your headset (go back to mirror room or quit the app). If you do not, Reachy will continue following your controllers and headset orientation during a few seconds, and this can cause damages to the robot." >}} - -### Stop teleoperation - -1. Come back to the **mirror room** to pause the teleoperation by **holding A** at any time during teleoperation. - -2. Leave the app by clicking "**Quit**" icons in the mirror room and connection menu. - -The motors are automatically turned into compliant mode when quitting the mirror room. Please make sure the arms are close enough to the lowest position they can reach when coming back to the menu to avoid them falling or hitting something. - - -## Step-by-step starting -1. Make sure that your VR equipement is up and running. Please refer to your device documentation. - -2. Make sure the robot is turned on, connected to the network and that all the robot services are running. *By default, if you haven't modified anything, all services should be automatically launched on start of the **full/starter kit** robots.* - -3. Launch the application *TeleoperateReachy.exe* file if you are using a VR device connected to a Windows computer. For Oculus Quest users, start the app from within the headset if you have installed the *.apk*. - -4. Equip yourself with your headset, make sure you can see both controllers and that the scene around you is moving correctly in accordance with your head movements. - -5. Choose the robot you want to connect to: you can select a robot with its IP address, or add a new one to the list of available robots. - -{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} -{{< img "images/vr/use-teleop/select-robot.png" 600x "Select robot to connect">}} - -6. Press *Connect* to initiate the communication with the robot. - -{{< img "images/vr/use-teleop/connect.png" 600x "Connect to a robot">}}
- -7. You should be now in the *transition room*, and see yourself controlling a virtual reachy. The actual robot is not in control at that time but the live camera stream is displayed at the top right of the mirror. The info, help and settings menus are available here (they are documented in the next section). Please get familiar with the robot controls and features (emotion, grasping lock). - -{{< img "images/vr/use-teleop/mirror.png" 600x "Mirror scene">}}
- -8. When you are ready, **face the mirror completely** and click on "Ready". The position of the actual robot appears in a semi-transparent green color. This may be useful when you've left the robot in a certain position that you would like to keep when entering the teleoperation. Hold (A) to start the teleoperation. - -{{< img "images/vr/use-teleop/mirror-ready.png" 600x "Start teleoperation">}}
- -9. (NEW) You first have the control of the head and the mobile base, but **not of the arms**. Take a few seconds to check the robot surroundings and go to an appropriate place before starting the full teleoperation. When the environment is safe, **press A** to get the full control. You can also go back to the mirror room pressing the related button with your laser beam. - -10. A 3 seconds timer appears while you enter the teleoperation. The motors speeds are reduced during this time to avoid sudden movements of the robot. Full speed is reached at the end of this countdown. - -{{< img "images/vr/use-teleop/timer-start.png" 600x "Validate position before starting">}} - -{{< alert icon="👉" text="Warning: you don't want to move your torso and body anymore after this step. Only your head and arms. The position of your VR controllers to master the robot arms are calculated depending on the position you had while pressing A." >}} - -11. Come back any time to menu by **pressing A**. Teleoperation of the robot is automatically paused if the headset is removed. - - -## Use Reachy's emotions -*Use of the antennas emotion is not available on Reachy 2.* - -## Application features - -### Connection page - -{{% expand "> Add a new robot" %}} -Click on the robot to select to open the panel of all saved robots: -{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} -Then click on "Add new robot +" at the bottom right of the page: -{{< img "images/vr/use-teleop/add-robot-button.png" 600x "Add robot button">}} -Enter a robot name and the IP address of the robot (if the headset is connected on a computer, use the computer keyboard), and save your robot card: -*The IP address is mandatory. If no name is given to the new robot, it will be called @Reachy by default* -{{< img "images/vr/use-teleop/add-robot-card.png" 600x "Add robot panel">}} -{{% /expand %}} - -{{% expand "> Modify an existing robot"%}} -Click on the robot to select to open the panel of all saved robots: -{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} -Then click on the pencil icon of the robot you want to modify: -{{< img "images/vr/use-teleop/modify-robot-button.png" 600x "Modify robot button">}} -Modify the info on the robot card and save the card: -{{< img "images/vr/use-teleop/modify-robot-panel.png" 600x "Modify robot panel">}} -{{% /expand %}} - -{{% expand "> Delete a saved robot"%}} -Click on the robot to select to open the panel of all saved robots: -{{< img "images/vr/use-teleop/choose-robot.png" 600x "Change robot to connect">}} -Then click on the bin icon of the robot you want to delete: -{{< img "images/vr/use-teleop/delete-robot-button.png" 600x "Delete robot button">}} -Validate the deletion: -{{< img "images/vr/use-teleop/delete-robot-panel.png" 600x "Delete robot panel">}} -{{% /expand %}} - - -### Mirror scene - -{{% expand "> Check robot status"%}} -Open the info menu in the mirror room: -{{< img "images/vr/use-teleop/mirror-info.png" 600x "Info menu">}} -The connection and services status, and motor temperature are reported here. -{{% /expand %}} - -{{% expand "> Controller mapping"%}} -Open the help menu in the mirror room: -{{< img "images/vr/use-teleop/mirror-help.png" 600x "Info menu">}} -The mapping of the controller buttons to the robot actions are displayed here. -{{% /expand %}} - -{{% expand "> Settings menu"%}} -Open the settings menu in the mirror room: -{{< img "images/vr/use-teleop/mirror-settings.png" 600x "Settings menu">}} -Here you can set your size to improve the mapping between your movements and reachy's motion. Individual parts of the robot can be deactivated in the case you don't need the mobile base, a specific arm, etc. -Motion sickness options are available in this panel: choose to display a reticle or not, and select a navigation effect that fit to your robot use. -You can also modify the grasping mode there: with full control you decide at each time the opening of the gripper, while the grasping lock option enables you to close the gripper with on trigger press and open it with another one. Grasping lock option can be turned on/off as well in the emotion menu. -{{% /expand %}} - -{{% expand "> Reset position"%}} -While facing the mirror, your body should be aligned with Reachy's body. This is mandatory to have a consistent control. If this is not the case after having pressed "Ready", face the mirror and click on "Reset position". -{{< img "images/vr/use-teleop/reset_position.png" 600x "Reset position">}} -The "Reset position" button is placed at the bottom of the mirror, under the A loader. -{{% /expand %}} - -### Teleoperation exit - -{{% expand "> Exit and lock position"%}} -While press (A) to exit the teleoperation, you may hold (X) to activate the position lock. A lock is displayed when doing so. -{{< img "images/vr/use-teleop/exit-lock.png" 600x "Exit and lock">}} -The robot will stayed locked while you'll be back in the mirror room. This can be useful to keep a certain position while you need to take a break, change position or remove the headset. The position of the robot will be displayed by the semi-transparent green robot when you will restart the teleoperation. -{{% /expand %}}