Previous
Input controller
Add a motor to your machine’s configuration so you can control it from the Viam app and from code.
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. Browse available motor models in the Viam registry.
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:
left-motor) and click Create.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. |
Click Save, then expand the TEST section for the motor.
max_rpm and have an encoder, try GoFor to rotate a
specific number of revolutions.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 SDK code sample. Toggle Include API key on. Copy the machine address, API key, and API key ID from the code sample. 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.
pip install viam-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"
"go.viam.com/rdk/utils"
)
func main() {
ctx := context.Background()
logger := logging.NewLogger("motor-test")
robot, err := client.New(ctx, "YOUR-MACHINE-ADDRESS", logger,
client.WithCredentials(utils.Credentials{
Type: utils.CredentialsTypeAPIKey,
Payload: "YOUR-API-KEY",
}),
client.WithAPIKeyID("YOUR-API-KEY-ID"),
)
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
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!