赞
踩
“今年(2023)九月份将在上海举办首届的 GOSIM Workshop (9.23-24)[1] 和 GOSIM Conference (9.26)[2] 盛会。GOSIM 会场将支持「同声传译」,小伙伴们可以放心购票参与。还不了解 GOSIM 大会的朋友,可以参考文章结尾的详细介绍。
本次 GOSIM Workshop 机器人与自动驾驶分论坛请来了 Rust 开源下一代机器人框架的项目核心维护者 Xavier Tao 和 Philipp 来给大家做精彩分享。在参加 Workshop 之前,你应该对 Dora-rs 有一定了解。在本文中,你也将学到 Rust 如何安全高效和 Python 交互。
点击观看:机器人与自动驾驶的开源之旅 | GOSIM 数字纪事 ,了解关于汽车与自动驾驶,以及 Dora 的更多故事。
Dora-rs[3] 是一个全新的现代化机器人框架,它基于 Rust 实现,具有极高的性能。dora-rs 也可以用于深度学习应用,旨在方便地集成最先进的深度学习模型,并希望能够在框架内进行训练。
2022年DORA-RS开源项目被发布,它全称为Dataflow Oriented Robotics Architecture。它借鉴了ROS,CyberRT和ERDOS这些项目的优点,试图解决机器人和自动驾驶领域长久以来的一大难题:如何能把繁荣的基于Python的AI算法生态集成到机器人和自动驾驶的软件开发中,同时能够高效地处理数据流。
它使用Rust语言做数据流的传输和调度管理,大大减少了数据的重复拷贝和传输。它提供了Rust语言和Python语言之间的无缝集成,减少了跨语言的性能代价。借助Python丰富的算法模块,开发者可以通过YAML蓝图脚本轻松设计出适用于各类机器人和自动驾驶场景的数据流。DORA为您提供与,实现数据流的零拷贝和高效IPC传输,极大提高性能。使得开发者可以专注于应用开发,而无需过多担心性能问题。
同时与Carla自动驾驶仿真系统完美结合,开发者可以使用DORA-RS提供的基线算法,开发先进的自动驾驶应用,并进行仿真测试。
不仅仅是仿真,DORA-RS同样支持真实的自动驾驶与控制器系统,无需更改代码,即可在仿真和现实环境中验证您的算法。
它的性能是ROS2 Python API 的 17 倍!是 ROS2 Rust API 的 10 倍!与 ROS2 C/Cpp API 共享内存快 0.06 ms。
Dora 的特点是:
零成本开销:在共享内存上进行零拷贝传输消息!使用Arrow和自己的共享内存守护程序,在单台机器上实现光速通信。
可扩展:专为机器和机器人扩展而设计!使用YAML描述来使软件具有声明性,以便在多台机器上进行分发。
快速原型制作:可复用YAML数据流中的现有节点和运算符,这样用户就不需要费心复制粘贴样板代码。用户还可以使用Python进行实时调试!支持热重载。
可观测:提供命令行界面和OpenTelemetry获取日志、跟踪和指标!
跨平台支持:Dora在大多数平台和架构上都提供Python、Rust、C和C++版本!
社区驱动:Dora 团队希望打造成一个由社区驱动的项目,并帮助其他人了解机器人技术。
dora 框架被划分为不同的组件:
节点(Node):Dora节点是通过Dora库与其他节点进行通信的独立进程。节点可以是自定义的、用户指定的程序,也可以是Dora运行时节点,允许运行Dora操作符。节点实现了自己的 main
函数,因此对其执行具有完全控制权。
算子(Operators:):算子是轻量级、协作的、基于库的组件,由dora运行时节点执行。它们必须根据所使用的语言实现特定的接口。算子可以使用dora运行时提供的各种高级功能,例如优先级调度或本地截止日期支持。
协调器(Coordinator):协调器负责从YAML文件中读取数据流,验证数据流,并将节点和运算符部署到指定或自动确定的机器上。它监控运算符的健康状况,并实现高级集群管理功能。例如,我们可以为云节点实现自动扩展或运算符的复制和重启。协调器可以通过命令行程序(CLI)进行控制。
通信层采用可插拔组件设计,目前支持 zenoh[4]。
Dora 目前提供 Rust/Cpp/Python Api,但编写一个多语言库并不容易。dora 的核心贡献者 Xavier 近日分享了他在构建 wonnx[5] 和 dora-rs 过程中遇到的 FFI 相关的问题和解决方案,将以Rust-Python FFI通过 pyo3
为例进行说明,demo源码见 blogpost_ffi[6]。该主题也会在 GOSIM Workshop 上面讲。
“wonnx 是纯 Rust 实现的 GPU 加速的 ONNX 推理运行时,适用于Web.
`pyo3`[7] 是最常用的Rust-Python绑定之一,可以为开发者创建FFI。我们所要做的就是用 #[pyfunction]
包装我们的函数,这样它就可以在Python中使用了。
- use pyo3::prelude::*;
-
- /// 两个数字之和必须被转为字符串
- /// `#[pyfunction]` 指定这是 Python 中用的函数
- #[pyfunction]
- fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
- Ok((a + b).to_string())
- }
-
- /// `#[pymodule]` 指定用 Rust 实现的 Python 函数
- /// 该函数名应该与 `Cargo.toml`的 `lib.name` 名字设定相同
- #[pymodule]
- fn blogpost_ffi(_py: Python, m: &PyModule) -> PyResult<()> {
- m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
- Ok(())
- }

然后在 Python 中就可以这样调用:
- maturin develop
- python -c "import blogpost_ffi; print(blogpost_ffi.sum_as_string(1,1))"
- # Return: "2"
这里有个问题就是,自动解释的类型不是最优化实现。
假如,我们想要使用数组进行操作,我们希望在Rust和Python之间接收一个数组输入并返回一个数组输出。默认的实现如下所示:
- #[pyfunction]
- fn create_list(a: Vec<&PyAny>) -> PyResult<Vec<&PyAny>> {
- Ok(a)
- }
-
- #[pymodule]
- fn blogpost_ffi(_py: Python, m: &PyModule) -> PyResult<()> {
- m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
- m.add_function(wrap_pyfunction!(create_list, m)?)?;
- Ok(())
- }
“对于
create_list
创建value = [1] * 100_000_000
这样的非常大的列表进行调用,返回时间将为2.27秒。参考 test_script.py[8]
这个速度有点慢...原因是这个列表将会在循环中逐个解释元素。我们可以尝试同时使用所有元素来提高效率。
假设我们的数组是一个可以表示为 PyBytes
的C连续数组。代码可以通过将输入和输出转换为 PyBytes
来进行优化:
- #[pyfunction]
- fn create_list_bytes<'a>(py: Python<'a>, a: &'a PyBytes) -> PyResult<&'a PyBytes> {
- let s = a.as_bytes();
-
- let output = PyBytes::new_with(py, s.len(), |bytes| {
- bytes.copy_from_slice(s);
- Ok(())
- })?;
- Ok(output)
- }
“对于相同的列表输入,
create_list_bytes
返回结果需要78毫秒。这是比之前快30倍 声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/343764
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。