Problem: Managing Robots Across Multiple Sites Is a Mess
You have autonomous robots operating across warehouses, factories, or hospitals — and no unified way to monitor their state, send commands, or coordinate them with each other. Each vendor has its own silo.
You'll learn:
- How to set up AWS IoT RoboRunner for multi-vendor fleet coordination
- How to register sites, workers, and worker fleets via the AWS CLI and SDK
- How to send tasks and listen to telemetry in real time
Time: 20 min | Level: Intermediate
Why This Happens
Most robotic systems ship with proprietary fleet management software. When you scale to multiple vendors or sites, you end up with incompatible APIs, no cross-fleet visibility, and brittle custom integrations.
AWS IoT RoboRunner solves this by acting as a coordination layer — it doesn't replace your robots' native software but gives you a unified API to track state, assign tasks, and aggregate telemetry.
Common symptoms without a fleet manager:
- Robot status only visible inside vendor dashboards
- No single source of truth for task assignment across fleets
- Manual re-routing when a robot in Fleet A blocks Fleet B
Solution
Step 1: Create a Site and Worker Fleet
A site maps to a physical location. A worker fleet groups robots that share a management system (e.g., all AMRs from one vendor).
# Create your site
aws iotroborunner create-site \
--name "warehouse-seattle" \
--country-code "US" \
--description "Seattle fulfillment center"
Expected: JSON response with a arn field — save this as SITE_ARN.
# Create a worker fleet within the site
aws iotroborunner create-worker-fleet \
--name "amr-fleet-1" \
--site "$SITE_ARN"
Save the returned ARN as FLEET_ARN.
If it fails:
- AccessDeniedException: Attach
AmazonIoTRoboRunnerFullAccessto your IAM role - ResourceNotFoundException on site: Double-check your
SITE_ARN— region must match
Step 2: Register Individual Robots as Workers
Each robot gets registered as a worker. You pass an additionalFixedProperties JSON blob for static metadata (robot model, max payload, etc.) and additionalTransientProperties for live state.
import { IoTRoboRunnerClient, CreateWorkerCommand } from "@aws-sdk/client-iot-roborunner";
const client = new IoTRoboRunnerClient({ region: "us-east-1" });
async function registerRobot(robotId: string, fleetArn: string) {
const command = new CreateWorkerCommand({
name: `robot-${robotId}`,
fleet: fleetArn,
// Static properties don't change at runtime
additionalFixedProperties: JSON.stringify({
model: "AMR-5000",
maxPayloadKg: 50,
chargeVoltage: 48,
}),
// Transient properties are updated via UpdateWorker during operation
additionalTransientProperties: JSON.stringify({
batteryPct: 100,
status: "IDLE",
currentZone: "receiving-dock",
}),
});
const response = await client.send(command);
console.log("Worker ARN:", response.arn);
return response.arn;
}
Why additionalTransientProperties: RoboRunner doesn't model every possible robot attribute — these JSON blobs let you store domain-specific state without fighting the schema.
Step 3: Push Live Telemetry Updates
As your robot moves, push state updates so the fleet manager always has current position and status.
import { UpdateWorkerCommand } from "@aws-sdk/client-iot-roborunner";
async function updateRobotState(
workerArn: string,
battery: number,
zone: string,
positionX: number,
positionY: number
) {
const command = new UpdateWorkerCommand({
id: workerArn,
// Orientation and position use RoboRunner's VendorProperties schema
vendorProperties: {
vendorWorkerId: "amr-5000-001",
vendorAdditionalTransientProperties: JSON.stringify({
batteryPct: battery,
status: battery < 15 ? "RETURNING_TO_CHARGE" : "ACTIVE",
currentZone: zone,
}),
},
position: {
cartesianCoordinates: { x: positionX, y: positionY, z: 0 },
},
orientation: {
degrees: 90, // Heading in degrees
},
});
await client.send(command);
}
Call this on a cadence from your robot's onboard software — every 2–5 seconds is typical for AMRs. Avoid sub-second polling; it's noisy and costs more.
Step 4: Create and Assign Tasks
Tasks are the unit of work you assign to a worker. RoboRunner tracks task state but doesn't execute them — your robot's native software does that via the taskBlob payload.
import { CreateTaskCommand, AssignWorkerCommand } from "@aws-sdk/client-iot-roborunner";
async function dispatchPickTask(workerArn: string, destinationArn: string) {
// Create the task
const createCmd = new CreateTaskCommand({
name: `pick-task-${Date.now()}`,
taskBlob: JSON.stringify({
action: "PICK",
sourceShelf: "A-14",
targetStation: "packing-3",
sku: "WIDGET-001",
quantity: 5,
}),
// Destination maps to a physical location in your site
destinations: [destinationArn],
});
const task = await client.send(createCmd);
// Assign the task to a specific worker
const assignCmd = new AssignWorkerCommand({
id: task.id!,
worker: workerArn,
});
await client.send(assignCmd);
console.log(`Task ${task.id} assigned to worker`);
}
Why separate create and assign: This lets you queue tasks before a robot is available, then assign when one becomes free — useful for building a basic dispatcher without a third-party system.
Verification
Poll a worker's current state to confirm telemetry is flowing:
aws iotroborunner get-worker --id "$WORKER_ARN"
You should see: vendorProperties with your latest telemetry JSON, plus position and orientation fields populated with coordinates.
To list all workers in a fleet:
aws iotroborunner list-workers --fleet "$FLEET_ARN"
You should see: All registered robots with their last-known state.
What You Learned
- RoboRunner is a coordination layer, not a replacement for vendor fleet software — your robots still run their own navigation stack
additionalTransientPropertiesis where your real-time state lives; update it on every telemetry push- Tasks decouple what to do from which robot does it — design your dispatcher to assign tasks based on worker state, not hard-coded robot IDs
- Limitation: RoboRunner doesn't handle path planning or inter-robot collision avoidance — you still need your AMR vendor's software or a third-party coordinator (OSRF Fleet Adapter, InOrbit) for that
- When NOT to use this: Single-vendor, single-site deployments where the vendor's dashboard already covers your needs — RoboRunner adds infrastructure overhead only worth it at multi-site or multi-vendor scale
Tested on AWS IoT RoboRunner (us-east-1), AWS SDK for JavaScript v3, Node.js 22.x