meadow

Crates.iomeadow
lib.rsmeadow
version0.1.0
sourcesrc
created_at2022-04-28 23:19:15.877128
updated_at2024-01-21 00:28:23.491811
descriptionRobotics-focused middleware for embedded Linux
homepage
repositoryhttps://github.com/quietlychris/meadow
max_upload_size
id577060
size208,575
chris m (quietlychris)

documentation

README

crates.io Documentation CI

Meadow

meadow is an experimental robotics-focused middleware for embedded Linux. It is built with a high preference for catching errors at compile-time over runtime and a focus on developer ergonomics, and can natively operate on any serde-compatible data type.

use meadow::*;

// `meadow` should be able to operate on any `serde`-compatible data types
// (the standard library Debug and Clone traits are also required)
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Coordinate {
    x: f32,
    y: f32,
}

fn main() -> Result<(), meadow::Error> {
    // The Host is running on localhost, but any network interface such as WiFi
    // or Ethernet are available as well
    let mut host: Host = HostConfig::default().build()?;
    host.start()?;
    // Other tasks can operate while the host is running in the background

    // Build a Node. Nodes can run over TCP, UDP, or QUIC
    let addr = "127.0.0.1:25000".parse::<std::net::SocketAddr>().unwrap();
    let node: Node<Udp, Idle, Coordinate> = NodeConfig::new("position")
        .with_config(node::NetworkConfig::<Udp>::default().set_host_addr(addr))
        .build()?;
    // Nodes use strict typestates; without using the activate() method first,
    // the compiler won't let allow publish() or request() methods on an Idle Node
    let node: Node<Udp, Active, Coordinate> = node.activate()?;

    // Since Nodes are statically-typed, the following lines would fail at
    // compile-time due to type errors
    // node.publish(1usize).unwrap()
    // let result: bool = node.request().unwrap();

    node.publish(Coordinate { x: 0.0, y: 0.0 })?;

    // Nodes can also be subscribers, which will request topic updates from the Host
    // at a given rate
    let subscriber = NodeConfig::<Tcp, Coordinate>::new("position")
        .with_config(node::NetworkConfig::<Tcp>::default().set_host_addr(addr))
        .build()?
        .subscribe(std::time::Duration::from_micros(100))?;

    for i in 0..5 {
        // Could get this by reading a GPS, for example
        let c = Coordinate {
            x: i as f32,
            y: i as f32,
        };
        node.publish(c)?;
        let result: Msg<Coordinate> = node.request()?;
        // or could use the value held by the subscribed node
        let subscription = subscriber.get_subscribed_data();
        println!("request: {:?}, subscription: {:?}", result, subscription);
    }

    Ok(())
}

Messaging Patterns

Meadow is more similar to ZeroMQ than to higher-level frameworks like ROS/2, but uses central coordination process similar to MOOS-IvP, resulting in a star-shaped network topology.

meadow currently supports the following messaging patterns:

Protocol Publish Request Subscribe Encryption
TCP X X X
UDP X X X
QUIC X X X X

Meadow's subscriber functionality currently works a bit differently than many other middlewares; rather than having the most recent data on the subscribed topic pushed to it by the Host upon receive, the Host will the most recent data subscribed topic as a requested rate to the Node, which will cache it locally to be available on-demand rather than on-request.

Key Dependencies

Under the hood, meadow relies on:

  • sled: High-performance embedded, thread-safe database
  • tokio: Asynchronous runtime, enabling a large number of simultaneous connections
  • postcard: Efficient #![no_std]-compatible, serde-based de/serializer designed for embedded or constrained environments. meadow should be able to operate native on any serde-compatible data types.

Benchmarks

Preliminary benchmark data is showing round-trip message times (publish-request-reply) on locahost using the --release compilation profile, on the README's Coordinate data (strongly-typed, 8 bytes) to be <100 microseconds. Statistical benchmarks on different data profiles can be run via criterion via cargo bench.

If you are doing robotics development, meadow is probably fast enough to move your data around (unless you're trying to do something like video streaming, in which case you should probably be using dedicated endpoints).

Stability

As mentioned above, this library should be considered experimental. While the goal is eventually to make this available at a level of maturity, stability, and reliability of other middlewares, meadow is not there yet. This library is being used as a dependency for robotics research, with interprocess communication focused on dozens of nodes on localhost or a few over a WLAN connection. While meadow can work for other use-cases, it has not been extensively tested in those areas. If you are using this library in other areas and come across issues or unexpected behavior, well-formatted bug reports or pull requests addressing those problems are welcomed.

Additional Resources

The following projects are built with Meadow:

  • Tutlesim: Simple 2D autonomy simulator
  • Orientation: Real-time 3D orientation visualization of a BNO055 IMU using Meadow and Bevy

License

This library is licensed under the Mozilla Public License, version 2.0 (MPL-2.0)

Commit count: 0

cargo fmt