|
| 1 | +--- |
| 2 | +title: "Move a robot arm with the arm API" |
| 3 | +linkTitle: "Use the arm API" |
| 4 | +weight: 70 |
| 5 | +type: "docs" |
| 6 | +tags: ["arm", "components"] |
| 7 | +images: ["/how-tos/move_to_position.gif"] |
| 8 | +videos: ["/how-tos/move_to_position.webm", "/how-tos/move_to_position.mp4"] |
| 9 | +description: "Connect to a robotic arm and control it with the arm API." |
| 10 | +aliases: |
| 11 | + - /tutorials/motion/accessing-and-moving-robot-arm |
| 12 | + - /tutorials/motion/ |
| 13 | + - /how-tos/move-robot-arm/ |
| 14 | +languages: ["Python", "Go"] |
| 15 | +viamresources: ["arm"] |
| 16 | +platformarea: ["mobility"] |
| 17 | +level: "Intermediate" |
| 18 | +date: "2024-10-31" |
| 19 | +# updated: "" # When the tutorial was last entirely checked |
| 20 | +cost: "8400" |
| 21 | +--- |
| 22 | + |
| 23 | +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. |
| 24 | + |
| 25 | +{{< alert title="In this page" color="tip" >}} |
| 26 | + |
| 27 | +1. [Access the arm](#access-the-arm) |
| 28 | +1. [Move the arm](#move-the-arm) |
| 29 | + |
| 30 | +{{< /alert >}} |
| 31 | + |
| 32 | +## Requirements |
| 33 | + |
| 34 | +You need the following hardware to complete this tutorial: |
| 35 | + |
| 36 | +- A single-board computer or other computer to run `viam-server`. |
| 37 | +- A Linux, macOS or Windows computer that can run SDK code. |
| 38 | +- A [robotic arm](/components/arm/). |
| 39 | + |
| 40 | +## Access the arm |
| 41 | + |
| 42 | +{{< table >}} |
| 43 | +{{% tablestep link="/configure/" %}} |
| 44 | +**1. Configure a machine with an arm** |
| 45 | + |
| 46 | +{{% snippet "setup.md" %}} |
| 47 | + |
| 48 | +Add an arm component. |
| 49 | +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. |
| 50 | + |
| 51 | +{{<imgproc src="/how-tos/access-arm/config.png" resize="500x" class="fill aligncenter" style="width: 400px" declaredimensions=true alt="Configuration builder UI with a blank arm component">}} |
| 52 | +Save your config. |
| 53 | + |
| 54 | +{{% /tablestep %}} |
| 55 | +{{% tablestep link="/appendix/apis/components/arm/#getendposition" %}} |
| 56 | +**2. Get the position of the end effector** |
| 57 | + |
| 58 | +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. |
| 59 | +The code to get this information is a part of the autogenerated code sample the Viam app provides for your machine. |
| 60 | +Go to the **Code sample** page of the **CONNECT** tab and select either Python or Go. |
| 61 | + |
| 62 | +{{% snippet "show-secret.md" %}} |
| 63 | + |
| 64 | +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/). |
| 65 | +For more information, see [`GetEndPosition`](/appendix/apis/components/arm/#getendposition). |
| 66 | + |
| 67 | +{{% /tablestep %}} |
| 68 | +{{% tablestep %}} |
| 69 | +**3. Get the joint positions** |
| 70 | + |
| 71 | +The state of a robot arm can also be described as the list of positions of each joint attached to the arm. |
| 72 | +To get that information, add the following code right after the code that gets the end effector pose from the prior code sample: |
| 73 | + |
| 74 | +{{< tabs >}} |
| 75 | +{{% tab name="Python" %}} |
| 76 | + |
| 77 | +```python |
| 78 | +# Joint Positions of arm1 |
| 79 | +my_arm_joint_positions = await arm_1.get_joint_positions() |
| 80 | +print(f"myArm get_joint_positions return value: {my_arm_joint_positions}") |
| 81 | +``` |
| 82 | + |
| 83 | +{{% /tab %}} |
| 84 | +{{% tab name="Go" %}} |
| 85 | + |
| 86 | +```go |
| 87 | +// Joint Positions of arm1 |
| 88 | +myArmJointPositions, err := arm1.JointPositions(context.Background(), nil) |
| 89 | +if err != nil { |
| 90 | + logger.Error(err) |
| 91 | + return |
| 92 | +} |
| 93 | +logger.Infof("myArm JointPositions return value:", myArmJointPositions) |
| 94 | +``` |
| 95 | + |
| 96 | +{{% /tab %}} |
| 97 | +{{< /tabs >}} |
| 98 | + |
| 99 | +Run your code again. |
| 100 | +Each individual value corresponds to the current position of a particular joint on your robot. |
| 101 | +You can also see these values reflected on the **CONTROL** tab in the Viam app for your robot arm. |
| 102 | + |
| 103 | +{{% /tablestep %}} |
| 104 | +{{< /table >}} |
| 105 | + |
| 106 | +## Move the arm |
| 107 | + |
| 108 | +The two main options for controlling arm movement are through **joint position commands** and through **pose commands**. |
| 109 | +Joint position commands allow for more detailed control and flexibility instead of commanding movement with the end effector position in a pose command. |
| 110 | + |
| 111 | +{{< alert title="Caution" color="caution" >}} |
| 112 | +Be careful when instructing robot arms to move. |
| 113 | +Before running any code, ensure your robotic arm has enough space and that there are no obstacles. |
| 114 | +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. |
| 115 | +{{< /alert >}} |
| 116 | + |
| 117 | +{{< table >}} |
| 118 | +{{% tablestep %}} |
| 119 | +**1. Initiate motion with a joint position command** |
| 120 | + |
| 121 | +{{< tabs >}} |
| 122 | +{{% tab name="Python" %}} |
| 123 | +Add the following line to your import list to be able to assign values to a `JointPositions` data structure: |
| 124 | + |
| 125 | +```python |
| 126 | +from viam.proto.component.arm import JointPositions |
| 127 | +``` |
| 128 | + |
| 129 | +Add the following code to your script: |
| 130 | + |
| 131 | +```python |
| 132 | +# Command a joint position move: move the forearm of the arm slightly up |
| 133 | +cmd_joint_positions = JointPositions(values=[0, 0, -30.0, 0, 0, 0]) |
| 134 | +await arm_1.move_to_joint_positions(positions=cmd_joint_positions) |
| 135 | +``` |
| 136 | + |
| 137 | +{{% /tab %}} |
| 138 | +{{% tab name="Go" link="/appendix/apis/components/arm/#movetojointpositions" %}} |
| 139 | +Add `armapi "go.viam.com/api/component/arm/v1"` to your import list. |
| 140 | +Add the following code to your script: |
| 141 | + |
| 142 | +```go |
| 143 | +// Command a joint position move: move the forearm of the arm slightly up |
| 144 | +cmdJointPositions := &armapi.JointPositions{Values: []float64{0.0, 0.0, -30.0, 0.0, 0.0, 0.0}} |
| 145 | +err = arm1.MoveToJointPositions(context.Background(), cmdJointPositions, nil) |
| 146 | +if err != nil { |
| 147 | + logger.Error(err) |
| 148 | + return |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +{{% /tab %}} |
| 153 | +{{< /tabs >}} |
| 154 | + |
| 155 | +{{<gif webm_src="/how-tos/joint_positions.webm" mp4_src="/how-tos/joint_positions.mp4" alt="The robot arm moving through joint position commands" max-width="200px" class="alignleft">}} |
| 156 | + |
| 157 | +Run the code. |
| 158 | +The third joint of your arm should move 30 degrees. |
| 159 | +For more information, see [`MoveToJointPositions`](/appendix/apis/components/arm/#movetojointpositions). |
| 160 | + |
| 161 | +{{% /tablestep %}} |
| 162 | +{{% tablestep link="/appendix/apis/components/arm/#movetoposition" %}} |
| 163 | +**2. Command to move to position** |
| 164 | + |
| 165 | +{{< tabs >}} |
| 166 | +{{% tab name="Python" %}} |
| 167 | + |
| 168 | +Add the following code to your script: |
| 169 | + |
| 170 | +```python |
| 171 | +# Generate a simple pose move +100mm in the +Z direction of the arm |
| 172 | +cmd_arm_pose = await arm_1.get_end_position() |
| 173 | +cmd_arm_pose.z += 100.0 |
| 174 | +await arm_1.move_to_position(pose=cmd_arm_pose) |
| 175 | +``` |
| 176 | + |
| 177 | +{{% /tab %}} |
| 178 | +{{% tab name="Go" %}} |
| 179 | +Add `"go.viam.com/rdk/spatialmath"` to your import list. |
| 180 | + |
| 181 | +Add the following code to your script: |
| 182 | + |
| 183 | +```go |
| 184 | +// Generate a simple pose move +100mm in the +Z direction of the arm |
| 185 | +currentArmPose, err := arm1.EndPosition(context.Background(), nil) |
| 186 | +if err != nil { |
| 187 | + logger.Error(err) |
| 188 | + return |
| 189 | +} |
| 190 | +adjustedArmPoint := currentArmPose.Point() |
| 191 | +adjustedArmPoint.Z += 100.0 |
| 192 | +cmdArmPose := spatialmath.NewPose(adjustedArmPoint, currentArmPose.Orientation()) |
| 193 | + |
| 194 | +err = arm1.MoveToPosition(context.Background(), cmdArmPose, nil) |
| 195 | +if err != nil { |
| 196 | + logger.Error(err) |
| 197 | + return |
| 198 | +} |
| 199 | +``` |
| 200 | + |
| 201 | +{{% /tab %}} |
| 202 | +{{< /tabs >}} |
| 203 | + |
| 204 | +{{<gif webm_src="/how-tos/move_to_position.webm" mp4_src="/how-tos/move_to_position.mp4" alt="A robot arm moving to a commanded position" max-width="200px" class="alignright">}} |
| 205 | + |
| 206 | +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. |
| 207 | +Run the code to see your arm move 100 mm upwards. |
| 208 | +For more information, see [`MoveToPosition`](/appendix/apis/components/arm/#movetoposition). |
| 209 | + |
| 210 | +{{% /tablestep %}} |
| 211 | +{{< /table >}} |
| 212 | + |
| 213 | +## Next steps |
| 214 | + |
| 215 | +{{< cards >}} |
| 216 | +{{% card link="/tutorials/services/plan-motion-with-arm-gripper" %}} |
| 217 | +{{% card link="/tutorials/projects/claw-game/" %}} |
| 218 | +{{< /cards >}} |
| 219 | + |
| 220 | +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). |
0 commit comments