Previous
Motor
Add a movement sensor to your machine’s configuration so you can track position, velocity, and orientation from the Viam app and from code.
Unlike a generic sensor (which returns arbitrary readings), a movement sensor has a structured API with specific methods for spatial data:
GetPosition: latitude, longitude, altitude.GetLinearVelocity: speed in X, Y, Z.GetAngularVelocity: rotation rate around each axis.GetCompassHeading: heading in degrees.GetOrientation: orientation as Euler angles or quaternion.Not every movement sensor supports every method. A GPS provides position and
compass heading but not angular velocity. An IMU provides orientation and
angular velocity but not GPS position. Use GetProperties to check which
methods a particular sensor supports.
| Model | Use case |
|---|---|
wheeled-odometry | Estimates position and velocity from motor encoders on a wheeled base. No additional hardware needed. |
merged | Combines data from multiple movement sensors into one. For example, GPS position + IMU orientation. |
Hardware-specific models (GPS modules, IMUs, RTK receivers) are available as modules in the Viam registry.
If you have a wheeled base with encoders on the motors, you can get position and velocity estimates without any additional sensors.
odometry) and click Create.
{
"base": "my-base",
"left_motors": ["left-motor"],
"right_motors": ["right-motor"]
}
| Attribute | Type | Required | Description |
|---|---|---|---|
base | string | Yes | Name of the wheeled base component. |
left_motors | list of strings | Yes | Left motor names (must have encoders). |
right_motors | list of strings | Yes | Right motor names (must have encoders). |
time_interval_msec | float | No | How often to recalculate. Default: 500. |
Combine data from multiple movement sensors into one.
{
"position": "gps-sensor",
"orientation": "imu-sensor",
"compass_heading": "gps-sensor",
"angular_velocity": "imu-sensor",
"linear_velocity": "odometry"
}
Each field names the movement sensor to use for that type of data. This lets you build a complete spatial picture from multiple hardware sources.
Click Save, then expand the TEST section.
Read position and velocity data from the movement sensor.
To get the credentials for the code below, go to your machine’s page in the Viam app, click the CONNECT tab, and select SDK code sample. Toggle Include API key on. Copy the machine address, API key, and API key ID from the code sample. When you run the code below, you’ll see which methods your sensor supports and the current readings for each.
pip install viam-sdk
Save this as movement_sensor_test.py:
import asyncio
from viam.robot.client import RobotClient
from viam.components.movement_sensor import MovementSensor
async def main():
opts = RobotClient.Options.with_api_key(
api_key="YOUR-API-KEY",
api_key_id="YOUR-API-KEY-ID"
)
robot = await RobotClient.at_address("YOUR-MACHINE-ADDRESS", opts)
sensor = MovementSensor.from_robot(robot, "odometry")
# Check which methods this sensor supports
properties = await sensor.get_properties()
print(f"Supports position: {properties.position_supported}")
print(f"Supports linear velocity: {properties.linear_velocity_supported}")
print(f"Supports angular velocity: {properties.angular_velocity_supported}")
print(f"Supports compass heading: {properties.compass_heading_supported}")
if properties.position_supported:
position = await sensor.get_position()
print(f"Position: {position}")
if properties.linear_velocity_supported:
velocity = await sensor.get_linear_velocity()
print(f"Linear velocity: {velocity}")
await robot.close()
if __name__ == "__main__":
asyncio.run(main())
Run it:
python movement_sensor_test.py
mkdir movement-sensor-test && cd movement-sensor-test
go mod init movement-sensor-test
go get go.viam.com/rdk
Save this as main.go:
package main
import (
"context"
"fmt"
"go.viam.com/rdk/components/movementsensor"
"go.viam.com/rdk/logging"
"go.viam.com/rdk/robot/client"
"go.viam.com/rdk/utils"
)
func main() {
ctx := context.Background()
logger := logging.NewLogger("movement-sensor-test")
robot, err := client.New(ctx, "YOUR-MACHINE-ADDRESS", logger,
client.WithCredentials(utils.Credentials{
Type: utils.CredentialsTypeAPIKey,
Payload: "YOUR-API-KEY",
}),
client.WithAPIKeyID("YOUR-API-KEY-ID"),
)
if err != nil {
logger.Fatal(err)
}
defer robot.Close(ctx)
sensor, err := movementsensor.FromProvider(robot, "odometry")
if err != nil {
logger.Fatal(err)
}
// Check which methods this sensor supports
properties, err := sensor.Properties(ctx, nil)
if err != nil {
logger.Fatal(err)
}
fmt.Printf("Supports position: %v\n", properties.PositionSupported)
fmt.Printf("Supports linear velocity: %v\n", properties.LinearVelocitySupported)
fmt.Printf("Supports angular velocity: %v\n", properties.AngularVelocitySupported)
fmt.Printf("Supports compass heading: %v\n", properties.CompassHeadingSupported)
if properties.PositionSupported {
pos, alt, err := sensor.Position(ctx, nil)
if err != nil {
logger.Fatal(err)
}
fmt.Printf("Position: %v, altitude: %.2f\n", pos, alt)
}
if properties.LinearVelocitySupported {
vel, err := sensor.LinearVelocity(ctx, nil)
if err != nil {
logger.Fatal(err)
}
fmt.Printf("Linear velocity: %v\n", vel)
}
}
Run it:
go run main.go
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!