diff --git a/assets/how-tos/access-arm/config.png b/assets/how-tos/access-arm/config.png new file mode 100644 index 0000000000..133298704b Binary files /dev/null and b/assets/how-tos/access-arm/config.png differ diff --git a/docs/_index.md b/docs/_index.md index 1f91d5936c..f2a29202c7 100644 --- a/docs/_index.md +++ b/docs/_index.md @@ -352,7 +352,7 @@ err = myArmComponent.MoveToPosition(context.Background(), cmdArmPose, referencef You can use any robotic arm with Viam. Configure it as an arm component. Then you can move it using the arm API. -[Move a robotic arm →](/tutorials/services/accessing-and-moving-robot-arm/) +[Move a robotic arm →](/how-tos/move-robot-arm/) diff --git a/docs/components/arm/_index.md b/docs/components/arm/_index.md index 75e381a01c..f8e4a6b3c1 100644 --- a/docs/components/arm/_index.md +++ b/docs/components/arm/_index.md @@ -92,7 +92,7 @@ For general configuration, development, and usage info, see: {{< cards >}} {{% card link="/how-tos/configure/" noimage="true" %}} {{% card link="/how-tos/develop-app/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} You can also use the arm component with the following services: diff --git a/docs/components/arm/eva.md b/docs/components/arm/eva.md index 6db4c2e0d8..4d8b9ef7c9 100644 --- a/docs/components/arm/eva.md +++ b/docs/components/arm/eva.md @@ -46,5 +46,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/fake.md b/docs/components/arm/fake.md index 248de36e31..68cccb969f 100644 --- a/docs/components/arm/fake.md +++ b/docs/components/arm/fake.md @@ -91,5 +91,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/lite6.md b/docs/components/arm/lite6.md index a9cfe4867e..2cad21691b 100644 --- a/docs/components/arm/lite6.md +++ b/docs/components/arm/lite6.md @@ -176,5 +176,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/ur5e.md b/docs/components/arm/ur5e.md index 02b7133bed..a2a8e5ad37 100644 --- a/docs/components/arm/ur5e.md +++ b/docs/components/arm/ur5e.md @@ -94,5 +94,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/xarm6.md b/docs/components/arm/xarm6.md index 81a09c5eb8..55c4386fd2 100644 --- a/docs/components/arm/xarm6.md +++ b/docs/components/arm/xarm6.md @@ -177,5 +177,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/xarm7.md b/docs/components/arm/xarm7.md index 74f4ef768d..d8afc2bef4 100644 --- a/docs/components/arm/xarm7.md +++ b/docs/components/arm/xarm7.md @@ -177,5 +177,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/components/arm/yahboom-dofbot.md b/docs/components/arm/yahboom-dofbot.md index 243c0ce28e..70d251ec19 100644 --- a/docs/components/arm/yahboom-dofbot.md +++ b/docs/components/arm/yahboom-dofbot.md @@ -84,5 +84,5 @@ For more configuration and usage info, see: {{< cards >}} {{% card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="true" %}} {{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} diff --git a/docs/how-tos/_index.md b/docs/how-tos/_index.md index 47a6ca78d4..4c9e8c2cd7 100644 --- a/docs/how-tos/_index.md +++ b/docs/how-tos/_index.md @@ -34,12 +34,13 @@ The guides on this page provide solutions for common tasks and workflows. Browse
-{{< how-to-expand title="Get started with Viam basics" tasks="4" level="BEGINNER-FRIENDLY" >}} +{{< how-to-expand title="Get started with Viam basics" tasks="5" level="BEGINNER-FRIENDLY" >}} {{< cards >}} {{% card link="/how-tos/drive-rover/" noimage="true" %}} {{% card link="/how-tos/control-motor/" noimage="true" %}} {{% card link="/how-tos/detect-people/" noimage="true" %}} {{% card link="/how-tos/collect-data/" noimage="true" %}} +{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} {{< /cards >}} {{< /how-to-expand >}} diff --git a/docs/how-tos/move-robot-arm.md b/docs/how-tos/move-robot-arm.md new file mode 100644 index 0000000000..cf5ca5c792 --- /dev/null +++ b/docs/how-tos/move-robot-arm.md @@ -0,0 +1,219 @@ +--- +title: "Move a robot arm" +linkTitle: "Move a robot arm" +weight: 70 +type: "docs" +tags: ["arm", "components"] +images: ["/how-tos/move_to_position.gif"] +videos: ["/how-tos/move_to_position.webm", "/how-tos/move_to_position.mp4"] +description: "Connect to a robotic arm and control it with the arm API." +aliases: + - /tutorials/motion/accessing-and-moving-robot-arm + - /tutorials/motion/ +languages: ["Python", "Go"] +viamresources: ["arm"] +platformarea: ["mobility"] +level: "Intermediate" +date: "2024-10-31" +# updated: "" # When the tutorial was last entirely checked +cost: "8400" +--- + +In this guide you'll use Viam's Python or Go SDK to get the current position of your robot arm and issue movement commands. + +{{< alert title="In this page" color="tip" >}} + +1. [Access the arm](#access-the-arm) +1. [Move the arm](#move-the-arm) + +{{< /alert >}} + +## Requirements + +You need the following hardware to complete this tutorial: + +- A single-board computer or other computer to run `viam-server`. +- A Linux, macOS or Windows computer that can run SDK code. +- A [robotic arm](/components/arm/). + +## Access the arm + +{{< table >}} +{{% tablestep link="/configure/" %}} +**1. Configure a machine with an arm** + +{{% snippet "setup.md" %}} + +Add an arm component. +Select a model that supports your arm. Refer to the [documentation for the model](/components/arm/#configuration) for information about your arm's configuration attributes. + +{{}} +Save your config. + +{{% /tablestep %}} +{{% tablestep link="/appendix/apis/components/arm/#getendposition" %}} +**2. Get the position of the end effector** + +One way to describe the state of a robot arm is with the position of the end effector, or the "tool" or "hand" of the arm. +The code to get this information is a part of the autogenerated code sample the Viam app provides for your machine. +Go to the **Code sample** page of the **CONNECT** tab and select either Python or Go. + +{{% snippet "show-secret.md" %}} + +Then, copy and paste the sample code into a file and run the resulting script to see the resources available on your screen and the position of the end effector output as a [`Pose`](/internals/orientation-vector/). +For more information, see [`GetEndPosition`](/appendix/apis/components/arm/#getendposition). + +{{% /tablestep %}} +{{% tablestep %}} +**3. Get the joint positions** + +The state of a robot arm can also be described as the list of positions of each joint attached to the arm. +To get that information, add the following code right after the code that gets the end effector pose from the prior code sample: + +{{< tabs >}} +{{% tab name="Python" %}} + +```python +# Joint Positions of arm1 +my_arm_joint_positions = await arm_1.get_joint_positions() +print(f"myArm get_joint_positions return value: {my_arm_joint_positions}") +``` + +{{% /tab %}} +{{% tab name="Go" %}} + +```go +// Joint Positions of arm1 +myArmJointPositions, err := arm1.JointPositions(context.Background(), nil) +if err != nil { + logger.Error(err) + return +} +logger.Infof("myArm JointPositions return value:", myArmJointPositions) +``` + +{{% /tab %}} +{{< /tabs >}} + +Run your code again. +Each individual value corresponds to the current position of a particular joint on your robot. +You can also see these values reflected on the **CONTROL** tab in the Viam app for your robot arm. + +{{% /tablestep %}} +{{< /table >}} + +## Move the arm + +The two main options for controlling arm movement are through **joint position commands** and through **pose commands**. +Joint position commands allow for more detailed control and flexibility instead of commanding movement with the end effector position in a pose command. + +{{< alert title="Caution" color="caution" >}} +Be careful when instructing robot arms to move. +Before running any code, ensure your robotic arm has enough space and that there are no obstacles. +Also pay attention to your surroundings, double-check your code for correctness, and make sure anyone nearby is aware and alert before issuing commands to your machine. +{{< /alert >}} + +{{< table >}} +{{% tablestep %}} +**1. Initiate motion with a joint position command** + +{{< tabs >}} +{{% tab name="Python" %}} +Add the following line to your import list to be able to assign values to a `JointPositions` data structure: + +```python +from viam.proto.component.arm import JointPositions +``` + +Add the following code to your script: + +```python +# Command a joint position move: move the forearm of the arm slightly up +cmd_joint_positions = JointPositions(values=[0, 0, -30.0, 0, 0, 0]) +await arm_1.move_to_joint_positions(positions=cmd_joint_positions) +``` + +{{% /tab %}} +{{% tab name="Go" link="/appendix/apis/components/arm/#movetojointpositions" %}} +Add `armapi "go.viam.com/api/component/arm/v1"` to your import list. +Add the following code to your script: + +```go +// Command a joint position move: move the forearm of the arm slightly up +cmdJointPositions := &armapi.JointPositions{Values: []float64{0.0, 0.0, -30.0, 0.0, 0.0, 0.0}} +err = arm1.MoveToJointPositions(context.Background(), cmdJointPositions, nil) +if err != nil { + logger.Error(err) + return +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{}} + +Run the code. +The third joint of your arm should move 30 degrees. +For more information, see [`MoveToJointPositions`](/appendix/apis/components/arm/#movetojointpositions). + +{{% /tablestep %}} +{{% tablestep link="/appendix/apis/components/arm/#movetoposition" %}} +**2. Command to move to position** + +{{< tabs >}} +{{% tab name="Python" %}} + +Add the following code to your script: + +```python +# Generate a simple pose move +100mm in the +Z direction of the arm +cmd_arm_pose = await arm_1.get_end_position() +cmd_arm_pose.z += 100.0 +await arm_1.move_to_position(pose=cmd_arm_pose) +``` + +{{% /tab %}} +{{% tab name="Go" %}} +Add `"go.viam.com/rdk/spatialmath"` to your import list. + +Add the following code to your script: + +```go +// Generate a simple pose move +100mm in the +Z direction of the arm +currentArmPose, err := arm1.EndPosition(context.Background(), nil) +if err != nil { + logger.Error(err) + return +} +adjustedArmPoint := currentArmPose.Point() +adjustedArmPoint.Z += 100.0 +cmdArmPose := spatialmath.NewPose(adjustedArmPoint, currentArmPose.Orientation()) + +err = arm1.MoveToPosition(context.Background(), cmdArmPose, nil) +if err != nil { + logger.Error(err) + return +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{}} + +This code gets the arm's end position, makes a 100 millimeter adjustment in the +Z direction, and then uses that adjustment as a goal [`Pose`](/internals/orientation-vector/) when commanding arm motion. +Run the code to see your arm move 100 mm upwards. +For more information, see [`MoveToPosition`](/appendix/apis/components/arm/#movetoposition). + +{{% /tablestep %}} +{{< /table >}} + +## Next steps + +{{< cards >}} +{{% card link="/tutorials/services/plan-motion-with-arm-gripper" %}} +{{% card link="/tutorials/projects/claw-game/" %}} +{{< /cards >}} + +For more resources on robot kinematics, read through the Wikipedia pages for [Forward kinematics](https://en.wikipedia.org/wiki/Forward_kinematics) and [Inverse kinematics](https://en.wikipedia.org/wiki/Inverse_kinematics). diff --git a/docs/services/motion/_index.md b/docs/services/motion/_index.md index 9e49fd7339..a4ade29ff6 100644 --- a/docs/services/motion/_index.md +++ b/docs/services/motion/_index.md @@ -60,6 +60,6 @@ The `plan_deviation_m` for `MoveOnMap()` on calls issued from the **CONTROL** ta The following tutorials contain complete example code for interacting with a robot arm through the arm component API, and with the motion service API, respectively: {{< cards >}} -{{% card link="/tutorials/services/accessing-and-moving-robot-arm" %}} +{{% card link="/how-tos/move-robot-arm/" %}} {{% card link="/tutorials/services/plan-motion-with-arm-gripper" %}} {{< /cards >}} diff --git a/docs/tutorials/services/accessing-and-moving-robot-arm.md b/docs/tutorials/services/accessing-and-moving-robot-arm.md deleted file mode 100644 index 1e6c2704fb..0000000000 --- a/docs/tutorials/services/accessing-and-moving-robot-arm.md +++ /dev/null @@ -1,486 +0,0 @@ ---- -title: "Access and Move a Robot Arm" -linkTitle: "Move a Robot Arm" -type: "docs" -description: "Access and control one of the most fundamental systems in robotics: A robotic arm." -imageAlt: "A robotic arm" -images: ["/tutorials/motion/preview.jpg"] -tags: ["arm", "motion", "services"] -aliases: - - "/tutorials/motion/accessing-and-moving-robot-arm" - - "/tutorials/motion/" -authors: [] -languages: ["python", "go"] -viamresources: ["arm"] -platformarea: ["mobility"] -level: "Intermediate" -date: "2023-03-07" -# updated: "" -cost: 8400 -no_list: true ---- - - - -{{< alert title="Caution" color="caution" >}} -Be careful when instructing robot arms to move. -Before running any code, ensure your robotic arm has enough space and that there are no obstacles. -Also pay attention to your surroundings, double-check your code for correctness, and make sure anyone nearby is aware and alert before issuing commands to your machine. -{{< /alert >}} - -The following instructions show you how to interact with an [arm component](/components/arm/), help you understand how an arm describes its state, and assist you in issuing movement commands to your robotic arm. - -
- {{}} -
- -Code examples in this tutorial use a [UFACTORY xArm 6](https://www.ufactory.us/product/ufactory-xarm-6), but you can use any [arm model](/components/arm/). - -If you do not have a robotic arm of your own, the [fake arm component page](/components/arm/fake/) shows how you can set up a virtual robotic arm with the same kinematic model as a real robotic arm. -Configure it with `"arm-model": "xArm6"` in its `attributes`. -You can then continue through the code examples in this tutorial without making any changes (and without needing to buy or build an expensive robot arm)! - -The [full tutorial code](#full-tutorial-code) is available at the end of this page. - -## Prerequisites - -Before starting this tutorial, make sure you have the [Viam Python SDK](https://python.viam.dev/) or the [Viam Go SDK](https://pkg.go.dev/go.viam.com/rdk/robot/client#section-readme) installed. - -If you are connecting to a real robotic arm during this tutorial, make sure your computer can communicate with the controller before continuing. - -## Configure a machine - -{{% snippet "setup.md" %}} - -1. Once your machine is live, select the **CONFIGURE** tab. -1. Click on the **+** symbol next to your machine in the **Builder** panel and select **Component** in the menu that opens: - - - Choose `arm` as the type. - - Choose your desired model. - - For example, if you're using an xArm 6, choose the `xArm6` model from the list. - - Enter `myArm` as the **Name** for this component, then click **Create**. - -1. In the newly created `myArm` component panel, configure any attributes as needed. - Refer to the documentation for the model for information about your arm's model. - -1. Switch to the **Frame** mode and select `myArm` in the left-hand menu to see the default values for your arm. - You do not need to change the default values that populate the new frame card. - - - - {{}} - -1. Save your machine configuration. - -1. Go to the **Code sample** page of the **CONNECT** tab and select the programming language you are working in. - - {{% snippet "show-secret.md" %}} - - Then, copy and paste the sample code into a file and run the resulting script to verify you can connect to your machine. - Throughout the rest of this tutorial, you will replace and amend this code. - The [full tutorial code](#full-tutorial-code) is available at the bottom of this tutorial for reference. - -## Access the arm - -The `arm` component library has several methods to simplify accessing and working with robotic arms. -In this step, you'll fetch data about the robotic arm's current position. - -{{< tabs >}} -{{% tab name="Python" %}} -Your script will resemble the following lines from the [full **Python** tutorial code](#full-tutorial-code) which enable you to use the `myArm` component you configured earlier. -The code then calls the [`get_end_position`](/appendix/apis/components/arm/#getendposition) method to get the position of the **end of the robot arm with respect to the arm's base**. - -```python {class="line-numbers linkable-line-numbers"} -# Access myArm -my_arm = Arm.from_robot(machine, "myArm") - -# End Position of myArm -my_arm_return_value = await my_arm.get_end_position() -print(f"myArm get_end_position return value: {my_arm_return_value}") -``` - -You should see output that looks similar to the following: - -```sh {class="command-line" data-prompt="$" data-output="1-10"} -myArm get_end_position return value: x: 200.73450755898915 -y: 0.0028507667654201754 -z: 108.63966593621173 -o_x: -0.019650946400315308 -o_y: -1.5485718223024914e-07 -o_z: -0.99980690150926033 -theta: -179.99979233107763 -``` - -The `x`, `y`, and `z` values correspond to the `position` element of the pose, while the `o_x`, `o_y`, `o_z`, and `theta` values are for the `orientation` element of the pose (presented as an [Orientation Vector](/internals/orientation-vector/)). - -{{% /tab %}} -{{% tab name="Go" %}} -Your script will resemble the following lines from the [full **Go** tutorial code](#full-tutorial-code) which enable you to use the `myArm` component you configured earlier. -The code then calls the [`EndPosition`](/appendix/apis/components/arm/#getendposition) method to get the position of the **end of the robot arm with respect to the arm's base**. - -```go {class="line-numbers linkable-line-numbers"} -// Access myArm -myArmComponent, err := arm.FromRobot(machine, "myArm") -if err!=nil { - logger.Error(err) - return -} - -// End Position of myArm -myArmReturnValue, err:= myArmComponent.EndPosition(context.Background(), map[string]interface{}{}) -if err!=nil { - logger.Error(err) - return -} -logger.Infof("myArm EndPosition return value: %+v", myArmReturnValue) - -``` - -You should see output that looks similar to the following: - -```sh {class="command-line" data-prompt="$" data-output="1-10"} -myArm EndPosition position return value: (200.734507558989150766137755, 0.002850766765420175395673, 108.639665936211727625959611) -``` - -The `Position` value is part of a `Pose`. - -{{% /tab %}} -{{< /tabs >}} - -The state of a robot arm can also be described as the **combined positions of each joint** attached to the arm. -You can access a robot arm's "joint states" (as they are sometimes referred to) by calling a different method on the arm component. -Add the following code right after the code that gets the end effector pose from the prior code sample. -When you run the code, you'll see that these two pieces of information are presented differently. - -{{< tabs >}} -{{% tab name="Python" %}} - -```python {class="line-numbers linkable-line-numbers"} -# Joint Positions of myArm -my_arm_joint_positions = await my_arm.get_joint_positions() -print(f"myArm get_joint_positions return value: {my_arm_joint_positions}") -``` - -You should see output that looks similar to the following: - -```sh {class="command-line" data-prompt="$" data-output="1-10"} -myArm get_joint_positions return value: values: 0.00043945314765093886 -values: 0.46724854536551791 -values: 0.64500731344456741 -values: -0.00098876951707685271 -values: 0.013732909913080547 -values: 0.00076904296930648713 -``` - -Each individual value corresponds to the current position of a particular joint on your robot. -You can also see these values reflected on the Control tab in the Viam app for your robot arm. - -{{% /tab %}} -{{% tab name="Go" %}} - -```go {class="line-numbers linkable-line-numbers"} -// Joint Positions of myArm -myArmJointPositions, err := myArmComponent.JointPositions(context.Background(), nil) -if err != nil { - logger.Error(err) - return -} -logger.Infof("myArm JointPositions return value:", myArmJointPositions) -``` - -You should see output that looks similar to the following: - -```sh {class="command-line" data-prompt="$" data-output="1-10"} -myArm JointPositions return value: values:0.00043945314765093886 values:0.4672485453655179 values:0.6450073134445674 values:-0.0009887695170768527 values:0.013732909913080547 values:0.0007690429693064871 -``` - -Each individual value corresponds to the current position of a particular joint on your robot. -You can also see these values reflected on the **Control** tab in the Viam app for your robot arm. - -{{% /tab %}} -{{< /tabs >}} - -Both representations of an arm's state are important. -Sometimes you may wish to direct an arm in terms of joint positions. -Other times you may need to describe the position of another object with respect to the end of the robot arm. -There is a mathematical relationship that allows you to convert between these two representations, known as the **forward and inverse kinematics**, which is foundational to complex robotic motion. -We will not cover forward and inverse kinematics in this tutorial, but resources for further reading on these topics are linked in the [**Next Steps**](#next-steps-and-references) section. - -## Move the arm - -The two main options for specifying arm movement are through **joint position commands** and through **pose commands**. -Let's start with joint position commands, as their formulation is a little simpler. - -### Joint position commands - -First, you can initiate motion with a joint position command. -A final note: - -{{< alert title="Caution" color="caution" >}} -Executing code presented after this point _will_ induce motion in a connected robotic arm! -{{< /alert >}} - -{{< tabs >}} -{{% tab name="Python" %}} -Add the following line to your import list to be able to assign values to a `JointPositions` data structure: - -```python {class="line-numbers linkable-line-numbers"} -from viam.proto.component.arm import JointPositions -``` - -See the [arm reference document](/appendix/apis/components/arm/#movetojointpositions) for further details on how to structure data that you pass to the `move_to_joint_positions` function. - -```python {class="line-numbers linkable-line-numbers"} -# Command a joint position move: move the forearm of the arm slightly up -cmd_joint_positions = JointPositions(values=[0, 0, -30.0, 0, 0, 0]) -await my_arm.move_to_joint_positions(positions=cmd_joint_positions) -``` - -{{% /tab %}} -{{% tab name="Go" %}} -You must import an additional Go library to access the data structure that Viam uses to encode joint positions, which is shown next. - -Add `armapi "go.viam.com/api/component/arm/v1"` to your import list to be able to assign values to an `armapi.JointPositions` data structure. -See the [arm reference document](/appendix/apis/components/arm/#movetojointpositions) for further details on how to structure data that you pass to the `MoveToJointPositions` function. - -```go {class="line-numbers linkable-line-numbers"} -// Command a joint position move: move the forearm of the arm slightly up -cmdJointPositions := &armapi.JointPositions{Values: []float64{0.0, 0.0, -30.0, 0.0, 0.0, 0.0}} -err = myArmComponent.MoveToJointPositions(context.Background(), cmdJointPositions, nil) -if err != nil { - logger.Error(err) - return -} -``` - -{{% /tab %}} -{{< /tabs >}} - -If you execute the sample joint move statement above, the third joint of your arm should move a small amount (30 degrees). -Feel free to experiment further with joint position commands by changing the values for each joint and re-sending the commands. - -When you are ready to move on, the next section will show you how to use **pose commands**. - -### Pose commands - -When you [got the end position of the arm](#access-the-arm), this data was returned in the format of a `Pose`. -The returned `Pose` is a combination of position and orientation data that indicates the end of the arm's full 6-dimensional configuration in space. - -The following code sample reuses the methods to get the pose of the end of the arm so that you can make small adjustments at will. -You can then pass the adjusted pose back to the arm as a **goal** pose for the purposes of starting motion. -For example, the following code gets the arm's end position, makes a 100 millimeter adjustment in the +Z direction, and then uses that adjustment as a goal when commanding arm motion. - -{{< tabs >}} -{{% tab name="Python" %}} -Add the sample code below to your own client script to try using the arm component's [`move_to_position`](/appendix/apis/components/arm/#movetoposition) command. -This example gets a `Pose` from `get_end_position()` so no additional imports are required. -If you want to synthesize new poses directly, note that you must import an additional Python package by adding `from viam.proto.common import Pose` to your import list. - -```python {class="line-numbers linkable-line-numbers"} -# Generate a simple pose move +100mm in the +Z direction of the arm -cmd_arm_pose = await my_arm.get_end_position() -cmd_arm_pose.z += 100.0 -await my_arm.move_to_position(pose=cmd_arm_pose) -``` - -{{% /tab %}} -{{% tab name="Go" %}} -You must import some additional Go packages to synthesize new poses through the `spatialmath` library for the arms's [`MoveToPosition`](/appendix/apis/components/arm/#movetoposition) command. -Add `"go.viam.com/rdk/referenceframe"` and `"go.viam.com/rdk/spatialmath"` to your import list and then add the sample code below to your own client script. - -```go {class="line-numbers linkable-line-numbers"} -// Generate a simple pose move +100mm in the +Z direction of the arm -currentArmPose, err := myArmComponent.EndPosition(context.Background(), nil) -if err != nil { - logger.Error(err) - return -} -adjustedArmPoint := currentArmPose.Point() -adjustedArmPoint.Z += 100.0 -cmdArmPose := spatialmath.NewPose(adjustedArmPoint, currentArmPose.Orientation()) - -err = myArmComponent.MoveToPosition(context.Background(), cmdArmPose, nil) -if err != nil { - logger.Error(err) - return -} -``` - -{{% /tab %}} -{{< /tabs >}} - -Using this code you can quickly adjust one or more elements of position AND orientation simultaneously, by modifying other elements of the original arm pose. - -For all motion actions taken in this tutorial, there may be joint positions or poses that are unreachable for particular reasons (potential collisions, a pose in space is unreachable because the arm is too short). -Regularly check your client script's feedback and the `viam-server` logs for any issues that may arise. - -## Next steps and references - -If you would like to continue onto working with Viam's motion service, check out one of these tutorials: - -{{< cards >}} -{{% card link="/tutorials/services/plan-motion-with-arm-gripper" %}} -{{% card link="/tutorials/projects/claw-game/" %}} -{{< /cards >}} - -{{< snippet "social.md" >}} - -For more resources on robot kinematics, read through the Wikipedia pages for [Forward kinematics](https://en.wikipedia.org/wiki/Forward_kinematics) and [Inverse kinematics](https://en.wikipedia.org/wiki/Inverse_kinematics). - -## Full tutorial code - -{{< tabs >}} -{{% tab name="Python" %}} - -```python {id="access-move-arm-python-ex" class="line-numbers linkable-line-numbers" data-line=""} -import asyncio - -from viam.components.arm import Arm -from viam.proto.component.arm import JointPositions -from viam.robot.client import RobotClient -from viam.rpc.dial import Credentials, DialOptions - - -async def connect(): - opts = RobotClient.Options.with_api_key( - # Replace "" (including brackets) with your machine's API key - api_key='', - # Replace "" (including brackets) with your machine's API key - # ID - api_key_id='' - ) - return await RobotClient.at_address('ADDRESS FROM THE VIAM APP', opts) - - -async def main(): - machine = await connect() - - print('Resources:') - print(machine.resource_names) - - # Access myArm - my_arm = Arm.from_robot(machine, "myArm") - - # End Position of myArm - my_arm_end_position = await my_arm.get_end_position() - print(f"myArm get_end_position return value: {my_arm_end_position}") - - # Joint Positions of myArm - my_arm_joint_positions = await my_arm.get_joint_positions() - print(f"myArm get_joint_positions return value: {my_arm_joint_positions}") - - # Command a joint position move: small adjustment to the last joint - cmd_joint_positions = JointPositions(values=[0, 0, 0, 0, 0, 15.0]) - await my_arm.move_to_joint_positions( - positions=cmd_joint_positions) - - # Generate a simple pose move +100mm in the +Z direction of the arm - cmd_arm_pose = await my_arm.get_end_position() - cmd_arm_pose.z += 100.0 - await my_arm.move_to_position(pose=cmd_arm_pose) - - # Don't forget to close the robot when you're done! - await machine.close() - -if __name__ == '__main__': - asyncio.run(main()) -``` - -{{% snippet "show-secret.md" %}} - -{{% /tab %}} -{{% tab name="Go" %}} - -```go {id="access-move-arm-go-ex" class="line-numbers linkable-line-numbers" data-line=""} -package main - -import ( - "context" - - armapi "go.viam.com/api/component/arm/v1" - "go.viam.com/rdk/logging" - "go.viam.com/rdk/robot/client" - "go.viam.com/rdk/components/arm" - "go.viam.com/rdk/referenceframe" - "go.viam.com/rdk/spatialmath" - "go.viam.com/rdk/utils" -) - -func main() { - logger := logging.NewLogger("client") - machine, err := client.New( - context.Background(), - "ADDRESS FROM THE VIAM APP", - logger, - client.WithDialOptions(utils.WithEntityCredentials( - // Replace "" (including brackets) with your machine's API key ID - "", - utils.Credentials{ - Type: utils.CredentialsTypeAPIKey, - // Replace "" (including brackets) with your machine's API key - Payload: "", - })), - ) - if err != nil { - logger.Fatal(err) - } - defer machine.Close(context.Background()) - - logger.Info("Resources:") - logger.Info(machine.ResourceNames()) - - // Access myArm - myArmComponent, err := arm.FromRobot(machine, "myArm") - if err != nil { - logger.Error(err) - return - } - - // End Position of myArm - myArmReturnValue, err := myArmComponent.EndPosition(context.Background(), nil) - if err != nil { - logger.Error(err) - return - } - logger.Infof("myArm EndPosition return value: %+v", myArmReturnValue) - - // Joint Positions of myArm - myArmJointPositions, err := myArmComponent.JointPositions(context.Background(), nil) - if err != nil { - logger.Error(err) - return - } - logger.Infof("myArm JointPositions return value:", myArmJointPositions) - - // Command a joint position move: small adjustment to the last joint - cmdJointPositions := &armapi.JointPositions{Values: []float64{0.0, 0.0, 0.0, 0.0, 0.0, 15.0}} - err = myArmComponent.MoveToJointPositions(context.Background(), cmdJointPositions, nil) - if err != nil { - logger.Error(err) - return - } - - // Generate a simple pose move +100mm in the +Z direction of the arm - currentArmPose, err := myArmComponent.EndPosition(context.Background(), nil) - if err != nil { - logger.Error(err) - return - } - adjustedArmPoint := currentArmPose.Point() - adjustedArmPoint.Z += 100.0 - cmdArmPose := spatialmath.NewPose(adjustedArmPoint, currentArmPose.Orientation()) - - err = myArmComponent.MoveToPosition(context.Background(), cmdArmPose, nil) - if err != nil { - logger.Error(err) - return - } -} -``` - -{{% snippet "show-secret.md" %}} - -{{% /tab %}} -{{< /tabs >}} diff --git a/docs/tutorials/services/plan-motion-with-arm-gripper.md b/docs/tutorials/services/plan-motion-with-arm-gripper.md index dbaa397b25..8d0e77b4c0 100644 --- a/docs/tutorials/services/plan-motion-with-arm-gripper.md +++ b/docs/tutorials/services/plan-motion-with-arm-gripper.md @@ -21,7 +21,7 @@ cost: 8400 no_list: true --- -With Viam you can move individual components, like [arms](../accessing-and-moving-robot-arm/), by issuing commands like `MoveToPosition` or `MoveToJointPosition`. +With Viam you can move individual components, like [arms](/components/arm/), by issuing commands like `MoveToPosition` or `MoveToJointPosition`. The [motion service](/services/motion/) enables you to do much more sophisticated movement involving one or many components of your robot. The service abstracts the lower-level commands away so that instead of passing in a series of joint positions, you can call the `Move()` command with the desired destination and any obstacles, and the service will move your machine to the desired location for you. @@ -49,15 +49,13 @@ Before starting this tutorial, make sure you have the [Viam Python SDK](https:// If you are connecting to a real robotic arm during this tutorial, make sure your computer can communicate with the controller before continuing. -Make sure you have mastery of the concepts outlined in the first motion tutorial, [Access and Move a Robot Arm](../accessing-and-moving-robot-arm/), before continuing. +Make sure you have mastery of the concepts outlined in the first motion guide, [Access and Move a Robot Arm](/how-tos/move-robot-arm/), before continuing. This tutorial picks up right where **Access and Move a Robot Arm** stops, so further examples depend on having a connected robot, client and service access, and other infrastructure in place. This also helps simplify and shorten the code examples presented below. -For a helpful recap of the code we previously added, look at [the full code sample from the prior tutorial](../accessing-and-moving-robot-arm/#full-tutorial-code). - ## Configure a robot -The [robot configuration from the prior tutorial](../accessing-and-moving-robot-arm/#configure-a-machine) should be used for this tutorial. +The [robot configuration from the prior tutorial](/how-tos/move-robot-arm/) should be used for this tutorial. We will revisit that robot configuration and add new components during specific sections below. The motion service is one of the "built-in" services, which means that no initial configuration is required to start planning and executing complex motion. diff --git a/layouts/docs/howto.html b/layouts/docs/howto.html index cc16d8cad0..6aad18385e 100644 --- a/layouts/docs/howto.html +++ b/layouts/docs/howto.html @@ -76,6 +76,7 @@

Javascript

{{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/upload-module/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/manage-modules/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/navigate/") }} + {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/move-robot-arm/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/one-to-many/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/provision-setup/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/how-tos/provision/") }} diff --git a/layouts/docs/tutorials.html b/layouts/docs/tutorials.html index ed2a973ced..b0d69c1c4e 100644 --- a/layouts/docs/tutorials.html +++ b/layouts/docs/tutorials.html @@ -89,7 +89,6 @@

Javascript

{{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/services/navigate-with-rover-base/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/get-started/lazy-susan/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/configure/build-a-mock-robot/") }} - {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/services/accessing-and-moving-robot-arm/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/services/plan-motion-with-arm-gripper/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/services/constrain-motion/") }} {{ partial "tutorialcard-no-js.html" (dict "link" "/tutorials/services/color-detection-scuttle/") }} diff --git a/static/how-tos/joint_positions.mp4 b/static/how-tos/joint_positions.mp4 new file mode 100644 index 0000000000..d4af9a6858 Binary files /dev/null and b/static/how-tos/joint_positions.mp4 differ diff --git a/static/how-tos/joint_positions.webm b/static/how-tos/joint_positions.webm new file mode 100644 index 0000000000..7cbbd898e5 Binary files /dev/null and b/static/how-tos/joint_positions.webm differ diff --git a/static/how-tos/move_to_position.gif b/static/how-tos/move_to_position.gif new file mode 100644 index 0000000000..5f1b29a8b0 Binary files /dev/null and b/static/how-tos/move_to_position.gif differ diff --git a/static/how-tos/move_to_position.mp4 b/static/how-tos/move_to_position.mp4 new file mode 100644 index 0000000000..25d24674b6 Binary files /dev/null and b/static/how-tos/move_to_position.mp4 differ diff --git a/static/how-tos/move_to_position.webm b/static/how-tos/move_to_position.webm new file mode 100644 index 0000000000..a35f0aff39 Binary files /dev/null and b/static/how-tos/move_to_position.webm differ