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
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \

ARG BRIDGE_FILE="bridge.yaml"

COPY --chmod=0755 script/entrypoint.sh /entrypoint.sh
COPY --chmod=0755 script/ros_entrypoint.sh /ros_entrypoint.sh
COPY --chmod=0755 script/ /
COPY --chmod=0644 "${BRIDGE_FILE}" /bridge.yaml
COPY --chmod=0644 config/demo_bridge.yaml /demo_bridge.yaml

ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["bash"]
Expand Down
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [Quick Start](#quick-start)
- [Usage](#usage)
- [Bridge Configuration](#bridge-configuration)
- [Demo](#demo)
- [Architecture](#architecture)
- [Directory Structure](#directory-structure)

Expand Down Expand Up @@ -127,6 +128,41 @@ services_2_to_1:
type: rcl_interfaces/GetParameters
```

## Demo

Two-terminal end-to-end bridge demo using `std_msgs/String`. Both demos
use the same pattern: a **server** terminal that owns `roscore` +
`parameter_bridge` (loaded from the baked-in `/demo_bridge.yaml`), and a
**client** terminal that just subscribes.

| Demo | Terminal 1 (server) | Terminal 2 (client) |
|------|---------------------|---------------------|
| A — ROS 1 → ROS 2 | `./exec.sh /ros1_server.sh` | `./exec.sh /ros2_client.sh` |
| B — ROS 2 → ROS 1 | `./exec.sh /ros2_server.sh` | `./exec.sh /ros1_client.sh` |

Steps (assuming the container is up via `./run.sh -d`):

```bash
# Terminal 1 (server) — pick one demo
./exec.sh /ros1_server.sh # Demo A
./exec.sh /ros2_server.sh # Demo B

# Terminal 2 (client) — matching pair
./exec.sh /ros2_client.sh # Demo A
./exec.sh /ros1_client.sh # Demo B
```

Server scripts log every step (`[ros1_server] step N/5: ...`) so it's
clear when `roscore` and `parameter_bridge` are up. Override the
published string with `MESSAGE`:

```bash
./exec.sh env MESSAGE="hi from ROS 1" /ros1_server.sh
```

`Ctrl+C` on the server terminal tears down `parameter_bridge` and
`roscore`; the client terminal then EOFs.

## Architecture

```mermaid
Expand Down Expand Up @@ -169,11 +205,16 @@ ros1_bridge/
├── template/ # Shared scripts, tests, CI (git subtree)
├── script/
│ ├── entrypoint.sh # Sources ROS 1 + ROS 2, loads bridge config
│ └── ros_entrypoint.sh # ROS env only (osrf-compatible)
│ ├── ros_entrypoint.sh # ROS env only (osrf-compatible)
│ ├── ros1_server.sh # Demo A publisher (bootstraps roscore + bridge)
│ ├── ros1_client.sh # Demo B subscriber
│ ├── ros2_server.sh # Demo B publisher (bootstraps roscore + bridge)
│ └── ros2_client.sh # Demo A subscriber
├── bridge.yaml # Default bridge configuration
├── config/ # Additional bridge configs
│ ├── scan_bridge.yaml # LaserScan bridge
│ └── release_bridge.yaml # Camera + depth bridge
│ ├── release_bridge.yaml # Camera + depth bridge
│ └── demo_bridge.yaml # Demo bidirectional std_msgs/String
├── doc/ # Translated READMEs
│ ├── README.zh-TW.md # Traditional Chinese
│ ├── README.zh-CN.md # Simplified Chinese
Expand Down
9 changes: 9 additions & 0 deletions config/demo_bridge.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Demo bridge config — std_msgs/String, both directions.
# Used by script/ros{1,2}_server.sh via parameter_bridge.
topics:
- topic: /chatter_1to2
type: std_msgs/msg/String
queue_size: 10
- topic: /chatter_2to1
type: std_msgs/msg/String
queue_size: 10
47 changes: 45 additions & 2 deletions doc/README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [クイックスタート](#クイックスタート)
- [使い方](#使い方)
- [ブリッジ設定](#ブリッジ設定)
- [Demo](#demo)
- [アーキテクチャ](#アーキテクチャ)
- [ディレクトリ構成](#ディレクトリ構成)

Expand Down Expand Up @@ -127,6 +128,43 @@ services_2_to_1:
type: rcl_interfaces/GetParameters
```

## Demo

2 つの terminal でエンドツーエンドの bridge デモを実行します。
メッセージ型は `std_msgs/String`。パターンは対称で、**server**
terminal が `roscore` + `parameter_bridge`(ビルド時にイメージへ
焼き込まれた `/demo_bridge.yaml` を読み込む)を起動し、**client**
terminal は subscribe するだけです。

| Demo | Terminal 1 (server) | Terminal 2 (client) |
|------|---------------------|---------------------|
| A — ROS 1 → ROS 2 | `./exec.sh /ros1_server.sh` | `./exec.sh /ros2_client.sh` |
| B — ROS 2 → ROS 1 | `./exec.sh /ros2_server.sh` | `./exec.sh /ros1_client.sh` |

実際の手順(コンテナを `./run.sh -d` で起動済みとして):

```bash
# Terminal 1 (server) — どちらかを選択
./exec.sh /ros1_server.sh # Demo A
./exec.sh /ros2_server.sh # Demo B

# Terminal 2 (client) — 対応するもう一方
./exec.sh /ros2_client.sh # Demo A
./exec.sh /ros1_client.sh # Demo B
```

Server スクリプトは各ステップを明示的にログ出力します
(`[ros1_server] step N/5: ...`)。`roscore` と `parameter_bridge` が
いつ準備完了になったかが一目で分かります。Publish するメッセージは
`MESSAGE` 環境変数で上書き可能です:

```bash
./exec.sh env MESSAGE="hi from ROS 1" /ros1_server.sh
```

Server terminal で `Ctrl+C` を押すと `parameter_bridge` と `roscore`
を停止し、client terminal も EOF になります。

## アーキテクチャ

```mermaid
Expand Down Expand Up @@ -169,11 +207,16 @@ ros1_bridge/
├── template/ # 共有スクリプト、テスト、CI(git subtree)
├── script/
│ ├── entrypoint.sh # ROS 1 + ROS 2 を source、bridge 設定を読み込み
│ └── ros_entrypoint.sh # ROS 環境のみ source(osrf 互換)
│ ├── ros_entrypoint.sh # ROS 環境のみ source(osrf 互換)
│ ├── ros1_server.sh # Demo A publisher(roscore + bridge を自起動)
│ ├── ros1_client.sh # Demo B subscriber
│ ├── ros2_server.sh # Demo B publisher(roscore + bridge を自起動)
│ └── ros2_client.sh # Demo A subscriber
├── bridge.yaml # デフォルト bridge 設定
├── config/ # 追加 bridge 設定
│ ├── scan_bridge.yaml # LaserScan bridge
│ └── release_bridge.yaml # Camera + depth bridge
│ ├── release_bridge.yaml # Camera + depth bridge
│ └── demo_bridge.yaml # Demo 双方向 std_msgs/String
├── doc/ # 翻訳版 README
│ ├── README.zh-TW.md # 繁体字中国語
│ ├── README.zh-CN.md # 簡体字中国語
Expand Down
44 changes: 42 additions & 2 deletions doc/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [快速开始](#快速开始)
- [使用方式](#使用方式)
- [Bridge 设置](#bridge-设置)
- [Demo](#demo)
- [架构](#架构)
- [目录结构](#目录结构)

Expand Down Expand Up @@ -126,6 +127,40 @@ services_2_to_1:
type: rcl_interfaces/GetParameters
```

## Demo

两个 terminal 跑 end-to-end bridge demo,消息类型 `std_msgs/String`。
规则对称:**server** terminal 负责起 `roscore` + `parameter_bridge`
(读 build 时烤进 image 的 `/demo_bridge.yaml`),**client** terminal 只订阅。

| Demo | Terminal 1 (server) | Terminal 2 (client) |
|------|---------------------|---------------------|
| A — ROS 1 → ROS 2 | `./exec.sh /ros1_server.sh` | `./exec.sh /ros2_client.sh` |
| B — ROS 2 → ROS 1 | `./exec.sh /ros2_server.sh` | `./exec.sh /ros1_client.sh` |

实际操作(假设容器已用 `./run.sh -d` 起好):

```bash
# Terminal 1 (server) — 二选一
./exec.sh /ros1_server.sh # Demo A
./exec.sh /ros2_server.sh # Demo B

# Terminal 2 (client) — 对应的另一半
./exec.sh /ros2_client.sh # Demo A
./exec.sh /ros1_client.sh # Demo B
```

Server 脚本每一步都打印进度(`[ros1_server] step N/5: ...`),所以
`roscore` 跟 `parameter_bridge` 何时就绪一目了然。要换消息字串用
`MESSAGE` 环境变量:

```bash
./exec.sh env MESSAGE="hi from ROS 1" /ros1_server.sh
```

Server terminal 按 `Ctrl+C` 会收掉 `parameter_bridge` 跟 `roscore`,
client terminal 接着就 EOF。

## 架构

```mermaid
Expand Down Expand Up @@ -168,11 +203,16 @@ ros1_bridge/
├── template/ # 共用脚本、测试、CI(git subtree)
├── script/
│ ├── entrypoint.sh # Source ROS 1 + ROS 2,载入 bridge 设置
│ └── ros_entrypoint.sh # 仅 source ROS 环境(兼容 osrf)
│ ├── ros_entrypoint.sh # 仅 source ROS 环境(兼容 osrf)
│ ├── ros1_server.sh # Demo A publisher(自起 roscore + bridge)
│ ├── ros1_client.sh # Demo B subscriber
│ ├── ros2_server.sh # Demo B publisher(自起 roscore + bridge)
│ └── ros2_client.sh # Demo A subscriber
├── bridge.yaml # 默认 bridge 设置
├── config/ # 额外 bridge 设置
│ ├── scan_bridge.yaml # LaserScan bridge
│ └── release_bridge.yaml # Camera + depth bridge
│ ├── release_bridge.yaml # Camera + depth bridge
│ └── demo_bridge.yaml # Demo 双向 std_msgs/String
├── doc/ # 翻译版 README
│ ├── README.zh-TW.md # 繁体中文
│ ├── README.zh-CN.md # 简体中文
Expand Down
44 changes: 42 additions & 2 deletions doc/README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [快速開始](#快速開始)
- [使用方式](#使用方式)
- [Bridge 設定](#bridge-設定)
- [Demo](#demo)
- [架構](#架構)
- [目錄結構](#目錄結構)

Expand Down Expand Up @@ -126,6 +127,40 @@ services_2_to_1:
type: rcl_interfaces/GetParameters
```

## Demo

兩個 terminal 跑 end-to-end bridge demo,訊息型別 `std_msgs/String`。
規則對稱:**server** terminal 負責起 `roscore` + `parameter_bridge`
(讀 build 時烤進 image 的 `/demo_bridge.yaml`),**client** terminal 只訂閱。

| Demo | Terminal 1 (server) | Terminal 2 (client) |
|------|---------------------|---------------------|
| A — ROS 1 → ROS 2 | `./exec.sh /ros1_server.sh` | `./exec.sh /ros2_client.sh` |
| B — ROS 2 → ROS 1 | `./exec.sh /ros2_server.sh` | `./exec.sh /ros1_client.sh` |

實際操作(假設容器已用 `./run.sh -d` 起好):

```bash
# Terminal 1 (server) — 二選一
./exec.sh /ros1_server.sh # Demo A
./exec.sh /ros2_server.sh # Demo B

# Terminal 2 (client) — 對應的另一半
./exec.sh /ros2_client.sh # Demo A
./exec.sh /ros1_client.sh # Demo B
```

Server 腳本每一步都印出進度(`[ros1_server] step N/5: ...`),所以
`roscore` 跟 `parameter_bridge` 何時就緒一目了然。要換訊息字串用
`MESSAGE` 環境變數:

```bash
./exec.sh env MESSAGE="hi from ROS 1" /ros1_server.sh
```

Server terminal 按 `Ctrl+C` 會收掉 `parameter_bridge` 跟 `roscore`,
client terminal 接著就 EOF。

## 架構

```mermaid
Expand Down Expand Up @@ -168,11 +203,16 @@ ros1_bridge/
├── template/ # 共用腳本、測試、CI(git subtree)
├── script/
│ ├── entrypoint.sh # Source ROS 1 + ROS 2,載入 bridge 設定
│ └── ros_entrypoint.sh # 僅 source ROS 環境(相容 osrf)
│ ├── ros_entrypoint.sh # 僅 source ROS 環境(相容 osrf)
│ ├── ros1_server.sh # Demo A publisher(自起 roscore + bridge)
│ ├── ros1_client.sh # Demo B subscriber
│ ├── ros2_server.sh # Demo B publisher(自起 roscore + bridge)
│ └── ros2_client.sh # Demo A subscriber
├── bridge.yaml # 預設 bridge 設定
├── config/ # 額外 bridge 設定
│ ├── scan_bridge.yaml # LaserScan bridge
│ └── release_bridge.yaml # Camera + depth bridge
│ ├── release_bridge.yaml # Camera + depth bridge
│ └── demo_bridge.yaml # Demo 雙向 std_msgs/String
├── doc/ # 翻譯版 README
│ ├── README.zh-TW.md # 繁體中文
│ ├── README.zh-CN.md # 簡體中文
Expand Down
10 changes: 9 additions & 1 deletion doc/changelog/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Rebuild `devel` stage from `ros:foxy-ros-base-focal` (multi-arch) plus the ROS 1 snapshot apt repo instead of the amd64-only `osrf/ros:foxy-ros1-bridge`. Enables Jetson (arm64) support.
- `ENV ROS1_DISTRO=noetic` / `ENV ROS2_DISTRO=foxy` now baked into the image so downstream scripts can reference the distro names without hardcoding.
- Test stage lint target uses `COPY script/*.sh /lint/` (glob) to pick up new scripts automatically.
- Dockerfile `COPY` for `script/` switched from per-file (`entrypoint.sh`, `ros_entrypoint.sh`) to directory glob (`COPY --chmod=0755 script/ /`) so new helpers (the four demo scripts) are picked up without further Dockerfile edits.
- Bridge YAML examples now document the full `parameter_bridge` schema: `bridge.yaml` ships `services_1_to_2` / `services_2_to_1` entries and an inline QoS block on `/scan`; `config/scan_bridge.yaml` and `config/release_bridge.yaml` set sensor-data QoS (BEST_EFFORT for image streams, RELIABLE for `camera_info`). READMEs in all four languages note the topic (ROS 2) vs service (ROS 1) `type` format asymmetry.
- **Split `devel` and `runtime` into separate stages (USER-VISIBLE BEHAVIOR CHANGE).** `devel` CMD is now `bash` — `./run.sh` drops into an interactive shell instead of auto-launching `parameter_bridge`. `devel` ENTRYPOINT is `/ros_entrypoint.sh` (sources ROS1+ROS2 env only, no `rosparam load`) so the shell is usable immediately. The new `runtime` stage (`FROM devel`) keeps `CMD ["ros2", "run", "ros1_bridge", "parameter_bridge"]` and switches ENTRYPOINT back to `/entrypoint.sh` (which does `rosparam load /bridge.yaml` before launch) for production-style auto-bridge deployments. CI builds both (`build_runtime: true` in `main.yaml`). Note: `./run.sh runtime` does not yet work because the auto-generated `compose.yaml` does not emit a `runtime` service (tracked upstream in template); invoke runtime via direct `docker build --target runtime && docker run` until template provides this.

### Added
- `script/ros_entrypoint.sh` — osrf-compatible entrypoint that only sources both ROS distros (no `rosparam load`), available at `/ros_entrypoint.sh` in the image. `devel` stage uses this as its `ENTRYPOINT`; `runtime` stage keeps `/entrypoint.sh` (with `rosparam load`).
- Smoke tests: `ROS1_DISTRO`/`ROS2_DISTRO` env vars, `/ros_entrypoint.sh` existence + ability to source both ROS envs + expose `ros2`.
- **Demo scripts** — symmetric server/client pairs that run a 2-terminal end-to-end bridge demo with std_msgs/String. Each `*_server.sh` self-bootstraps `roscore` + `parameter_bridge` (loading `/demo_bridge.yaml`) before publishing, with explicit step-by-step logs (`[ros1_server] step N/5: ...`); each `*_client.sh` only sources the relevant distro and subscribes. Trap on the server tears down `roscore` + bridge on Ctrl+C.
- `script/ros1_server.sh` — Demo A publisher: bootstraps + `rostopic pub /chatter_1to2 std_msgs/String`. Pair with `ros2_client.sh`.
- `script/ros2_client.sh` — Demo A subscriber: `ros2 topic echo /chatter_1to2`.
- `script/ros2_server.sh` — Demo B publisher: bootstraps + `ros2 topic pub /chatter_2to1 std_msgs/msg/String`. Pair with `ros1_client.sh`.
- `script/ros1_client.sh` — Demo B subscriber: `rostopic echo /chatter_2to1`.
- `MESSAGE` env var overrides the published string on either server.
- `config/demo_bridge.yaml` — bidirectional `std_msgs/msg/String` bridge for `/chatter_1to2` and `/chatter_2to1`, baked into the image as `/demo_bridge.yaml` so the demo scripts pick it up without env overrides.
- Smoke tests: `ROS1_DISTRO`/`ROS2_DISTRO` env vars, `/ros_entrypoint.sh` existence + ability to source both ROS envs + expose `ros2`, plus 9 new demo-helper tests (4 scripts exist+executable, 4 `-h` prints `Usage:`, `/demo_bridge.yaml` exists). Total: 28 → 37.

### Removed
- `COPY config/ /config/` from Dockerfile and the `config directory exists` smoke test — the `/config/` directory was never read at runtime (entrypoint only loads `/bridge.yaml`). `config/*.yaml` files remain in the repo as reference examples and can still be consumed via `--build-arg BRIDGE_FILE=config/<file>.yaml`.
Expand Down
18 changes: 16 additions & 2 deletions doc/test/TEST.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TEST.md

**29 tests** total.
**38 tests** total.

## test/smoke/ros_env.bats

Expand All @@ -21,7 +21,7 @@
|------|-------------|
| `ros1_bridge package is available` | `ros2 pkg list` includes ros1_bridge |

### Bridge config (5)
### Bridge config (6)

| Test | Description |
|------|-------------|
Expand All @@ -32,6 +32,20 @@
| `ros_entrypoint.sh exposes ros2 command` | `ros2` binary is on `PATH` after entrypoint |
| `entrypoint.sh skips rosparam load when roscore unreachable` | `timeout 2 rosparam list` guards the `rosparam load` so a missing roscore doesn't hang container boot |

### Demo helpers (9)

| Test | Description |
|------|-------------|
| `demo_bridge.yaml exists` | `/demo_bridge.yaml` exists (built into image from `config/demo_bridge.yaml`) |
| `ros1_server.sh exists and is executable` | `/ros1_server.sh` is executable |
| `ros1_client.sh exists and is executable` | `/ros1_client.sh` is executable |
| `ros2_server.sh exists and is executable` | `/ros2_server.sh` is executable |
| `ros2_client.sh exists and is executable` | `/ros2_client.sh` is executable |
| `ros1_server.sh -h prints usage` | Help exits 0 with "Usage:" |
| `ros1_client.sh -h prints usage` | Help exits 0 with "Usage:" |
| `ros2_server.sh -h prints usage` | Help exits 0 with "Usage:" |
| `ros2_client.sh -h prints usage` | Help exits 0 with "Usage:" |

## test/smoke/script_help.bats

### build.sh (3)
Expand Down
41 changes: 41 additions & 0 deletions script/ros1_client.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
#
# Demo B — ROS 1 client (subscriber).
#
# Subscribes to /chatter_2to1 from ROS 1. Run ros2_server.sh on the other
# terminal first — it owns roscore + parameter_bridge.

set -e

readonly TOPIC="/chatter_2to1"

usage() {
cat >&2 <<EOF
Usage: ros1_client.sh [-h|--help]

Demo B (ROS 2 -> ROS 1) — client / subscriber side.

Subscribes to ${TOPIC} from ROS 1. Start ros2_server.sh on a second
terminal first — it owns roscore + parameter_bridge.
EOF
}

log() {
printf '[ros1_client] %s\n' "$*"
}

main() {
case "${1:-}" in
-h|--help) usage; exit 0 ;;
esac

log "step 1/2: sourcing ROS 1 (${ROS1_DISTRO})"
unset ROS_DISTRO
# shellcheck source=/dev/null
source "/opt/ros/${ROS1_DISTRO}/setup.bash"

log "step 2/2: subscribing to ${TOPIC} (Ctrl+C to stop)"
rostopic echo "${TOPIC}"
}

main "$@"
Loading
Loading