Base Component

A base is the platform that the other parts of a mobile robot attach to.

Configure your robot’s base component to reference any motor components attached to the base. By configuring a base component, organizing individual components to produce coordinated movement, you gain an interface to control the movement of the whole physical base of the robot without needing to send separate commands to individual motors.

A robot comprised of a base (motors, wheels and chassis) as well as some other components. The wheels are highlighted to indicate that they are part of the concept of a 'base', while the non-base components are not highlighted. The width and circumference are required attributes when configuring a base component.

Most mobile robots with a base need at least the following hardware:

  • A board component that can run a viam-server instance. For example, a Raspberry Pi, or another model of single-board computer with GPIO (general purpose input/output) pins.

  • Some sort of actuators to move the base. Usually motors attached to wheels or propellers.

  • A power supply for the board.

  • A power supply for the actuators.

  • Some sort of chassis to hold everything together.

Example wiring diagram for a base with one motor on each side:

Wiring diagram showing a Raspberry Pi, motor drivers, motors, power supply, and voltage regulator for the rover.

Note that your base’s wiring will vary depending on your choice of board, motors, motor drivers, and power supply.

Configuration

To configure a base as a component of your robot, first configure the board controlling the base and any motors attached to the base.

This is how you configure a wheeled base:

Picture of what an example configuration for a wheeled base looks like in the Viam app, with Attributes & Depends On drop-downs and the option to add a frame.
{
  "components": [
    {
      "attributes": {},
      "model": <model>,
      "name": <board_name>,
      "type": "board"
    },
    {
      "attributes": {
        "board": <board_name>,
        "max_rpm": <max_rpm>,
        "pins": { ... }
      },
      "model": <model>,
      "name": <motor_name>,
      "type": "motor"
    },
    ... ,
    {
      "attributes": {
        "left": [
          <left_motor_name_1>
        ],
        "right": [
          <right_motor_name_1>
        ],
        "wheel_circumference_mm": <#>,
        "width_mm": <#>
      },
      "model": <model>,
      "name": <base_name>,
      "type": "base"
    }
  ]
}
{
  "components": [
    {
      "attributes": {},
      "model": "pi",
      "name": "follow-pi",
      "type": "board"
    },
    {
      "attributes": {
        "board": "follow-pi",
        "max_rpm": 300,
        "pins": {
          "dir": "16",
          "pwm": "15"
        }
      },
      "model": "gpio",
      "name": "rightm",
      "type": "motor"
    },
    {
      "attributes": {
        "board": "follow-pi",
        "max_rpm": 300,
        "pins": {
          "dir": "13",
          "pwm": "11"
        }
      },
      "model": "gpio",
      "name": "leftm",
      "type": "motor"
    },
    {
      "attributes": {
        "left": [
          "leftm"
        ],
        "right": [
          "rightm"
        ],
        "wheel_circumference_mm": 183,
        "width_mm": 195
      },
      "model": "wheeled",
      "name": "tread-base",
      "type": "base"
    }
  ]
}
An image of the JSON configuration file with annotations explaining some of the attributes.

Required Attributes

AttributeTypeDescription
leftarray of stringsList with the names of all drive motors on the left side of the base. There may be one or more motors.
rightarray of stringsList with the names of all drive motors on the right side of the base. There may be one or more motors.
wheel_circumference_mmintThe outermost circumference (not diameter!) of the drive wheels in millimeters. Used for odometry, so try to enter your best approximation of the effective circumference.
width_mmintWidth of the base in millimeters. In other words, the distance between the approximate centers of the right and left wheels.

Optional Attributes

AttributeTypeDescription
spin_slip_factorfloatUsed in steering calculations to correct for slippage between the wheels and the floor. To be calibrated by the user.

Control your base with Viam’s client SDK libraries

Check out the Client SDK Libraries Quick Start documentation for an overview of how to get started connecting to your robot using these libraries.

The following example assumes you have a wheeled base called “my_base” which is configured as a component of your robot. If your base has a different name, change the name in the example.

from viam.components.base import BaseClient
from viam.proto.common import Vector3

async def main():
    # Connect to your robot.
    robot = await connect()

    # Log an info message with the names of the different resources that are connected to your robot.
    print('Resources:')
    print(robot.resource_names)

    # Connect to your base.
    my_base = BaseClient.from_robot(robot=robot, name='my_base')

    # Disconnect from your robot.
    await robot.close()

if __name__ == '__main__':
    asyncio.run(main())
import (
  "context"

  "github.com/edaniels/golog"

  "go.viam.com/rdk/components/base"
  "github.com/golang/geo/r3"
)

func main() {

  // Create an instance of a logger.
  logger := golog.NewDevelopmentLogger("client")

  // Connect to your robot.
  robot, err := client.New(
      context.Background(),
      "[ADD YOUR ROBOT ADDRESS HERE. YOU CAN FIND THIS ON THE SECURITY TAB OF THE VIAM APP]",
      logger,
      client.WithDialOptions(rpc.WithCredentials(rpc.Credentials{
          Type:    utils.CredentialsTypeRobotLocationSecret,
          Payload: "[PLEASE ADD YOUR SECRET HERE. YOU CAN FIND THIS ON THE LOCATION'S PAGE IN THE VIAM APP]",
      })),
  )

  // Log any errors that occur.
  if err != nil {
      logger.Fatal(err)
  }

  // Delay closing your connection to your robot until main() exits.
  defer robot.Close(context.Background())

  // Log an info message with the names of the different resources that are connected to your robot.
  logger.Info("Resources:")
  logger.Info(robot.ResourceNames())

  // Connect to your base.
  myBase, err := base.FromRobot(robot, "my_base")
  if err != nil {
    logger.Fatalf("cannot get base: %v", err)
  }

}

API

The base component supports the following methods:

Method NameDescription
MoveStraightMove the base in a straight line across the given distance at the given velocity.
SpinMove the base to the given angle at the given angular velocity.
SetPowerSet the relative power (out of max power) for linear and angular propulsion of the base.
SetVelocitySet the linear velocity and angular velocity of the base.
StopStop the base.
DoCommandSends or receives model-specific commands.

MoveStraight

Move the base in a straight line across the given distance (mm) at the given velocity (mm/sec).

Parameters:

  • distance (int): The distance to move in millimeters. Negative implies backwards.
  • velocity (float): The velocity at which to move in millimeters per second. Negative implies backwards.

Returns:

  • None

For more information, see the Python SDK Docs.

myBase = BaseClient.from_robot(robot=robot, name='my_base')

# Move the base 10 mm at a velocity of 1 mm/s, forward.
await myBase.move_straight(distance=10, velocity=1)

# Move the base 10 mm at a velocity of -1 mm/s, backward.
await myBase.move_straight(distance=10, velocity=-1)

Parameters:

  • Context (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • distanceMm (int): The distance to move the base in millimeters. Negative implies backwards.
  • mmPerSec (float64): The velocity at which to move the base in millimeters per second. Negative implies backwards.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

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

For more information, see the Go SDK Docs.

myBase, err := base.FromRobot(robot, "my_base")
if err != nil {
  logger.Fatalf("cannot get base: %v", err)
}

// Move the base forward 10 mm at a velocity of 1 mm/s.
myBase.MoveStraight(context.Background(), distanceMm: 10, mmPerSec: 1)

// Move the base backward 10 mm at a velocity of -1 mm/s.
myBase.MoveStraight(context.Background(), distanceMm: 10, mmPerSec: -1)

Spin

Turn the base in place, rotating it to the given angle (degrees) at the given angular velocity (degrees/sec).

Parameters:

  • angle (float): The angle to spin in degrees. Negative implies backwards.
  • velocity (float): The angular velocity at which to spin in degrees per second. Negative implies backwards.

Returns:

  • None

For more information, see the Python SDK Docs.

my_base = BaseClient.from_robot(robot=robot, name='my_base')

# Spin the base 10 degrees at an angular velocity of 1 deg/sec.
await my_base.spin(angle=10, velocity=1)

Parameters:

  • Context (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • angleDeg (float64): The angle to spin in degrees. Negative implies backwards.
  • degsPerSec (float64): The angular velocity at which to spin in degrees per second. Negative implies backwards.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

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

For more information, see the Go SDK Docs.

myBase, err := base.FromRobot(robot, "my_base")
if err != nil {
  logger.Fatalf("cannot get base: %v", err)
}

// Spin the base 10 degrees at an angular velocity of 1 deg/sec.
myBase.Spin(context.Background(), angleDeg: 10, degsPerSec: 1)

SetPower

Set the linear and angular power of the base, represented as a percentage of max power for each direction in the range of [-1.0 to 1.0].

Parameters:

  • linear (Vector3): The percentage of max power of the base’s linear propulsion. In the range of -1.0 to 1.0, with 1.0 meaning 100% power. Viam’s coordinate system considers +Y to be the forward axis (+/- X left/right, +/- Z up/down), so use the Y component of this vector to move forward and backward when controlling a wheeled base. Negative “Y:” values imply moving backwards.
  • angular (Vector3): The percentage of max power of the base’s angular propulsion. In the range of -1.0 to 1.0, with 1.0 meaning 100% power. Use the Z component of this vector to spin left or right when controlling a wheeled base. Negative “Z:” values imply spinning to the right.

Returns:

  • None

For more information, see the Python SDK Docs.

my_base = BaseClient.from_robot(robot=robot, name='my_base')

# Make your wheeled base move forward. Set linear power to 75%.
print("move forward")
await my_base.set_power(linear=Vector3(x=0,y=-.75,z=0), angular=Vector3(x=0,y=0,z=0))

# Make your wheeled base move backward. Set linear power to -100%.
print("move backward")
await my_base.set_power(linear=Vector3(x=0,y=-1.0,z=0), angular=Vector3(x=0,y=0,z=0))

# Make your wheeled base spin left. Set angular power to 100%.
print("spin left")
await my_base.set_power(linear=Vector3(x=0,y=0,z=0), angular=Vector3(x=0,y=0,z=1))

# Make your wheeled base spin right. Set angular power to -75%.
print("spin right")
await my_base.set_power(linear=Vector3(x=0,y=0,z=0), angular=Vector3(x=0,y=0,z=-.75))

Parameters:

  • Context (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • linear (r3.Vector): The percentage of max power of the base’s linear propulsion. In the range of -1.0 to 1.0, with 1.0 meaning 100% power. Viam’s coordinate system considers +Y to be the forward axis (+/- X left/right, +/- Z up/down), so use the Y component of this vector to move forward and backward when controlling a wheeled base. Negative “Y:” values imply moving backwards.
  • angular (r3.Vector): The percentage of max power of the base’s angular propulsion. In the range of -1.0 to 1.0, with 1.0 meaning 100% power. Use the Z component of this vector to spin left or right when controlling a wheeled base. Negative “Z:” values imply spinning to the right.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

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

For more information, see the Go SDK Docs.

myBase, err := base.FromRobot(robot, "my_base")
if err != nil {
  logger.Fatalf("cannot get base: %v", err)
}

// Make your wheeled base move forward. Set linear power to 75%.
logger.Info("move forward")
err = myBase.SetPower(context.Background(), linear: r3.Vector{Y: .75}, angular: r3.Vector{})
if err != nil {
    logger.Fatal(err)
}

// Make your wheeled base move backward. Set linear power to -100%.
logger.Info("move backward")
err = myBase.SetPower(context.Background(), linear: r3.Vector{Y: -1}, angular: r3.Vector{})
if err != nil {
    logger.Fatal(err)
}

// Make your wheeled base spin left. Set angular power to 100%.
logger.Info("spin left")
err = myBase.SetPower(context.Background(), linear: r3.Vector{}, angular: r3.Vector{Z: 1})
if err != nil {
  logger.Fatal(err)
}

// Make your wheeled base spin right. Set angular power to -75%.
logger.Info("spin right")
err = mybase.SetPower(context.Background(), r3.Vector{}, r3.Vector{Z: -.75}, nil)
if err != nil {
  logger.Fatal(err)
}

SetVelocity

Set the linear velocity (mm/sec) and angular velocity (degrees/sec) of the base.

Parameters:

  • linear (Vector3): The linear velocity in mm per second. Only the Y component of the vector is used for a wheeled base.
  • angular (Vector3): The angular velocity in degrees per second. Only the Z component of the vector is used for a wheeled base.

Returns:

  • None

For more information, see the Python SDK Docs.

my_base = BaseClient.from_robot(robot=robot, name='my_base')

# Set the angular velocity to 1 mm/sec and the linear velocity to 1 degree/sec.
await my_base.set_velocity(linear=Vector3(x=0,y=1,z=0), angular=Vector3(x=0,y=0,z=1))

Parameters:

  • Context (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • linear (r3.Vector): The linear velocity in mm per second. Only the Y component of the vector is used for a wheeled base.
  • angular (r3.Vector): The angular velocity in degrees per second. Only the Z component of the vector is used for a wheeled base.
  • extra (map[string]interface{}): Extra options to pass to the underlying RPC call.

Returns:

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

For more information, see the Go SDK Docs.

// import "github.com/golang/geo/r3" ...

myBase, err := base.FromRobot(robot, "my_base")
if err != nil {
  logger.Fatalf("cannot get base: %v", err)
}

// Set the angular velocity to 1 mm/sec and the linear velocity to 1 deg/sec.
myBase.SetVelocity(context.Background(), linear: r3.Vector{Y: 1}, angular: r3.Vector{Z: 1})

Stop

Stop the base from moving immediately.

Parameters:

  • None

Returns:

  • None.

For more information, see the Python SDK Docs.

my_base = BaseClient.from_robot(robot=robot, name='my_base')

# Move the base forward 10 mm at a velocity of 1 mm/s.
await my_base.move_straight(distance=10, velocity=1)

# Stop the base.
await my_base.stop()

Parameters:

  • Context (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:

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

For more information, see the Go SDK Docs.

myBase, err := base.FromRobot(robot, "my_base")
if err != nil {
  logger.Fatalf("cannot get base: %v", err)
}

// Move the base forward 10 mm at a velocity of 1 mm/s.
myBase.MoveStraight(context.Background(), 10, 1)

// Stop the base.
myBase.Stop(context.Background())

DoCommand

Execute model-specific commands that are not otherwise defined by the component API. For built-in models, model-specific commands are covered with each model’s documentation. If you are implementing your own base and add features that have no built-in API method, you can access them with DoCommand.

Parameters:

  • command (Dict[str, Any]): The command to execute.

Returns:

  • result (Dict[str, Any]): Result of the executed command.
my_base = BaseClient.from_robot(robot, "my_base")

command = {"cmd": "test", "data1": 500}
result = my_base.do(command)

For more information, see the Python SDK Docs.

Parameters:

  • ctx (Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
  • cmd (cmd map[string]interface{}): The command to execute.

Returns:

  • result (cmd map[string]interface{}): Result of the executed command.
  • error (error): An error, if one occurred.
  myBase, err := base.FromRobot(robot, "my_base")

  command := map[string]interface{}{"cmd": "test", "data1": 500}
  result, err := myBase.DoCommand(context.Background(), command)

For more information, see the Go SDK Code.

Troubleshooting

You can find additional assistance in the Troubleshooting section.

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

Next Steps