Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"remoteEnv": {
"SSH_AUTH_SOCK": "/ssh-agent"
},
"postCreateCommand": "bash -lc 'source \"/opt/ros/${ROS_DISTRO}/setup.bash\" && mkdir -p src/externals && if [ -f external.repos ]; then vcs import --recursive --skip-existing src/externals < external.repos; fi && ./scripts/apply-external-patches.sh && ./src/externals/cpp-tools/install.sh --repo-root \"$PWD\" && rosdep update --rosdistro \"${ROS_DISTRO}\" && apt-get update && rosdep install --from-paths src/ros_portal src/ros_portal_config src/ros_portal_msgs src/externals/ros2_medkit/src/ros2_medkit_cmake src/externals/ros2_medkit/src/ros2_medkit_serialization --ignore-src -r -y --rosdistro \"${ROS_DISTRO}\" --skip-keys ament_cmake_clang_tidy'",
"postCreateCommand": "bash -lc 'source \"/opt/ros/${ROS_DISTRO}/setup.bash\" && mkdir -p src/externals && if [ -f external.repos ]; then vcs import --recursive --skip-existing src/externals < external.repos; fi && ./scripts/apply-external-patches.sh && ./src/externals/cpp-tools/install.sh --repo-root \"$PWD\" && rosdep update --rosdistro \"${ROS_DISTRO}\" && apt-get update && rosdep install --from-paths src/ros_portal src/ros_portal_config src/ros_portal_msgs src/externals/ros2_medkit/src/ros2_medkit_cmake src/externals/ros2_medkit/src/ros2_medkit_serialization src/test/waver/bringup/ src/test/cobra_flex/bringup/ --ignore-src -r -y --rosdistro \"${ROS_DISTRO}\" --skip-keys ament_cmake_clang_tidy'",
"postStartCommand": "bash -lc 'if [ -d src/externals ]; then for repo in src/externals/*; do if [ -d \"$repo/.git\" ]; then if [ -n \"$(git -C \"$repo\" status --porcelain)\" ]; then echo \"Skipping pull for $repo because it has local changes\"; elif ! git -C \"$repo\" symbolic-ref --quiet --short HEAD >/dev/null; then echo \"Skipping pull for $repo because it is detached HEAD\"; else git -C \"$repo\" pull --recurse-submodules; fi; fi; done; fi'",
"customizations": {
"vscode": {
Expand Down
156 changes: 156 additions & 0 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Copyright 2026 LiveKit
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
cpp-tools:
name: C++ Tools
uses: ./.github/workflows/cpp-tools.yml

build-and-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
name: linux-x64
- os: ubuntu-24.04-arm
name: linux-arm64

name: Build and Tests (${{ matrix.name }})
runs-on: ${{ matrix.os }}

steps:
- name: Check out repository
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1

- name: Prepare devcontainer SSH agent mount
run: touch /tmp/devcontainer-empty-ssh-agent

- name: Setup devcontainer environment
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3
env:
GITHUB_TOKEN: ${{ github.token }}
with:
configFile: .devcontainer/devcontainer.json
push: never

- name: Build packages
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3
env:
DEVCONTAINER_SSH_AUTH_SOCK: /tmp/devcontainer-empty-ssh-agent
GITHUB_TOKEN: ${{ github.token }}
with:
configFile: .devcontainer/devcontainer.json
push: never
runCmd: |
bash -lc '
set -eo pipefail
source /opt/ros/jazzy/setup.bash
set -u
# target specific packages to avoid unneeded/wanted dependencies
colcon build --packages-up-to ros2_livekit_bridge test_utilities custom_msgs waver_bringup
'

- name: "colcon test: unit"
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3
with:
configFile: .devcontainer/devcontainer.json
push: never
runCmd: |
bash -lc '
set -eo pipefail
source /opt/ros/jazzy/setup.bash
source install/setup.bash
set -u

# --event-handlers console_direct+ streams test output live
# --ctest-args -R ros2_livekit_bridge_unit_tests runs only the unit tests
test_exit=0
GTEST_COLOR=1 colcon test \
--packages-up-to ros2_livekit_bridge test_utilities custom_msgs waver_bringup \
--packages-skip ros2_medkit_serialization \
--event-handlers console_direct+ \
--return-code-on-test-failure \
--ctest-args -R ros2_livekit_bridge_unit_tests \
|| test_exit=$?
colcon test-result --verbose --all
exit $test_exit
'

- name: Start livekit-server
id: livekit_server
uses: livekit/dev-server-action@6562d7d9343e46c26ead1223151f64f00e4fc37f # v1.1.0
with:
github-token: ${{ github.token }}
version: v1.13.3
config: |
enable_participant_data_blob: true

- name: Install livekit-cli
run: |
set -euxo pipefail
curl -sSL https://get.livekit.io/cli | bash
lk --version

- name: "colcon test: integration"
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3
env:
CI: true
GITHUB_TOKEN: ${{ github.token }}
LIVEKIT_URL: ws://127.0.0.1:7880
LIVEKIT_ROOM: ros2_livekit_bridge_test_room
with:
configFile: .devcontainer/devcontainer.json
push: never
runCmd: |
bash -lc '
set -eo pipefail
source /opt/ros/jazzy/setup.bash
source install/setup.bash
set -u

source .token_helpers/set_test_tokens.bash

# --event-handlers console_direct+ streams test output live
# -R selects only the integration test
test_exit=0
GTEST_COLOR=1 colcon test \
--packages-select ros2_livekit_bridge \
--event-handlers console_direct+ \
--return-code-on-test-failure \
--ctest-args -R ros2_livekit_bridge_integration_tests \
|| test_exit=$?
colcon test-result --verbose --all
exit $test_exit
'

- name: Dump LiveKit server log on failure
if: failure()
run: tail -n 500 "${{ steps.livekit_server.outputs.log-path }}" || true
24 changes: 23 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,31 @@ RUN if [ "${INSTALL_SIMULATION_DEPS}" = "true" ]; then \
ros-${ROS_DISTRO}-navigation2 \
ros-${ROS_DISTRO}-robot-localization \
ros-${ROS_DISTRO}-ros-gz-* \
ros-${ROS_DISTRO}-ros2-control* && \
ros-${ROS_DISTRO}-ros2-control* \
&& \
rm -rf /var/lib/apt/lists/*; \
fi

# CycloneDDS RMW. This stack runs on Cyclone rather than the ROS 2 default
# (Fast DDS): on the CPU-bound Pi 4, Fast DDS starved the slam_toolbox
# (map->odom) and rf2o (odom->base) TF publishers and produced continuous TF
# extrapolation errors. Cyclone is lighter and Nav2 is most reliable with it.
# Selected via RMW_IMPLEMENTATION (set below). See src/test/waver/README.md.
RUN apt-get update && apt-get install -y \
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
&& \
rm -rf /var/lib/apt/lists/*

# Middleware config baked into the image so EVERY shell and process in the
# container inherits it (no manual export needed). Cyclone as the RMW (installed
# above); DDS discovery restricted to localhost because cross-machine transport
# goes over the LiveKit bridge, not raw DDS — this saves CPU and prevents two
# robots on the same LAN + ROS_DOMAIN_ID from cross-discovering each other's
# graphs. Trade-off: the graph is no longer reachable via ros2 CLI / RViz from
# another machine (inspect on the Pi, or via LiveKit/Foxglove). To allow remote
# DDS access, override at runtime: -e ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET.
ENV RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
ENV ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST

COPY ./setup-shell-env.sh /tmp/setup-shell-env.sh
RUN chmod +x /tmp/setup-shell-env.sh && /tmp/setup-shell-env.sh && rm /tmp/setup-shell-env.sh
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ ros2 launch ros_portal ros_portal.launch.py

To get familiar with using ROS Portal, you can follow the [tutorials](docs/tutorials.md).

To run in a container without an IDE, see [Running the container without an IDE](docs/development.md#running-the-container-without-an-ide).

## User Guides

- [Installing Debian packages](docs/installation.md): supported ROS and Ubuntu
Expand Down Expand Up @@ -88,6 +90,7 @@ To get familiar with using ROS Portal, you can follow the [tutorials](docs/tutor
- `ros_portal_msgs`: custom message definitions for ROS Portal.
- [`ros_portal_tutorials`](src/ros_portal_tutorials/README.md):
tutorials for using ROS Portal in a variety of scenarios.
- [`waveshare_launch`](src/test/waveshare_launch/README.md): a package for for launching real world and simulated 4-wheeled waveshare WAVER robot.
- [`waver`](src/test/waver/README.md): packages for launching the physical and simulated Waveshare WAVE ROVER.
- [`cobra_flex`](src/test/cobra_flex/README.md): packages for launching the physical and simulated Cobra Flex robot.

Other package READMEs under `src/` document package-specific setup, fixtures, or examples.
50 changes: 50 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,53 @@ From the rootful devcontainer, run:
The package and its checksum are written to `artifacts/debian/`. CI performs
the same build and then installs the package into a clean ROS base image for
smoke testing.
__NOTE:__ If in the devcontainer, mount the SDK install prefix from the host before building. Or move the install artifacts to the root of the repo.

### Building Against A PR Pipeline Artifact

To build against the SDK produced by a `client-sdk-cpp` GitHub Actions run, pass
the run ID:

```bash
GITHUB_TOKEN=<pat-with-actions-read> colcon build \
--packages-select ros2_livekit_bridge \
--cmake-args -DLIVEKIT_SDK_ARTIFACT_RUN_ID=<run-id>
```

- Find the run ID in the trailing number of the Actions run URL:
`.../actions/runs/<run-id>`.
- A token with Actions read access is required. `gh auth token` is usually
enough when authenticated with the GitHub CLI.
- Artifacts are matched by name, defaulting to `livekit-sdk-<host-triple>`, such
as `livekit-sdk-linux-x64`.
- Override the artifact name with `-DLIVEKIT_SDK_ARTIFACT_NAME=<name>`.
- Override the source repository with
`-DLIVEKIT_SDK_ARTIFACT_REPO=<org/repo>`. The default is
`livekit/client-sdk-cpp`.

The artifact is cached under
`build/.../_deps/livekit-sdk/artifact-<run-id>-<triple>/`. Delete that directory
to force a refetch. `LIVEKIT_SDK_ARTIFACT_RUN_ID` takes precedence over
`LIVEKIT_SDK_VERSION` but not over `LIVEKIT_LOCAL_SDK_DIR`.

If the artifact does not include the exported `lib/cmake/LiveKit` package
config, the bridge build synthesizes a minimal one into the extracted prefix so
`find_package(LiveKit CONFIG)` resolves. A future SDK workflow should install to
a staging prefix and upload that instead.


## Running the container without an IDE
1. Build the cointainer
```bash
docker build -t ros2-livekit-bridge-dev --build-arg WS_ROS=livekit_ws .
```

2. Run the container
```bash
docker run -d --name livekit-dev --privileged --init --ipc=host --network=host -v "$PWD":/livekit_ws -w /livekit_ws ros2-livekit-bridge-dev sleep infinity
```

3 Exec into the container
```bash
docker exec -it livekit-dev bash
```
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Testing

There are unit and integration tests which are run in CI. For more manual integration testing we have a simulation, see [`waveshare_launch`](../src/test/waveshare_launch/README.md): a package for for launching real world and simulated 4-wheeled waveshare WAVER robot.
There are unit and integration tests which are run in CI. For more manual integration testing we have a simulation, see [`waver`](../src/test/waver/README.md): packages for launching the physical and simulated Waveshare WAVE ROVER.

## Unit Tests

Expand Down
4 changes: 4 additions & 0 deletions external.repos
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ repositories:
type: git
url: https://github.com/GGomezMorales/waver.git
version: 9146ead456dc57f6b4bdaa1a8ca1c7b9fdb59465
rf2o_laser_odometry:
type: git
url: https://github.com/MAPIRlab/rf2o_laser_odometry.git
version: ros2
Loading
Loading