|
| 1 | +--- |
| 2 | +title: Run the example end to end |
| 3 | +weight: 4 |
| 4 | + |
| 5 | +# FIXED, DO NOT MODIFY |
| 6 | +layout: learningpathall |
| 7 | +--- |
| 8 | + |
| 9 | +## Overview |
| 10 | + |
| 11 | +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. |
| 12 | + |
| 13 | +### Option 1: Run on a single machine |
| 14 | + |
| 15 | +For a proof-of-conect, follow the steps using two terminal windows on your machine with the virtual environment set up. |
| 16 | + |
| 17 | +### Option 2: Run with real hardware |
| 18 | + |
| 19 | +If you have access to an external device, you can use it with this setup as well. You will need: |
| 20 | + |
| 21 | +- Your machine with the virtual environment set up. This machine will be referred to as the host. |
| 22 | +- A Raspberry Pi (or any similar device) connected to the same network as your host machine. This machine is your target. |
| 23 | +- An SSH connection or keyboard and monitor attached to the target. |
| 24 | + |
| 25 | +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. |
| 26 | + |
| 27 | +| Machine | Terminal | Purpose | |
| 28 | +|---------|----------|---------| |
| 29 | +| Host or Target | 1 | Simulated robot — keep running throughout | |
| 30 | +| Host | 2 | Agent tool invocations | |
| 31 | + |
| 32 | +Make sure you are in the repository directory and that your virtual environment is activated: |
| 33 | + |
| 34 | +```bash |
| 35 | +cd ~/strands-device-connect/robots |
| 36 | +source .venv/bin/activate |
| 37 | +``` |
| 38 | + |
| 39 | +## Start the simulated robot |
| 40 | + |
| 41 | +In terminal 1, run the following command to create and start the simulated SO-100 robot arm: |
| 42 | + |
| 43 | +```python |
| 44 | +python <<'PY' |
| 45 | +import logging |
| 46 | +logging.basicConfig(level=logging.INFO) |
| 47 | +from strands_robots import Robot |
| 48 | +r = Robot('so100') |
| 49 | +r.run() |
| 50 | +PY |
| 51 | +``` |
| 52 | + |
| 53 | +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`. |
| 54 | + |
| 55 | +You should see INFO-level log output similar to: |
| 56 | + |
| 57 | +```output |
| 58 | +device_connect_sdk.device.so100-abc123 - INFO - Using ZENOH messaging backend |
| 59 | +device_connect_sdk.device.so100-abc123 - INFO - Connected to ZENOH broker: [] |
| 60 | +device_connect_sdk.device.so100-abc123 - INFO - Driver connected: strands_sim |
| 61 | +device_connect_sdk.device.so100-abc123 - INFO - Subscribed to commands on device-connect.default.so100-abc123.cmd |
| 62 | +🤖 so100-abc123 is online. Ctrl+C to stop. |
| 63 | +``` |
| 64 | + |
| 65 | +Leave this process running. The simulated robot is only discoverable as long as this process is alive. |
| 66 | + |
| 67 | +## Control the robot using the robot_mesh Strands tool |
| 68 | + |
| 69 | +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. |
| 70 | + |
| 71 | +### List peers |
| 72 | + |
| 73 | +Start by confirming which robots are currently visible on the mesh: |
| 74 | + |
| 75 | +```python |
| 76 | +python <<'PY' |
| 77 | +from strands_robots.tools.robot_mesh import robot_mesh |
| 78 | +print(robot_mesh(action='peers')) |
| 79 | +PY |
| 80 | +``` |
| 81 | + |
| 82 | +The output is similar to: |
| 83 | + |
| 84 | +```output |
| 85 | +Discovered 1 device(s): |
| 86 | + [robot] so100-abc123 — idle |
| 87 | + Functions: execute, getFeatures, getStatus, reset, step, stop |
| 88 | +``` |
| 89 | + |
| 90 | +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. |
| 91 | + |
| 92 | +### Execute an instruction |
| 93 | + |
| 94 | +Send a task to one of the discovered robots. Replace `so100-abc123` with the peer ID shown in your `peers` output: |
| 95 | + |
| 96 | +```python |
| 97 | +python <<'PY' |
| 98 | +from strands_robots.tools.robot_mesh import robot_mesh |
| 99 | +print(robot_mesh( |
| 100 | + action='tell', |
| 101 | + target='so100-abc123', |
| 102 | + instruction='pick up the cube', |
| 103 | + policy_provider='mock', |
| 104 | +)) |
| 105 | +PY |
| 106 | +``` |
| 107 | + |
| 108 | +You will see the following output: |
| 109 | + |
| 110 | +```output |
| 111 | +-> so100-abc123: pick up the cube |
| 112 | + {"status": "success", "content": [...]} |
| 113 | +``` |
| 114 | + |
| 115 | +{{% notice Robot output in terminal 1 %}} |
| 116 | +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: |
| 117 | + |
| 118 | +```output |
| 119 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 120 | +*** EVENT so100-abc123::stateUpdate [111aaabb] |
| 121 | + payload: sim_time=4.34, step_count=2070, running_policies={'so100': {'steps': 814, 'instruction': 'pick up the cube'}} |
| 122 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 123 | +``` |
| 124 | +{{% /notice %}} |
| 125 | + |
| 126 | + |
| 127 | +### Emergency stop |
| 128 | + |
| 129 | +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: |
| 130 | + |
| 131 | +```python |
| 132 | +python <<'PY' |
| 133 | +from strands_robots.tools.robot_mesh import robot_mesh |
| 134 | +print(robot_mesh(action='emergency_stop')) |
| 135 | +PY |
| 136 | +``` |
| 137 | + |
| 138 | +The output is similar to: |
| 139 | + |
| 140 | +```output |
| 141 | +E-STOP: 1/1 devices stopped |
| 142 | +``` |
| 143 | + |
| 144 | +## Optional: Discover and invoke the robot using the agent tools |
| 145 | + |
| 146 | +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: |
| 147 | + |
| 148 | +```python |
| 149 | +python <<'PY' |
| 150 | +from device_connect_agent_tools import connect, discover_devices, invoke_device |
| 151 | + |
| 152 | +connect() |
| 153 | + |
| 154 | +devices = discover_devices(device_type='') |
| 155 | +print(f'Found {len(devices)} robot(s):') |
| 156 | +for d in devices: |
| 157 | + print(f' {d["device_id"]}') |
| 158 | + |
| 159 | +if devices: |
| 160 | + result = invoke_device( |
| 161 | + devices[0]['device_id'], |
| 162 | + 'execute', |
| 163 | + {'instruction': 'pick up the cube', 'policy_provider': 'mock'}, |
| 164 | + ) |
| 165 | + print(f'Execute result: {result}') |
| 166 | + |
| 167 | + status = invoke_device(devices[0]['device_id'], 'getStatus') |
| 168 | + print(f'Status: {status}') |
| 169 | +PY |
| 170 | +``` |
| 171 | + |
| 172 | +{{% notice About the snippet %}} |
| 173 | +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. |
| 174 | + |
| 175 | +`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. |
| 176 | +{{% /notice %}} |
| 177 | + |
| 178 | + |
| 179 | +The output is similar to: |
| 180 | + |
| 181 | +```output |
| 182 | +Found 1 robot(s): |
| 183 | + so100-abc123 — idle |
| 184 | +Execute result: {'success': True, 'result': {'status': 'success', 'content': [...]}} |
| 185 | +Status: {'success': True, 'result': {...}} # full sim state dict |
| 186 | +``` |
| 187 | + |
| 188 | +## What you've accomplished and what's next |
| 189 | + |
| 190 | +In this section you: |
| 191 | + |
| 192 | +- Started a simulated SO-100 robot that registered itself on the Device Connect device mesh. |
| 193 | +- Used `device-connect-agent-tools` to discover the robot and invoke an RPC call against it. |
| 194 | +- Used the `robot_mesh` Strands tool to list peers, send an instruction, and trigger an emergency stop. |
| 195 | + |
| 196 | +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. |
0 commit comments