Tomasz Czajka

Robotikk · Async Rust

Hvorfor r2r slår den klassiske ROS 2-stakken

ROS 2 er ryggraden i moderne robotikk, men måten de fleste av oss skriver noder på, med rclcpp eller rclpy bygget av colcon, har ikke eldet godt. r2r gir deg idiomatisk async Rust på den samme ROS 2-kjernen, og når du først har prøvd det, er det vanskelig å gå tilbake.

Rust r2r ROS 2 Tokio DDS
Den humanoide roboten Atlas sett forfra
Den humanoide roboten Atlas. Foto: DARPA, offentlig eiendom.

Først: hva r2r egentlig er

r2r erstatter ikke ROS 2 i seg selv. Det er et Rust-klientbibliotek som binder direkte mot rcl, det samme C-laget som rclcpp og rclpy bygger på, så nodene dine snakker fortsatt med alle andre ROS 2-noder over DDS. Det som endres, er alt over det laget: språket, samtidighetsmodellen og byggeverktøyene. Sammenligningen står altså mellom r2r og standardmåten å skrive ROS 2-noder på: C++ eller Python, bygget med colcon.

8 fordeler med r2r

1

Asynkront fra grunnen av

Abonnementer er Streams, tjenestekall og action-mål er Futures. Du kombinerer dem med tokio::select!, tidsavbrudd og kanaler i stedet for å sjonglere executors, callback-grupper og tilstand delt mellom callbacks.

2

Bare cargo, ingen colcon

Meldingsbindinger genereres ved bygging fra det innlastede ROS 2-miljøet. Ingen package.xml, ingen CMakeLists, ingen ament: cargo build, cargo test og rust-analyzer bare fungerer.

3

Minne- og trådsikkerhet

Kompilatoren utelukker datakappløp, use-after-free og hengende pekere i callbacks, de klassiske årsakene til at C++-noder krasjer. På en gående humanoid betyr det noe.

4

Samme ROS 2-kjerne under

Fordi r2r pakker inn rcl, fungerer det med enhver RMW-implementasjon (Fast DDS, Cyclone DDS, Zenoh) og samvirker med eksisterende C++- og Python-noder: topics, tjenester, actions, parametere og klokker.

5

Native hastighet, ingen GIL

Kompilert Rust med nullkostnadsabstraksjoner og uten søppeltømming. I motsetning til rclpy finnes det ingen Global Interpreter Lock som struper høyfrekvente topics, så latensen forblir forutsigbar.

6

Hele crates.io-økosystemet

serde, nalgebra, tracing, axum, WebRTC: en ROS 2-node, et web-API og en telemetristrøm i én binærfil, uten en eneste CMake find_package.

7

Utypede meldinger for broer

subscribe_untyped og create_publisher_untyped jobber med JSON via serde, så generiske broer, opptakere og feilsøkingsverktøy trenger ingen meldingstyper ved kompilering.

8

Moderne verktøy og utrulling

clippy, rustfmt, cargo test og reproduserbare Cargo.lock-bygg i CI. Lever én selvstendig binærfil i en slank container i stedet for et helt install/-tre.

Slik ser det ut

En komplett node: abonner på leddtilstander og publiser hastighetskommandoer, alt inne i en Tokio-runtime. Sammenlign med tilsvarende rclcpp-boilerplate.

# Cargo.toml
[dependencies]
r2r = "0.9"
tokio = { version = "1", features = ["full"] }
futures = "0.3"

# build & run: no colcon, no package.xml
$ source /opt/ros/jazzy/setup.bash
$ cargo run --release
use futures::StreamExt;
use r2r::{geometry_msgs::msg::Twist, sensor_msgs::msg::JointState, QosProfile};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ctx = r2r::Context::create()?;
    let mut node = r2r::Node::create(ctx, "teleop_bridge", "")?;

    let mut joints = node.subscribe::<JointState>("/joint_states", QosProfile::default())?;
    let cmd = node.create_publisher::<Twist>("/cmd_vel", QosProfile::default())?;

    // rcl spins on its own thread, everything else is plain async Rust
    tokio::task::spawn_blocking(move || loop {
        node.spin_once(std::time::Duration::from_millis(5));
    });

    while let Some(state) = joints.next().await {
        let mut twist = Twist::default();
        twist.linear.x = state.velocity.first().copied().unwrap_or(0.0) * 0.5;
        cmd.publish(&twist)?;
    }
    Ok(())
}

For å være rettferdig: avveiningene

  • r2r vedlikeholdes av fellesskapet og er ikke et av de offisielle ROS 2-klientbibliotekene, så det finnes færre veiledninger og svar enn for rclcpp eller rclpy.
  • Bygging krever en innlastet ROS 2-installasjon, siden bindingene genereres fra meldingspakkene den finner.
  • Det første bygget er tregt, fordi bindgen og meldingsgenerering kjører for hver pakke. Inkrementelle bygg går fint.
  • Launch-filer og colcon-arbeidsområder trenger litt lim (for eksempel colcon-ros-cargo) for å behandle en cargo-crate som en ROS-pakke.

Konklusjon

For ny mellomvare, broer, teleoperasjon og styringspipelines er r2r det beste standardvalget: asynkronitet som faktisk passer robotikk-I/O, sikkerhet ved kompilering og et bygg som bare er cargo. Behold rclcpp for eldre kode og leverandørdrivere; velg r2r for alt nytt.