はじめに
関係ありませんが、今年初の投稿です。
最近Zenohの開発をしていてROS2のLaunchみたいなことできないかなと思い、奮闘した記録です。
どのようにしたか
はじめはコマンドラインツールによる実装を考え作ろうとしてみたのですが、うまくいかず挫折しました。
そこでROS2みたいな実装を思い出しcomponent.cppとnode.cppに分ける感じでつくればいいのではと考えました。(説明下手でスミマセン...)
成果
ノード実装例
適当なコードを実装しました
ファイル構造はリポジトリをご確認ください。
まずlib.rsでメインの機能を定義します。
use zenoh::{
Error,
config::Config,
prelude::r#async::*,
};
use std::time::Duration;
pub async fn pub_test(node_name:&str)->Result<(), Error>
{
let session = zenoh::open(Config::default()).res().await.unwrap();
let topic = "test_topic";
let publisher = session.declare_publisher(topic).res().await.unwrap();
let mut count = 0;
println!("Start {}", node_name);
loop {
let msg = format!("Hello {}", count);
publisher.put(msg).res().await.unwrap();
count += 1;
std::thread::sleep(Duration::from_millis(1000));
}
}
pub async fn sub_test(node_name:&str)->Result<(), Error>
{
let session = zenoh::open(Config::default()).res().await.unwrap();
let topic = "test_topic";
let subscriber = session.declare_subscriber(topic).res().await.unwrap();
println!("Start {}", node_name);
loop {
let sample = subscriber.recv_async().await.unwrap();
println!("Recv:{}", sample.value.to_string());
}
}
適当なPubSubですね
引数でノード名を指定できるようにしました。(ROS2でいうRemapとかできそうですね)
Launchしてみる
それでは別のパッケージから呼び出してみます。
Cargo.tomlでは今回呼び出すパッケージを指定しています。
[dependencies]
async-std = "1.0"
zenoh = "0.7.0-rc"
zenoh_pubsub = {git = "https://github.com/motii8128/zenoh_pubsub.git"}
Githubのリポジトリのリンク貼っただけですね
メインコードです
use async_std;
use zenoh::Error;
use zenoh_pubsub::pub_test;
#[async_std::main]
async fn main()->Result<(), Error>
{
let pub_task = async_std::task::spawn(pub_test("PUBLISHER_A"));
pub_task.await?;
Ok(())
}
実行したところ以下のようなログになりました。
user@laptop:~/test_launch$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.10s
Running `target/debug/test_launch`
Start PUBLISHER_A
指定したノード名で起動できていますね。
ではここでSubscriberの方も同時に呼び出しましょう。
先程のコードに加えます。
use async_std;
use zenoh::Error;
use zenoh_pubsub::{pub_test, sub_test};
#[async_std::main]
async fn main()->Result<(), Error>
{
let pub_task = async_std::task::spawn(pub_test("PUBLISHER_A"));
let sub_task = async_std::task::spawn(sub_test("SUBSCRIBER_B"));
pub_task.await?;
sub_task.await?;
Ok(())
}
実行すると
user@Laptop:~/test_launch$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/test_launch`
Start SUBSCRIBER_B
Start PUBLISHER_A
Recv:Hello 0
Recv:Hello 1
Recv:Hello 2
Recv:Hello 3
Recv:Hello 4
Recv:Hello 5
Recv:Hello 6
Recv:Hello 7
Recv:Hello 8
どちらも呼び出せました。
おわりに
最適解かわかりませんが、一応目的は達成できたと思います。
yamlのパスを引数にした関数にすれば、パラメーターをyamlから取得するみたいにできることは色々ありそうですね。今から色々つくっておいて、ロボコンの時にはつなぐだけみたいな形が理想です。
また、以下のように純粋なRustで動くロボットのソフトウェアを開発中です。issue等お待ちしております。