Phase 2: Configure the SO-ARM101
In this phase you configure the arm and gripper, verify them with their test cards on the CONTROL tab, then place both in the frame system so the rest of the platform knows where they sit.
Add the discovery service
Rather than typing the arm and gripper configs by hand, start with the SO-ARM101 module’s discovery service. A discovery service reports the hardware attached to a machine and suggests configurations for it, so you configure the right components without hunting for serial ports or attribute names by hand. See Discovery service to learn more about the general pattern.
On the CONFIGURE tab for your Viam machine, click the + icon and select Blocks. Search for so101 and select the so101-arm/discovery result. Leave its name as the default and save the config. Once you save, viam-server downloads the SO-ARM101 module; the arm and gripper models you add later in this phase come from that same module, so the download happens only once.
Before you open the discovery service’s test panel, know what it is looking for: the serial port your SO-ARM101 is connected to over USB.
- On Linux, the port shows up as
/dev/ttyUSB0or/dev/ttyACM0. - On macOS, look under
/dev/tty.*for a name containingusbmodemorusbserial.
With the arm connected and powered, open the discovery service’s TEST panel. It scans for a connected SO-ARM101 and, if it finds one, returns ready-made configuration snippets for the arm and the gripper, with the detected port already filled in.
The discovery service also shows a calibration module. If you have already calibrated your arm, you can ignore it.

Select Add component next to each suggested snippet to create the arm and gripper components from it. If discovery does not find your arm, confirm the USB cable is connected and that no other program is holding the serial port open, then retry.
Save your machine config to enable the new components.
Discovery has done its job
Like the config it suggests, the discovery service is not part of the pack sequence you build later in this workshop. Leave it in place if you expect to re-discover hardware, or remove it once the arm and gripper are configured.
Add the arm component
Confirm the arm component it created has one attribute, port, set to your arm’s serial port:
{
"port": "/dev/ttyUSB0"
}
By default, the discovery service gives your component a name based on the port. Rename it to “arm-1” to match the example code in this tutorial.
By default, the SO-101 module uses a conservative model to describe the arm’s geometry in Viam’s motion planning system. Because this exercise requires moving the arm to precise poses in tight quarters, we recommend using the more precise URDF geometry by adding "use_urdf": true to the JSON configuration.
{
"port": "/dev/ttyUSB0",
"use_urdf": true
}
Open the CONTROL tab and find the arm’s test card. Test cards call the same API your Python code calls later in this workshop; jogging a joint here is a real API call that moves the hardware. Under MoveToJointPositions, move the Joint 0 slider a small amount and press Execute, then watch the physical arm turn.
Checkpoint
Add the gripper component
The gripper is the SO-ARM101’s sixth servo, on the same serial bus as the other five, so instead of its own port, its config points at the arm component.
Update the arm key in the gripper’s configuration JSON to match the name you gave your arm in the previous step, arm-1.
{
"arm": "arm-1"
}
As with the arm, change the component name generated by the discovery service to “gripper-1”.
Open the gripper’s test card on the CONTROL tab. Press Open and watch the jaw open, then press Grab and watch it close.
Checkpoint
arm matches the arm’s name precisely.Place the arm and gripper in the frame system
Adding the arm and gripper tells viam-server how to talk to them, but not where they sit in the cell. The frame system answers that question for every component in the workshop: a frame places a component relative to a parent, and every frame traces back to world. See Frame system for the general concept.
The world frame is the fixed reference point for the whole cell, the origin that every other position is measured from. Every frame in the system traces back to it. Placing the arm’s frame with parent world and translation (0, 0, 0) puts the arm’s base exactly at that origin.
That choice matters for the next phase. Because the arm’s base is the world origin, every world-frame position, including the gripper poses you capture by hand in Phase 3, is measured directly from the arm’s base. You use the arm itself as your measuring tool, and what it reports is directly usable.
Configure the arm
Open the arm’s card on the CONFIGURE tab and select Frame. The default frame already describes parent world, translation (0, 0, 0), and no rotation, so you can leave the defaults and save.
{
"parent": "world",
"translation": { "x": 0, "y": 0, "z": 0 },
"orientation": {
"type": "ov_degrees",
"value": { "x": 0, "y": 0, "z": 1, "th": 0 }
}
}
Configure the gripper
The gripper is a separate component with its own collision geometry, so it needs its own frame to place that geometry in the cell by “attaching” it to the arm. Open the gripper’s card, select Frame, set its parent to arm-1, and leave the translation and rotation at zero:
{
"parent": "arm-1",
"translation": { "x": 0, "y": 0, "z": 0 },
"orientation": {
"type": "ov_degrees",
"value": { "x": 0, "y": 0, "z": 1, "th": 0 }
}
}
The value of “parent” is an identity, not a description. The value must match the name you gave to your arm component in the Viam app.
Attaching the gripper to the arm places its shape in the cell: the 3D scene draws the gripper on the end of the arm, and the motion service accounts for the gripper’s shape when it plans, so it keeps the jaws clear of obstacles.
See it in the 3D scene
Open the 3D scene tab. The arm renders using the kinematics built into the so101/arm model, sitting at the frame you configured, with the gripper attached at its end point. This is the same view you will return to throughout the rest of the workshop to watch the pack sequence run.

Jog a joint on the arm’s test card again and watch the 3D scene update alongside the physical arm.
Checkpoint
arm-1 with zero translation. If the scene is blank, confirm the arm’s frame saved and that the arm shows online in the CONFIGURE tab.With the arm and gripper configured, verified, and placed in the frame system, you are ready for Phase 3, where you map the physical cell, the staging spot and the pallet, into the arm’s frame by hand.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!