#middleware #embedded-linux #networking #autonomy

bissel

针对嵌入式 Linux 的机器人专注的发布/订阅/请求/响应中间件

2 个不稳定版本

0.2.0 2022 年 2 月 7 日
0.1.0 2022 年 1 月 27 日

#141机器人

MPL-2.0 许可协议

40KB
771

crates.io Documentation CI

bissel

bissel 是一个针对嵌入式 Linux 的实验性机器人专注中间件。它使用星形网络拓扑,注重易用性和透明的设计和操作。它比高级框架如 ROS/2 更类似于 ZeroMQ,但使用类似于 MOOS-IvP 的中央协调过程。Bissel 目前支持 TCP 上的发布/订阅和发布/请求消息模式。

在底层,bissel 依赖于

  • sled: 高性能嵌入式、线程安全数据库
  • tokio: 异步运行时,支持大量并发连接
  • postcard: 高效的 #![no_std]-兼容,基于 serde 的 de/序列化器,适用于嵌入式或受限环境
use bissel::*;
use serde::{Deserialize, Serialize};

// Any type implementing Debug and serde's De/Serialize traits are Bissel-compatible
// (the standard library Debug and Clone traits are also required)
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Coordinate {
    x: f32,
    y: f32,
}

fn main() -> Result<(), Box<dyn std::error::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::new("lo")
        .socket_num(25_000)
        .store_filename("store")
        .build()
        .unwrap();
    host.start().unwrap();
    // Other tasks can operate while the host is running in the background
    
    // Build a Node
    let addr = "127.0.0.1:25000".parse::<std::net::SocketAddr>().unwrap();
    let node: Node<Idle, Coordinate> = NodeConfig::new("GPS_NODE")
        .topic("position")
        .host_addr(addr)
        .build()?;
    // Bissel Nodes use strict typestates; without using the connect() method first,
    // the compiler won't let you use the publish() or request() methods on an Idle Node
    let mut node: Node<Active, Coordinate> = node.connect()?;

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

    let c = Coordinate { x: 4.0, y: 4.0 };
    node.publish(c).unwrap();

    // 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();

    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)?;
        std::thread::sleep(std::time::Duration::from_millis(100));
        let result = node.request()?;
        // or could use the value held by the subscribed node
        let subscription = subscriber.get_subscribed_data().unwrap();
        println!("Got position: {:?}", result);
    }

    // host.stop()?;
    Ok(())
}

基准测试

初步基准数据显示,使用 --release 编译配置在 locahost 上进行的往返消息时间(发布-请求-回复)在 README 的 Coordinate 数据(强类型,8 字节)上约为 100 微秒。

更多信息可以使用 cargo run --release --example benchmark 命令获取。

许可协议

此库根据Mozilla公共许可证,版本2.0(MPL-2.0)授权

依赖项

~9–17MB
~206K SLoC