2 unstable releases
0.2.0 | Feb 7, 2022 |
---|---|
0.1.0 | Jan 27, 2022 |
#162 in Robotics
40KB
771 lines
bissel
bissel
is an experimental robotics-focused middleware for embedded Linux. It uses a star-shaped network topology, with a focus on ease-of-use and transparent design and operation. It is more similar to ZeroMQ than to higher-level frameworks like ROS/2, but uses central coordination process similar to MOOS-IvP. Bissel currently supports both publish/subscribe and publish/request messaging patterns over TCP.
Under the hood, bissel
relies on:
sled
: High-performance embedded, thread-safe databasetokio
: Asynchronous runtime, enabling a large number of simultaneous connectionspostcard
: Efficient#![no_std]
-compatible, serde-based de/serializer designed for embedded or constrained environments
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(())
}
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.
Additional benchmarking information can be found using cargo run --release --example benchmark
.
License
This library is licensed under the Mozilla Public License, version 2.0 (MPL-2.0)
Dependencies
~9–17MB
~207K SLoC