rust嵌入式开发之总结

我们用rust开发的新版产品刚刚交付,已经在海上安装测试完毕并顺利投产。终于松了口气,同时也有时间和精力来做个全面的总结了。

这个产品,目前差不多有三版:

  • 第一个版本是用c+rt-thread写的,投产后出了一个内存泄露的bug,由于我们的产品是安装到海上,bug修复了也很难更新到产品上,最后穷尽洪荒之力才找出对策进行了处置【不是排除】,但现在依然象个定时炸弹一样悬在那。导致我对c失去信心,最终下定决心换用rust
  • 第二个是用rust写的demo版本,是基于RTIC框架写的。后因认为RTIC框架的限制比较大,在写完主体功能后就废弃了
  • 第三个版本就是基于Embassy框架写的这一刚交付的版本

ps:海上的情况太过复杂,很多情况是我们现在的测试环境无法完全模拟的

本文即是基于笔者开发这三个版本的经验,对rust嵌入式的开发所做的一个阶段性的总结。

开发门槛高 vs 现场智能化

就嵌入式来说,rust+Embassy vs c+rt-thread的门槛是两个级别。

我是java和python的系统工程师,开发第一个版本时,就没用过c,也没开发过嵌入式!但花了一个月的时间,第一个版本就写完了。

开发第三个版本时,有了第一个版本的所有设备功能的开发经验,有第二个版本的rust尝试,但总的开发时间是从年后到5月下旬,合到三个月了。

当然,这里面主要的原因有两个:

1、rust在嵌入式方面的生态没有c这么成熟:有rt-thread这样的RTOS。虽然Embassy也比较成熟了,但它不是一个完整的RTOS,需要花大量的精力来开发一些较为底层的功能部件,如之前介绍过的数据锁:rust嵌入式开发之基于await构造应用级临界区。

当然,如果只是如多数嵌入式的应用场景那样的话,用RTIC框架完全可以:rust嵌入式开发之RTICvsEmbassy,那就简单很多了。但如我上面那篇文章所述,RTIC框架能力有限,起码对我司来说的是不够的:

  • 我们需要连接大量各厂家的设备,串口之多以至于只能用10串口的STM32F403VG,每种设备的协作机制完全不同,所以就需要强大的异步协作能力,RTIC就没有提供异步支持
  • 海上工程的特殊性,决定了我们必须提供多种的错误恢复手段,RTIC太弱

2、除了第一版中通常的现场操控能力之外,在新版中我还开发了额外的应用能力,如命令行,这相当于在做RTOS中的shell了,所以本质上还是rust嵌入式的生态还不够成熟的问题。

第一个版本是以在服务器上抄收到现场数据为完工标志,但海上施工非常困难,出海时一切正常,突然瓢泼大雨的再正常不过了,所以有必要提供现场的检查手段,因此需要提供命令行功能。

其它还有debug、对象锁之类。

这也是我坚持认为,随着MCU的资源越来越丰富,嵌入式编程必然会走向复杂化、应用化的原因:为了在竞争中获胜,现场器件越来越智能化是必要的、必须的趋势

如我们现在就在考虑海上碰撞的预警、检测与证据固定,已经在进行功能方面的论证。

也正是基于这个判断,我才会坚定的抛弃c而拥抱rust。

概要之,如果只是瞄准目前通常的嵌入式应用场景:固定功能的现场操控。其实没必要用rust嵌入式编程【rust+RTIC功能有限又自带rust的高门槛,完全属于自找麻烦】,门槛太高、成本也高出很多;开发周期【尤其是产品成型的第一个版本的开发周期】太长,可能会导致产品验证出现问题。

但是,如果希望提高竞争水准、抬升行业准入门槛,并将其中一个发力点落在现场感知、反应的智能化能力上,我认为除非有极深的积累,否则rust嵌入式自然拥有相当强的竞争力,毕竟c太古老了,不太适合快速低成本开发高可靠、高价值的应用。

对冲rust的高门槛

rust门槛高、心智负担重,这是公认的rust的缺点。但就嵌入式而言,这个缺点其实是不存在的。

原因非常简单,嵌入式再如何复杂,现在也远比后台应用简单的多,所以完全可以采取措施来对冲rust的高门槛:

1、用静态变量互斥访问来对冲rust的生命周期、借用难

对rust的生命周期、借用,作为初学者的我也很头疼,而我的解决办法非常粗暴:

嵌入式的应用场景简单,所以我直接把主要功能所需要的数据静态化、然后进行包裹、再用互斥锁进行保护,这样一来,所有的操作接口都是:&'static self。

这就完全不再需要考虑生命周期和借用的问题了,编程难度直线下降,编译器一声都不敢吱:)

这个方法在上线后,轻松抗住了一天40万条数据的采集压力!而且经过计算,还远没到设备极限,大家可以放心大胆的用:)

2、用资源的高耗费来对冲编程的复杂度

既然现在MCU的资源极大的丰富了,堆资源就好,绕开死磕技术难度的坑就是了。

就如我们的串口读取,底层申请了内存,上层应用什么时候用完、需要进行释放是不清楚的,而且串口读取到的数据,还可能流经多种功能模块,比如用蓝牙模块以modbus协议读取设备数据,就需要流经串口模块、蓝牙模块、modbus模块、应用模块。这对内存管理就带了很大的压力。

所以我同样是用简单粗暴的方法来应对:每层自己申请自己释放,要提交给上层的,就做一次内存copy。

这样过一层就做一次内存copy的资源耗费显然太过巨大,但这样简单啊,硬怼资源就很容易实现,反正内存copy那点开销相比现在的MCU和嵌入式场景实在不值一提。

这个以资源开销来换简化编程、消弭bug的方法在我们多个串口、多种设备管控,一天40多万条数据的采集、海上无线传输的压力下工作良好!

一句话:在目前的情况下,rust嵌入式编程不需要考虑优化、不需要担心浪费,堆资源是最应优先考虑的方案。

在我来看,对一个产品来说,有两个指标是决定性的:

  • 关键需求的满足度
  • 产品的稳定性

前者是客户花钱的理由,rust的现代性和良好生态是支撑我们依托智能化产品来提升核心竞争力的利器,自然就是选择rust的最大理由;后者是客户付钱的理由,rust写出的程序天然自带的健壮性和可靠性,就是选择rust的第二大理由。

当然,rust在嵌入式方面的生态还有所不足,但这只是时间问题,总要给新生儿成长的时间。

谁都有缺点,弥补缺点就需要成本。借用工程技术手段和高资源开销来弥补rust的缺点,就是我们目前必要的成本。

现在看下来,这些成本完全可以接受。

rust嵌入式的不足

生态、生态、生态。这必须是rust嵌入式的最大不足。尤其是在芯片国产替代的当下,国产芯片在rust嵌入式方面的投入基本可以忽略。

如我们第一版用的就是国产的GD32,但在看好rust嵌入式的前景之后,由于芯片厂商等在基础设施方面的投入不足,最后只好又选了STM32。

当然,我相信国内的芯片厂家既然提供了这么强大的MCU,最终一定是需要软件来消耗掉这些资源的,我们的新版本已经消耗掉了384K的Flash,还有很大空间值得挖掘:)

而这要靠c肯定不现实,最终还是要在rust上发力的。只是需要提提速啊:(

rust嵌入式在生态方面的最大不足,对我们来说,自然就是缺乏一个如国产的rt-thread这样的国产RTOS。由于缺了不少必要的基础部件,就需要自己来开发,这相当于提升了开发门槛和成本。

rust嵌入式的第二个不足,就是no_std和std的隔离。这就导致rust的良好生态在嵌入式方面被大幅度的削弱了。

比如:我在命令行中原本要实现参数的核验,但rust工业标准的正则表达式crate在no_std下就用不了,只好用了可以支持no_std的regex-automata,但用下来总感觉有些问题,由于时间太紧张了,实在无法全面测试,最后干脆就先取消了命令行的参数核验能力。

就目前来说,no_std的问题还影响不大,但随着现场智能化诉求的提升,这个问题势必会带来越来越大的限制。

第三个不足应该是rust的不足,就是IDE在编辑界面无法自动扩展宏。

我选择rust的一个重要理由,就是相比c中的宏,rust的过程宏异常的强大:完全可以媲美java中的反射和python中的@修饰符,关键还是零开销:rust嵌入式之用类函数宏简写状态机定义。

在java和python中我都自己实现了ORM、状态机等,所以我深知反射技术是各种框架的基础,对现代软件工程和编程技术具有无与伦比的巨大意义,当然,还有所要花费的巨大开销。

在rust中,我同样用过程宏实现了状态机、命令行、debug、控制台、串口/pwm等接口操作的自动扩写、扩展对象锁、命令-期望等等。

对rust的过程宏,我实在是太满意了。

但是,宏用得太多,某些利用宏扩写出来的技术细节我自己也就记不清楚了,当需要探究某个技术细节的时候,IDE竟然不给自动展开所扩写的代码,还需要手动执行命令来展开宏,然后去另外的文件中来查看,非常低效。

这个不足,在排错的时候尤其讨厌!

结语

虽然rust嵌入式有着种种的不足,但我依然相信rust在嵌入式领域前程远大

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/21109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

521源码-源码论坛-宝塔面板操作日志是存放在哪里的? 如何删除部分日志记录

我们帮别人搭建或者登录了(不是自己权属的宝塔面板),会留下登录及操作的日志,我们不想留下这些操作日志,可以通过下面的方法处理掉,以达到无痕迹访问操作的目的: 如图所示的面板操作日志&#…

Python-3.12.0文档解读-内置函数sum()详细说明+记忆策略+常用场景+巧妙用法+综合技巧

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 详细说明 sum(iterable, /, start0) 参数: 返回值: 注意事…

骑砍2霸主MOD开发(10)-游戏大地图(MapScene)制作

一.MapScene中初始化NavMeshFaceID与TerrainType public TerrainType GetFaceTerrainType(PathFaceRecord navMeshFace){switch (navMeshFace.FaceGroupIndex){case 1:return TerrainType.Plain;case 2:return TerrainType.Desert;case 3:return TerrainType.Snow;case 4:retur…

算法优化:空间与时间复杂度的权衡

引言 在软件开发中,算法的性能至关重要。算法的性能通常通过其时间复杂度和空间复杂度来衡量。时间复杂度指的是算法执行时间与输入规模的关系,而空间复杂度则关注算法执行过程中所占用的存储空间。本文将探讨如何权衡这两者,以实现算法的最…

排序方法大汇总

以下所有排序方法均以排升序为例 一.插入排序 1.直接插入排序 1>方法介绍:假定前n个数据有序,将第n1个数据依次与前n个数据相比,若比第i个数据小且比第i-1个数据大则插入两者之间 2>时间复杂度:O(N^2) 空间复杂度&#…

【JS】对象转变成数组

1、Object.keys() 方法: 将对象的键转换为数组 const a { name: aa,age: 18 }; const arr Object.keys(a); console.log(arr); // 输出 [name, age] 2、Object.values() 方法: 将对象的值转换为数组 const a { name: aa,age: 18 }; const arr Obj…

BUUCTF中的密码题目解密

BUUCTF 1.MD5 题目名称就是MD5,这个题目肯定和md5密码有关,下载题目,打开后发现这确实是一个md5加密的密文 Md5在线解密网站:md5在线解密破解,md5解密加密 经过MD5在线解密网站解密后,获取到flag为:flag{…

域名主机服务器配置失败的原因和解决方法

域名主机服务器配置失败的原因可能涉及多个方面,包括域名设置、DNS配置、服务器设置、网络问题等。以下是一些常见的原因和相应的解决方案: 1. DNS配置错误 原因: 域名解析错误:域名没有正确指向服务器的IP地址。 DNS记录未更新&a…

网络编程TCP

White graces:个人主页 🙉专栏推荐:Java入门知识🙉 🙉 内容推荐:Java网络编程(下)🙉 🐹今日诗词: 壮士当唱大风哥, 宵小之徒能几何?🐹 ⛳️点赞 ☀️收藏⭐️关注💬卑微…

CentOS7单用户模式,救援模式操作记录

CentOS7单用户模式,救援模式操作记录 1. 单用户模式 单用户模式进入不需要密码,无网络连接,拥有root权限,禁止远程登陆。一般用于用于系统维护,例如忘记root密码后可以通过进入单用户模式进行重置。 开机启动&#…

数据结构 实验 1

题目一:用线性表实现文具店的货品管理问题 问题描述:在文具店的日常经营过程中,存在对各种文具的管理问题。当库存文具不足或缺货时,需要进货。日常销售时需要出库。当盘点货物时,需要查询货物信息。请根据这些要求编…

使用低代码系统的意义与价值主要体现在哪里?

使用低代码系统的意义与价值主要体现在以下几个方面,这些观点基于驰骋低代码设计者的专业洞察和行业经验: 快速原型创建: 低代码平台通过提供图形化界面和预构建的模块,极大地加速了系统原型的创建过程。这意味着企业能够更快地验…

60 关于 SegmentFault 的一些场景 (1)

前言 呵呵 此问题主要是来自于 帖子 月经结贴 -- 《Segmentation Fault in Linux》 这里主要也是 结合了作者的相关 case, 来做的一些 调试分享 当然 很多的情况还是 蛮有意思 本文主要问题如下 1. 访问可执行文件中的 只读数据 2. 访问不存在的虚拟地址 3. 访问内核地址…

嵌入式笔试面试刷题(day16)

文章目录 前言一、PWM波形的占空比计算公式是什么?二、ADC和DAC在嵌入式系统中的应用场景有哪些?三、watchdog定时器的作用及其在系统中的使用是什么?四、JTAG接口在嵌入式开发中的作用是什么?五、实时操作系统(RTOS)的任务调度策…

嵌入式工程师人生提质的十大成长型思维分享

大家好,作为一名嵌入式开发者,很多时候,需要考虑个人未来的发展,人生旅途复杂多变,时常面临各种各样的挑战。如何在这个复杂多变的社会中稳步向前,不断成长,成为每个人都应该思考的问题。实际上,思维方式的差异决定我们应对挑战的能力与成长的速度。 第一:寻找自我坐…

HNCTF2022 REVERSE

[HNCTF 2022 WEEK2]esy_flower 简单花指令 Nop掉 然后整段u c p然后就反汇编 可能反编译的不太对&#xff0c;&#xff0c;看了别人的wp就是ida反编译的有问题 #include<stdio.h> #include<string.h> int main() {int i,j;char ch[]"c~scvdzKCEoDEZ[^roDICU…

NumPy应用(二)

numpy高效的处理数据&#xff0c;提供数组的支持&#xff0c; python 默认没有数组。 pandas 、 scipy 、 matplotlib 都依赖 numpy 。 pandas主要用于数据挖掘&#xff0c;探索&#xff0c;分析 maiplotlib用于作图&#xff0c;可视化 scipy进行数值计算&#xff0c;如&…

微软远程连接工具:Microsoft Remote Desktop for Mac 中文版

Microsoft Remote Desktop 是一款由微软开发的远程桌面连接软件&#xff0c;它允许用户从远程地点连接到远程计算机或虚拟机&#xff0c;并在远程计算机上使用桌面应用程序和文件。 下载地址&#xff1a;https://www.macz.com/mac/5458.html?idOTI2NjQ5Jl8mMjcuMTg2LjEyNi4yMz…

C++进阶之AVL树+模拟实现

目录 目录 一、AVL树的基本概念 1.1 基本概念 二、AVL树的模拟实现 2.1 AVL树节点的定义 2.2 插入操作 2.3 旋转操作 2.4 具体实现 一、AVL树的基本概念 1.1 基本概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十四)- 微服务(4)

目录 8. http客户端Feign 8.1 feign远程调用 8.2 feign自定义配置 8.3 feign性能优化 8.4 feign最佳实践 8. http客户端Feign 8.1 feign远程调用 RestTemplate存在的问题 &#xff1a; 代码可读性差 参数复杂URL难以维护 Feign是声明式的http客户端 使用步骤 &#xf…