The Navigation Service

The Navigation service is the stateful definition of Viam’s motion service. It uses GPS to autonomously navigate a rover base to user defined endpoints called Waypoints. Once these waypoints are added and the mode of the service is set to MODE_WAYPOINT, the service begins to define the robot’s path.

Configuration

You must configure a base with a movement sensor as part of your robot to configure a Navigation service.

Navigate to the Config tab of your robot’s page in the Viam app. Click the Services subtab, then click Create service in the lower-left corner. Select the type Navigation. Enter a name for your service, then click Create.

An example configuration for a Navigation service in the Viam app Config Builder.

"services": [
{
    "name": "your-navigation-service",
    "type": "navigation",
    "attributes": {
        "store": {
            "type": "<your-store-type>"
        },
        "movement_sensor": "<your-movement-sensor>",
        "base": "<your-base>"
    }
}
    ... // Other services
]
{
  "name": "test_navigation",
  "type": "navigation",
  "attributes": {
    "store": {
      "type": "mongodb",
      // Remove "config": { ... } below if using "type": "memory"
      "config": {
        "uri": "mongodb://127.0.0.1:12345"
      }
    }
  },
  "movement_sensor": "your-movement-sensor",
  "base": "your-base",
  "obstacles": [
    {
      "geometries": [
        {
          "label": "your-label-for-this-obstacle",
          "orientation": {
            "type": "ov_degrees",
            "value": {
              "x": 1,
              "y": 0,
              "z": 0,
              "th": 90
            }
          },
          "x": 10,
          "y": 10,
          "z": 10
        }
      ],
      "location": {
        "latitude": 1,
        "longitude": 1
      }
    }
  ]
}

Edit and fill in the attributes as applicable. The following attributes are available for Navigation services:

NameTypeInclusionDescription
storeobjRequiredThe type and configuration of data storage to use. Either type "memory", where no additional configuration is needed and the waypoints are stored in local memory while the Navigation process is running, or "mongodb", where data persists at the specified MongoDB URI of your MongoDB deployment.
basestringRequiredThe name you have configured for the base you are operating with this service.
movement_sensorstringRequiredThe name of the movement sensor you have configured for the base you are operating with this service.
motion_servicestringOptionalThe name of the motion service you have configured for the base you are operating with this service. If you have not added a motion service to your robot, the default motion service will be used. Reference this default service in your code with the name "builtin".
vision_servicesarrayOptionalThe name of each vision service you have configured for the base you are operating with this service.
position_polling_frequencyfloatOptionalThe frequency to poll for the position of the robot.
Default: 2
obstacle_polling_frequency_hzfloatOptionalThe frequency in hz to poll each vision service for new obstacles.
Default: 2
plan_deviation_mfloatOptionalThe distance in meters that a robot is allowed to deviate from the motion plan.
Default: 3
degs_per_secfloatOptionalThe default angular velocity for the base in degrees per second.
Default: 60
meters_per_secfloatOptionalThe default linear velocity for the base in meters per second.
Default: 0.3
obstaclesobjOptionalAny obstacles you wish to add to the robot’s path. See the motion service for more information.

Configure and calibrate the frame system service for GPS navigation

To make sure your rover base’s autonomous GPS navigation with the navigation service is accurate, configure and calibrate the frame system service for the components of your robot. To start, add the frame system service to your rover base and movement sensor.

  • Navigate to the Config tab of your robot’s page in the Viam app. Scroll to the card with the name of your base:

    The button to add a frame selected with the cursor on the Viam app config builder.
  • Click Add Frame.

    • Keep the parent frame as world. Select the Geometry drop-down menu.

    • Configure a Geometry for the base that reflects its physical dimensions. Reference these instructions to configure your geometry and measure the physical dimensions of your base.

      The frame card for the base in the Viam app config builder.

  • Scroll to the card with the name of your movement sensor. Click Add Frame and select the Parent box.

    • Type in the name of your base to specify this component as the parent of the sensor in the reference frame coordinate system, and click Save Config to save your configuration. See how to configure nested reference frames for an explanation of this configuration process. The frame card for the base in the Viam app config builder.

    • Give the movement sensor a Translation that reflects where it is mounted on your base, measuring the coordinates with respect to the origin of the base.

      In other words, designate the origin of the base as (0,0,0), and measure the distance between the origin of the base and the origin of the sensor to obtain the coordinates of the Translation.

      See the frame system service for more information, and the Viam Internals for a detailed guide on conducting this measurement.

Then, to calibrate your frame system for the most accurate autonomous GPS navigation with the navigation service:

  • After configuring your robot, navigate to the Control page and select the card matching the name of your movement sensor.
  • Monitor the readings displayed on the card, and verify that the compass or orientation readings from the movement sensor report 0 when the base is facing north.
  • If you cannot verify this:
    • Navigate back to your robot’s Config page. Scroll to the card with the name of your movement sensor. Adjust the Orientation of the frame to compensate for the mismatch.
    • Navigate back to the Navigation card on your Control page, and confirm that the compass or orientation readings from the movement sensor now report 0 when the base is facing north, confirming that you’ve successfully calibrated your robot to be oriented accurately within the frame system.
    • If you cannot verify this, repeat as necessary.

API

The navigation service supports the following methods:

Method NameDescription
ModeGet the mode the service is operating in.
SetModeSet the mode the service is operating in.
LocationGet the current location of the robot.
WaypointsGet the waypoints currently in the service’s data storage.
AddWaypointAdd a waypoint to the service’s data storage.
RemoveWaypointRemove a waypoint from the service’s data storage.
GetObstaclesGet the obstacles currently in the service’s data storage.

Mode

Get the Mode the service is operating in.

There are two options for modes: MODE_MANUAL or MODE_WAYPOINT.

  • MODE_WAYPOINT: Start to look for added waypoints and begin autonomous navigation.
  • MODE_MANUAL: Stop autonomous navigation between waypoints and allow the base to be controlled manually.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • (Mode): The Mode the service is operating in.
  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Get the Mode the service is operating in
mode, err := myNav.Mode(context.Background(), nil)

Parameters:

  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Get the Mode the service is operating in
await my_nav.get_mode()

SetMode

Set the Mode the service is operating in.

There are two options for modes: MODE_MANUAL or MODE_WAYPOINT.

  • MODE_WAYPOINT: Start to look for added waypoints and begin autonomous navigation.
  • MODE_MANUAL: Stop autonomous navigation between waypoints and allow the base to be controlled manually.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • mode (Mode): The Mode for the service to operate in.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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)

Parameters:

Returns:

  • None

For more information, see the Python SDK Docs.

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)

Location

Get the current location of the robot in the navigation service.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • (*geo.Point): The current location of the robot in the navigation service, represented in a Point with latitude and longitude values.
  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Get the current location of the robot in the navigation service
location, err := myNav.Location(context.Background(), nil)

Parameters:

  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

  • (navigation.GeoPoint): The current location of the robot in the navigation service, represented in a GeoPoint with latitude and longitude values.

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Get the current location of the robot in the navigation service
location = await my_nav.get_location()

Waypoints

Get an array of waypoints currently in the service’s data storage. These are locations designated within a path for the robot to navigate to.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • ([]Waypoints): An array comprised of each Waypoint in the service’s data storage. These are locations designated within a path for the robot to navigate to.
  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Get an array containing each waypoint stored by the navigation service
waypoints, err := myNav.Waypoints(context.Background(), nil)

Parameters:

  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

  • (List[navigation.Waypoint]): An array comprised of each Waypoint in the service’s data storage. These are locations designated within a path for the robot to navigate to.

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Get a list containing each waypoint stored by the navigation service
waypoints = await my_nav.get_waypoints()

AddWaypoint

Add a waypoint to the service’s data storage.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • point (*geo.Point): The current location of the robot in the navigation service, represented in a Point with latitude (lat) and longitude (lng) values.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Create a new waypoint with latitude and longitude values of 0 degrees
location = geo.NewPoint(0, 0)

// Add your waypoint to the service's data storage
err := myNav.AddWaypoint(context.Background(), location, nil)

Parameters:

  • point(navigation.GeoPoint): The current location of the robot in the navigation service, represented in a GeoPoint with latitude and longitude values.
  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

  • None

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Create a new waypoint with latitude and longitude values of 0 degrees
location = GeoPoint(latitude=0, longitude=0)


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

RemoveWaypoint

Remove a waypoint from the service’s data storage. If the robot is currently navigating to this waypoint, the motion will be canceled, and the robot will proceed to the next waypoint.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • id (primitive.ObjectID): The MongoDB ObjectID of the Waypoint to remove from the service’s data storage.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Create a new ObjectID
waypoint_id = primitive.NewObjectID()

// Remove the waypoint matching that ObjectID from the service's data storage
err := myNav.RemoveWaypoint(context.Background(), waypoint_id, nil)

Parameters:

  • id(str): The MongoDB ObjectID of the Waypoint to remove from the service’s data storage.
  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

  • None

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Remove the waypoint matching that ObjectID from the service's data storage
await my_nav.remove_waypoint(waypoint_id)

GetObstacles

Get an array of obstacles currently in the service’s data storage. These are locations designated for the robot to avoid when navigating. See the motion service for more information.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

  • ([]*spatialmath.GeoObstacle): An array comprised of each GeoObstacle in the service’s data storage. These are locations designated for the robot to avoid when navigating.
  • (error): An error, if one occurred.

For more information, see the Go SDK Docs.

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

// Get an array containing each obstacle stored by the navigation service
obstacles, err := myNav.GetObstacles(context.Background(), nil)

Parameters:

  • timeout (Optional[float]): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.

Returns:

  • (List[navigation.GeoObstacle]): An array comprised of each GeoObstacle in the service’s data storage. These are locations designated for the robot to avoid when navigating.

For more information, see the Python SDK Docs.

my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")

# Get a list containing each obstacle stored by the navigation service
obstacles = await my_nav.get_obstacles()

Concepts

The following concepts are important to understand when utilizing the navigation service. Each concept is a type of relative or absolute measurement, taken by a movement sensor, which can then be utilized by your robot to navigate across space.

Here’s how to make use of the following types of measurements:

Compass Heading

The following models of movement sensor take compass heading measurements:

An example of a Compass Heading reading:

// heading is a float64 between 0-360
heading, err := gps.CompassHeading(context.Background, nil)

Use compass heading readings to determine the bearing of your robot, or, the cardinal direction that your robot is facing.

To read compass headings, configure a capable movement sensor on your robot. Then use the movement sensor API’s GetCompassHeading() method to get readings from the sensor.

Orientation

The following models of movement sensor take orientation measurements:

An example of an Orientation reading:

// orientation is a OrientationVector struct with OX, OY, OZ denoting the coordinates of the vector and rotation about z-axis, Theta
orientation, err := imuwit.Orientation(context.Background, nil)

Use orientation readings to determine the orientation of an object in 3D space as an orientation vector. An orientation vector indicates how it is rotated relative to an origin coordinate system around the x, y, and z axes. You can choose the origin reference frame by configuring it using Viam’s frame system. The GetOrientation readings will report orientations relative to that initial frame.

To read orientation, first configure a capable movement sensor on your robot. Additionally, follow these instructions to configure the geometries of each component of your robot within the frame system. Then use the movement sensor API’s GetOrientation() method to get orientation readings.

Angular Velocity

The following models of the movement sensor component take angular velocity measurements:

An example of an AngularVelocity reading:

// angularVelocity is an AngularVelocity r3 Vector with X, Y, and Z magnitudes
angularVelocity, err := imu.AngularVelocity(context.Background, nil)

Use angular velocity readings to determine the speed and direction at which your robot is rotating.

To get an angular velocity reading, first configure a capable movement sensor on your robot. Then use the movement sensor API’s GetAngularVelocity() method to get angular velocity readings from the sensor.

Position

The following models of the movement sensor component take position measurements:

An example of a Position reading:

// position is a geo.Point consisting  of Lat and Long: -73.98 and an altitude in float64
position, altitude, err:= imu.Position(context.Background, nil)

Use position readings to determine the GPS coordinates of an object in 3D space or its position in the geographic coordinate system (GCS). These position readings reflect the absolute position of components.

To get a position, configure a capable movement sensor on your robot. Then use the movement sensor API’s GetPosition() method to get position readings from the sensor.

Linear Velocity

The following models of movement sensor take linear velocity measurements:

An example of a Linear Velocity reading:

// linearVelocity is an r3.Vector with X, Y, and Z magnitudes
linearVelocity, err := imu.LinearVelocity(context.Background, nil)

Use linear velocity readings to determine the speed at which your robot is moving through space.

To get linear velocity, configure a capable movement sensor on your robot. Then use the movement sensor API’s GetLinearVelocity() method to get linear velocity readings from the sensor.

Linear Acceleration

The following models of movement sensor take linear acceleration measurements:

An example of a Linear Acceleration reading:

// linearAcceleration is an r3.Vector with X, Y, and Z magnitudes
linearAcceleration, err := imu.LinearAcceleration(context.Background, nil)

You can use linear acceleration readings to determine the rate of change of the linear velocity of your robot, or, the acceleration at which your robot is moving through space.

To get linear acceleration, configure a capable movement sensor on your robot. Then use the movement sensor API’s GetLinearAcceleration() method to get linear acceleration readings from the sensor.