记一次工业软件开发经历
项目概述
项目背景:工厂表面处理产线项目
b司接了a司一条表面处理产线的项目,包含硬件及软件,由于现在b司做的软件难用且数据难以查找,a司不满意验收不通过,款项没有结清。所有b司找到我们,希望我们能帮他搞定这个软件系统。
公司关系:
- 互联网软件公司,A司(我在的公司)
- 工业服务集成商,B司(我们直接接触的客户)
- 工厂C司(制造业的工厂,B司的客户)
人员关系:
- H工,A司的软件开发人员(即在下)
- I工,A司的某部门leader(即在下领导)
- J工,B司该项目负责人
- K工,B司该项目的驻场协调人员(J工的手下)
- L工,外包人员,负责电路设计,plc开发,原有的软件系统开发。
系统架构(旧):
- 软件(给工人使用的人机交互程序,基于组态王软件开发的工业软件)
- plc,工业中普遍采用的可编程控制器,用来控制物理设备
- 物理设备,各种传感器及物理设备。(如温度传感,水泵设备,超声设备等)
控制流程, 软件 < -----> PLC <--------->物理设备
阶段一 (10月10)
需求
此时的需求是,需要有生产数据导出的Excel.
技术准备
通过看组态王的说明文件,了解到其有一个web,api接口可拿到所有字段的数据。
技术方案
于是此时考虑的技术方案,就是从组态王里面拿到数据进行格式化后输出。
采用该技术方案的原因:
- 该方案可以满足客户需要数据的需求。
- 该方案开发周期短,不需要接管麻烦的硬件控制。
开发
我在开发电脑安装了一个演示版组态王(演示版2小时会自动关闭),开发了一个脚本不断请求组态王web接口的数据,然后格式化生成excel。
碰到的技术点:通过测试发现组态王程序不允许使用Connection: Keep-Alive,该选项会使组态王崩溃。
一两天的时间开发完成,就等待安排时间去现场部署。(因为部署时会影响生产,只能等待安排时间)
部署
部署时发生的问题:
- 现场电脑使用win7系统,缺少一些重要组件导致python无法直接安装。
- 现场的组态王程序没有我在公司测试的api接口
此时与原先的软件开发人员L工沟通这个问题,他解释说现场使用的加密狗没有开通这个功能,这个功能要单独收费。
因为组态王使用的是加密狗授权。我在公司测试运行的演示版是全功能的。
结果
所以阶段一的开发工作是无效的,主要问题是双方缺少沟通,这个技术方案需要俩套系统的功能上的支持。我对工业软件按模块收费的模式不了解,我以为花钱了就是所有的功能都有的,和演示版一样,只是不会自动关闭。
阶段二 (准备期,10月10日至11月10日)
需求
每天一个生产数据报表excel文件。
准备
下一步方案考虑绕开组态王和plc通讯。让plc开发给我一个tcp通讯口。
找了很多关于plc的资料学习,使用plc开发软件进行联系。使用仿真软件模拟测试。
- plc程序开发软件与plc设备具有很强的关联性。不同设备要使用不同的软件开发。
- 没有官方的仿真软件,且仿真软件模拟不了网络通讯。
后来强烈要求leader搞一个真实plc设备。
plc设备搞来后,花了两周了解熟悉了plc程序开发,能写一些简单的逻辑程序辑器网络通讯(socket)开发。
准备工作完成后开始正式开发,开了一个专门的工厂项目。原来只是一些单文件脚本,挂在其他项目里。
技术方案一
我在plc中的变量区定义一个地址块,plc程序把我需要的数据传到这个地址块。我会高频的读取这个地址块的数据,写入到我定义的数据库里面。然后按需求输出一个客户需要的excel文件。
开发一
进行demo开发,确认技术方案可以实现。
与L工同步这个技术方案,L工表示数据都有的组态王已经把数据存在数据库了,不需要这么麻烦。
调整技术方案
技术方案二
调整技术方案, 直接从组态王的数据库提取数据,不做plc通讯。
通过沟通发现L工并不懂数据库,经过自己研究发现他所谓的数据库是ms access。
不断读取ms access的数据来生成今日报表excel文件,每当有新的数据产生,今日报表文件就会刷新。
到了第二天,就会产生一个不断更新的excel文件。(为什么不生成昨日的数据?忘了,且客户需要当日数据)
开发二
通过观察组态王的演示程序,其中演示功能有数据库存储即ms access的模块。我可以直接基于这个演示模块进行开发, 到现场只要替换掉字段名称,即ms access 文件即可。
- 通过统计行数来判断是否有的新的数据产生。 有新的数据则重新加载数据。
- 加载的数据放在内存,当重新加载时,把新的数据添加内存。
- 当有新数据重写整个excel文件。由于数据时基于每天的,所以量不可能很大。
- 原来是生成2013的excel文件, 为了适应现场改成2007的excel文件。
- python程序打包Windows系统服务
部署
约时间到现场部署, 这次L工也在现场。L工见到我马上抛出一个重要问题。
数据只有行车是自动模式才会存,手动模式不存数据。(此时心里mmp)
感觉又是浪费时间,因为这个线基本不用自动模式,win7系统组件装上去,python环境安装。部署服务。
看了一下历史数据只有少数的几次,估计还是测试的数据。所以这个功能虽然可行,但是源头上就没有数据。
结果
功能可行,部署也很顺利。 但是源头没有数据,后来去看确实没有数据。
阶段三 (11月14日至12月22日)
需求
完成对产线的自动化生产的控制,在实现原来组态王实现的所有功能上增加数据保存
解除原来程序的一些操作限制方便工人使用。
准备
和leader即b司leader沟通, 直接把整个组态王干掉。我这个写一个界面程序直接与plc通讯。
leader 出原型图,我负责系统结构设计及开发,另外一个同事配合我与L工沟通一些问题。
技术方案
- 使用cs结构socket通讯,因为后面可能会有前端来配合我完成开发工作,也可能做成ipad应用。
- 目前前台使用使用pyqt5 实现。
- 操作方式尽可能倾向与触摸操作。
- 与plc的通讯使用S7协议
- 上位机与plc的协作方式。
在plc变量区中定义一个上位机只读块,和上位机只写块。通过这两个块的字段修改进行控制反馈。
开发
前台开发:基于pyqt5进行开发,一边开发一边学。官网文档主要是c++的,只能看个大概,多多谷歌。
有个pyqt5群,这帮人闲得很,可以解答各种问题。
- 数据模块,利用import实现单例, 主要衔接了界面和通讯。对接口进行分发处理
- 网络通讯模块
- qt designer 生成的界面模型
- 界面程序,继承界面模型,定义槽及事件关联。
- tableview 模块
- tablemodel模块
- 对话框模块
后台开发:基于Python开发
- 数据模块, 使用Init()实例引用传递的方式实现单例(缺点,pycharm不知道具体结构,无法自动提示)
- s7 协议模块, 用于和西门子plc通信
- plc字段对象,协商的地址块的每个此段抽象出来的对象
- socketserver, 与界面程序通信。
- 数据库结构定义模块。
- 数据库操作模块。
写给plc使用的接口文档。 即地址断的定义说明
开发过程心得,
- 由于采用了这个分离结构,导致工作量翻倍。要时刻记得这是客户端尽量不要有逻辑处理。
- 如果是一个人开发再也不要使用这种结构。
- 用了非常多的动态挂载,导致到了后面查找一个功能要用全局搜索。
- 数据满天乱飞,自己看了都怕。
- 轻重缓急要分清楚,要为最核心的功能做最简单的实现,再去优化。类似于TDD。
花了一些时间在无关紧要的细节上(细节最后还没用上),最后只能把需求砍了。 - 日志模块真的是挺难的。由于代码复杂,出了问题也不好复现。一般都需要查日志解决。
一个好的日志应该能帮助快速且正确的定位问题。现在这个日志用得太烂了。
联调
早上到了现场准备联调, 结果工厂说线停错了,等到下午才开始联调。
因为我们这里开始联调的话现场无法进行生产。
碰到了一个plc浮点数问题,一开始我让另一个同事跟L工对好字段的数据类型,
这个工作没做到位。因为我觉得出了问题我也还能hold住,也就没管了。
花了一个多小时解决整个问题。
碰到了一个位的问题,我代码里的bit位是按字节流顺序的即高位到低位的顺序,
而PLC代码里的位是按低位到高位的顺序排的。最后把所有位类型的数据改成字节类型。浪费了空间。
然后就是对天车的控制,整个中间出了很多问题。
基本就是我这边出问题改半天,L工在边上等着。L工那边PLC出问题改半天,我在边上等着。
就这样搞了一个通宵,只对完了一些基本控制。只好约下次再去搞了。让他们还是先用原来的系统。
结果
只完成了一部分的联调,联调必须在现场才能完成。
阶段四 (12月30日至 1月2日)
联调
元旦工厂放假三天,给了我们充足的联调时间。
第一天 12月30日
动作联调,改了很多逻辑。晚上11点就撤了,第二天早上继续搞。
晚上在酒店看俄罗斯电影,《夜空飞燕》真的挺好看,俄罗斯妹子真漂亮
第二天 12月31日
联调基本完成,优化了一下策略及界面,准备部署。内部联合验收时出了问题,
因为我的程序是没有保存过程数据。每天开始要手动录入数据昨天没做完的数据,因为设备晚上会断电。
为什么不保存过程数据?
- 因为在我的设计里活每天都要干完的。活不可能干到一半的。这钱算谁的。
- 保存数据需要进行数据库操作,我的逻辑很多这样实现起来很麻烦。
- 工人可以每天早上来的时候录一下数据。
我们几个重新沟通了一下,确定了这个功能必须实现。 然后我就回酒店加班改代码。
那天是跨年夜,而我在酒店里加班改代码。浙江卫视放着《追梦》的节目。我在想我是不是在
追梦。我想应该不是,那天我在群里和朋友说,这不是我心爱的代码,这只是让我我苟且的代码。
我心爱的代码平时不肯多花点时间去写,现在却在为这破玩意而竭尽全力。真是想打自己一顿。
这个其实不是一天时间内可以写完的(以我目前的能力),但我挑战一下这个极限编程,
我不想认输,想把他做好。我在工作上总是有一种莫名的责任感,鞭策我吧,公瑾!
那天晚上本来想晚上12点睡的,但是压力太大实在睡不着。 在床上失眠了一个小时决定起来继续写代码。
在这个极限编程的时候发现了自己的一些问题,过度依赖ide的提示及自动补全。自己取得名字自己记不住,
英文太差了。(最近正好学词根词缀,感觉这个非常适合用来写代码)。对多线程的理解不到位,直到在真正调试的时候我才意识到这个问题,多线程必须结合类似于队列的东西使用。
我的多线打破了我分模块解耦的设计。由于这个多线程的错误使用导致代码高度耦合,
还好python内置全局锁,没有出现错误数据。代码正常运行。只是我也难以把握代码代码运行轨迹。
差不到写到了早上五点,终于有了困意就开始睡觉,定了个8点半的闹钟,
第三天 1月1日
8点半爬起来去酒店吃早餐,被告知没有早餐,只好拿出百度地图开始找吃的。找到了一家快餐店。吃了早饭就回去改代码,从早上9点改代码,中午1点的时候花了半个小时去吃饭, 就这样改到了下午3点半,然后我让K工和L工接我到现场调试。
调试过程依然不顺利,搞到了晚上22点才把联调完成,动作符合预期行为。开始准备进行部署。
由于我的分离结构,设备部署也很麻烦,服务端我部署在centos上,使用了多网卡,网络问题也搞了半天才接通。客户端部署发现了由于目标设备分辨率问题,导致整个页面显示效果很不理想。然后调整代码。还出了界面显示修改,一开始以为是硬件问题导致,到了后面才发现是代码里有个路径问题。这样差不多折腾到了早上6点,才把流程跑通。我教了一下K工如何使用我开发的这个软件,等工人上班由K工教工人如何使用。
K工把L工和我送回酒店休息,L工中午要赶火车就先和我回酒店休息。
第四天 1月2日
我睡到了9点多,有点不放心打车跑现场去看看,毕竟这个代码我自己都没测过。K工在现场教工人使用我开发的软件,使用过程中由于代码出了bug导致自动化跑不起来。在我配合实际生产使用的时候,发现我这个软件不能帮助工人提高生产效率,手自动模式衔接的不是很好。这整个交互可能需要重新进行设计。我在现场留下了我的电话,一再叮嘱工人出了问题打我电话, 因为这个未经过测试,我也不清楚会出现什么问题。我和K工一起去吃饭,K工送我回酒店,就回去睡觉了毕竟昨晚通宵一直没睡。然后我就回酒店把那个bug改掉,还有一个页面优化的问题。晚上7点的时候我打电话给K工让他接我去现场,
因为这个bug不是我预料的错误,必须在现场才能调试出来。到了现场,工人反馈说,
因为我软件崩溃一直打不开,泵关不掉,水溢出了。这个是由于前天晚上赶出来的代码,没有添加限制导致下标越位,工人在操作的不知道有这个要求。而且因为数据是持久化的,所有每次程序重启的使用的时候会
加载这个错误数据,然后程序报错退出。我首先简单修改了一下程序,能正常打开程序,先帮工人把泵关了。考虑了一下这其中的风险,我程序崩溃会导致现场无法进行生产,而且现在用我的程序并不能提高生产效率。我打电话给 leader说明一下现场情况及我的考虑。准备回滚为原来旧的系统。leader和B司的leader沟通后同意我的做法,于是我准备进行系统回滚。打电话给L工,让他把原来的PLC代码发给我,因为我部署的方式是直接换硬盘的所有他这个回滚倒是方便的。这个时候发现了一个问题,原来系统的加密狗不见了(应该是L工拿走了)L工说会寄一个新的加密狗过来。这样只有明天才能回滚了。我在代码把自动化相关的那块,具有复杂逻辑的东西给禁用了。减少出问题的概率。再三叮嘱工人出了问题一定要打电话给我。我开发的电脑先放在现场,等明天加密狗到了再去现场代码进行回滚。就这样我们折腾到了晚上11点才走。晚上终于可以好好睡觉了,电视放着百家讲坛。
阶段五 (1月3日至1月4日)
1月3日
这天睡到10天,我电话给L工追问加密狗的事,让他寄快递加急件,把快递单号发给我。我看快递单号是标快,打电话过去追问情况,他说寄不了加急,只有标快的。这样的今天就到不了。我打电话给leader说明情况,leader让我把操作步骤写下来,让K工找个现场的人明天配合我进行远程回滚。我把步骤写下给leader看,leader认为步骤过于复杂,工人搞不定的。说明天带我去现场回滚。中午时候K工来酒店接我。我告诉K工,人不用安排,明天我们会过来回滚的。让他和现场的人交代一下,出了问题一定要打电话给我。我们就一起回杭州了,我的东西先扔现场,反正明天就过来了。回来高速还堵车了。
下午我和leader碰了一下,沟通一下现状和后续计划。leader表示工人先这么用着,出了问题开车过去也就一个小时。明天和b司leader碰一下。
晚上我在家的时候用远程连了一下,看了下现场服务端代码的运行情况,正常使用,我把数据库同步脚本开起来。
1月4日
K工打电话说了现场有了问题,我告诉他正确的操作流程。晚上远程的修改了一下代码,初始化时加载持久化数据的功能。减少问题发生的概率
结语
- 需求搞错了
我是基于leader的ppt进行开发和构思的,leader和b司的leader也一起对过了ppt。
然而这俩人压根不知道现场情况,导致我很多设计是错误的。 - 工业软件一定到了解真实的使用场景。挖到客户的真正需求。
- 代码一到现场就大改了,所以一开始在公司写的很多的代码都是无效的。