Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Connect AI agents to edge devices using Device Connect and Strands

minutes_to_complete: 30

who_is_this_for: This Learning Path is for software developers who want to connect AI agents to physical or simulated edge devices using Device Connect — Arm's platform for structured device access — and Strands, the open-source agent SDK from AWS.

learning_objectives:
- Understand how Device Connect and Strands work together to give AI agents structured access to Arm-based edge devices.
- Set up a Python environment with the Device Connect SDK and agent tools installed from source.
- Start a simulated robot that registers itself on the local network and is discovered automatically by an agent.
- Discover and invoke the robot using the Device Connect agent tools and the robot_mesh Strands tool.

prerequisites:
- An development machine with Python 3.12 installed.
- Git installed.
- Basic familiarity with Python virtual environments and command-line tools.
- (Optional) A Raspberry Pi for testing a full device-to-device (D2D) setup.

author:
- Annie Tallund
- Kavya Sri Chennoju



### Tags
skilllevels: Introductory
subjects: ML
armips:
- Cortex-A
- Neoverse
operatingsystems:
- Linux
- macOS
tools_software_languages:
- Python
- Docker
- strands-agents

further_reading:
- resource:
title: Strands Agents SDK documentation
link: https://strandsagents.com/
type: website
- resource:
title: Strands robots repository
link: https://github.com/strands-labs/robots/tree/dev
type: website
- resource:
title: Device Connect integration guide
link: https://github.com/atsyplikhin/robots/blob/feat/device-connect-integration-draft/strands_robots/device_connect/GUIDE.md
type: website

### FIXED, DO NOT MODIFY
# ================================================================================
weight: 1 # _index.md always has weight of 1 to order correctly
layout: "learningpathall" # All files under learning paths have this same wrapper
learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content.
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# ================================================================================
# FIXED, DO NOT MODIFY THIS FILE
# ================================================================================
weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation.
title: "Next Steps" # Always the same, html page title.
layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing.
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Background and architecture
weight: 2

# FIXED, DO NOT MODIFY
layout: learningpathall
---

## Why connect AI agents to edge devices?

Arm processors are at the heart of a remarkable range of systems — from Cortex-M microcontrollers in industrial sensors to Neoverse servers running in the cloud. That breadth of hardware is one of Arm's greatest strengths, but it raises a practical question for AI developers: how do you give an agent structured, safe access to devices that are physically distributed and built on different software stacks?

Device Connect is Arm's answer to that question. It is a platform layer that handles device registration, discovery, and remote procedure calls across a network of devices, with no bespoke networking code required. Strands is an open-source agent SDK from AWS that takes a model-driven approach to building AI agents — an LLM calls Python tools in a structured reasoning loop, and the SDK handles the rest. When you combine them, an agent can ask "which devices are online and what can they do?" and then invoke a function on a specific device, turning natural language intent into physical action.

This Learning Path puts both tools through their paces. It starts with a single machine, for example a laptop, where a simulated robot and an agent discover each other automatically, then extends to a two-machine setup where a Raspberry Pi joins the same device mesh over the network.

## The two layers

**Device layer**

A device is any process that registers itself on the mesh and exposes callable functions. In this Learning Path you will create a simulated robot arm, namely the simulated robotic arm SO-100 from Hugging Face, from the `strands-robots` SDK. The moment this object is created, it registers on the local network under a unique device ID (for example, `so100_sim-abc23`) and begins publishing a presence heartbeat. No explicit registration call is required. Device Connect uses Zenoh as its underlying messaging transport, which handles low-level connectivity and routing automatically.

**Agent layer**

Two interfaces sit at this layer. The `device-connect-agent-tools` package exposes `discover_devices()` and `invoke_device()` as plain Python functions you can call directly from a script or REPL, with no LLM involved. The `robot_mesh` tool from `robots` wraps the same capabilities as a Strands agent tool, which means an LLM can also call them during a reasoning loop. Both share the same underlying Device Connect transport, so anything you can do with one you can do with the other.

The diagram below shows how these layers communicate at runtime:

```
┌──────────────────────────────────────┐
│ Agent layer │
│ discover_devices · invoke_device │
│ robot_mesh Strands tool │
└──────────────┬───────────────────────┘
│ Device Connect
│ (device-to-device discovery & RPC)
┌──────────────▼───────────────────────┐
│ Device layer │
│ Simulated SO-100 arm |
| — so100-abc123 │
│ heartbeat · execute · getStatus │
└──────────────────────────────────────┘
```

## How device discovery works

When the `SO-100 arm` instance starts, Device Connect automatically announces the device on the local network. Any process running `discover_devices()` or `robot_mesh(action='peers')` on the same network will hear the announcement and add the device to its live table of available hardware.

## What the simulated robot provides
Comment thread
annietllnd marked this conversation as resolved.

When you run `Robot('so100')`, the SDK downloads the MuJoCo physics model for the SO-100 arm (this happens once on first run) and starts a local simulation. The robot exposes three functions that any agent can call via RPC:

- `execute` — start a task with a given instruction and policy provider
- `getStatus` — query the current task state
- `stop` — halt the current task

For this Learning Path, the `policy_provider='mock'` argument is used, which means `execute` accepts the call and returns `{'status': 'accepted'}` without actually running a motion policy. This keeps the focus on the connectivity and invocation patterns rather than robotics.

Once you have the flow working end to end, replacing `'mock'` with a real policy is a one-line change.

## What you'll accomplish in this Learning Path

By working through the remaining sections you will:

- Clone the sample repository and install the Device Connect SDK, agent tools, and Strands robot runtime from source into a single virtual environment.
- Start a simulated robot that registers itself on the local device mesh.
- Discover and invoke the robot using `device-connect-agent-tools` directly.
- Discover and command the robot through the `robot_mesh` Strands tool, including an emergency stop.
- Optionally extend the setup to a Raspberry Pi connected over the network, discovering and commanding it from your laptop through the Device Connect infrastructure.

The next section covers the environment setup.

TODO: replace robots and feat/device-connect-integration-draft. Update furhter reading links. Clarify device support.
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
---
title: Run the example end to end
weight: 4

# FIXED, DO NOT MODIFY
layout: learningpathall
---

## Overview

This section runs Device Connect's device-to-device discovery. There are two ways to walk through this setup. Optionally, you can connect an external device.

### Option 1: Run on a single machine

For a proof-of-conect, follow the steps using two terminal windows on your machine with the virtual environment set up.

### Option 2: Run with real hardware

If you have access to an external device, you can use it with this setup as well. You will need:

- Your machine with the virtual environment set up. This machine will be referred to as the host.
- A Raspberry Pi (or any similar device) connected to the same network as your host machine. This machine is your target.
- An SSH connection or keyboard and monitor attached to the target.

You will need two terminal windows open at the same time: one to keep the simulated robot running, and one to invoke it from the agent side. Both terminals need the virtual environment activated.

| Machine | Terminal | Purpose |
|---------|----------|---------|
| Host or Target | 1 | Simulated robot — keep running throughout |
| Host | 2 | Agent tool invocations |

Make sure you are in the repository directory and that your virtual environment is activated:

```bash
cd ~/strands-device-connect/robots
source .venv/bin/activate
```

## Start the simulated robot

In terminal 1, run the following command to create and start the simulated SO-100 robot arm:

```python
python <<'PY'
import logging
logging.basicConfig(level=logging.INFO)
from strands_robots import Robot
r = Robot('so100')
r.run()
PY
```

When the `Robot('so100')` object is created, the SDK downloads the MuJoCo physics model for the SO-100 arm (this download happens only on the first run and takes a minute or two), then starts the simulation and registers the robot on the Device Connect device mesh. The robot publishes a presence heartbeat every 0.5 seconds under a unique device ID, for example `so100-abc123`.

You should see INFO-level log output similar to:

```output
device_connect_sdk.device.so100-abc123 - INFO - Using ZENOH messaging backend
device_connect_sdk.device.so100-abc123 - INFO - Connected to ZENOH broker: []
device_connect_sdk.device.so100-abc123 - INFO - Driver connected: strands_sim
device_connect_sdk.device.so100-abc123 - INFO - Subscribed to commands on device-connect.default.so100-abc123.cmd
🤖 so100-abc123 is online. Ctrl+C to stop.
```

Leave this process running. The simulated robot is only discoverable as long as this process is alive.

## Control the robot using the robot_mesh Strands tool

The `robot_mesh` tool wraps the same discovery and invocation primitives as a Strands agent tool. You can call it directly from a Python script or attach it to an LLM agent; the API is identical either way.

### List peers

Start by confirming which robots are currently visible on the mesh:

```python
python <<'PY'
from strands_robots.tools.robot_mesh import robot_mesh
print(robot_mesh(action='peers'))
PY
```

The output is similar to:

```output
Discovered 1 device(s):
[robot] so100-abc123 — idle
Functions: execute, getFeatures, getStatus, reset, step, stop
```

The peer ID (for example `so100-abc123`) is assigned at startup and changes each run. Note the actual ID shown in your terminal - you will need it in the next step.

### Execute an instruction

Send a task to one of the discovered robots. Replace `so100-abc123` with the peer ID shown in your `peers` output:

```python
python <<'PY'
from strands_robots.tools.robot_mesh import robot_mesh
print(robot_mesh(
action='tell',
target='so100-abc123',
instruction='pick up the cube',
policy_provider='mock',
))
PY
```

You will see the following output:

```output
-> so100-abc123: pick up the cube
{"status": "success", "content": [...]}
```

{{% notice Robot output in terminal 1 %}}
The robot also logs event updates as it processes the task. If you switch back to terminal 1, it logs the execution of the task, similar to:

```output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*** EVENT so100-abc123::stateUpdate [111aaabb]
payload: sim_time=4.34, step_count=2070, running_policies={'so100': {'steps': 814, 'instruction': 'pick up the cube'}}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
{{% /notice %}}


### Emergency stop

The emergency stop broadcasts a halt command to every device on the mesh simultaneously. This is useful when you want to stop all robots without knowing their individual peer IDs:

```python
python <<'PY'
from strands_robots.tools.robot_mesh import robot_mesh
print(robot_mesh(action='emergency_stop'))
PY
```

The output is similar to:

```output
E-STOP: 1/1 devices stopped
```

## Optional: Discover and invoke the robot using the agent tools

The `device-connect-agent-tools` package gives you direct programmatic access to the mesh, without involving an LLM. This is useful for testing, scripting, or validating the stack before wiring it up to an agent. Open terminal 2, activate the virtual environment, then run:

```python
python <<'PY'
from device_connect_agent_tools import connect, discover_devices, invoke_device

connect()

devices = discover_devices(device_type='')
print(f'Found {len(devices)} robot(s):')
for d in devices:
print(f' {d["device_id"]}')

if devices:
result = invoke_device(
devices[0]['device_id'],
'execute',
Comment thread
annietllnd marked this conversation as resolved.
{'instruction': 'pick up the cube', 'policy_provider': 'mock'},
)
print(f'Execute result: {result}')

status = invoke_device(devices[0]['device_id'], 'getStatus')
print(f'Status: {status}')
PY
```

{{% notice About the snippet %}}
When an agent calls `execute(instruction="pick up the cup", policy_provider="groot")`, Device Connect handles the RPC delivery, and the policy handles the actual arm movement.

`discover_devices(device_type='')` returns all devices on the mesh regardless of type. If you pass `device_type='strands_robot'` you can filter to only `Robot()` instances. `invoke_device` sends an RPC to the named device; here `policy_provider='mock'` tells the robot to accept the task without executing real motion, which is appropriate for this connectivity test.
{{% /notice %}}


The output is similar to:

```output
Found 1 robot(s):
so100-abc123 — idle
Execute result: {'success': True, 'result': {'status': 'success', 'content': [...]}}
Status: {'success': True, 'result': {...}} # full sim state dict
```

## What you've accomplished and what's next

In this section you:

- Started a simulated SO-100 robot that registered itself on the Device Connect device mesh.
- Used `device-connect-agent-tools` to discover the robot and invoke an RPC call against it.
- Used the `robot_mesh` Strands tool to list peers, send an instruction, and trigger an emergency stop.

This showcases the ease of setting up a mesh on a local network. In the next section, you can extend the configuration to a Docker-based approach, opening up a new category of possibilites with agent integration.
Loading
Loading