Add a servo | Add a component

Add a servo

Add a servo to your machine’s configuration so you can control its angular position from the Viam app and from code.

Concepts

A servo moves to a specific angle (typically 0-180 degrees) and holds that position. Continuous-rotation servos also exist; they use the same Move API, but the angle value maps to speed and direction rather than absolute position. Check the specific servo model’s reference page for how it interprets the value.

The built-in gpio servo model uses a single PWM-capable pin on a board component. Other servo models in the registry support serial, I2C, or dedicated servo-driver boards.

Search for servo in the Viam registry to see available models.

Built-in models

Micro-RDK:

Registry modules

Viam-maintained servo modules:

Module Servos supported
viam:raspberry-pi rpi-servo model for hobby servos on Raspberry Pi variants

For servos not covered above, search for servo in the Viam registry.

Steps

1. Prerequisites

2. Add a servo component

  1. Click the + button.
  2. Select Blocks.
  3. For a standard hobby servo controlled by a PWM pin on your board, search for gpio servo.
  4. Name your servo (for example, pan-servo) and click Add to machine.

3. Configure servo attributes

{
  "board": "my-board",
  "pin": "12"
}
Attribute Type Required Description
board string Yes Name of the board component.
pin string Yes GPIO pin for the servo signal wire.
min_angle_deg float No Minimum angle. Default: 0.
max_angle_deg float No Maximum angle. Default: 180.
starting_position_deg float No Position on startup. Default: 0.
frequency_hz int No PWM frequency. Default: 300. Most servos expect 50-330 Hz.

If your servo doesn’t reach its full range or jitters at the extremes, adjust the pulse width:

Attribute Type Description
min_width_us int Minimum pulse width in microseconds (>450).
max_width_us int Maximum pulse width in microseconds (<2500).

4. Save and test

Click Save, then expand the Test section.

Try it

Sweep the servo through a range of positions.

To get the credentials for the code below, go to your machine’s page in the Viam app, click the CONNECT tab, and select API keys. Copy the Key and ID. Then click the CONFIGURE tab, and click Details, and copy the Remote address. If you’re using real hardware, you’ll see the servo sweep through positions when you run the code below.

Install the Viam Python SDK in a virtual environment by following Install the Python SDK.

Save this as servo_test.py:

import asyncio
from viam.robot.client import RobotClient
from viam.components.servo import Servo

async def main():
    opts = RobotClient.Options.with_api_key(
        api_key="YOUR-API-KEY",
        api_key_id="YOUR-API-KEY-ID"
    )
    robot = await RobotClient.at_address("YOUR-MACHINE-ADDRESS", opts)

servo = Servo.from_robot(robot, "pan-servo")

# Sweep through positions
    for angle in [0, 45, 90, 135, 180]:
        await servo.move(angle)
        current = await servo.get_position()
        print(f"Moved to {angle}°, position reads {current}°")
        await asyncio.sleep(0.5)

# Return to center
    await servo.move(90)
    print("Returned to 90°")

await robot.close()

if __name__ == "__main__":
    asyncio.run(main())

Run it:

python servo_test.py

Save this as main.go:

package main

import (
    "context"
    "fmt"
    "time"

"go.viam.com/rdk/components/servo"
    "go.viam.com/rdk/logging"
    "go.viam.com/rdk/robot/client"
)

func main() {
    ctx := context.Background()
    logger := logging.NewLogger("servo-test")

robot, err := client.New(ctx, "YOUR-MACHINE-ADDRESS", logger,
        client.WithDialOptions(client.WithEntityCredentials(
            "YOUR-API-KEY-ID",
            client.Credentials{
                Type:    client.CredentialsTypeAPIKey,
                Payload: "YOUR-API-KEY",
            })),
    )
    if err != nil {
        logger.Fatal(err)
    }
    defer robot.Close(ctx)

s, err := servo.FromProvider(robot, "pan-servo")
    if err != nil {
        logger.Fatal(err)
    }

// Sweep through positions
    for _, angle := range []uint32{0, 45, 90, 135, 180} {
        if err := s.Move(ctx, angle, nil); err != nil {
            logger.Fatal(err)
        }
        position, err := s.Position(ctx, nil)
        if err != nil {
            logger.Fatal(err)
        }
        fmt.Printf("Moved to %d°, position reads %d°\n", angle, position)
        time.Sleep(500 * time.Millisecond)
    }

// Return to center
    if err := s.Move(ctx, 90, nil); err != nil {
        logger.Fatal(err)
    }
    fmt.Println("Returned to 90°")
}

Run it:

go run main.go

Troubleshooting

Servo jitters or buzzes
Servo doesn't reach full range
Servo doesn't respond

If your servo is not working as expected, follow these steps:

  1. Check your machine logs on the LOGS tab to check for errors.
  2. Review this servo model’s documentation to ensure you have configured all required attributes.
  3. Check that all wires are securely attached to the correct pins on the board.
  4. Click on the TEST panel on the CONFIGURE or CONTROL tab and test if you can use the servo there.

If none of these steps work, reach out to us on the Community Discord and we will be happy to help.