C++和Rust_【译文】为什么说Rust是机器人技术的未来

C++和Rust_【译文】为什么说Rust是机器人技术的未来_第1张图片
原文:Why Rust is the future of robotics
作者:Pierre Rouanet

Rust是一门比较新的编程语言,在2006年由Graydon Hoare启动,2010年由Mozilla正式发布。速度极快的火狐量子浏览器就是用Rust开发的。过去几年里,Rust凭借着许多超棒的特性,产生了很大的吸引力,尤其对机器人技术。

Rust吸收了像C和C++这些低级语言的特性——运行速度极快且占用内存少,同时具有很多高级语言的特性保障。它可以避免段错误、保证线程安全。需要特别指出的是Rust在保障所有这些安全特性和抽象特性的同时并不产生额外的开销。它的座右铭:

Rust:快,可靠,高产 —— 一石三鸟

基于上述,我们相信Rust是机器人技术的未来,它使开发者无所畏惧,去创建和执行标准,去建立并依靠一个强大的社区。我们接下来会更详细的解释,在此之前先回顾下当今机器人技术中的嵌入式软件困局。

嵌入式编程的困局

在嵌入式软件中存在两大难题:

  • 很难写出安全的代码。C和C++的内存使用不安全,易发人为错误。很多的bug源于缓冲区溢出,数据损坏,读写未分配的内存。检测和调试变得非常困难,很多攻击和病毒便趁虚而入。你的项目越复杂,就会越难维护。换句话说,嵌入式程序员最担心:添新功能,毁所有。
  • 在嵌入式软件中几乎无法实现并发,所以很难完成从玩具示例到量产的跨越。竞争条件,死锁,数据损坏导致的bug调试起来本来就很复杂。对于嵌入式系统来说,开发环境相比基于OS的世界就更没优势了。调试硬件中断甚至会让信心满满的嵌入式开发者感到恐惧。

你可以在这里找到更多关于为什么嵌入式软件如此艰难。

除了这些技术层面的问题,尤其在机器人领域,还缺少标准化和可直接复用的代码。当然,Internet上总能找到你想要的示例代码。但是通常不能拿来直接用。这导致开发人员大部分时间都花在他人代码和和自己代码的对接上。浪费了大量时间。引入了许多安全漏洞。

Rust可以解决所有这些问题,甚至更多。

无所畏惧

编译即安全。再重复一遍。编译即安全。

保证。对于嵌入式开发来说,这是极大的缓解。Rust是如何做到的?本篇不打算深入探讨,让我简单说一下。

Rust中的一个重要原则是所有权。所有权跟踪和确保每个变量在同一时刻只能有一个所有者,如果所有者超出范围,该值就被释放。这个原则非常强悍,它一次性解决了两个重要问题:内存安全和无痛并发,通常来自在不该访问数据的时候进行访问。

  • 内存安全——Rust不允许空指针和悬挂指针。也没有垃圾收集器来确保可预测的代码行为。
  • 无痛并发——基于借用概念,Rust能跟踪到数据竞争风险的存在,从而不进行编译。它提供了高级的机制把这些条件封装在互斥锁,利于你继续。

这已经有点意思了,但是要花费多少呢?好吧,几乎为零。

  • 零成本抽象——抽象是计算机科学中的一个发明。John V Guttag给了一个很好的定义:“抽象的本质是保留和上下文相关的信息,忽略与上下文不相关的信息”。这就是之所以像Python这类高级语言产生的原因。但是Python附带了很多开销处理,都难以跟踪,比如垃圾回收,运行期指针的检查等等。但是嵌入式系统经常处理关键应用,最差情况执行时间是必须的。想想数控制动器。你猜对了,Rust允许抽象,但没有开销。大部分的检查都在编译期进行,所以在运行期没有额外的计算。

Rust还提供:

  • 现代化的语法
  • 精确的错误信息
  • 无痛打包和依赖管理——Rust搭配有最好包管理器,叫Cargo。对于嵌入式编程,有Xargo。

对于嵌入式系统,还开发了专用工具:

  • 周边控制——有个叫做svd2rust的东东,它可以直接从SVC描述为每个周边控制器自动生成Rust API。Rust很聪明,它可以在编译时强制您使用这些外围设备。如果尝试写入只读寄存器或读取只写寄存器,则无法编译。你也不能将无效的位模式写入寄存器。SVD会定义一个有效值的范围,Rust不会让你超出范围。
  • 资源冲突预防——在下个版本,他们将引入单例,让Rust知道何时代码想使用一个正在使用的外围设备,比如一个定时器。这是在嵌入式系统中常见的问题根源,即多个设备想要使用有限的资源。一个经典案例就是Arduino Uno开发板,上面只有很少的定时器。所以当你使用Servo库时,你不能在引脚9和10上使用PWM。但是代码可以编译,加载到开发板上,然后产生各种奇怪的行为,且难以调适,并最终导致严重的失败。这使得许许多多的Arduino用户感到困惑。有了单例,Rust就可以在编译期告诉你,定时器是否已经在使用了,这样就可以避免掉很多让用户头痛的问题,而且没有任何的运行期开销。
  • 不要担心,Rust同时兼容C和C++。

如果你以前从事过嵌入式编程,你一定在这些问题上花了不少精力。Rust不仅会让你对自己的代码有信心,而且对你想重用的其他人的代码也有信心。

说说机器人技术

对于嵌入式系统的代码共享和重用,有两个主要的挫折点:

  • 第一,每个人的工作都可以进行分类,比如读取一个模拟值,记录一个编码器的位置,更改马达的速度或者LED的颜色。但是,没有人使用相同的接口,一个马达的两个实现总是使用不同的函数名和API来做同一件事情。这使得写一个适用于两个马达的通用马达控制器变得很困难。
  • 第二,源于第一点,就是我们希望重用别人的代码时能充满信心。我们希望确保不会引入新的bug,因为我们使用代码的场景是最初的开发者没有测试过的。

这些挫败中的大部分,Rust都能自然克服。从一个函数的签名,你就能很好的了解到这个函数会做什么,而且你可以确保所有的变量都能完整的声明,初始化和正确的使用。如果你向工程中添加了一个模块通过了编译,它很可能不会破坏任何东西(当然总有些不安全的情况)。还有很多其他方面,这里我强调两个重要功能:

  • Traits——和面向对象编程类似,类和集成?Rust Traits用于相似类型的抽象,但是与继承不同,它使用组合原则。通过组合,能定义一个可以安全混合和匹配的属性集合。所有这些的计算开销为零。
  • 类型推断——简单的说,如果一个函数要求输入角度而你输入了弧度,Rust能自动的检测到需要进行类型转换。而且如果定义了类型转换函数,它会自动使用它把弧度转换为角度。在机器人技术领域,我们经常会做一些数学运算,而使用错误的单位常常导致糟糕的意外,有些花费数百万美元。幸运的是Rust回来了。你可以在这里阅读更多关于类型推断的信息。如果你对组合有兴趣,可以看下这个视频。

如果我们希望机器人技术能按预期快速传播,标准化就是非常关键的。我们对Rust能够进行大规模的共享充满信心。

一流的社区

在2016和2017年的Stack Overflow开发者调查中,Rust获得了“最受欢迎开发语言”第一名。这真的不稀奇。Rust社区有热情,有组织,很活跃。

热情——去年聚焦的一个重点就是降低初学者的学习曲线,为各个级别提供指导,在编辑-编译-调试循环过程中提升用户体验。

有组织——Rust有一个完善的文档系统,它覆盖了所有的标准库和错误码。Rust社区有一套行为守则而且每年他们会总结社区成就并在所有社区的帮助下产生一个新的路线图。他们建立了一个完善的评论请求流程RFC征求社区对于新发展和方向的反馈。

活跃——我们在4个月前开始使用Rust开发库,为的是机器人产品开发能够变得简单,Rust社区的活力实在帮了我们快速起步。就在这周,在Philipp Oppermann的可用于no_std系统的简单分配器linked-list-allocator项目我们开启了一个拉取请求。不到两小时我们的拉取请求就被集成了。还不止一次。

这个社区在嵌入式方面非常的积极并正在成长,有很多积极的Embedded in Rust开发者和博客作者。雄心勃勃的项目正在涌现,在实时框架和安全的嵌入式操作系统,有望迎来光明的未来。甚至Android也正在转向Rust。

无需多说一个有组织和有纪律的社区,使你感受到热情、被倾听和受支持,对我们在机器人领域使用和开发Rust,是一个强大的动力。

我希望使你相信,Rust在嵌入式编程尤其是机器人技术方面具有巨大的潜力。但是Rust嵌入式社区仍然很小而且很多东西都有缺失。不要害怕,创造,构建,重用标准并享受社区的乐趣!

刚开始,你可能会感觉到这是你和Rust编译器之间的斗争:写代码→ 尝试编译→ 编译失败→ 写代码的方式使其不安全→ 羞辱编译器→ 否则继续尝试→ 再次编译→ 可以用了→咕哝“好吧这样的确更好些”:)但是这个旅程中Rust会使你变成更好的开发者,并极大的帮助你写出安全和高效的代码!

我们将会持续写关于Rust和机器人技术的博客,解释在Rust in Embedded中我们的工具链,工作流,专用库,编程技巧,以及我们如何构建机器人。我们已经在Github上开源了我们所有的工作:https://github.com/pollen-robotics。

你可能感兴趣的:(C++和Rust)