1、dora简介
Dora-rs[1] 是一个基于 Rust 实现的化机器人框架,其具有极高的实时性能。Dora-rs使用Rust语言做数据流的传输和调度管理,可以大大减少了数据的重复拷贝和传输。它提供了Rust语言和Python语言之间的无缝集成,减少了跨语言的性能代价。Dora-rs通过YAML脚本配置节点、节点之间的数据流。
多语言支持:Dora 目前提供 Rust 、Cpp 、Python三种语言。
性能:Dora-rs 性能是ROS2 Python API 的 17 倍!是 ROS2 Rust API 的 10 倍!与 ROS2 C/Cpp API 共享内存快 0.06 ms。(图片来源于github[1]) (对Python有很强的优化能力,对C++性能提升不大)
)
2、dora安装
dora_安装文档
dora_rs版本为 V0.3.6
注意python版本 必须要3.11.5
我使用的环境是ubuntu20.04 + conda, 推荐安装conda然后再安装python https://blog.csdn.net/wyf2017/article/details/118676765
2.1 二进制安装
在linux上打开一个终端,输入以下指令
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/dora-rs/dora/main/install.sh | bash
如果提示以下错误
)
更新一下rustc的版本
apt autoremove rustc
apt install rustc
或者 通过以下命令更新rustc版本
sudo apt autoremove rustc
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
export PATH=~/.cargo/bin:$PATH
sudo apt install cargo
2.2从源码编译安装
step1: 从dora仓库下载源代码
git clone https://github.com/dora-rs/dora.git
step2: 编译源代码及C++库
cd dora
cargo build -p dora-cli --release
# 编译c++接口
cd ../examples/c++-dataflow
cargo run --example cxx-dataflow # compile C++ node
cargo build -p dora-node-api-c --release # compile dora-node-api-c
# 编译DORA-ROS2 bridge
cd ../c++-ros2-dataflow
source /opt/ros/galactic/setup.bash
cargo run --example cxx-ros2-dataflow --features ros2-examples
step3 将编译生成的dora 二进制文件链接到linux环境变量中
export PATH=$PATH:$(pwd) >> ~/.bashrc
step4 安装dora python的接口 注意这里的版本号 DORA_VERSION 要与主仓库的版本号对应
pip install dora-rs== DORA_VERSION ## For Python API
export PATH=$PATH:$(pwd) >> ~/.bashrc
3、运行测试程序
与官方给出的demo程序相同,我们先试用python创建程序验证程序dora-rs是否安装完整
3.1 first project
在终端中输入以下命令,创建dora工程(工程名为abc_project )
dora new abc_project --lang python
cd abc_project
打开该文件夹,这个工程下面创建一个yaml文件、一个节点文件夹,两个操作符(dora中称作operator,有点类似于功能节点、算子的概念), 该工程目录结构如下
├── dataflow.yml
├── node_1
│ └── node_1.py
├── op_1
│ └── op_1.py
└── op_2
└── op_2.py
3.2 编写节点
1、其中dataflow.yml 文件的内容为:
nodes:
- id: op_1
operator:
python: op_1/op_1.py
inputs:
tick: dora/timer/millis/100
outputs:
- some-output
- id: op_2
operator:
python: op_2/op_2.py
inputs:
tick: dora/timer/secs/2
outputs:
- some-output
- id: custom-node_1
custom:
source: python3
args: ./node_1/node_1.py
inputs:
tick: dora/timer/secs/1
input-1: op_1/some-output
input-2: op_2/some-output
2、node_1.py 文件的内容为:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from dora import Node
node = Node()
event = node.next()
if event["type"] == "INPUT":
print(
f"""Node received:
id: {event["id"]},
value: {event["value"]},
metadata: {event["metadata"]}"""
)
3、op_1.py 文件的内容为:
from typing import Callable, Optional
from dora import DoraStatus
class Operator:
"""
Template docstring
"""
def __init__(self):
"""Called on initialisation"""
pass
def on_event(
self,
dora_event: dict,
send_output: Callable[[str, bytes, Optional[dict]], None],
) -> DoraStatus:
if dora_event["type"] == "INPUT":
return self.on_input(dora_event, send_output)
return DoraStatus.CONTINUE
def on_input(
self,
dora_input: dict,
send_output: Callable[[str, bytes, Optional[dict]], None],
):
"""
Args:
dora_input (dict): Input dict containing an `id`, `data` and `metadata`.
send_output Callable[[str, bytes | pa.Array, Optional[dict]], None]:
Function for sending output to the dataflow:
- First argument is the `output_id`
- Second argument is the data as either bytes or `pa.Array`
- Third argument is dora metadata dict
e.g.: `send_output("bbox", pa.array([100], type=pa.uint8()), dora_event["metadata"])`
Returns:
DoraStatus:
CONTINUE means that the operator will
keep listening for further inputs.
STOP means that the operator stop listening for inputs.
"""
print(f"Received input {dora_input['id']}, with data: {dora_input['value']}")
return DoraStatus.CONTINUE
def __del__(self):
"""Called before being deleted"""
pass
4、op_2.py 文件的内容为:
from typing import Callable, Optional
from dora import DoraStatus
class Operator:
"""
Template docstring
"""
def __init__(self):
"""Called on initialisation"""
pass
def on_event(
self,
dora_event: dict,
send_output: Callable[[str, bytes, Optional[dict]], None],
) -> DoraStatus:
if dora_event["type"] == "INPUT":
return self.on_input(dora_event, send_output)
return DoraStatus.CONTINUE
def on_input(
self,
dora_input: dict,
send_output: Callable[[str, bytes, Optional[dict]], None],
):
"""
Args:
dora_input (dict): Input dict containing an `id`, `data` and `metadata`.
send_output Callable[[str, bytes | pa.Array, Optional[dict]], None]:
Function for sending output to the dataflow:
- First argument is the `output_id`
- Second argument is the data as either bytes or `pa.Array`
- Third argument is dora metadata dict
e.g.: `send_output("bbox", pa.array([100], type=pa.uint8()), dora_event["metadata"])`
Returns:
DoraStatus:
CONTINUE means that the operator will
keep listening for further inputs.
STOP means that the operator stop listening for inputs.
"""
print(f"Received input {dora_input['id']}, with data: {dora_input['value']}")
return DoraStatus.CONTINUE
def __del__(self):
"""Called before being deleted"""
pass
3.3 启动程序
1、启动数据流
dora start dataflow.yml --name first-dataflow
开启程序以后在终端会输出一个类似于 “6a9279a7-e048-4e28-9616-cb3ae0adb774” 的一长串数字,这是数据流ID
参数 --name 后面的名称是我们自定义的节点名称,后续查看日志文件等操作,可以利用该自定义的名称替换数据流ID
2、结束该数据流
dora stop --name first-dataflow
3.4 查看节点输出
dora 可以通过log文件 查看节点输出(这一点不方便)
dora logs first-dataflow op_1
dora logs first-dataflow op_2
dora logs first-dataflow custom-node_1
其中 first-dataflow 是该程序的名称,也就是我们再启动命令时候 "- -name"后面跟的参数; custom-node_1 是yaml文件中一个节点的名称,
数据流 first-dataflow 下节点 op_1 的日志输出如下:
4 注意事项
1)若终端提示找不到 dora命令,则可以将 dora可执行文件所在目录加入到 ~/.bashrc最后一行,如在我电脑上dora安装与 ~ 目录,因此需要在 ~/.bashrc 文件中加入 PATH=$PATH:/home/crp
2) 若终端提示在python中没有 dora模块
则按照提示信息执行命令安装dora 即可
pip install dora-rs==0.3.6 --force
参考资料
[1] https://github.com/dora-rs/dora
[2] https://dora.carsmos.ai/docs/guides/Installation/installing
dora-rs目前资料较少 欢迎大家点赞在评论区交流讨论(cenruping@vip.qq.com) O(∩_∩)O
或者加群水一波(1149897304)