Add a motor | Add a component

Add a motor

Add a motor to your machine’s configuration so you can control it from the Viam app and from code.

Concepts

The motor API gives you SetPower, GoFor (rotate a number of revolutions at a given speed), GoTo (move to an absolute position), and Stop. Other models exist as modules for network-controlled motors and specific motor controllers. Search for motor in the Viam registry to see available models.

This page covers the gpio model, which controls a motor through a motor driver wired to GPIO pins on a board. You need to add a board first.

GPIO motor drivers typically use one of two wiring schemes:

Built-in models

Micro-RDK:

Registry modules

Viam-maintained motor modules:

Module Motors supported
viam:analog-devices Stepper motors through the Analog Devices TMC5072 driver
viam:odrive ODrive brushless motor controllers (serial)
viam:uln2003 28BYJ-48 stepper motor through the ULN2003 driver

For motors not covered above, search for motor in the Viam registry.

Steps

1. Prerequisites

2. Add a motor component

  1. Click the + button.
  2. Select Blocks.
  3. Search for the motor model that matches your hardware:
    • For a brushed DC motor controlled through a motor driver with GPIO pins, search for gpio motor.
    • For a stepper motor controlled through a stepper driver with GPIO pins, search for gpiostepper.
    • For other motor types, search by your motor driver or manufacturer name.
  4. Name your motor (for example, left-motor) and click Add to machine.

3. Configure motor attributes

The gpio model requires you to specify the board and pin mappings.

A/B mode (for example, L298N driver):

{
  "board": "my-board",
  "max_rpm": 200,
  "pins": {
    "a": "11",
    "b": "13",
    "pwm": "15"
  }
}

PWM/DIR mode:

{
  "board": "my-board",
  "max_rpm": 200,
  "pins": {
    "dir": "11",
    "pwm": "13"
  }
}
Attribute Type Required Description
board string Yes Name of the board component.
max_rpm int Yes Estimated max RPM under no load. Used to calculate speed for GoFor.
pins object Yes GPIO pin mappings (see wiring modes above).
dir_flip bool No Reverse forward/backward direction. Default: false.
pwm_freq int No PWM frequency in Hz. Default: 800.
min_power_pct float No Minimum power to spin the motor (0.0-1.0). Default: 0.0.
max_power_pct float No Maximum power cap (0.06-1.0). Default: 1.0.

If you have an encoder attached, also set:

Attribute Type Description
encoder string Name of the encoder component.
ticks_per_rotation int Encoder ticks per full motor shaft rotation.

4. Save and test

Click Save, then expand the Test section for the motor.

Try it

Spin the motor forward for 2 revolutions, then check if it’s still moving.

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 motor spin when you run the code below. Without an encoder, position readings will be estimates based on time and max RPM.

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

Save this as motor_test.py:

import asyncio
from viam.robot.client import RobotClient
from viam.components.motor import Motor

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)

motor = Motor.from_robot(robot, "left-motor")

# Spin at 60 RPM for 2 revolutions
    await motor.go_for(rpm=60, revolutions=2)

moving = await motor.is_moving()
    print(f"Motor is moving: {moving}")

position = await motor.get_position()
    print(f"Motor position: {position} revolutions")

await motor.stop()
    print("Motor stopped")

await robot.close()

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

Run it:

python motor_test.py
mkdir motor-test && cd motor-test
go mod init motor-test
go get go.viam.com/rdk

Save this as main.go:

package main

import (
    "context"
    "fmt"

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

func main() {
    ctx := context.Background()
    logger := logging.NewLogger("motor-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)

m, err := motor.FromProvider(robot, "left-motor")
    if err != nil {
        logger.Fatal(err)
    }

// Spin at 60 RPM for 2 revolutions
    if err := m.GoFor(ctx, 60, 2, nil); err != nil {
        logger.Fatal(err)
    }

moving, err := m.IsMoving(ctx)
    if err != nil {
        logger.Fatal(err)
    }
    fmt.Printf("Motor is moving: %v\n", moving)

position, err := m.Position(ctx, nil)
    if err != nil {
        logger.Fatal(err)
    }
    fmt.Printf("Motor position: %.2f revolutions\n", position)

if err := m.Stop(ctx, nil); err != nil {
        logger.Fatal(err)
    }
    fmt.Println("Motor stopped")
}

Run it:

go run main.go

Troubleshooting

Motor doesn't spin
Motor spins the wrong direction
GoFor doesn't stop at the right position

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

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

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