毕业实习总结报告
这既是毕业实习要求的总结报告,也是我对AutoSAR的一点理解,更是个人对未来生活的一点思考。我不希望把这份报告草草水过,而是希望把现在的感受记录下来,给以后的自己看一看,好记性不如记下来。涉及到工作细节和隐私的部分不在此展示了。
时间像一头野驴呀,跑起来就不停。
自今年三月底拿到实习录用通知后,当时的我总有一种不真实的感觉,毕竟接下来的数个月将是与学校生活完全不同、又没有其他同学能够借鉴的经验的一种生活。四月还有三门专业必修课在读,其中还有一门跨级修读、令人身心俱疲的毕业综合实践,自己真的有能力能平衡好学业和实习吗?从▇▇▇▇校区到虹桥的国家会展中心,自己能坚持每天通勤往返将近两个半小时吗?这是我的第一份实习,对自己的能力是否能匹配实习工作也有些担忧。相比于嵌入式领域这片汪洋大海,我简历上的项目不过是几点浮在表面的浪花。会不会被发现自己很“水”,不能符合项目的需要?现在看来,这些烦恼大多没有真实存在,适应在▇▇▇▇▇▇▇▇的实习工作比我想象中快很多,每天忙忙碌碌,一转眼就来到了实习的第六个月。在实习即将结束之际,我通过本篇实习总结报告的形式,记录自己实习阶段感受与思考。
技术升级驱动,市场普及加速。
▇▇▇▇▇▇▇▇(本节主要介绍实习单位与产品领域)
在标准上合作,在实现上竞争。
什么是 AutoSAR
AutoSAR(AUTomotive Open Systems ARchitecture)是汽车开放系统架构,它定义了一套支持分布式的、功能驱动的汽车电子软件开发方法和电子控制单元上的软件架构标准化方案,以便应用于不同的汽车平台,提高软件复用,降低开发成本。这是标准描述,但却很难理解。如果毫无了解地查资料,感觉这又是一套工具、一套架构解决方案、一种操作系统、一种开发方法论、一套标准、一个组织等等。所以,不妨首先来看它的出现是想解决什么问题。
汽车电子系统的复杂性不断增长,软件代码量急速上升,开发、测试和维护的成本显著提高,不同组件和系统之间的兼容性和集成问题变得更加复杂。如果存在统一的标准,各家厂商围绕这个标准开发产品,就能减少大量开发成本。
从汽车的生命周期上讲,整车生命周期往往长于ECU的生命周期。在一款成熟的车型上,整车平台可以沿用相当长的时间,想一下销量排行榜上的那些熟面孔,例如大众捷达、桑塔纳,日产轩逸等。但单独的ECU的更新速度快,可能仅仅两三年就有更好用、更便宜的ECU可供替换,可以根据需要进行升级,且较少影响整车设计。当然,这里也涉及到一个汽车零部件选型的重要因素,即厂家的供货稳定性和支持时间。曾经看到过一篇文章,一些公司在产品器件选型时,选择了部分在价格上有优势的国产MCU,但在产品SOP后,这款MCU突然停产或不再受支持,这对已SOP的产品打击很大,可能需要不得不变更设计或者紧急在市场上高价购买存货。而在这方面,ST等成熟公司会一般更有保障些。
既然讲到硬件的更换,就可以拓展到嵌入式系统那五花八门的硬件平台了。嵌入式不同于普通的PC软件,它的软件和硬件耦合性特别高,尤其是在实时性要求高和资源受限的情况下。而不同的硬件平台就可能导致在硬件更换后,软件部分要花大量时间移植和修改,这又导致开发成本的增加。汽车电子能不能像纯软件一样,不关心底层硬件的变化,而实现一套统一的软件系统?另外,一旦硬件能够实现自由更换,对零部件的依赖也可以降低许多。从采购方讲,“历史包袱”可以轻松许多;从供应方讲,能够允许更多新厂家愿意参与竞争,而不是望着巨头止步不前。
软件的模块化、可靠性愈发重要。 以CAN通信为例,CAN通信本身已经是规定完善的标准,如果各家自己实现,不仅需要投入人力开发,还可能因为自己开发有缺陷,导致可靠性不足。UDS服务等等亦是如此,比起每家厂商都去自己实现,行业更希望像Python的库一样,有各种符合所有标准,通过多类测试检验后的高可靠的模块,需要时拿来即用,“开袋即食”。把模块配置成所需的样子,而非是去一遍遍地造轮子。
AutoSAR愿景:Cooperate on standards, and compete on implementation.(在标准上合作,在实现上竞争)。就是希望各家厂商把成本投入到产品的应用和功能上,实现所谓的“软件定义汽车”。
AutoSAR 组织与标准
那么,这样一介绍,首先可以引出AutoSAR组织,这个组织由OEM、Tire1、软件服务商等在这个星球算是相当懂车的一批组织作为成员。这个联盟负责研发满足上述需求的AutoSAR架构标准,所有标准都是免费的。
AutoSAR 工具链
但是,免费的往往也是很贵的。上面提到,AutoSAR 架构标准是免费的,也就是这个组织只定义了这样一套标准和方法论,而没有任何实现的代码。这怎么和之前讲的模块化、可靠性不大一样,不是不造轮子吗?软件服务商此时登场了,他们负责投入开发成本,联合 MCU 等硬件提供商,来实现符合AutoSAR 标准的工具链,再卖给 OEM、Tire1 们。当我第一次认识到这点时,我的第一直觉是“不愧是老牌资本主义国家,在这等我呢😠!”
国际上的AutoSAR的御三家是 Vector 、ETAS 、EB,是影响很深的德国公司。一方面,芯片厂商为了让他们的芯片卖得出去,需要花钱请这类公司适配他们的芯片(对,在和上海知从科技的一次聊天时我才明白,是芯片厂花钱采购),像 Vector 因其市场占有多,几乎有所有芯片的适配(每换一套平台也是要重新购买 License 的)。另一方面,OEM 和 Tire1 等由需要花钱买他们的工具链(甚至是按照每个模块谈采购),用这套工具链基础上开发。部分OEM已经有了合作多年的厂家,也要求其采购的 Tire1 使用其定制的工具链开发。对于需要这套工具链的公司来说,更换供应商需要开发人员花时间去适应。对于开发工具链的公司来说,怎么拿到芯片厂的支持和卖得出去也很麻烦。国内这块,普华、经纬恒润、东软这些比较领先,但是没有接触过。从使用体验上讲,Vector Davinci 的使用体验我觉得比ETAS要强很多,一方面,报错的指向比较清晰,也能够很快修复;ETAS 就不那么好用,有时候甚至会报工具内部的一些错误(Java),Debug 困难。另外一个对比点是代码生成时间,在 Vector 工具里面生成 BSW+RTE 仅需要 2Min 的活,ETAS 需要数十分钟才能完成,而能够加快这个速度的方法是换台更好的设备,有点无语。
既然AutoSAR工具这么贵,那能不能干脆不用 AutoSAR 架构?前面提到,AutoSAR 只是行业内自行组织编写的一套标准,而不是强制性的规定。特斯拉就选择放弃使用 AutoSAR 框架,使用自研的软硬件架构连接各个组件。使用 AutoSAR 同样受 ISO-26262 标准等安全标准影响很大。如果厂商有实力有自信能够把车做安全,通过各种安全认证,用什么都无所谓。
AutoSAR 架构
终于可以介绍到AutoSAR的详细架构了,架构又分为CP和AP两种平台,这里主要介绍的是比较熟悉的CP。
CP架构的软件架构自底向上有三层,分别为BSW、RTE、ASW。每一层只能调用下一层的接口,并为其上一层提供接口,保证其独立性。
基础软件层 BSW
基础软件层(Basic Software Layer,BSW)可分为四层,即服务层(Services Layer)、ECU抽象层(ECU Abstraction Layer)、微控制器抽象层(Microcontroller Abstraction Layer,MCAL)和复杂驱动(Complex Drivers)
-
服务层(Services Layer)提供系统服务(操作系统)、存储器服务以及通信服务三大部分。除了操作系统外,服务层的软件模块都是与ECU平台无关的,这些服务提供接口给上层的ASW层和BSW内部其他服务使用。此外,服务层可以由故障诊断事件管理器(Dem)和故障诊断通信管理器(Dcm)实现诊断服务,分别负责对错误事件进行记录和诊断信息的传输(诊断通信栈)。
-
ECU抽象层(ECU Abstraction Layer)包括板载设备抽象(Onboard Devices Abstraction)、存储器硬件抽象(Memory Hardware Abstraction)、通信硬件抽象(Communication Hardware Abstraction)和I/O硬件抽象(Input/Output Hardware Abstraction)。该层提供访问外设的API(无论外设在微控制器的内部还是外部,以及如何与MCU连接)。MCU无关但和整个ECU平台相关。在模块上,给服务层提供接口,便于服务层操作。
-
微控制器抽象层(Microcontroller Abstraction Layer,MCAL)是实现不同硬件接口统一化的特殊层。MCAL直接操作MCU,提供接口给ECU抽象层。通过MCAL可将硬件封装起来,避免上层软件直接对微控制器的寄存器进行操作,我个人认为和HAL库可能差不多,作为驱动层。
-
复杂驱动层(Complex Drivers, CDD),对复杂传感器和执行器进行操作的模块涉及严格的时序问题,难以抽象,没有被标准化。在我从事的工作范围内,CDD层的内容不少,一般都是由其他同事负责处理这块内容,并暴露接口给ASW层,遇到问题调试起来难度也很大。
运行时环境 RTE
运行时环境(Runtime Environment,RTE)作为ASW层与BSW层交互的桥梁,为软硬件分离提供了可能。RTE可以实现软件组件间、基础软件间以及软件组件与基础软件之间的通信。RTE是通过工具配置组件等生成的代码。生成RTE后,再由各个组件把自己的实现与RTE生成后的代码合并起来。各个组件原则上讲不应该出现直接调用原始接口或者直接访问变量的情况,而是通过RTE的方式套个外壳。套这个外壳并不是没有意义的,一方面提高了系统访问的安全性,这个外壳包括了其他信息;另一个方面是通过RTE能实现多种方式的访问,这个在下面会有提到。
应用软件层 ASW
应用软件层(ASW),这层做的就是和业务强相关的部分了。在讲软件组件的时候,主要是要理解软件组件的内部组成和组件与组件的连接。从这块的介绍,也会逐步过渡到AutoSAR的开发过程上,那就先从这块讲起。
一个SWC Component内,一定会涉及到数据的处理,所以需要明确所需要使用的数据类型。
应用数据类型(Application Data Type,ADT)是在软件组件设计阶段抽象出来的数据类型,用于表征实际物理世界的量,是提供给应用层使用的,仅仅是功能定义,并不生成实际代码。需要配置Compu Method,也就是数据从内部到物理含义的转换。Data Constraiint则是约束条件。比如电压、温度这类数据类型,就可以定义成一种ADT,ADT是在VFB设计这个层面上使用的。
实现数据类型(Implementation Data Type,IDT)是代码级别的数据类型,是对应用数据类型的具体实现;它需要引用基础数据类型(Base Type),并且还可以配置一些计算方法(Compute Method)与限制条件(Data Constaint)。IDT就比较容易理解,因为他是以基础数据类型上为基础的(有点绕口),基础数据类型就是uint16、sint8这些真正反映在代码里的变量。
在AUTOSAR中,对于ADT没有强制要求使用,用户可以直接使用IDT。若使用了ADT,则必须进行数据类型映射(Data Type Mapping),每个ADT进行具体实现。
规定数据类型后,就要考虑数据在组件之间的通信了。这时候引出Interface,Interface在我的理解是更像一座预制的桥,配置Interface就是相当于规定这座桥上只允许通过什么类型的车。Interface又分为三大类
- AUTOSAR Interface 多用于Application、Abstraction于Complex Driver上;
- Standardized AUTOSAR Interface 多用于BSW中的Service上;
- Standardized Interface 是AutoSAR定义的BSW中的模块直接交互用的接口。
其中,最常见的又有这几种Interface: - 发送者-接收者接口(Sender-Receiver Interface,S/R)。S/R接口是一组数据类型的集合,连接的两个组件通过类似全局变量的方式传递数据。S/R接口可以1:n(1个模块发送,多个模块接收)或者n:1(多个模块发送,1个模块接收)。
- 客户端-服务器接口(Client-Server Interface,C/S)。C/S接口是一组函数原型集合,定义了IN(输入参数),OUT(输出参数,传入的是地址)等函数的参数以及返回值,相当于调用其他组件的函数。
- 模式转换接口(Mode Switch Interface)。和模式管理强相关,这个只接触过一次。
- 非易失性数据接口(Non-volatile Data Interface)。为了实现非易失性数据数据通信,用于和非易失性数据组件通信用的接口,没用过。
- 参数接口(Parameter Interface)。参数通信,这个也没用过。
- 触发接口(Trigger Interface)。Trigger Interface定义了一组在软件组件之间通信的触发器,使用Trigger Interface进行外部触发源事件通信。这个也没有用过。
Interface在此时也属于VFB设计的一部分,没有实体代码。
Port是每个SWC组件的端口,也可以说是Interface这座桥的两端。只有一座桥跨越两岸的时候才有意义,所以Port和Interface是分不开的。作为一座桥,首先要确定的是通信方向,也就是Port的三种通信方向。P-Port代表提供方(Provide),R-Port代表需求方(Require),PR-Port代表进出均可。然后就对应到每种Interface上,Interface决定了端口的属性。例如,Sender/Server相当于是P-Ports,Receiver/Client相当于R-Ports。
由于组件之间已经规定了类型一致的Interface和Ports,只要将P/R-Ports连线再生成代码,就可以看到实质性的函数,加入用户代码即可。
组件间的部分实现后,下面要介绍的是组件内部的实现。软件组件的内部行为(Internal Behaviour,IB)下包括:
- 运行实体(Runnable Entity,RE)。运行实体是一段可执行的代码,也就是实际需要执行的函数。
- 运行实体的RTE事件(RTE Event)。RE是静态的,它需要一个能让其运行起来的条件,这个条件被称之为Event。每个运行实体都需要有一个Event,能引发这个运行实体的执行。Event又分为以下数类:
- 周期性(Periodic)事件,即Timing Event;
- 数据接收事件(Data-received Event);
- 客户端调用服务器事件(Server-call Event)。
- 运行实体与所属软件组件的端口访问(Port Access)。C/S Interface有同步和异步之分,S/R Interface可能需要配置缓冲区等等,这里就不再多说。
- 运行实体间变量(Inter Runnable Variable,IRV)。就是RE和RE之间交互的变量,这个也是第一次看到,我理解就是组件内部的一些全局变量吧,但是这种全局变量,应该是要通过接口函数提供对外读写的方式,不知道AutoSAR里面是怎么处理的。
在组件内部定义好和组件与组件之间的关系通过VFB设计描述好的,这个时候不需要考虑跨ECU的交互关系。这些设计都会保存在对应的Arxml文件内。Arxml是用来描述配置的一种标记语言。再提取(有的叫萃取,很神奇的翻译)各个ECU相关描述将SWC映射到各个ECU上,再将子系统独立出来,之后就可以开发单个ECU的SWC、BSW,将生成的代码集成。生成RTE前必须要进行ECU的萃取。萃取后,将每个Event映射到OS上不同类型的Task,即可在OS调度时,执行相应的代码操作。生成RTE和检查编译通过后,就可以下载程序到MCU上看运行是否正常了,这又是一个极为漫长的故事。上面所述的过程,也是我经历的一部分AutoSAR开发过程,也是AutoSAR开发方法论的一部分。
整个学习下来,很多内容不是立刻就开悟的。作为实习生,在这块工作时,刚开始只会接触很小的一部分操作,这部分操作已经有组内很详细的文档介绍了操作流程,只需要照例完成就行。但就是这样一点点接触不同的各部分的操作,再加上自己查阅资料,才能有恍然大悟的机会。我在第一次感觉有点理解这套开发过程时,当天把各个部分的操作都点进去看过一遍,用从底到顶的方法知道为什么需要这样配置后,再顺着下来配置了几次,有种心旷神怡的感觉。当然,这里介绍的也只是我个人的理解,总会有不足和缺陷的。
“工欲善其事,必先利其器。”——开发环境
开发环境如同厨师的厨房,一个稳定、正常和项目组匹配的开发环境能保证自己在接下来的工作中,不会遇到因为某个设置不一致而导致耽误工作的情况。我所在的开发小组有比较完善的文档供配置,建议一定要按照文档的步骤配置,如果有不同或者没有提到的地方,应该是多问而不是想当然。我自己安装完某个IDE后,就发现没法调试项目所使用的芯片,这当然是自己的问题,还得返工重装(这种重装又可能引发没删干净等等新问题,很讨厌)。所以,在开发环境全部配置好后也要检验测试,确定是否能正常编译和调试。
“Code and Documents are all you need.” ——项目代码和文档
拿到仓库权限后,就可以把代码拉到本地仔细浏览了。项目代码和文档真的是最好的老师。首先就是项目的代码结构,各个模块在项目的什么位置,都可以很清晰地了解到。第二个是通过Commit记录,查看当前的主分支、开发分支,提交规范等等信息,确定自己在什么分支基础开发,又合入什么分支。题外话是通过Commit也能看到大家真实的工作时间😄。在我的工作中,每笔代码合入都需要Code Review,记得刚开始的提交的Merge Request,因为不符合组内要求的开发规范和细节,待整改的Comment多的吓人,来来回回跑好多次改。但有效的Code Review确实能学习到很多。有空的时候我也会查看其他同事的MR,能学习到很多更好的组织代码的方法。
“在小小的代码里面挖大大的Bug” ——自测与Debug
自测检验两个方面的问题,第一个是检查本次合入的功能是否符合预期需求,第二个是检查这个功能是否对其他原有功能造成影响,其实第二个的意义更大一些,因为耽误的是更多人的进度。这点我深有体悟,举个例子,有次代码合入在经过自测后一切正常,合入后却发现在一批新板上会自动复位,导致无法运行。虽然最终发现是时序冲突和硬件变更原因,但是这样的情况也需要尽快修复。Debug一般有两个原因,一种是自己正常开发过程中的,另一种是由其他组提出的缺陷等,分配到自己需要查看原因和解决的。后一种更要紧些,首先就需要确定问题产生的条件,版本、现象、是否可以稳定复现等等都很重要,有稳定复现的一般好解决,不能稳定复现的,则可能需要回退版本、压力测试等情况一点点对比,这点就很复杂了,很吃经验,也很头大。
“沟通的价值,取决于听者的需要。” ——沟通与协作
在学校的时候,大多是我自己独立地做项目,合作项目的大部分实施细节也是我完成,很少遇到需要沟通的情况。而在实际的开发工作中,一个需求或者是问题整改往往需要涉及到多个模块、多个部门的协调,这是一个系统工程。开发过程中,可能有的时候写代码并不多,但是协调各个环节很费工夫。我的经验有两点:找对人和把话说全很重要,别人可能并不清楚你描述的问题的背景;按照正规的流程去沟通和上升,部门应当是一个整体,需要注意自己发送的信息是否应当让接收者知道。
“别把整个大的变成整坨大的” ——从最小可用出发与不要憋大招
有的时候自己做事有点完美主义,总是在脑海里面有了一个想做的东西后,就给他填上各种功能。然后兴致冲冲地开始写代码,但是写着写着就觉得“啊,这么写太丑了”,就这样来回纠结半天,实际想做的核心功能进展却很少。这样并不对,因为这不是只能做一次的艺术品。所以在完成的时候,就是要优先从可用性出发,哪怕它很丑,没有界面,用的是命令行,代码可读性一塌糊涂,性能也不好,只有完全按照方法用才有正确的输出,不然连错误处理也没有。但这就已经是很好的起点,在这个起点上,能够有无限的可能性和优化方向。而优化是需要投入人力的。
不要憋大招,就是指一定在工作中积极反馈进度,不能埋头蛮干,要让相关人知道你的工作进展和可能的风险,而不是到最后说自己没有完成,这样反而会给更多人带来麻烦。有些工作是可以商量调整的,不合理的需求完全可以提出自己的意见。
“纵观世界风云,这边风景独好” ——外界环境
进入新的环境,有太多可以熟悉的了。从通勤角度考虑,比如坐地铁从哪个门下车可以走路最少,公交大概几点钟会有一班到站等等,这些都可以把通勤上的不确定减少很多,我喜欢减少生活中的不确定性,但是谋事在人,成事在天,当然很多事情也没法预见到。到工作地点,交集比较多的同事坐在哪里,会议室都分布在哪,各个楼层大概是哪些部门,包括公司的架构都可以一起熟悉起来。HRBP、财务、行政、设备、OA、公司内部的一些政策和福利等等都是需要了解的内容,虽然一时半会没有需要,但是比需要用到时,找不到合适的联络人要好。
“残酷的现实已直逼我心理防线了”——个人心态
既然已经决定要直接走向社会了,那么心态和思维也要尽快转为“社会”的形态。首先就是对于压力的处置,很多时候面对版本交付节点,总感觉有无形的压力,再来一个临时更改的点需要加班改,更是压力山大。但既然压力客观存在,就要分析和解决。进入职场多年的同事教我们在这个时候,更是要分析事情的根因和优先级,坚决克服浮在表面这种现象,一件一件总能完成下去,少想多做。再就是身心健康,不能让不合理的压力摧毁自己的身体。大学四年,如果说学到什么,最深刻的就是身体永远是最前面的1。宇宙很大,生命更大,工作之余一定要有自己的生活,哪怕是下班后洗个澡。努力工作,快乐生活,保持自信,别害怕尴尬,工作中做个钝角。
实习的感受是相当复杂的。在刚开始的两个月里面,在学校里面还有课要上,又要兼顾学业,有的时候一边上课一边还得回飞书的消息。等到后面单位搬迁和放暑假后,情况好了很多,感觉好像也不是那么累了,但这还是吃住都在学校,几乎没有生活压力。等到后面这层保护去掉,生活的挑战就会露出它本来的面目。
我不知道自己有没有做好准备,去承受这种压力,但至少也曾体验过这半年的酸甜苦辣。第一次实习,就能把自己的工作转化为一个即将生产装车的产品,不久的将来,我也能指着某款车型说这是我曾经做过的,这种成就感比学校里面的任何荣誉都要强烈,也是我选择嵌入式方向的最初动力。我深知自己要学的还有太多太多,离“半瓶水”都还远着。感谢遇到的各位同事同学对我的帮助,也感谢家人朋友的理解和支持,当然也感谢自己能够坚持下来。今年高校毕业生超过1200万人,在上大参加招聘会时又体会到自己和大家的渺小与普通。早点认识清楚现实,走好自己的路,把选择做正确,这也足够了,时代往哪发展,下一个风口又在哪,不是这个年纪的我们能够想明白的。人好比盆中鲜花,生活就是一团乱麻,房子修的再好那是个临时住所,小盒才是我们所有人永远的家:)