Navigate with a Rover Base

One key feature of Viam is the navigation service, the stateful definition of Viam’s motion service.

Using Navigation, you can queue up user-defined waypoints and your robot will move to them in the order that you specify. You can also add obstacles or set linear and angular velocity targets in your navigation service config. Viam’s motion planner will plan routes that avoid those obstacles and attempt to keep the robot at your specified velocity.

To try it out yourself, you need a mobile base and a movement sensor that can track the robot’s GPS coordinates and angular and linear velocity. Follow this tutorial to get started using Viam’s Navigation service to help your wheeled base navigate across space with our recommended stack.

Requirements

  1. A base

    We used a LEO rover, configured as a wheeled base, but you can use whatever model of rover base you have on hand:

    Leo rover that is navigating using the navigation service in a robotics lab.
  2. A movement sensor with GPS position, compass heading, and angular and linear velocity readings

    We used three movement sensors to satisfy these requirements:

    1. A SparkFun GPS-RTK-SMA Breakout movement sensor configured as a gps-nmea-rtk-serial model, providing GPS position and compass heading measurements.
    2. A wheeled-odometry model gathering angular and linear velocity information from the encoders wired to our base’s motors.
    3. A merged model aggregating the readings together for the navigation service to consume.

    You can use any combo of movement sensors you want as long as you are getting all the types of measurements required. See the navigation service for more info on movement sensor requirements.

Before you start, make sure to create a machine in the Viam app and install viam-server on your robot.

Configure the components you need

First, configure the components of your robot.

Click to see how we configured our LEO rover

Configure movement sensors

  1. Configure a GPS movement sensor so the robot knows where it is while navigating. We configured ours as a gps-nmea-rtk-serial movement sensor:

    An example configuration for a GPS movement sensor in the Viam app Config Builder.

    We named ours gps. Refer to the gps-nmea-rtk-serial movement sensor documentation for attribute information.

  2. Configure a wheeled odometry movement sensor to provide angular and linear velocity measurements from the encoded motors on our base.

    An example configuration for a wheeled-odometry movement sensor in the Viam app Config Builder.

    We named ours enc-linear. Refer to the wheeled-odometry movement sensor documentation for attribute information.

  3. Now that you’ve got movement sensors which can give you GPS position and linear and angular velocity readings, configure a merged movement sensor to aggregate the readings from our other movement sensors into a singular sensor:

    An example configuration for a merged movement sensor in the Viam app Config Builder.

    We named ours merged. Refer to the merged movement sensor documentation for attribute information.

    • Make sure your merged movement sensor is configured to gather "position" readings from the gps movement sensor.

    • Configure the frame system for this movement sensor so that the navigation service knows where it is in relation to the base.

      • Switch to Frame mode on the CONFIGURE tab and select your movement sensor. If your movement sensor is mounted on top of the rover like ours is, set Orientation’s third input field, Z, to 1.

      • Select the base as the parent frame.

        An example configuration for a merged movement sensor in the Viam app Frame System.

In the JSON mode in your machine’s CONFIGURE tab, add the following JSON objects to the "components" array:

    {
      "name": "gps",
      "type": "movement_sensor",
      "attributes": {
        "ntrip_password": "yourpassword",
        "ntrip_url": "http://your.url:8082",
        "ntrip_username": "yourusername",
        "serial_baud_rate": 115200,
        "serial_path": "/dev/serial/by-id/usb-u-blox_AG_-_www.u-blox.com_u-blox_GNSS_receiver-if00",
        "ntrip_connect_attempts": 10,
        "ntrip_mountpoint": "NJI2"
      },
      "depends_on": [],
      "model": "gps-nmea-rtk-serial"
    },
    {
      "name": "merged",
      "type": "movement_sensor",
      "attributes": {
        "angular_velocity": [
          "enc-linear"
        ],
        "compass_heading": [
          "gps"
        ],
        "orientation": [
          "enc-linear"
        ],
        "position": [
          "gps"
        ]
      },
      "depends_on": [],
      "frame": {
        "orientation": {
          "value": {
            "z": 1,
            "th": 0,
            "x": 0,
            "y": 0
          },
          "type": "ov_degrees"
        },
        "parent": "base",
        "translation": {
          "y": 0,
          "z": 0,
          "x": 0
        }
      },
      "model": "merged"
    },
    {
      "model": "wheeled-odometry",
      "type": "movement_sensor",
      "namespace": "rdk",
      "attributes": {
        "base": "base",
        "left_motors": [
          "left-motor"
        ],
        "right_motors": [
          "right-motor"
        ]
      },
      "depends_on": [],
      "name": "enc-linear"
    }

Configure a navigation service

Add the navigation service so that your wheeled base can navigate between waypoints and avoid obstacles. To add the navigation service to your robot, do the following:

  1. Navigate to the CONFIGURE tab of your machine’s page in the Viam app.

  2. Click the + icon next to your machine part in the left-hand menu and select Service.

  3. Select the navigation type.

  4. Enter a name or use the suggested name for your service and click Create.

  5. Select JSON mode. Copy and paste the following into your new service’s attributes field:

    {
      "base": "base",
      "movement_sensor": "merged",
      "obstacles": [],
      "store": {
        "type": "memory"
      },
      "position_polling_frequency": 2,
      "meters_per_sec": 1.2,
      "degs_per_sec": 90,
      "plan_deviation_m": 0.25
    }
    

    Edit the attributes as applicable. Attribute information is available in the navigation service documentation.

  6. Click Save in the top right corner of the screen to save your changes.

Your navigation service should now appear in your machine’s CONFIGURE tab as a card with a map like the following:

Navigation Card

For more detailed information see the navigation service.

In JSON mode in your machine’s CONFIGURE tab, add the following JSON object to the "services" array:

"services": [
  {
    "name": "nav",
    "type": "navigation",
    "attributes": {
    "base": "base",
    "movement_sensor": "merged",
    "obstacles": [],
    "store": {
        "type": "memory"
    },
    "position_polling_frequency": 2,
    "meters_per_sec": 1.2,
    "degs_per_sec": 90,
    "plan_deviation_m": 0.25
    }
  }
]

Click Save in the top right corner of the screen to save your changes.

Start navigating with the navigation service

Now that you have configured your navigation service, add waypoints to your navigation service. You can add waypoints from the CONTROL tab or programmatically.

Control tab method

Go to the CONTROL tab of your robot in the Viam app, and open the navigation service card.

From there, ensure that Navigation mode is selected as Manual, so your robot will not begin navigation while you add waypoints.

Add waypoints

Select Waypoints on the upper-left corner menu of the navigation card. Zoom in on your current location and click on the map to add a waypoint.

Waypoint 0 being added in the Viam app config builder on a New York City street

Add as many waypoints as you desire. Hover over a waypoint in the left-hand menu and click the trash icon to delete a waypoint.

Waypoint 1 being added in the Viam app config builder, further down the street

(Optional) Add obstacles

If you want your robot to avoid certain obstacles in its path while navigating, you can also add obstacles. In the CONFIGURE tab, select the Obstacles subtab on the navigation card. Zoom in on your current location, then hold shift and drag on the map to draw an obstacle. Add as many obstacles as you desire. Hover over an obstacle in the left-hand menu and click the trash icon to delete an obstacle.

Begin navigation

Toggle Navigation mode to Waypoint. Your rover will begin navigating between waypoints.

Programmatic method

If you want to do add waypoints programmatically, use the service’s API method AddWaypoint():

Add waypoints

myNav, err := navigation.FromRobot(robot, "my_nav_service")

// Create a new waypoint at the specified latitude and longitude
location = geo.NewPoint(40.76275, -73.96)

// Add your waypoint to the service's data storage
err := myNav.AddWaypoint(context.Background(), location, nil)
my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Create a new waypoint at the specified latitude and longitude
location = GeoPoint(latitude=40.76275, longitude=-73.96)

# Add your waypoint to the service's data storage
await my_nav.add_waypoint(point=location)

Begin navigation

To start navigating, set your service to MODE_WAYPOINT with the service’s API method SetMode():

myNav, err := navigation.FromRobot(robot, "my_nav_service")

// Set the Mode the service is operating in to MODE_WAYPOINT and begin navigation
mode, err := myNav.SetMode(context.Background(), Mode.MODE_WAYPOINT, nil)
my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Set the Mode the service is operating in to MODE_WAYPOINT and begin
# navigation
await my_nav.set_mode(Mode.ValueType.MODE_WAYPOINT)

Next steps: automate obstacle detection

In this tutorial, you have learned how to use Navigation to navigate across waypoints. Now, you can make navigation even better with automated obstacle detection.

First, configure a depth camera that your robot can sense how far away it is from obstacles.

We configured ours as an Intel RealSense Camera, which is available as a modular resource in the Viam registry:

An example configuration for an Intel RealSense camera in the Viam app Config Builder.

If you want the robot to be able to automatically detect obstacles in front of it, configure a Vision service segmenter. For example, configure the Vision service model obstacles_depth to detect obstacles in front of the robot. Then, use one of Viam’s client SDKs to automate obstacle avoidance with the navigation service like in the following Python program:

Click to view full example of automated obstacle avoidance with the Python SDK

You can also ask questions in the Community Discord and we will be happy to help.