Skip to content

Commit f1c4716

Browse files
committed
Merge execution structure PR
Signed-off-by: Michael X. Grey <[email protected]>
2 parents 22d2c84 + 0918476 commit f1c4716

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+3790
-627
lines changed

.github/workflows/rust.yml renamed to .github/workflows/rust-minimal.yml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
name: Rust
1+
name: Rust Minimal
22

33
on:
44
push:
55
branches: [ main ]
66
pull_request:
77
branches: [ main ]
88
schedule:
9-
- cron: '0 0 * * *'
9+
# Run the CI at 02:22 UTC every Tuesday
10+
# We pick an arbitrary time outside of most of the world's work hours
11+
# to minimize the likelihood of running alongside a heavy workload.
12+
- cron: '22 2 * * 2'
1013

1114
env:
1215
CARGO_TERM_COLOR: always
@@ -42,7 +45,11 @@ jobs:
4245
- name: Search packages in this repository
4346
id: list_packages
4447
run: |
45-
echo ::set-output name=package_list::$(colcon list --names-only)
48+
{
49+
echo 'package_list<<EOF'
50+
colcon list --names-only
51+
echo EOF
52+
} >> "$GITHUB_OUTPUT"
4653
4754
- name: Setup ROS environment
4855
uses: ros-tooling/[email protected]
@@ -51,7 +58,7 @@ jobs:
5158
use-ros2-testing: ${{ matrix.ros_distribution == 'rolling' }}
5259

5360
- name: Setup Rust
54-
uses: dtolnay/rust-toolchain@1.74.0
61+
uses: dtolnay/rust-toolchain@1.75
5562
with:
5663
components: clippy, rustfmt
5764

@@ -69,10 +76,6 @@ jobs:
6976
cd -
7077
done
7178
72-
- name: Install cargo-ament-build
73-
run: |
74-
cargo install --debug cargo-ament-build
75-
7679
- name: Build and test
7780
id: build
7881
uses: ros-tooling/[email protected]
@@ -90,9 +93,9 @@ jobs:
9093
echo "Running clippy in $path"
9194
# Run clippy for all features except generate_docs (needed for docs.rs)
9295
if [ "$(basename $path)" = "rclrs" ]; then
93-
cargo clippy --all-targets -F default,dyn_msg -- -D warnings
96+
cargo clippy --no-deps --all-targets -F default,dyn_msg -- -D warnings
9497
else
95-
cargo clippy --all-targets --all-features -- -D warnings
98+
cargo clippy --no-deps --all-targets --all-features -- -D warnings
9699
fi
97100
cd -
98101
done

.github/workflows/rust-stable.yml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
name: Rust Stable
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
schedule:
9+
# Run the CI at 02:22 UTC every Tuesday
10+
# We pick an arbitrary time outside of most of the world's work hours
11+
# to minimize the likelihood of running alongside a heavy workload.
12+
- cron: '22 2 * * 2'
13+
14+
env:
15+
CARGO_TERM_COLOR: always
16+
17+
jobs:
18+
build:
19+
strategy:
20+
matrix:
21+
ros_distribution:
22+
- humble
23+
- iron
24+
- rolling
25+
include:
26+
# Humble Hawksbill (May 2022 - May 2027)
27+
- docker_image: rostooling/setup-ros-docker:ubuntu-jammy-ros-humble-ros-base-latest
28+
ros_distribution: humble
29+
ros_version: 2
30+
# Iron Irwini (May 2023 - November 2024)
31+
- docker_image: rostooling/setup-ros-docker:ubuntu-jammy-ros-iron-ros-base-latest
32+
ros_distribution: iron
33+
ros_version: 2
34+
# Rolling Ridley (June 2020 - Present)
35+
- docker_image: rostooling/setup-ros-docker:ubuntu-jammy-ros-rolling-ros-base-latest
36+
ros_distribution: rolling
37+
ros_version: 2
38+
runs-on: ubuntu-latest
39+
continue-on-error: ${{ matrix.ros_distribution == 'rolling' }}
40+
container:
41+
image: ${{ matrix.docker_image }}
42+
steps:
43+
- uses: actions/checkout@v4
44+
45+
- name: Search packages in this repository
46+
id: list_packages
47+
run: |
48+
{
49+
echo 'package_list<<EOF'
50+
colcon list --names-only
51+
echo EOF
52+
} >> "$GITHUB_OUTPUT"
53+
54+
- name: Setup ROS environment
55+
uses: ros-tooling/[email protected]
56+
with:
57+
required-ros-distributions: ${{ matrix.ros_distribution }}
58+
use-ros2-testing: ${{ matrix.ros_distribution == 'rolling' }}
59+
60+
- name: Setup Rust
61+
uses: dtolnay/rust-toolchain@stable
62+
with:
63+
components: clippy, rustfmt
64+
65+
- name: Install colcon-cargo and colcon-ros-cargo
66+
run: |
67+
sudo pip3 install git+https://github.com/colcon/colcon-cargo.git
68+
sudo pip3 install git+https://github.com/colcon/colcon-ros-cargo.git
69+
70+
- name: Check formatting of Rust packages
71+
run: |
72+
for path in $(colcon list | awk '$3 == "(ament_cargo)" { print $2 }'); do
73+
cd $path
74+
rustup toolchain install nightly
75+
cargo +nightly fmt -- --check
76+
cd -
77+
done
78+
79+
- name: Build and test
80+
id: build
81+
uses: ros-tooling/[email protected]
82+
with:
83+
package-name: ${{ steps.list_packages.outputs.package_list }}
84+
target-ros2-distro: ${{ matrix.ros_distribution }}
85+
vcs-repo-file-url: ros2_rust_${{ matrix.ros_distribution }}.repos
86+
87+
- name: Run clippy on Rust packages
88+
run: |
89+
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
90+
. /opt/ros/${{ matrix.ros_distribution }}/setup.sh
91+
for path in $(colcon list | awk '$3 == "(ament_cargo)" { print $2 }'); do
92+
cd $path
93+
echo "Running clippy in $path"
94+
# Run clippy for all features except generate_docs (needed for docs.rs)
95+
if [ "$(basename $path)" = "rclrs" ]; then
96+
cargo clippy --no-deps --all-targets -F default,dyn_msg -- -D warnings
97+
else
98+
cargo clippy --no-deps --all-targets --all-features -- -D warnings
99+
fi
100+
cd -
101+
done
102+
103+
- name: Run cargo test on Rust packages
104+
run: |
105+
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
106+
. install/setup.sh
107+
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" && $1 != "rust_pubsub" { print $2 }'); do
108+
cd $path
109+
echo "Running cargo test in $path"
110+
# Run cargo test for all features except generate_docs (needed for docs.rs)
111+
if [ "$(basename $path)" = "rclrs" ]; then
112+
cargo test -F default,dyn_msg
113+
elif [ "$(basename $path)" = "rosidl_runtime_rs" ]; then
114+
cargo test -F default
115+
else
116+
cargo test --all-features
117+
fi
118+
cd -
119+
done
120+
121+
- name: Rustdoc check
122+
run: |
123+
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
124+
. /opt/ros/${{ matrix.ros_distribution }}/setup.sh
125+
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" && $1 != "rust_pubsub" { print $2 }'); do
126+
cd $path
127+
echo "Running rustdoc check in $path"
128+
cargo rustdoc -- -D warnings
129+
cd -
130+
done

Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ RUN apt-get update && apt-get install -y \
1111
python3-pip \
1212
&& rm -rf /var/lib/apt/lists/*
1313

14-
# Install Rust and the cargo-ament-build plugin
15-
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.74.0 -y
14+
# Install Rust
15+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.75.0 -y
1616
ENV PATH=/root/.cargo/bin:$PATH
17-
RUN cargo install cargo-ament-build
1817

1918
RUN pip install --upgrade pytest
2019

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
ROS 2 for Rust
22
==============
33

4-
| Target | Status |
5-
|----------|--------|
6-
| **Ubuntu 20.04** | [![Build Status](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust.yml?branch=main) |
4+
[![Minimal Version Status](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust-minimal.yml/badge.svg?branch=main)](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust-minimal.yml)
5+
[![Stable CI Status](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust-stable.yml/badge.svg?branch=main)](https://github.com/ros2-rust/ros2_rust/actions/workflows/rust-stable.yml)
6+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
77

88
Introduction
99
------------
@@ -37,7 +37,6 @@ Here are the steps for building the `ros2_rust` examples in a vanilla Ubuntu Foc
3737
# Assuming you installed the minimal version of ROS 2, you need these additional packages:
3838
sudo apt install -y git libclang-dev python3-pip python3-vcstool # libclang-dev is required by bindgen
3939
# Install these plugins for cargo and colcon:
40-
cargo install --debug cargo-ament-build # --debug is faster to install
4140
pip install git+https://github.com/colcon/colcon-cargo.git
4241
pip install git+https://github.com/colcon/colcon-ros-cargo.git
4342

docs/building.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ The exact steps may differ between platforms, but as an example, here is how you
4343
# Assuming you installed the minimal version of ROS 2, you need these additional packages:
4444
sudo apt install -y git libclang-dev python3-pip python3-vcstool # libclang-dev is required by bindgen
4545
# Install these plugins for cargo and colcon:
46-
cargo install cargo-ament-build
4746
pip install git+https://github.com/colcon/colcon-cargo.git
4847
pip install git+https://github.com/colcon/colcon-ros-cargo.git
4948
```

docs/message-generation.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# `ros2_rust` Message Generation
2+
3+
The `ros2_rust` project strives to maintain consistency with the upstream ROS 2 message generation
4+
system. To this end, it provides two main packages: `rosidl_generator_rs` and `rosidl_runtime_rs`.
5+
These packages provide the infrastructure required for defining and using ROS 2 messages, services,
6+
and actions in Rust.
7+
8+
At a high level, the `rosidl_generator_rs` package handles generation of interface crates from the
9+
`.msg`, `.srv`, and `.action` files defined by a user. The `rosidl_runtime_rs` package provides
10+
common functionality shared across message packages, such as support types and traits. Each of these
11+
packages is described in more detail below.
12+
13+
## `rosidl_generator_rs`
14+
15+
`rosidl_generator_rs` follows a very similar pattern to the other message generation packages for
16+
ROS 2. To tie into this pipeline, it registers itself as a `"rosidl_generate_idl_interfaces"`
17+
extension with `ament`. Doing so ensures that message packages calling `rosidl_generate_interfaces`
18+
will invoke the Rust language generator in addition to any others. This is accomplished using the
19+
various CMake scripts under the `cmake` directory. When this happens, the input interface files will
20+
be converted into IDL files which, along with additional metadata, are fed into the `generate_rs`
21+
function of `rosidl_generator_rs/__init__.py`.
22+
23+
From here, the IDL files are parsed into an internal representation using the upstream
24+
[`rosidl_parser`](https://github.com/ros2/rosidl/tree/rolling/rosidl_parser) package. This abstract
25+
representation is then used to instantiate the various template files under the `resource`
26+
subdirectory, producing a full Rust crate for each package.
27+
28+
For each input message type, two `struct`s are generated:
29+
30+
- An ergonomic representation of the message, using more idiomatic `std` types like `Vec` and
31+
`String` for sequence and string fields. These are placed directly in the `msg` submodule of the
32+
crate.
33+
- A FFI-suitable `struct` that is ABI-compatible with the layout expected by the RMW layer. While
34+
less ergonomic, these avoid the conversion overhead when passed to RMW. These `struct`s are placed
35+
under the `msg::rmw` submodule.
36+
37+
All the produced `struct`s implement the standard traits from `std` when possible, such as `Clone`,
38+
`PartialEq`, and `Debug`. Additionally, when the generated crate's `serde` feature is enabled, these
39+
structs implement the `Serialize` and `Deserialize` traits.
40+
41+
## `rosidl_runtime_rs`
42+
43+
`rosidl_runtime_rs` is a runtime support package, providing `Message`, `Service`, and `Action`
44+
traits that are implemented by the corresponding structs generated by `rosidl_generator_rs`. These
45+
allow for generic interaction with these various interface types, both in client libraries like
46+
`rclrs` and in user code.
47+
48+
The package also provides a number of string and sequence types that are ABI-compatible with their
49+
`rosidl_runtime_c` equivalents. This allows for more ergonomic use of the RMW-native message types.

examples/message_demo/src/message_demo.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{convert::TryInto, env, sync::Arc};
1+
use std::convert::TryInto;
22

33
use anyhow::{Error, Result};
44
use rosidl_runtime_rs::{seq, BoundedSequence, Message, Sequence};
@@ -138,8 +138,8 @@ fn demonstrate_sequences() {
138138
fn demonstrate_pubsub() -> Result<(), Error> {
139139
println!("================== Interoperability demo ==================");
140140
// Demonstrate interoperability between idiomatic and RMW-native message types
141-
let context = rclrs::Context::new(env::args())?;
142-
let node = rclrs::create_node(&context, "message_demo")?;
141+
let mut executor = rclrs::Context::default_from_env()?.create_basic_executor();
142+
let node = executor.create_node("message_demo")?;
143143

144144
let idiomatic_publisher = node.create_publisher::<rclrs_example_msgs::msg::VariousTypes>(
145145
"topic",
@@ -166,10 +166,10 @@ fn demonstrate_pubsub() -> Result<(), Error> {
166166
)?;
167167
println!("Sending idiomatic message.");
168168
idiomatic_publisher.publish(rclrs_example_msgs::msg::VariousTypes::default())?;
169-
rclrs::spin_once(Arc::clone(&node), None)?;
169+
executor.spin(rclrs::SpinOptions::spin_once())?;
170170
println!("Sending RMW-native message.");
171171
direct_publisher.publish(rclrs_example_msgs::msg::rmw::VariousTypes::default())?;
172-
rclrs::spin_once(Arc::clone(&node), None)?;
172+
executor.spin(rclrs::SpinOptions::spin_once())?;
173173

174174
Ok(())
175175
}

examples/minimal_client_service/src/minimal_client.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
use std::env;
2-
31
use anyhow::{Error, Result};
42

53
fn main() -> Result<(), Error> {
6-
let context = rclrs::Context::new(env::args())?;
4+
let mut executor = rclrs::Context::default_from_env()?.create_basic_executor();
75

8-
let node = rclrs::create_node(&context, "minimal_client")?;
6+
let node = executor.create_node("minimal_client")?;
97

108
let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;
119

@@ -30,5 +28,7 @@ fn main() -> Result<(), Error> {
3028
std::thread::sleep(std::time::Duration::from_millis(500));
3129

3230
println!("Waiting for response");
33-
rclrs::spin(node).map_err(|err| err.into())
31+
executor
32+
.spin(rclrs::SpinOptions::default())
33+
.map_err(|err| err.into())
3434
}

examples/minimal_client_service/src/minimal_client_async.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use std::env;
2-
31
use anyhow::{Error, Result};
42

53
#[tokio::main]
64
async fn main() -> Result<(), Error> {
7-
let context = rclrs::Context::new(env::args())?;
5+
let mut executor = rclrs::Context::default_from_env()?.create_basic_executor();
86

9-
let node = rclrs::create_node(&context, "minimal_client")?;
7+
let node = executor.create_node("minimal_client")?;
108

119
let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;
1210

@@ -22,7 +20,8 @@ async fn main() -> Result<(), Error> {
2220

2321
println!("Waiting for response");
2422

25-
let rclrs_spin = tokio::task::spawn_blocking(move || rclrs::spin(node));
23+
let rclrs_spin =
24+
tokio::task::spawn_blocking(move || executor.spin(rclrs::SpinOptions::default()));
2625

2726
let response = future.await?;
2827
println!(

examples/minimal_client_service/src/minimal_service.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::env;
2-
31
use anyhow::{Error, Result};
42

53
fn handle_service(
@@ -13,13 +11,15 @@ fn handle_service(
1311
}
1412

1513
fn main() -> Result<(), Error> {
16-
let context = rclrs::Context::new(env::args())?;
14+
let mut executor = rclrs::Context::default_from_env()?.create_basic_executor();
1715

18-
let node = rclrs::create_node(&context, "minimal_service")?;
16+
let node = executor.create_node("minimal_service")?;
1917

2018
let _server = node
2119
.create_service::<example_interfaces::srv::AddTwoInts, _>("add_two_ints", handle_service)?;
2220

2321
println!("Starting server");
24-
rclrs::spin(node).map_err(|err| err.into())
22+
executor
23+
.spin(rclrs::SpinOptions::default())
24+
.map_err(|err| err.into())
2525
}

0 commit comments

Comments
 (0)