This is a Viam module for the SO-101 5-DOF + Gripper collaborative robotic arm designed by TheRobotStudio and HuggingFace. It can be used to control either the leader or follower arm, as well as configuring both has separate arm components for mirrored teleoperation!
Note
For more information on modules, see Modular Resources.
This SO-101 module is particularly useful in applications that require the SO-101 arm to be operated in conjunction with other resources (such as cameras, sensors, actuators, CV) offered by the Viam Platform and/or separately through your own code.
Navigate to the CONFIGURE tab of your machine's page in the Viam app. Click the + icon next to your machine part in the left-hand menu and select Component. Select the arm
type, then search for and select the arm / devrel:so101:arm
model. Click Add module, then enter a name or use the suggested name for your arm and click Create.
Note
Before configuring your SO-101, you must add a machine.
The arm component controls the first 5 joints of the SO-101: shoulder_pan, shoulder_lift, elbow_flex, wrist_flex, and wrist_roll.
{
"port": "/dev/ttyUSB0",
"baudrate": 1000000,
"calibration_file": "/path/to/calibration.json"
}
The following attributes are available for the arm component:
Name | Type | Inclusion | Description |
---|---|---|---|
port |
string | Required | The serial port for communication with the SO-101 (e.g., /dev/ttyUSB0 , /dev/ttyACM0 ). |
baudrate |
int | Optional | The baud rate for serial communication. Default is 1000000 . |
servo_ids |
[]int | Optional | List of servo IDs for the arm joints. Default is [1, 2, 3, 4, 5] . |
timeout |
duration | Optional | Communication timeout. Default is system default. |
calibration_file |
string | Optional | Path to the calibration file. If not provided, uses default calibration values. |
The SO-101 uses serial communication over USB with Feetech STS3215 servos. The module uses a shared controller architecture to manage all 6 servos while preventing resource conflicts when both arm and gripper components are used.
The module provides several custom commands accessible through the DoCommand
interface:
Enable or disable joint torque:
{
"command": "set_torque",
"enable": true
}
Test communication with all servos:
{
"command": "ping"
}
Check the shared controller status for debugging:
{
"command": "controller_status"
}
Run comprehensive connection diagnostics:
{
"command": "diagnose"
}
Verify servo configuration and communication:
{
"command": "verify_config"
}
Reinitialize servo communication with retry attempts:
{
"command": "reinitialize",
"retries": 3
}
Test communication and read positions from arm servos:
{
"command": "test_servo_communication"
}
Reload calibration from file:
{
"command": "reload_calibration"
}
Retrieve current calibration data:
{
"command": "get_calibration"
}
The gripper component controls the 6th servo of the SO-101, which functions as a parallel gripper.
{
"port": "/dev/ttyUSB0",
"baudrate": 1000000,
"servo_id": 6,
"calibration_file": "/path/to/calibration.json"
}
Name | Type | Inclusion | Description |
---|---|---|---|
port |
string | Required | The serial port for communication with the SO-101. |
baudrate |
int | Optional | The baud rate for serial communication. Default is 1000000 . |
servo_id |
int | Optional | The servo ID for the gripper. Default is 6 . |
timeout |
duration | Optional | Communication timeout. Default is system default. |
calibration_file |
string | Optional | Path to the calibration file (shared with arm component). |
The gripper component provides several custom commands:
Get the current gripper position:
{
"command": "get_position"
}
Set the gripper to a specific servo position:
{
"command": "set_position",
"servo_position": 2000
}
Check the shared controller status:
{
"command": "controller_status"
}
The SO-101 requires calibration to map servo positions to joint angles based on how the arm was assembled.
The SO-101 Calibration Sensor provides a calibration workflow integrated into Viam's component system. It guides you through the calibration process using DoCommand calls and provides status updates through sensor readings.
{
"port": "/dev/ttyUSB0",
"calibration_file": "my_awesome_arm.json",
}
Name | Type | Required | Description |
---|---|---|---|
port |
string | Required | Serial port for servo communication (e.g., /dev/ttyUSB0 ) |
baudrate |
int | Optional | Serial communication speed. Default: 1000000 |
servo_ids |
[]int | Optional | List of servo IDs to calibrate. Default: [1,2,3,4,5] (arm only) |
calibration_file |
string | Optional | Path where calibration will be saved. If relative path, uses $VIAM_MODULE_DATA directory. Default: "so101_calibration.json" |
timeout |
duration | Optional | Communication timeout. Default: "5s" |
Example output:
{
"calibration_state": "range_recording",
"instruction": "Recording range of motion. Move all joints through their full ranges.",
"available_commands": ["stop_range_recording", "abort"],
"servo_count": 5,
"recording_time_seconds": 15.3,
"position_samples": 306,
"joints": {
"shoulder_pan": {
"id": 1,
"current_position": 2150,
"homing_offset": -103,
"recorded_min": 758,
"recorded_max": 3292,
"is_completed": false
}
}
}
{
"command": "command_name"
}
Command | Description | Required State |
---|---|---|
start |
Begin calibration workflow | idle , completed , error |
set_homing |
Set homing offsets and write to servo registers | started |
start_range_recording |
Begin recording servo ranges | homing_position |
stop_range_recording |
Complete range recording | range_recording |
save_calibration |
Write limits to servos and save file | completed |
abort |
Cancel calibration | Any |
reset |
Reset to initial state | error |
Command | Description |
---|---|
get_current_positions |
Read current servo positions |
The calibration sensor also provides motor setup commands for initial SO-101 servo configuration. These commands implement the systematic motor setup process described in MOTOR_SETUP.md
and are separate from the calibration workflow.
Command | Description | Parameters |
---|---|---|
motor_setup_discover |
Discover a single motor connected to the bus | motor_name (string): Motor name (e.g., "gripper", "wrist_roll") |
motor_setup_assign_id |
Assign target ID and baudrate to discovered motor | motor_name (string), current_id (int), target_id (int), current_baudrate (int) |
motor_setup_verify |
Verify all SO-101 motors are properly configured | None |
motor_setup_scan_bus |
Scan the entire bus for connected servos | None |
motor_setup_reset_status |
Reset motor setup status | None |
The motor setup process should be performed in reverse order (gripper → shoulder_pan) to avoid ID conflicts:
- Connect only one motor (e.g., gripper) to the controller
- Discover:
{"command": "motor_setup_discover", "motor_name": "gripper"}
- Assign ID:
{"command": "motor_setup_assign_id", "motor_name": "gripper", "current_id": 1, "target_id": 6, "current_baudrate": 57600}
- Repeat for each motor in order: wrist_roll → wrist_flex → elbow_flex → shoulder_lift → shoulder_pan
- Verify:
{"command": "motor_setup_verify"}
(connect all motors)
Motor setup status is included in sensor readings:
{
"motor_setup": {
"in_progress": false,
"step": 0,
"status": "Motor setup ready"
}
}
The calibration sensor operates as a state machine:
idle
: Ready to start calibrationstarted
: Torque disabled, ready for homing positionhoming_position
: Homing set, ready for range recordingrange_recording
: Recording min/max positionscompleted
: Calibration data ready to saveerror
: Error occurred, use reset command
The sensor saves calibration in the standard format:
{
"shoulder_pan": {
"id": 1,
"drive_mode": 0,
"homing_offset": -1470,
"range_min": 758,
"range_max": 3292,
"norm_mode": 3
},
"shoulder_lift": {
"id": 2,
"drive_mode": 0,
"homing_offset": 157,
"range_min": 612,
"range_max": 3401,
"norm_mode": 3
},
"gripper": {
"id": 6,
"drive_mode": 0,
"homing_offset": 1407,
"range_min": 2031,
"range_max": 3476,
"norm_mode": 1
}
}
- Range recording not working: Ensure you call
start_range_recording
and manually move joints - Invalid ranges: Move joints through their complete range of motion
- Servo communication errors: Check port, baudrate, and servo connections
- Permission denied: Ensure proper access to serial port (
sudo chmod 666 /dev/ttyUSB0
)
-
Serial Connection Failed:
- Check that the USB cable is properly connected
- Verify the correct port (Linux:
/dev/ttyUSB0
,/dev/ttyACM0
; Windows:COM3
,COM4
, etc.) - Ensure no other applications are using the serial port
- Check USB permissions on Linux:
sudo chmod 666 /dev/ttyUSB0
-
Servo Communication Errors:
- Verify servo IDs are correctly configured (1-6)
- Check calibration file path and format
- Use the
diagnose
DoCommand for detailed diagnostics - Try reinitializing with the
reinitialize
DoCommand
-
Shared Controller Conflicts:
- Check controller status using the
controller_status
DoCommand - Ensure consistent configuration across arm and gripper components
- Verify the same serial port and baudrate are used
- Restart components if configuration changes are needed
- Check controller status using the
- Power: Connect the properly rated power adapter to the arm's controller board, either 5-7.4V or 12V depending on your servos
- USB Communication: Connect the USB cable between the controller board and your computer
- Servo Connections: Ensure all servos are properly daisy-chained with 3-pin cables
- Initial Position: Manually position the arm in a safe configuration before powering on
Warning
- Always ensure the arm's workspace is clear before operation
- The arm can move quickly - maintain safe distances during operation
- Use the torque control features to enable safe manual positioning when needed
- Proper calibration is essential for safe operation within expected ranges
This module includes a web-based setup application that provides guided workflows for configuring your SO-101 robotic arm. The application is hosted as a Viam App and automatically deployed with each module version.
Access the Setup App: https://so101-setup_devrel.viamapplications.com
The setup application provides three main workflows to guide you through different aspects of SO-101 configuration:
Complete setup workflow from unboxed hardware to fully configured and calibrated SO-101 arm. This comprehensive process includes:
- Hardware connection verification
- Motor ID configuration for all servos (1-6)
- Joint calibration with homing positions and range limits
- Final system testing and validation
Configure servo IDs and communication parameters for SO-101 motors. Use this workflow when you need to:
- Set up servos with proper IDs (1-6) from factory defaults
- Configure communication baudrate (1,000,000 bps)
- Verify motor connectivity and response
- Resolve servo ID conflicts
Calibrate joint ranges and homing positions for arms with already configured motors. This workflow covers:
- Setting homing positions for all joints
- Recording joint range limits through guided manual movement
- Saving calibration data in the proper format
- Verifying calibration accuracy
- Connect to your robot: The app integrates directly with your Viam machine through the Viam SDK
- Select your workflow: Choose from Full Setup, Motor Setup Only, or Calibration Only
- Follow guided steps: The application provides clear instructions and real-time feedback
- Save configuration: Calibration data is automatically saved and applied to your SO-101 components
The setup application provides an intuitive alternative to the DoCommand-based calibration workflow described in the devrel:so101:calibration
component documentation above.
For more information about the SO-101 robotic arm: