Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ The transport abstraction lives inside the plugin at `extensions/openclaw-plugin
- **`ros2_ws/`** — ROS2 colcon workspace
- **`docker/`** — Docker Compose and Dockerfiles
- **`examples/`** — Demo projects
- **`docs/`** — Architecture and design docs
- **`docs/`** — Architecture and design docs (see `docs/missions.md` for Follow Me and other missions)
- **`ros2_ws/src/rosclaw_follow_me/`** — Follow Me mission: ROS2 node (person tracking + cmd_vel), used by the plugin via ROS2 services

## Key Commands

Expand Down
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# RosClaw

> [!IMPORTANT]
> **My pull requests were never accepted so I decided to start a new multi-AI agent ROS platform called [AgenticROS](https://github.com/agenticros/agenticros).

**Natural language control of ROS2 robots through messaging apps, powered by AI agents.**

RosClaw connects [OpenClaw](https://github.com/openclaw) to [ROS2](https://docs.ros.org/) (the Robot Operating System) through an intelligent plugin layer. Send a message on Telegram, WhatsApp, Discord, or Slack — the robot moves. Connect to your own robot or "lease" any robot registered into our portal globally. Each robot registers their own profile with capabilitie.
Expand Down Expand Up @@ -78,6 +81,47 @@ docker compose up

This starts ROS2 + rosbridge + Gazebo. Then configure your OpenClaw instance to use the RosClaw plugin with `ws://localhost:9090`.

### Run without ROS installed (Docker + OpenClaw on your machine)

If you don’t have ROS on your host (e.g. macOS with only OpenClaw and Docker):

1. **Start the simulation in Docker** (from the repo root):
```bash
cd docker
docker compose up ros2
```
This runs ROS2, rosbridge, and Gazebo in a container and exposes rosbridge at `localhost:9090`.

2. **Build the RosClaw plugin** (in the repo root):
```bash
pnpm install
pnpm build
```

3. **Install the plugin into OpenClaw** from the local path:
```bash
openclaw plugins install -l ./extensions/openclaw-plugin
```
Use the path to your cloned `rosclaw` repo (e.g. `/Users/you/Projects/rosclaw/extensions/openclaw-plugin` if needed).

4. **Configure the plugin** in OpenClaw with rosbridge URL **`ws://localhost:9090`** (this is the default).

5. Start OpenClaw and use your configured messaging channel; the plugin will talk to the simulation in Docker over WebSocket.

### Run on your own robot (Ubuntu + ROS2)

**New robot?** Use the onboarding wizard: `./scripts/onboard_robot.sh` (run from the repo root). It guides you through robot-side and/or gateway-side setup.

For manual steps, see **[Robot Setup Guide](docs/robot-setup.md)**. Quick path: `./scripts/setup_robot.sh` on the robot, `./scripts/setup_gateway_plugin.sh` where OpenClaw runs, then `./scripts/run_demo_native.sh` to start the bridges.

### Phase 3: Teleop Web App

When the gateway supports plugin HTTP routes, open the **teleop web app** in a browser for live camera and twist controls:

- **URL:** `http://<gateway-host>:<port>/rosclaw/teleop/` (e.g. `http://localhost:18789/rosclaw/teleop/`)
- Supports 2D webcam and RealSense; if multiple camera streams exist, choose the source from a dropdown.
- See [Teleop (Phase 3)](docs/teleop.md) for config and requirements.

### Try It

Send a message to your robot:
Expand Down
36 changes: 36 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# RosClaw Docker Stack

Run ROS2, rosbridge, and (optionally) Gazebo simulation in containers so you don’t need ROS installed on your host.

## Quick start (no ROS on host)

From the **repository root**:

```bash
cd docker
docker compose up ros2
```

Then use OpenClaw on your machine with the RosClaw plugin pointing at **`ws://localhost:9090`**. See the main [README](../README.md) section **“Run without ROS installed”** for plugin install and config.

## What runs

| Service | Purpose |
|--------|---------|
| **ros2** | ROS2 Jazzy + rosbridge WebSocket (port 9090) + Gazebo + TurtleBot3. Use this when you run OpenClaw on the host. |
| **rosclaw** | Pre-built plugin image for containerized OpenClaw; optional if you run OpenClaw locally. |

## Ports

- **9090** — rosbridge WebSocket (plugin connects here)
- **11311** — ROS master (if needed by tools)

## Build

Images are built on first `docker compose up`. To rebuild:

```bash
docker compose build
```

The `ros2` image is built from the repo root so it can include `ros2_ws` and the entrypoint script.
4 changes: 2 additions & 2 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ services:
# ROS2 + rosbridge_server + Gazebo simulation
ros2:
build:
context: .
dockerfile: Dockerfile.ros2
context: ..
dockerfile: docker/Dockerfile.ros2
image: rosclaw/ros2:latest
ports:
- "9090:9090" # rosbridge WebSocket
Expand Down
59 changes: 55 additions & 4 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ across all modes — only the transport between them changes.
│ │ │ │ │ │
│ │ │ ros2_publish ros2_subscribe_once ros2_service_call │ │ │
│ │ │ ros2_action_goal ros2_param_get/set ros2_list_topics │ │ │
│ │ │ ros2_camera_snapshot │ │ │
│ │ │ ros2_camera_snapshot follow_robot (Follow Me mission) │ │ │
│ │ └──────────────────────────────┬──────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────┐ ┌───────────▼──────────┐ ┌─────────────────────┐ │ │
Expand All @@ -48,6 +48,7 @@ across all modes — only the transport between them changes.
│ │ │ take-photo │ │ · velocity limits │ │ · capabilities │ │ │
│ │ │ check-status │ │ · workspace bounds │ │ · topics/services │ │ │
│ │ │ pick-object │ │ · blocked ops │ │ · safety config │ │ │
│ │ │ follow-me │ │ │ │ │ │ │
│ │ └──────────────┘ └──────────┬───────────┘ └─────────────────────┘ │ │
│ │ │ │ │
│ │ ┌────────────────────────────┤ ┌──────────────────────────────────┐ │ │
Expand All @@ -59,7 +60,7 @@ across all modes — only the transport between them changes.
┌───────────────────────┐
│ Mode A, B, or C
│ Mode A, B, C, or D
│ (see below) │
└───────────────────────┘
```
Expand Down Expand Up @@ -230,6 +231,53 @@ needs a public IP or open inbound ports.

---

## Deployment Mode D: Zenoh

When the robot uses **ROS 2 with Zenoh RMW** (`RMW_IMPLEMENTATION=rmw_zenoh_cpp`),
the plugin can connect directly to a Zenoh router via **zenoh-ts** (WebSocket to
`zenoh-plugin-remote-api`). No rosbridge or WebRTC bridge is required.

Best for: robots already on Zenoh, low-latency pub/sub, or deployments that
prefer the Zenoh stack over DDS.

```
User (Telegram, WhatsApp, etc.)
│ internet
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
│ OPENCLAW MACHINE │ │ ROBOT (Zenoh RMW) │
│ │ │ │
│ ┌──────────────────────────┐ │ │ ┌─────────────────────────┐ │
│ │ OPENCLAW + ROSCLAW │ │ │ │ Zenoh router │ │
│ │ PLUGIN │ │ │ │ (zenohd) │ │
│ │ │ │ │ └───────────┬─────────────┘ │
│ │ zenoh-ts (WebSocket) │───┼─────┼─► │ │
│ └──────────────────────────┘ │ │ │ Zenoh │
│ │ │ ┌─────────────▼─────────────┐ │
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ ROS2 (rmw_zenoh_cpp) │ │
│ │ /cmd_vel /odom ... │ │
│ └─────────────┬─────────────┘ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ ROBOT HARDWARE │ │
│ └─────────────────────────────┘ │
│ │
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘

Transport: Zenoh (WebSocket to Zenoh router; plugin uses zenoh-ts)
Latency: ~ms
NAT issue: depends on network — router must be reachable from OpenClaw
```

Set `transport.mode` to `zenoh`, configure `zenoh.routerEndpoint` (e.g.
`ws://router-host:10000` for zenoh-ts), and optionally `zenoh.domainId` to
match `ROS_DOMAIN_ID` / rmw_zenoh. The `robot.namespace` config applies to
topic names (and thus to Zenoh key expressions), e.g. namespace `robot-uuid`
yields `/robot-uuid/cmd_vel`.

---

## Transport Adapter Abstraction

All plugin tools call `getTransport()` instead of directly using a specific
Expand All @@ -248,8 +296,11 @@ a unified API for all three deployment modes:
├── LocalTransport (Mode A — @rosclaw/transport-local, stub)
│ └── rclnodejs → ROS2 DDS directly
└── WebRTCTransport (Mode C — @rosclaw/transport-webrtc, stub)
└── WebRTC data channel → rosclaw_agent → ROS2 DDS
├── WebRTCTransport (Mode C — @rosclaw/transport-webrtc, stub)
│ └── WebRTC data channel → rosclaw_agent → ROS2 DDS
└── ZenohTransport (Mode D — zenoh-ts)
└── WebSocket → Zenoh router → ROS2 (rmw_zenoh_cpp)
```

The `createTransport(config)` factory in `@rosclaw/transport` uses dynamic
Expand Down
35 changes: 35 additions & 0 deletions docs/cameras.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Camera Support

The RosClaw plugin’s **ros2_camera_snapshot** tool captures a single frame from any ROS2 image topic and returns it as base64 for display in chat. With **Zenoh** (Mode D), the plugin decodes `sensor_msgs/msg/Image` and `sensor_msgs/msg/CompressedImage` from CDR; no rosbridge is required.

**After updating the plugin** (e.g. pulling code that adds Image/CompressedImage over Zenoh), **restart the OpenClaw gateway** so it loads the new code: `openclaw gateway restart`. Otherwise the assistant may still report “CDR subscribe not implemented for Image/CompressedImage”.

## Message types

- **CompressedImage** (`sensor_msgs/msg/CompressedImage`) — JPEG/PNG topics (e.g. `/camera/image_raw/compressed`). Default.
- **Image** (`sensor_msgs/msg/Image`) — Raw image topics. Use parameter `message_type: "Image"` for raw RGB or depth.

## RealSense (realsense-ros)

The [RealSense ROS2 wrapper](https://github.com/realsenseai/realsense-ros) publishes standard ROS2 topics. RosClaw supports them via `ros2_camera_snapshot` with the appropriate topic and message type.

| Use case | Topic | message_type |
|----------|--------|----------------|
| Color (compressed) | `/camera/camera/color/image_raw/compressed` | CompressedImage (default) |
| Color (raw) | `/camera/camera/color/image_raw` | Image |
| Depth | `/camera/camera/depth/image_rect_raw` | Image |
| Aligned depth to color | `/camera/camera/aligned_depth_to_color/image_raw` | Image |

Default namespace/name in realsense-ros is `camera`/`camera`; if you launch with `camera_namespace` or `camera_name`, adjust the topic prefix (e.g. `/robot1/D455_1/color/image_raw`).

### Example (Natural language)

- “What do you see?” → agent uses `ros2_camera_snapshot` with default or discovered color topic.
- For RealSense color: topic `/camera/camera/color/image_raw`, `message_type: Image`.
- For RealSense depth: topic `/camera/camera/depth/image_rect_raw`, `message_type: Image`.

Discovery: use **ros2_list_topics** to list available topics, then choose the correct topic and message type for the snapshot.

### Zenoh + robot namespace

When using Zenoh with **robot.namespace** set (e.g. for cmd_vel), camera topics are usually **not** under that namespace—they stay under `/camera/...`. The plugin now includes camera topics in discovery and defaults **ros2_camera_snapshot** to `/camera/camera/color/image_raw/compressed` (RealSense). To override, set **robot.cameraTopic** in the plugin config to your camera topic (e.g. `/camera/camera/color/image_raw/compressed`).
65 changes: 65 additions & 0 deletions docs/missions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# RosClaw Missions

Missions are higher-level behaviors exposed to the AI agent via **skills** and **mission tools**. The **Follow Me** mission is **native** to OpenClaw + RosClaw: it uses the robot's camera (ROS2), a Qwen vision model (Ollama), and cmd_vel (ROS2)—no external apps or separate ROS2 nodes.

## Follow Me (native)

**Mission:** The robot finds a person in the room (using a 2D or RealSense camera) and follows them, staying about 1 m behind. The logic runs **inside the RosClaw plugin**: a control loop grabs camera frames over ROS2, sends them to Ollama (Qwen VLM) for person detection and position/distance, then publishes Twist commands to cmd_vel.

### Run from OpenClaw webchat

1. **On the robot**: ROS2 and rosbridge running so the gateway can subscribe to the camera and publish to cmd_vel. A camera topic must be available (e.g. `/camera/image_raw/compressed` or RealSense `/camera/camera/color/image_raw`).

2. **Where OpenClaw runs**: Ollama with a vision model (e.g. `ollama pull qwen2-vl:7b`). Configure the RosClaw plugin if needed:
- **followMe.ollamaUrl** — Ollama API (default `http://localhost:11434`)
- **followMe.vlmModel** — e.g. `qwen2-vl:7b`
- **followMe.cameraTopic** — ROS2 camera topic (default `/camera/image_raw/compressed`); use a RealSense topic if that’s what the robot has.
- **followMe.targetDistance** — follow distance in meters (default 1.0).

3. **In the webchat**, say **"Follow me"** or **"Start following"** — the assistant uses the **follow_robot** tool with action **start**. Say **"Stop following"** to stop. The interface is the webchat; no separate app.

### When to use

- User says "follow me", "start following", "stop following".

### How it works

- **follow_robot** tool (actions: `start`, `stop`, `status`) starts or stops a **background loop** in the plugin.
- The loop: subscribe to the configured camera topic → get one frame → send it to Ollama (Qwen VLM) with a prompt asking for person visibility, position (left/center/right), and distance hint (close/medium/far) → compute linear and angular velocity → publish to cmd_vel. Repeats at the configured rate (default 5 Hz). Velocities are clamped to the plugin’s safety limits.
- No dependency on openclaw-robotics or the rosclaw_follow_me ROS2 package; everything is in the plugin + Ollama + ROS2 transport.

### Modes: depth-only, Ollama, or vision callback

- **Depth-only (default):** No Ollama, no camera for detection. The loop only uses **RealSense depth** to stay at **followMe.targetDistance** (e.g. 0.5 m). If depth is missing, the robot **stops** (no spinning). Set **followMe.depthTopic** if your depth topic is not the default RealSense one.
- **Ollama:** Set **followMe.useOllama** to true for Qwen-based person detection and left/right steering. Distance for follow still comes from depth when available.
- **Vision callback (e.g. OpenAI):** Set **followMe.visionCallbackUrl** to an HTTP endpoint that accepts POST `{ "image": "<base64>" }` and returns JSON `{ "person_visible": boolean, "position"?: "left"|"center"|"right", "distance_hint"?: "close"|"medium"|"far" }`. That endpoint can call OpenAI (or the same model as OpenClaw’s “what do you see”) and return this format. **Distance for follow is always from RealSense depth**; the callback is only for person_visible and left/right.

### Requirements

- **ROS2** depth topic (e.g. RealSense) for distance; optionally camera + Ollama or vision callback for person detection.

### Troubleshooting: motors not moving

1. **Confirm cmd_vel topic**
The plugin now sends an **advertise** (topic + type) before publishing, so rosbridge creates the publisher correctly. Ensure **followMe.cmdVelTopic** (or **robot.namespace**) matches the topic the base uses, e.g. `/robot3946b404c33e4aa39a8d16deb1c5c593/cmd_vel`.

2. **See if Twist messages reach the robot**
On the robot, with Follow Me running, run:
```bash
ros2 topic echo /robot3946b404c33e4aa39a8d16deb1c5c593/cmd_vel
```
If Twist messages appear, the gateway/rosbridge side is fine; the issue is likely the base driver (QoS or not subscribed to that topic). If no messages appear, check the gateway→rosbridge connection and that the plugin is publishing to that exact topic.

3. **Test the base from the robot**
On the robot:
```bash
ros2 topic pub /robot3946b404c33e4aa39a8d16deb1c5c593/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}" -r 5
```
If the wheels move, the topic and subscriber are correct; the problem is getting messages from the gateway (e.g. rosbridge or QoS). If they don’t move, the base may be subscribed to another topic or the motors may need to be enabled.

---

## Adding more missions

- Add a skill under `extensions/openclaw-plugin/skills/missions/<name>/SKILL.md`.
- Implement the mission (e.g. another plugin loop or tool) and document it here.
Loading