How to Build a Mock Robot

Instructions for creating a mock robot using just your personal computer so you can try using Viam without any robotic hardware.

Introduction

In this post, we will show you how to build a mock robot using just your personal laptop so you can try using Viam without any robotic hardware. This is a great way to learn how to build robots the Viam way.

Most Viam components come with a fake model that can be useful when testing. These fake components interact with Viam like real hardware, but of course, do not actually exist. We will be using these fake components to build out a mock robot and explore how to use Viam.

In this tutorial, you will set up, control, and program a mock robotic arm and a mock motor sub-part using fake components.

What you’ll need for this guide

  • A laptop or desktop running Linux or macOS.
  • Golang or Python 3.9+.
  • A code editor of your choice.
  • If you are running macOS, ensure you have Homebrew installed and up to date on your Mac.

How to set up a mock robot

Set up your account on the Viam app

The first thing you need to do is set up your account on the Viam App. Go to app.viam.com and sign up.

Configure your mock robot

A screenshot from the Viam app showing the CONFIG tab from the mock robot.

For this tutorial, we will show you how to set up a mock robot with a fake motor and arm.

For each component, you will need to create a new component. For the component Type, select arm/motor. Then you can name them whatever you like (You will need to reference these names later once we connect to your mock robot with the Python SDK). For each Model, select fake, then click new component.

How to install viam-server on your computer

Before you proceed with controlling your mock robot, you are going to need to install viam-server on your development machine.

Follow the steps outlined on the SETUP tab of the Viam app in order to install viam-server on your local computer.

Controlling your mock robot using the Viam app

When you add the fake motor and arm components to your robot, the Viam app automatically generates a UI for your motor and arm under the CONTROL tab.

Screenshot from the Viam app showing the CONTROL tab with the fake arm, and motor components.

If you were configuring a real motor and arm, you would be able to control it from this section of the app. You could do things like control the direction and speed of the motor, and change the joint positions of your robotic arm. However, since we are building a mock robot using fake components, you will only see the robot’s reported positions and speeds change from the UI. You will not be able to see your robot move in the physical world.

Next, you will need to configure your mock robotic arm with the Viam Python SDK so you can write custom logic to control the mock robot.

Controlling your mock robot using a Viam SDK

How to install a Viam SDK

In this step, you are going to install either the Viam Python SDK (Software Development Kit) or the Viam Golang SDK. Use which ever programming language you are most comfortable with.

How to connect to your mock robot with the Viam SDK

The easiest way to get started writing an application with Viam is to navigate to the robot page on the Viam App, select the CODE SAMPLE tab, and copy the boilerplate code from the section labeled Python SDK or Golang SDK. These code snippets import all the necessary libraries and set up a connection with the Viam app in the cloud. Next, paste that boilerplate code from the CODE SAMPLE tab of the Viam app into a file named index.py or index.go file in your code editor, and save your file.

You can now run the code. Doing so will verifies that the Viam SDK is properly installed, that the viam-server instance on your robot is alive, and that the computer running the program is able to connect to that instance.

You can run your code by typing the following into the terminal:

python3 index.py

go run index.go

If you successfully configured your robot and it is able to connect to the Viam app you should see something like this printed to the terminal after running your program. What you see here is a list of the various resources (Like components, and services) that have been configured to your robot in the Viam app.

A screenshot from the Visual Studio Code command line that prints the output of print(robot.resource_names) when your Raspberry Pi has correctly connected and initialized with the Viam App. The output is an array of resources that have been pulled from the Viam App. Some of these are the Vision Service, Data Manager, and Board.

How to control your mock robot

Next, you will be writing some code to control and move your mock robotic arm. We are going to write a program that will move the mock robotic arm into a new random position every second. You will be able to verify that your mock robotic arm is working by checking that the joint positions of the fake arm in the CONTROL tab of the Viam app are changing.

At the top of your index.py file, paste the following:

The first thing you need to do is import the arm component from the Viam Python SDK, and the random and async.io libraries.

from viam.components.arm import ArmClient, JointPositions
import random
import asyncio

The first thing you need to do is import the arm component from the Viam Golang SDK, and the random and time libraries.

import (
  "fmt"
  "math/rand"
  "time"
  componentpb "go.viam.com/api/component/arm/v1"
  "go.viam.com/rdk/components/arm"
)

Next, you will need to initialize your fake robotic arm. In the main function, paste the following, while ensuring that the name of your fake arm matches the arm named in your config file.

arm = ArmClient.from_robot(robot=robot, name='my_main_arm')

myArm, err := arm.FromRobot(robot, "my_main_arm")
if err != nil {
    logger.Fatalf("cannot get arm: %v", err)
}

Now that your mock arm has been initialized, you can write some code to control it.

# Gets a random position for each servo on the arm that is within the safe range of motion of the arm. Returns a new array of safe joint positions.
def getRandoms():
    return [random.randint(-90, 90),
    random.randint(-120, -45),
    random.randint(-45, 45),
    random.randint(-45, 45),
    random.randint(-45, 45)]

# Moves the arm into a new random position every second
async def randomMovement(arm: ArmClient):
    while (True):
        randomPositions = getRandoms()
        newRandomArmJointPositions = JointPositions(values=randomPositions)
        await arm.move_to_joint_positions(newRandomArmJointPositions)
        print(await arm.get_joint_positions())
        await asyncio.sleep(1)
    return

// Returns an array of random floats between two numbers
func getRandoms(min, max float64) []float64 {
    res := make([]float64, 5)
    for i := range res {
        res[i] = min + rand.Float64() * (max - min)
    }
    return res
}

// Moves the arm into a new random position every second
func randomMovement (ctx context.Context, a arm.Arm ) {
  for {
    randomPositions := getRandoms(-90, 90)
    newRandomArmJointPositions := &componentpb.JointPositions{Values: randomPositions}
    a.MoveToJointPositions(ctx, newRandomArmJointPositions, nil)
    fmt.Println(a.JointPositions(ctx, nil))
    time.Sleep(1 * time.Second)
  }
}

You can run this code by invoking this function located below your arm initialization in main. Your main function, should look like this:

async def main():
    robot = await connect()

    print('Resources:')
    print(robot.resource_names)

    arm = ArmClient.from_robot(robot=robot, name='my_main_arm')
    await randomMovement(arm)

    await robot.close()

func main() {
  // Connect to the robot...
  myArm, err := arm.FromRobot(robot, "my_main_arm")
  if err != nil {
    logger.Fatalf("cannot get arm: %v", err)
  }
  randomMovement(context.Background(), myArm)
}

Now when you run this code, you should see the new mock arm positions listed in the command line, if you open the CONTROL tab of your mock robot, you should see the robot’s arm positions changing in real-time along with the code on your development machine.

GIF of a terminal window on the right with 'python3 index.py' being run, then a list of four values is printed each second to the terminal. On the left side, is the mock arm from the CONTROL tab of the Viam app. As the joint positions are updated in the terminal from the left, you can see that the joint positions are updated in realtime on the Viam app.

How to create a mock sub-part

Now that you have your mock robotic arm working, let’s add a mock sub-part to your robot.

What is a part?

A robot in Viam is one or more computers combined into one logical robot. The bounds of a robot are usually pretty clear, but can be subjective. However, it’s possible with Viam to create a robot that is made out of multiple computers. Each of these computer-controlled units is referred to as a part. Most simple robots will have only one part, but can have as many parts as needed.

Parts are organized in a tree, with one of them being the main part, and the others being sub-parts. You can access any sub-part either directly, or via any part above it in the tree. Each part runs a single viam-server instance.

How to configure a sub-part in the Viam app

On your robot’s page on the Viam app, click on the MAIN PART button, name your part and click ADD NEW.

Screenshot of the Viam app with a dropdown below the main part. 'SubPart' is written in the textbox.

You will be creating a mock independent computer-controlled sub-part with a motor. This could be anything, but let’s say for the purpose of this tutorial that this motor controls a conveyor belt in front of our mock arm on an assembly line.

Navigate to your new part’s CONFIG page and create a new motor using the fake model.

How to add your sub-part as a remote

Connecting your sub-part as a remote from your main robot will allow you to control your sub-parts all from one place inside of your main robot.

From the CODE SAMPLE tab of your sub-part:

  • Copy the Config as Remote Part.
  • Navigate back to the CONFIG and then the REMOTES tab of your main robot
  • Paste your sub-part’s configuration.

Screenshot from the Viam App showing the CONFIG > REMOTES with the sub-part's remote config file pasted in.

How to start a new instance of viam-server for your mock sub-part

Since every part needs to run an instance of viam-server, you will need to bind the sub-part to a new port so we can run two servers on your machine at the same time. We are using port 8081, but you can use any open port you want.

You can do this by going to CONFIG and then going to the NETWORK tab. Here, you will paste the following:

{
    "bind_address": "localhost:8081"
}

Be sure to save before continuing.

How to run a second instance of viam-server for your sub-part

Under the CONFIG tab, click COPY VIAM-SERVER CONFIG.

Screenshot from the Viam app showing the 'Copy Viam-Server Config' button highlighted by a red box.

On your local machine, create a new file called viam-sub-part.json, then paste the contents of your server config into that file and save. From the terminal, navigate to the directory where you saved the config file, and run this command to create a new instance of viam-server using this configuration.

viam-server -config viam-sub-part.json

If you have two instances of viam-server running on your local machine, you should be able to see both your main robot arm and your new mock sub motor listed on your main robots CONTROL tab.

Screenshot of Viam app’s Control tab for the main part. List’s the main arm, and the sub motor part.

How to control a sub-part using the Viam SDK

Now that you have your mock sub-part connected as a remote to your main mock robot, you will be able to control all of your robot’s sub-parts with Viam’s Python SDK. In fact, if you run your Python script again, and you review the output of print(robot.resource_names), you will see that your sub-part will now be listed as an available resource for you to use.

To control your motor sub-part, you will need to import the Motor Client. Paste this at the top of your file:

from viam.components.motor import MotorClient

To control your motor sub-part, you will need to import the Motor Client. Paste this at the top of your file:

import (
  "go.viam.com/rdk/components/motor"
)

Now in your main function, you will need to instantiate your mock sub motor. Be sure that your motor’s name matches the one that you have listed in your robot’s resource names.

motor = MotorClient.from_robot(robot=robot, name='sub-part:my_sub_motor')

myMotor, err := motor.FromRobot(robot, "my_sub_motor")
if err != nil {
  logger.Fatalf("cannot get motor: %v", err)
}

Let’s write a function that toggles your mock sub motor on and off every second. You can do that with this function.

# Toggles the motor on and off every second
async def toggleMotor(motor: MotorClient):
    while (True):
        await motor.set_power(1)
        print("go")
        await asyncio.sleep(1)
        await motor.stop()
        print("stop")
        await asyncio.sleep(1)
    return

// Toggles the motor on and off every second
func toggleMotor (ctx context.Context, m motor.Motor) {
  for {
    m.SetPower(ctx, 1, nil)
    fmt.Println("go")
    time.Sleep(1 * time.Second)
    m.Stop(ctx, nil)
    fmt.Println("stop")
    time.Sleep(1 * time.Second)
  }
}

And now, you must invoke your new function. Your main function should look similar to this snippet:

async def main():
    robot = await connect()
    print('Resources:')
    print(robot.resource_names)
    arm = ArmClient.from_robot(robot=robot, name='my_main_arm')
    motor = MotorClient.from_robot(robot=robot, name='sub-part:my_sub_motor')
    await toggleMotor(motor)
    # await randomMovement(arm)
    await robot.close()

func main() {
  // Connect to the robot...
  myMotor, err := motor.FromRobot(robot, "my_sub_motor")
    if err != nil {
    logger.Fatalf("cannot get motor: %v", err)
  }
  toggleMotor(context.Background(), myMotor)

  myArm, err := arm.FromRobot(robot, "my_main_arm")
  if err != nil {
    logger.Fatalf("cannot get arm: %v", err)
  }
  randomMovement(context.Background(), myArm)
}

When you run this code, you will see your mock sub motor toggling between running and idle in real time from the Viam app!

Next Steps

In this tutorial, we showed you how to set up a mock robot with a sub-part so that you can learn more about using fake components, setting up a local development environment, and writing code using a Viam SDK.

If you’re ready to get started with building robots with real hardware components, you should pick up a Raspberry Pi and try building one of Viam’s introductory robots on the tutorials page in our documentation.

If you have any issues or if you want to connect with other developers learning how to build robots with Viam, be sure that you head over to the Viam Community Slack.