Control a motor in 2 minutes | Tutorial

Control a motor in 2 minutes

In this guide you’ll configure and control a motor.

You will learn

Requirements

You don’t need to buy or own any hardware to complete this tutorial.

If you have the following components, you can follow along on your own hardware:

Make sure to wire your motor to your board before starting. Power the board on if you want to test your machine while configuring it.

No motor at hand? No problem. If you do not have both a board and motor, install viam-server on your laptop or computer and follow the instructions to use a fake motor, which is a model that serves for testing.

Step 1: Device setup

  1. Create a Viam account and log in.

Navigate to Viam in a web browser. Create a free account and log in.

  1. Navigate to your first location.

Click FLEET in the upper-left corner of the page and click LOCATIONS. Then select the First Location.

Viam automatically created an organization for you and a location called First Location. You can create more organizations and locations to organize your machines, but for this guide you can use the automatically created ones.

  1. Create a new machine.

Click + Add machine to create your first machine and name it motor-controller.

A machine represents at least one computer running viam-server along with all the hardware components and software services that the computer controls.

  1. Install viam-server.

On the machine’s page, follow the setup instructions to install viam-server on the computer you’re using for your project. If you can choose an installation method, use viam-agent.

Wait until your machine has successfully connected to Viam.

By installing viam-server on your device, you’ve turned your computer into a Viam machine.

At this point, your machine only runs the Viam software. To make your machine control a motor, you must add a motor component and a board component for the board that controls the motor.

Step 2: Configure a board

On the CONFIGURE page you can add components and services to your machine. Click on the + icon to select a suitable board.

If you are using a physical board to follow along, look through the Supported Models to determine the model of component to configure. For example, configure a viam:raspberry-pi:rpi board for a Raspberry Pi 4, Raspberry Pi 3 or Raspberry Pi Zero 2 W:

If you do not have a physical board, use the fake board model.

Follow the instructions in the board model’s documentation to configure any required attributes. For the fake model, there are no required attributes.

Step 3: Configure a motor

Add a motor component that supports the type of motor and motor driver you’re using. Look through the Supported Models to determine the model of component to configure. For example, if you are using a standard DC motor (brushed or brushless) wired to a typical GPIO pin-controlled motor driver, configure a gpio motor.

Follow the motor driver manufacturer’s data sheet to wire your motor driver to your board and to your motor. Follow the model’s documentation to configure the attributes so that the computer can send signals to the motor.

If you do not have a physical motor, use the fake motor model. For the fake model, there are no required attributes.

Save your configuration.

Step 4: Choose how you will control the motor

You can control your motor directly using the web UI, the mobile app, or the SDKs.

Option 1: Control from the app

Navigate to your machine’s CONTROL tab and click on the motor panel. Then use the Power % slider to set the motor’s speed. Use the Backwards and Forwards buttons to change the direction.

Option 2: Control from the mobile app

You can use the Viam mobile app to control your motor’s speed and direction directly from your smart phone.

Open the Viam mobile app and log in to your account. Select the location that your machine is in from the Locations tab.

Choose your machine from the list and use the mobile interface to adjust the motor settings.

Option 3: Control programmatically

Each component has a standardized API. The following code shows you how to control the motor’s speed and direction using the Motor API.

If you’d like to try it, find your machine’s API key and address on your machine’s CONNECT tab and run the code sample:

import asyncio
import time

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

async def connect():
    opts = RobotClient.Options.with_api_key(
        # TODO: Replace "<API-KEY>" (including brackets) with your machine's
        # API key
        api_key='<API-KEY>',
        # TODO: Replace "<API-KEY-ID>" (including brackets) with your machine's
        # API key ID
        api_key_id='<API-KEY-ID>'
    )
    # TODO: Replace "<MACHINE-ADDRESS>" with address from the CONNECT tab.
    return await RobotClient.at_address("<MACHINE-ADDRESS>", opts)

async def main():
    async with await connect() as machine:
        print('Resources:')
        print(machine.resource_names)

# Instantiate the motor client
        motor_1 = Motor.from_robot(machine, "motor-1")
        # Turn the motor at 35% power forwards
        await motor_1.set_power(power=0.35)
        # Let the motor spin for 3 seconds
        time.sleep(3)
        # Stop the motor
        await motor_1.stop()

if __name__ == '__main__':
    asyncio.run(main())
package main

import (
  "context"
  "time"

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

func main() {
  logger := logging.NewDebugLogger("client")
  machine, err := client.New(
    context.Background(),
    // TODO: Replace "<MACHINE-ADDRESS>" with address from the CONNECT tab.
    "<MACHINE-ADDRESS>",
    logger,
    client.WithDialOptions(client.WithEntityCredentials(
      // TODO: Replace "<API-KEY-ID>" (including brackets) with your machine's
      // API key ID
      "<API-KEY-ID>",
      client.Credentials{
        Type:    client.CredentialsTypeAPIKey,
        // TODO: Replace "<API-KEY>" (including brackets) with your machine's
        // API key
        Payload: "<API-KEY>",
      }),
    ),
  )
  if err != nil {
    logger.Fatal(err)
  }

defer machine.Close(context.Background())
  logger.Info("Resources:")
  logger.Info(machine.ResourceNames())

// Instantiate the motor client
  motor1Component, err:= motor.FromProvider(machine, "motor-1")
  if err != nil {
    logger.Error(err)
    return
  }
  // Turn the motor at 35% power forwards
  err = motor1Component.SetPower(context.Background(), 0.35, nil)
  if err != nil {
    logger.Error(err)
    return
  }
  // Let the motor spin for 3 seconds
  time.Sleep(3 * time.Second)
  // Stop the motor
  err = motor1Component.Stop(context.Background(), nil)
  if err != nil {
    logger.Error(err)
    return
  }
}
#include <boost/optional.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <unistd.h>
#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/components/motor.hpp>

using namespace viam::sdk;

int main() {
    // Every Viam C++ SDK program must have one and only one Instance object which is created
    // before
    // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
    Instance inst;

std::string host("<MACHINE-ADDRESS>");
    DialOptions dial_opts;
    dial_opts.set_entity(std::string("<API-KEY-ID>"));
    // Replace "<API-KEY-ID>" (including brackets) with your machine's
    // API key ID
    Credentials credentials("api-key", "<API-KEY>");
    // Replace "<API-KEY>" (including brackets) with your machine's API key
    dial_opts.set_credentials(credentials);
    boost::optional<DialOptions> opts(dial_opts);
    Options options(0, opts);

auto machine = RobotClient::at_address(host, options);

std::cout << "Resources:\n";
    for (const Name& resource : machine->resource_names()) {
        std::cout << "\t" << resource << "\n";
    }

std::string motor_name("motor-1");

std::cout << "Getting motor: " << motor_name << std::endl;
    std::shared_ptr<Motor> motor;
    try {
        // Get the motor client
        motor = machine->resource_by_name<Motor>(motor_name);
        // Turn the motor at 35% power forwards
        motor->set_power(0.35);
        // Let the motor spin for 3 seconds
        sleep(3);
        // Stop the motor
        motor->stop();
    } catch (const std::exception& e) {
        std::cerr << "Failed to find " << motor_name << ". Exiting." << std::endl;
        throw;
    }
    return EXIT_SUCCESS;
}

Next steps

You now know how to build a machine that controls two components.

For a more elaborate tutorial using more components, see the Try Viam tutorial.