Drive a rover in a square in 2 minutes

This is the first of a few quickstarts which will guide you through the concepts you need to know to get started with Viam. In this guide you’ll write code that makes a rover drive in a square.

Error

Requirements

You don’t need to buy or own any hardware to complete this tutorial. You only need the following:

Instructions

Follow these steps to get your rover ready inside the Viam app and write code to control it:

Step 1: Borrow a Viam Rover

Go to Try Viam and borrow a rover. If a rover is available, the rover will take up to 30 seconds to be configured for you.

Step 2: Copy and run the sample code

The sample code on the CONNECT tab will show you how to authenticate and connect to a machine, as well as some of the methods you can use on your configured components and services.

Go to the CONNECT tab and select Python. Save your API key and API key ID as environment variables or include them in the code:

Copy the code into a file called square.py and run the sample code to connect to your machine:

python3 square.py

The program prints an array of resources. These are the components and services that the machine is configured with in the Viam app.

python3 square.py
2024-08-09 13:21:52,423    INFO    viam.rpc.dial (dial.py:293)    Connecting to socket: /tmp/proxy-BzFWLZQ2.sock
Resources:
[<viam.proto.common.ResourceName rdk:service:sensors/builtin at 0x105b12700>, <viam.proto.common.ResourceName rdk:component:motor/left at 0x105b122a0>, <viam.proto.common.ResourceName rdk:component:camera/cam at 0x105b12390>, <viam.proto.common.ResourceName rdk:component:board/local at 0x105b129d0>, <viam.proto.common.ResourceName rdk:component:base/viam_base at 0x105b12610>, <viam.proto.common.ResourceName rdk:service:motion/builtin at 0x105b12a20>, <viam.proto.common.ResourceName rdk:component:encoder/Lenc at 0x105b12a70>, <viam.proto.common.ResourceName rdk:component:motor/right at 0x105b12ac0>, <viam.proto.common.ResourceName rdk:component:encoder/Renc at 0x105b12b10>]
Step 3: Drive a rover in a square

Now that you have connected the rover to Viam with the SDK, you can write code to move the rover in a square:

The base is responsible for controlling the motors attached to the base of the rover. Ensure that the Base class is being imported:

from viam.components.base import Base

Then paste this snippet above your main() function, it will move any base passed to it in a square:

async def moveInSquare(base):
    for _ in range(5):
        # moves the rover forward 500mm at 500mm/s
        await base.move_straight(velocity=500)
        print("move straight")
        # spins the rover 90 degrees at 120 degrees per second
        await base.spin(velocity=100, angle=90)
        print("spin 90 degrees")

Next, remove all the code in the main() function between where the machine connection is established and closed and instead initialize your base and invoke the moveInSquare() function.

On the Try Viam rovers, the default base name is viam_base. If you have a different base name, update the name in your code.

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

    # Get the base component from the rover
    roverBase = Base.from_robot(machine, 'viam_base')

    # Move the rover in a square
    await moveInASquare("roverBase")

    # await machine.close()

If you have a borrowed Try Viam rover, navigate to your machine’s CONTROL tab, which allows you to interact with your machine’s resources.

Click on one of the camera panels and toggle the camera stream on so you can observe the rover’s movements.

Then run your code and watch your rover move in a square.

Step 4: Add a vision service

As you have seen from the CONTROL tab, your rover has cameras. You can use these cameras to adjust your rovers behaviour.

We will start by adding a vision service called color_detector. Go to your machine’s CONFIGURE tab in the Viam app.

Click the add component button and add the color_detector vision service. Configure it to detect dark blue (#1b2c69). Set Hue tolerance to 0.05 and segment size to 100.

Use the TEST panel to check that vision service works as expected.

Step 5: Test your rover's vision

If you haven’t yet, move your rover into the middle of its enclosure.

Start by writing the code to detect the color:

async def check_detections(camera_name, detector):
    detections = await detector.get_detections_from_camera(camera_name)
    print(detections)
    for d in detections:
        if d.confidence > 0.6:
            print("detected")
            return true
    return false

Now we’ll slowly make the rover spin until it detects the configured color.

async def spin_slowly_until_color_detected(base, camera, detector):
    # spins the rover 5 degrees at 10 degrees per second
    white True:
      await base.spins(velocity=100, angle=5)
      print("spin 5 degrees")
      time.sleep(0.1)
      ret = await check_detections(camera, detector)
      if ret:
        return

Once it has found the color, let’s make the rover do a small victory dance by making it move forward and backwards twice and then spinning in a circle for a random time. Since the rover’s victory dance will make the rover lose focus of the color, it will then need to recommence finding its color.

from random import randint

async def victory_dance(base):
    print("performing victory dance")
    await base.move_straight(velocity=500, distance=100)
    await base.move_straight(velocity=500, distance=-100)
    await base.move_straight(velocity=500, distance=100)
    await base.move_straight(velocity=500, distance=-100)

    rand_angle = randint(500,2000)
    print("spinning: {}".format(rand_angle))
    await base.spin(velocity=500, angle=rand_angle)

Use this code in a loop:

import time

    detector = VisionClient.from_robot(machine, "vision-1")

    while True:
      await spin_slowly_until_color_detected(roverBase, "cam", detector)
      await victory_dance(roverBase)
      time.sleep(3)

Next steps

Now that you have run your first code to control a machine running Viam code to control your machine, move to the next quickstart to learn how to configure and control a motor: