# AgenticROS Robot Setup Guide

This guide gets the AgenticROS project running on your robot (Ubuntu + ROS2 + OpenClaw) for testing and demos.

Still assembling the chassis, L298N, motors, or RealSense? Start with **[Hardware getting started](hardware.md)**, then come back here for ROS 2 and the OpenClaw plugin.

## Onboarding (quick path)

For a **new robot**, use the setup scripts after cloning the repo:

```bash
git clone https://github.com/agenticros/agenticros.git
cd agenticros
```

- **Interactive wizard** (asks robot vs gateway, then runs the right steps):
  ```bash
  ./scripts/onboard_robot.sh
  ```

- **Robot only** (run on the robot):
  ```bash
  ./scripts/setup_robot.sh
  ```
  Optionally: `--ros-distro jazzy` or `humble`, `--skip-apt` to skip apt and build rosbridge from source.

- **Gateway only** (run where OpenClaw runs):
  ```bash
  ./scripts/setup_gateway_plugin.sh
  ```
  Optionally: `--rosbridge-url ws://ROBOT_IP:9090`, `--robot-namespace YOUR_NAMESPACE` to document config.

Then start the bridges on the robot with `./scripts/run_demo_native.sh` and restart the OpenClaw gateway. See the rest of this doc for manual steps and troubleshooting.

---

## Deployment modes

| Setup | OpenClaw runs on | Robot runs | Use case |
|-------|------------------|------------|----------|
| **Mode A** (same machine) | The robot | ROS2 + (optional) rosbridge on localhost | Single robot, all-in-one demo |
| **Mode B** (network) | Your laptop or server | ROS2 + rosbridge_server | Dev/testing, multi-robot |
| **Mode C** (cloud / remote) | Cloud or VPS | ROS2 + agenticros_agent (WebRTC node) | Remote ops, robot behind NAT |
| **Mode D** (Zenoh) | Any | ROS2 with zenoh-bridge-ros2dds or Zenoh RMW | Zenoh-based stacks |

Choose **Mode A** if OpenClaw is installed on the robot. Choose **Mode B** if OpenClaw runs on another machine on the same network. Choose **Mode C** if OpenClaw is in the cloud and the robot is behind NAT (see [Architecture](architecture.md#deployment-mode-c-cloud--remote)). Choose **Mode D** if your robot uses Zenoh.

---

## Prerequisites on the robot

- Ubuntu (22.04 or 24.04 recommended)
- ROS2 **Humble** or **Jazzy** (match your existing install)
- (For Mode A) OpenClaw installed on the robot
- (For Mode B) Robot and OpenClaw machine on the same network

---

## Step 1: Clone and prepare the repo on the robot

On the robot (or on your dev machine if you’ll copy the built workspace to the robot):

```bash
cd ~  # or your preferred path
git clone https://github.com/agenticros/agenticros.git
cd agenticros
```

Use `--ros-distro` to match your ROS2 install (e.g. `humble` or `jazzy`):

```bash
./scripts/setup_workspace.sh --ros-distro humble
```

If you already have ROS2 and only need the AgenticROS workspace built:

```bash
# Use your distro: humble, jazzy, or kilted
source /opt/ros/humble/setup.bash   # or jazzy
cd agenticros/ros2_ws
colcon build --symlink-install
source install/setup.bash
```

---

## Step 2: Install the rosbridge WebSocket server (required for plugin)

The plugin talks to ROS2 via **rosbridge** over WebSocket. The robot needs the **rosbridge_suite** (which provides the WebSocket server). Install it for your distro:

```bash
# Ubuntu/Debian — use your ROS2 distro (humble or jazzy)
sudo apt update
sudo apt install -y ros-<DISTRO>-rosbridge-suite
```

Example for Humble:

```bash
sudo apt install -y ros-humble-rosbridge-suite
```

Example for Jazzy:

```bash
sudo apt install -y ros-jazzy-rosbridge-suite
```

---

## Step 3: Run the robot-side stack

Activate the workspace and start **rosbridge** (and optionally **agenticros_discovery**).

### Option A: Activate once, then run (recommended)

```bash
cd /path/to/agenticros
source scripts/activate_workspace.sh ros_env humble   # or jazzy
```

In **one terminal**, start the rosbridge WebSocket server (port 9090):

```bash
ros2 launch rosbridge_server rosbridge_websocket_launch.xml
```

In a **second terminal** (optional but useful for the AI agent), start the discovery node so the plugin knows your topics/services/actions:

```bash
source /path/to/agenticros/scripts/activate_workspace.sh ros_env humble
ros2 run agenticros_discovery discovery_node
```

Keep both running while you use OpenClaw.

### Option B: Use the launch script

From the repo root:

```bash
./scripts/run_robot_rosbridge.sh [humble|jazzy]
```

This sources the workspace and starts `rosbridge_server`. In another terminal, run the discovery node as above if you want it.

---

## Step 4: Configure OpenClaw and the AgenticROS plugin

> **Install note (OpenClaw 2026.6+).** The OpenClaw install-time code-safety
> scan rejects any `node_modules/*` symlink that resolves outside the plugin
> install root. pnpm workspaces always trip this (every dep is a symlink into
> the hoisted store), so `openclaw plugins install -l ./packages/agenticros`
> no longer works against the source tree. The supported flow is to flatten
> the plugin into a deploy directory first with `pnpm deploy --prod`, then
> link that. The helper script `scripts/setup_gateway_plugin.sh` does this
> end-to-end; the commands below show the manual steps it runs.

### If OpenClaw is on the robot (Mode A) — default

Mode A uses **local DDS** (`LocalTransport`): OpenClaw runs on the **same machine** as ROS 2, and the plugin talks to the ROS graph directly (no rosbridge or Zenoh router required). `ROS_DOMAIN_ID` must match your stack (often **`0`**). **This is the default** — `transport.mode` defaults to `local` in the plugin schema, so you can skip the transport block entirely on the robot.

One-shot install with the helper script:

```bash
cd /path/to/agenticros
./scripts/setup_gateway_plugin.sh \
    --robot-namespace robot3946b404c33e4aa39a8d16deb1c5c593 \
    --camera-topic /camera/camera/color/image_raw/compressed
```

Or the manual equivalent:

```bash
cd /path/to/agenticros
pnpm install
pnpm --filter @agenticros/core build
pnpm --filter @agenticros/ros-camera build
pnpm --filter ./packages/agenticros build

# Flatten into a deploy dir OpenClaw will accept
pnpm --filter ./packages/agenticros deploy --prod ~/.agenticros/plugin-deploy
rm -f ~/.agenticros/plugin-deploy/node_modules/.pnpm/node_modules/agenticros

# Register with OpenClaw (linked from the deploy dir, not the workspace)
openclaw plugins install -l ~/.agenticros/plugin-deploy

# Apply
systemctl --user restart openclaw-gateway.service   # or however you run the gateway
```

(Optional) **Gazebo + TurtleBot3 simulation** on the same host, aligned with the repo bringup package:

```bash
source /opt/ros/jazzy/setup.bash
cd /path/to/agenticros/ros2_ws && source install/setup.bash
ros2 launch agenticros_bringup mode_a_gazebo.launch.py
```

Or with RViz: `ros2 launch agenticros_bringup mode_a_gazebo_rviz.launch.py`. Use `ros_domain_id:=N` if the plugin uses a non-zero domain. See the repository README section **“RViz2 and Gazebo”**.

If you prefer rosbridge on localhost instead (e.g. for debugging), you can still run **`rosbridge_server`** and set **Transport mode** to **`rosbridge`** with **`ws://localhost:9090`** — that is closer to Mode B wiring, not strict Mode A.

**Re-deploying after a code change.** The deploy directory is a snapshot, not a symlink to the workspace. After editing the plugin source, re-run `scripts/setup_gateway_plugin.sh` (it's idempotent), or repeat the `pnpm --filter ./packages/agenticros build` + `pnpm deploy --prod ~/.agenticros/plugin-deploy` + gateway-restart steps.

**Laptop browser → robot OpenClaw.** By default the gateway binds loopback only. For plain-HTTP LAN access you also need `gateway.controlUi.allowedOrigins` **and** `gateway.controlUi.dangerouslyDisableDeviceAuth` (device identity requires HTTPS/`localhost`). Do not set `gateway.controlUi.enabled: false` — that kills the dashboard on localhost too. See [Open OpenClaw web chat from another machine on the LAN](openclaw-releases-and-plugin-routes.md#open-openclaw-web-chat-from-another-machine-on-the-lan).

### If OpenClaw is on another machine (Mode B)

1. On your **laptop/server** where OpenClaw runs:
   ```bash
   cd /path/to/agenticros
   ./scripts/setup_gateway_plugin.sh \
       --transport rosbridge \
       --rosbridge-url "ws://<ROBOT_IP>:9090" \
       --robot-namespace <YOUR_NAMESPACE>
   ```
   Or the manual equivalent of the deploy flow shown in Mode A.
2. Find the robot’s IP (on the robot run `hostname -I` or check your router).
3. In OpenClaw, the plugin config will already have:
   - **Transport mode:** `rosbridge`
   - **Rosbridge URL:** `ws://<ROBOT_IP>:9090`  
     Example: `ws://192.168.1.50:9090`
4. Ensure the robot’s firewall allows TCP port **9090** (rosbridge):
   ```bash
   sudo ufw allow 9090/tcp
   sudo ufw reload
   ```
5. Start OpenClaw and your messaging app; the plugin will connect to the robot at that URL.

### If using cloud + WebRTC (Mode C)

OpenClaw runs in the cloud; the robot runs the **AgenticROS Agent Node** (`agenticros_agent`) and connects via WebRTC (STUN/TURN). Setup is different from A/B/D: the robot does **not** run rosbridge or Zenoh — it runs the WebRTC agent node and talks to the cloud plugin over a data channel. For full steps, see [Deployment Mode C: Cloud / Remote](architecture.md#deployment-mode-c-cloud--remote) in the Architecture doc. Configure the plugin with **Transport mode:** `webrtc` and the appropriate signaling URL, API URL, robot ID, and key.

### If using Zenoh (Mode D)

1. Generate matching router and bridge configs with [`npx zenoh-fleet`](https://github.com/agenticros/zenoh-fleet) (hub on the OpenClaw machine, member on each robot — not a second `zenohd`). Then run **zenohd** with **zenoh-plugin-remote-api** so the plugin can connect. AgenticROS uses **zenoh-ts**, which connects only via **WebSocket** (e.g. `ws://localhost:10000` or `ws://<hub>:10000`), not native TCP. If you only start `zenohd` with default TCP (7447), native tools like `z_sub -e tcp/127.0.0.1:7447` will see traffic but AgenticROS will not. Full steps and a manual JSON5 fallback: [Zenoh setup for AgenticROS](zenoh-agenticros.md).
2. Install the plugin via the helper script with Zenoh wiring:
   ```bash
   cd /path/to/agenticros
   ./scripts/setup_gateway_plugin.sh \
       --transport zenoh \
       --zenoh-endpoint "ws://<ROUTER_IP>:10000" \
       --robot-namespace <YOUR_NAMESPACE>
   ```
3. Or set the AgenticROS plugin config manually:
   - **Transport mode:** `zenoh`
   - **Zenoh Router Endpoint:** `ws://<ROUTER_IP>:10000` (or the URL your router advertises)
   - **Zenoh Domain ID:** match your `ROS_DOMAIN_ID` (default `0`)
4. Optionally set **ROS2 Robot Namespace** (e.g. `robot-uuid`). Topics will be namespaced (e.g. `/robot-uuid/cmd_vel`). This applies to all transport modes.

### ROS2 topic namespace

The **robot.namespace** config (e.g. `robot-uuid`) makes the plugin use namespaced topics: root-level names like `cmd_vel` become `/robot-uuid/cmd_vel`. Use this when multiple robots share the same ROS 2 / Zenoh network. Documented in the plugin config as “ROS2 topic namespace; e.g. robot-uuid gives topics like /robot-uuid/cmd_vel”.

---

## Quick checks

- **Rosbridge listening:** On the robot, with rosbridge running:
  ```bash
  ss -tlnp | grep 9090
  ```
  You should see something like `*:9090`.

- **Discovery:** With discovery running, you can inspect what the agent will see:
  ```bash
  ros2 topic echo /agenticros/capabilities --once
  ```

- **Plugin connection:** In OpenClaw, after starting a chat, the plugin should connect to the robot; check OpenClaw logs for AgenticROS connection messages.

---

## Try a demo

Once everything is running:

1. Send a message to your bot, e.g. **“Move forward 1 meter”** (if your robot has `/cmd_vel`).  
   **If the robot doesn’t move:** the base may subscribe to a **namespaced** cmd_vel (e.g. `/robot3946b404c33e4aa39a8d16deb1c5c593/cmd_vel`). Set **robot.namespace** in the plugin config to that prefix (e.g. `robot3946b404c33e4aa39a8d16deb1c5c593`), then restart the gateway. From the repo: `./scripts/configure_agenticros.sh --mode zenoh --zenoh-endpoint ws://localhost:10000 --namespace robot3946b404c33e4aa39a8d16deb1c5c593`.
2. Or **“What do you see?”** if you have a camera topic.
3. Use **`/estop`** for emergency stop (bypasses the AI).

---

## Troubleshooting

| Issue | What to check |
|-------|----------------|
| Plugin won’t connect | Rosbridge URL correct? Robot IP (Mode B)? Firewall allows 9090? |
| “Package not found” (rosbridge_server) | Install `ros-<distro>-rosbridge-suite` (Step 2). |
| “Package not found” (agenticros_discovery) | Run `source scripts/activate_workspace.sh` and ensure `ros2_ws` is built. |
| Different ROS distro | Use `--ros-distro humble` or `jazzy` in `setup_workspace.sh` and when sourcing. |

### "Rate limited" in webchat (OpenAI)

The message comes from **OpenAI's API limits**, not from AgenticROS. The gateway sends your chat to OpenAI; when OpenAI returns 429 (rate limit), OpenClaw shows "rate limited".

1. **Confirm it's OpenAI** — Check gateway logs:  
   `journalctl --user -u openclaw-gateway.service -n 100 --no-pager | grep -i "429\|rate\|limit\|error"`
2. **Check your OpenAI account** — [Usage](https://platform.openai.com/usage), [API keys](https://platform.openai.com/api-keys). Free/low tiers have strict RPM/TPM and can stay limited for a while.
3. **What helps** — Wait (RPM/TPM reset in minutes; daily limits at UTC midnight). Or switch OpenClaw to a **local Ollama VLM** — see [local-vlm.md](local-vlm.md). Or in OpenClaw switch to a model with higher limits if available.
4. **AgenticROS** — We only trim context/tool output to use fewer tokens; we can't remove OpenAI's limits.

### 404 errors when installing rosbridge_suite

If `sudo apt install ros-jazzy-rosbridge-suite` fails with **404 Not Found** (stale ROS or Ubuntu mirror):

1. **Refresh and retry**
   ```bash
   sudo apt update
   sudo apt install -y ros-jazzy-rosbridge-suite
   ```

2. **If it still fails**, install **from source** so you don't depend on the broken packages:
   ```bash
   cd /home/ubuntu/Projects/agenticros
   ./scripts/install_rosbridge_from_source.sh jazzy
   ```
   Then run rosbridge with:
   ```bash
   source /opt/ros/jazzy/setup.bash
   source ros2_ws/install/setup.bash
   ros2 launch rosbridge_server rosbridge_websocket_launch.xml
   ```

For deployment with OpenClaw in the cloud and the robot behind NAT, see **Mode C** in [Architecture](architecture.md) (WebRTC + `agenticros_agent` on the robot).

---

## Launch script (mode and namespace)

Use the configuration script to set transport mode, robot namespace, and optional Docker in one go:

```bash
./scripts/configure_agenticros.sh --interactive
```

Or with flags:

| Goal | Example |
|------|---------|
| Mode A (OpenClaw on robot) | `--mode A` |
| Mode B (robot on network) | `--mode B --robot-ip 192.168.1.50` |
| Mode C (cloud + WebRTC) | `--mode C` (then set signaling/API/robot in config) |
| Mode D (Zenoh) | `--mode D --zenoh-endpoint ws://localhost:10000` |
| Robot namespace | `--namespace robot-uuid` (topics like `/robot-uuid/cmd_vel`) |
| Demo with Docker (Mode B + local rosbridge) | `--docker` |

The script updates `~/.openclaw/openclaw.json` (or `OPENCLAW_CONFIG`) with `plugins.entries.agenticros.config`. It requires **jq** for JSON edits; without jq it prints the options for you to set manually. With `--docker`, it also starts the Docker Compose ROS2+rosbridge service so you can point the plugin at `ws://localhost:9090`.

## Mapping a room

To build an occupancy map and walk around without hitting furniture, install Nav2 + RTAB-Map, bring them up **without AMCL**, and install `@agenticros/start-slam` + `@agenticros/explore`.

```bash
sudo apt-get install -y \
  ros-jazzy-navigation2 \
  ros-jazzy-nav2-bringup \
  ros-jazzy-rtabmap-ros
```

See **[Mapping a room](mapping.md)**.
