Gantry Component
A robotic gantry is a mechanical system of linear actuators used to hold and position an end effector. A 3D printer is an example of a three-axis gantry where each linear actuator can move the print head along one axis. The linear rail design makes gantries a common and reliable system for simple positioning and placement tasks.
This component abstracts the hardware of a gantry to give you an easy interface for coordinated control of linear actuators, even many at once (multi-axis). A multi-axis gantry is composed of many single-axis gantries.
Gantry components can only be controlled in terms of linear motion (you cannot rotate them). Each gantry can only move in one axis within the limits of the length of the linear rail.
Most robots with a gantry need at least the following hardware:
- A board or controller component that can detect changes in voltage on GPIO pins
- A motor that can move linear rails
- Encoded motor: See DC motor with encoder and encoder component.
- Stepper motor: See Stepper motor. Requires setting limit switches in the config of the gantry, or setting offsets in the config of the stepper motor.
- Limit switches, to attach to the ends of the gantry’s axis
Configuration
Configuring this component on your robot with a gantry enables you to get and change the position of the linear rail axes. You can configure your robot, as shown below, on the Viam app.
One-Axis
This is how you configure a one-axis gantry:

{
"components": [
{
"depends_on": [],
"name": <your_gantry_name>,
"type": "gantry",
"model": "oneaxis",
"attributes": {
"board": <your_board_name>,
"motor": <your_motor_name>,
"gantry_rpm": 500,
"limit_pins": [
<your_lim_1>,
<your_lim_2>
],
"limit_pin_enabled_high": false,
"length_mm": 800,
"axis": {
"Z": 0,
"X": 1,
"Y": 0
}
}
}
]
}
Attribute | Inclusion | Description |
---|---|---|
board | Optional | The name of the board that is connected to the limit switches and pins. If limit pins exist, board is required. |
motor | Required | The name of the motor that moves the gantry. |
limit_pins | Optional | The pins attached to the limit switches on either end. If motor type is not encoded, limit_pins is required. |
limit_pin_enabled_high | Optional | If it is true or false that the limit pins are enabled. Default is false. |
length_mm | Required | The length of the axis of the gantry in mm. |
mm_per_rev | Optional | How far the gantry moves (linear, distance in mm) per one revolution of the motor’s output shaft. This typically corresponds to Distance = PulleyDiameter*pi, or the pitch of a linear screw. |
gantry_rpm | Optional | The gantry motor’s default rpm. |
axis | Required | The axis in which the gantry is allowed to move (x, y, z). |
Multi-Axis
A multi-axis gantry component is made up of many single-axis gantries, with each referenced in configuration in the multi-axis models’ attribute subaxes_list
.
This is how you configure a multi-axis gantry:

{
"components": [
{
"name": <your_multiaxis_gantry_name>,
"type": "gantry",
"model": "multiaxis",
"attributes": {
"subaxes_list": [
<your_oneaxis_gantry_name_1>,
<your_oneaxis_gantry_name_2>,
<your_oneaxis_gantry_name_3>
]
},
"depends_on": []
}
]
}
{
"components": [
{
"name": "local",
"type": "board",
"model": "pi"
},
{
"name": "xmotor",
"type": "motor",
"model": "gpiostepper",
"attributes": {
"board": "local",
"pins": {
"dir": "dirx",
"pwm": "pwmx",
"step": "stepx"
},
"stepperDelay": 50,
"ticksPerRotation": 200
}
},
{
"name": "ymotor",
"type": "motor",
"model": "gpiostepper",
"attributes": {
"board": "local",
"pins": {
"dir": "diry",
"pwm": "pwmy",
"step": "stepy"
},
"stepperDelay": 50,
"ticksPerRotation": 200
}
},
{
"name": "zmotor",
"type": "motor",
"model": "gpiostepper",
"attributes": {
"board": "local",
"pins": {
"dir": "dirz",
"pwm": "pwmz",
"step": "stepz"
},
"stepperDelay": 50,
"ticksPerRotation": 200
}
},
{
"name": "xaxis",
"type": "gantry",
"model": "oneaxis",
"attributes": {
"length_mm": 1000,
"board": "local",
"limit_pin_enabled_high": false,
"limit_pins": [
"xlim1",
"xlim2"
],
"motor": "xmotor",
"gantry_rpm": 500,
"axis": {
"x": 1,
"y": 0,
"z": 0
}
}
},
{
"name": "yaxis",
"type": "gantry",
"model": "oneaxis",
"attributes": {
"length_mm": 1000,
"board": "local",
"limit_pin_enabled_high": false,
"limit_pins": [
"ylim1",
"ylim2"
],
"motor": "ymotor",
"gantry_rpm": 500,
"axis": {
"x": 0,
"y": 1,
"z": 0
}
}
},
{
"name": "zaxis",
"type": "gantry",
"model": "oneaxis",
"attributes": {
"length_mm": 1000,
"board": "local",
"limit_pin_enabled_high": false,
"limit_pins": [
"zlim1",
"zlim2"
],
"motor": "zmotor",
"gantry_rpm": 500,
"axis": {
"x": 0,
"y": 0,
"z": 1
}
},
"frame": {
"parent": "world",
"orientation": {
"type": "euler_angles",
"value": {
"roll": 0,
"pitch": 40,
"yaw": 0
}
},
"translation": {
"x": 0,
"y": 3,
"z": 0
}
}
},
{
"name": "test",
"type": "gantry",
"model": "multiaxis",
"attributes": {
"subaxes_list": [
"xaxis",
"yaxis",
"zaxis"
]
}
}
]
}
Attribute | Inclusion | Description |
---|---|---|
subaxes_list | Required | A complete list of the sub-axes, the one-axis gantries that make up the multi-axis gantry. |
Control your gantry 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 gantry called “my_gantry” configured as a component of your robot.
If your gantry has a different name, change the name
in the example.
from viam.components.gantry import Gantry
from viam.proto.common import WorldState
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 gantry.
my_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Disconnect from your robot.
await robot.close()
if __name__ == '__main__':
asyncio.run(main())
import (
"context"
"github.com/edaniels/golog"
"go.viam.com/rdk/components/gantry"
"go.viam.com/rdk/referenceframe"
)
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 Code Sample tab of app.viam.com.",
logger,
client.WithDialOptions(rpc.WithCredentials(rpc.Credentials{
Type: utils.CredentialsTypeRobotLocationSecret,
Payload: "ADD YOUR LOCATION SECRET HERE. You can find this on the Code Sample tab of app.viam.com",
})),
)
// 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 gantry.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
}
API
The gantry component supports the following methods:
Method Name | Description |
---|---|
Position | Get the current positions of the axes of the gantry in mm. |
MoveToPosition | Move the axes of the gantry to the desired positions. |
Lengths | Get the lengths of the axes of the gantry in mm. |
Stop | Stop the gantry from moving. |
IsMoving | Get if the gantry is currently moving. |
DoCommand | Sends or receives model-specific commands. |
Position
Get the current positions of the axis of the gantry (mm).
Parameters:
extra
(Optional[Dict[str, Any]]): Extra options to pass to the underlying RPC call.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:
positions
(List[float]): A list of the position of the axes of the gantry in millimeters.
For more information, see the Python SDK Docs.
my_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Get the current positions of the axes of the gantry in millimeters.
positions = await my_gantry.get_position()
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:
positions
([]float64): A list of the position of the axes of the gantry in millimeters.error
(error): An error, if one occurred.
For more information, see the Go SDK Docs.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
// Get the current positions of the axes of the gantry in millimeters.
position, err := myGantry.Position(context.Background(), nil)
// Log any errors that occur.
if err != nil {
logger.Fatalf("cannot get positions of gantry axes: %v", err)
}
MoveToPosition
Move the axes of the gantry to the desired positions (mm).
Parameters:
positions
(List[float]): A list of positions for the axes of the gantry to move to, in millimeters.world_state
(WorldState): Optional and not yet fully implemented, see the arm component for an example of usage with full component implementation. Specifies obstacles that the gantry must avoid while it moves from its original position to the position specified inpose
.extra
(Optional[Dict[str, Any]]): Extra options to pass to the underlying RPC call.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_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Create a list of positions for the axes of the gantry to move to. Assume in this example that the gantry is multiaxis, with 3 axes.
examplePositions = [1, 2, 3]
# Move the axes of the gantry to the positions specified.
await my_gantry.move_to_position(positions=examplePositions, world_state=WorldState())
Parameters:
Context
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.positions
([]float64): A list of positions for the axes of the gantry to move to, in millimeters.world_state
(WorldState): Optional and not yet fully implemented, see the arm component for an example of usage with full component implementation. Specifies obstacles that the gantry must avoid while it moves from its original position to the position specified inpose
.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.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
// Create a list of positions for the axes of the gantry to move to. Assume in this example that the gantry is multiaxis, with 3 axes.
examplePositions = []float64{1, 2, 3}
// Move the axes of the gantry to the positions specified.
myGantry.MoveToPosition(context.Background(), examplePositions, referenceframe.WorldState(), nil)
Lengths
Get the lengths of the axes of the gantry (mm).
Parameters:
extra
(Optional[Dict[str, Any]]): Extra options to pass to the underlying RPC call.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:
lengths_mm
(List[float]): A list of the lengths of the axes of the gantry in millimeters.
For more information, see the Python SDK Docs.
my_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Get the lengths of the axes of the gantry in millimeters.
lengths_mm = await my_gantry.get_lengths()
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:
lengths_mm
([]float64): A list of the lengths of the axes of the gantry in millimeters.error
(error): An error, if one occurred.
For more information, see the Go SDK Docs.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
// Get the lengths of the axes of the gantry in millimeters.
lengths_mm, err := myGantry.Lengths(context.Background(), nil)
// Log any errors that occur.
if err != nil {
logger.Fatalf("cannot get axis lengths of gantry: %v", err)
}
Stop
Stop all motion of the gantry.
Parameters:
extra
(Optional[Dict[str, Any]]): Extra options to pass to the underlying RPC call.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_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Stop all motion of the gantry. It is assumed that the gantry stops immediately.
await my_gantry.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.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
// Stop all motion of the gantry. It is assumed that the gantry stops immediately.
myGantry.Stop(context.Background(), nil)
IsMoving
Get if the gantry is currently moving.
Parameters:
- None
Returns:
is_moving
(bool): If it is true or false that the gantry is currently moving.
For more information, see the Python SDK Docs.
my_gantry = Gantry.from_robot(robot=robot, name='my_gantry')
# Stop all motion of the gantry. It is assumed that the gantry stops immediately.
await my_gantry.stop()
# Print if the gantry is currently moving.
print(my_gantry.is_moving())
Parameters:
Context
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
Returns:
is_moving
(bool): If it is true or false that the gantry is currently moving.error
(error): An error, if one occurred.
For more information, see the Go SDK Docs.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
if err != nil {
logger.Fatalf("cannot get gantry: %v", err)
}
// Stop all motion of the gantry. It is assumed that the gantry stops immediately.
myGantry.Stop(context.Background(), nil)
// Log if the gantry is currently moving.
is_moving, err := myGantry.IsMoving(context.Background())
if err != nil {
logger.Fatalf("cannot get if gantry is moving: %v", err)
}
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 gantry 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_gantry = Gantry.from_robot(robot, "my_gantry")
command = {"cmd": "test", "data1": 500}
result = my_gantry.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.
myGantry, err := gantry.FromRobot(robot, "my_gantry")
command := map[string]interface{}{"cmd": "test", "data1": 500}
result, err := myGantry.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.