|
本帖最后由 晨枫 于 2014-1-1 21:23 编辑 4 [6 @$ [1 p7 P
7 |1 ^* z0 N* R8 e) L) ?意广才疏兄在软件人家开了一个帖子:
+ Y5 X. t* F& T7 n b" C! B4 X9 |关于丰田车载控制系统问题的分析! ]" D- B$ d$ i9 n' o3 T& g
本想在那里接着讨论的,但要说的东西比较多,就另外开一贴了,意广才疏兄请勿见怪。征求了老兵的意见,说可以在帮外贴,就贴到这里来了。
3 ?9 v* C$ ?" F& D* K
4 i8 w W8 r8 F9 M+ f3 ` r按照转贴的说法,丰田车载控制系统(实际上是动力和刹车控制系统)有如下几大罪状:9 D6 V% Z; ]3 J# {$ A9 W* R
1、模块复杂度过高,不便于查错、修复和扩展,有的已经达到“非可维护程度”了
- a+ _4 ]5 | q' q2、全局变量过多
% b/ y/ ~1 W2 n3、违反丰田和行业的编程规范+ h; o6 P% S$ V9 C1 K& i7 P( P. a
4、使用递归
A2 _3 T$ ? I+ y5、缺乏关键变量出错保护
: C' A' ~1 I% E3 [' Q6、对操作系统的代码没有深度校核,选用的操作系统没有通过认证: m; s* I( z4 v5 \# r1 J9 |% W% a
7、关键task死后,公用变量没有保护
& [7 V: W! @7 x; F8、内存分配容量不足,位置不合理,堆栈溢出造成任务分配表错乱
& R) r3 ^1 G0 e7 b9、没有用task来监视task,没有用watchdog自动重启系统
) g; L6 P, ~( J# w2 R10、watchdog只用于监视CPU过载,但容许CPU过载1.5秒9 l1 ]5 K" Q0 ~- p) ~2 @
11、用硬件时钟“喂狗”
$ r1 i9 x) t: p' }- o; G; r7 m8 L6 m/ S12、Brake Echo Check
! M2 a7 Z+ m; z13、刹车“触发动作”:change of state?8 ?$ J9 p% }% ]6 k; d
14、顶层设计:没有考虑mutually exclusive action的cross check,但后面有提到“刹车优先”
T$ A0 E( V6 L! W6 x15、节气门大开导致刹车助力不足( b( c& A! k& \" B
" n! y. M7 y' |9 A9 Z0 ~" e7 J' w
原帖在这里http://blog.jobbole.com/50915/: O' ^7 Z* H& p: ]0 i" j! Z
# c3 P N& i3 f# H
我会逐条评论这些罪状,不过需要一点时间。顺便说一句,根据维基的介绍,Michael Barr是从事嵌入式系统设计的,但就介绍来看,他做过的嵌入式系统似乎与实时控制无关。不大好判别他究竟对实时控制有多少在行。如果原帖里的评论精确反应了Michael Barr的意图的话,那至少评论者对实时控制的理解有一定的偏差。
% K5 W7 P+ W0 X9 v7 W& V
. B2 _6 @* E: c$ P$ z7 t' K' L0 j另外,历史上最有名的unintended acceleration案例不是2009-10年的丰田,而是1986年的Audi 5000。有意思的是,那个时代油门和刹车还是全机械的。这个案例差点毁了Audi。
' H% R, G$ `4 \2 y' X3 Z E' C, Z$ U* I5 o6 @
在评论丰田汽车控制的具体问题之前,先说说个人对一般工业过程控制编码的想法。我对化工过程控制最为熟悉,但想起来别的工业过程也有差不多的问题。最大特点是:这一行是三个绝然不同领域的重叠,所以需要三方面的技能。这三方面就是:过程、控制和编程。
6 H% O- Y) \# `( ^
Y9 C9 O- w' G0 {, T7 P2 B化工过程本身是一个巨大的领域,里面可以分各种专业。具体到工厂,一比较复杂的聚合物化工厂为例,前段工艺偏重反应、分离,精馏等,需要反应、流体、相变、传热方面的一般知识和牵涉到具体工艺的具体知识,这本身已经是一个无底洞了。更“吃亏”的是,工艺上这可能是两个工程师分管的,但自控支援这一边你一个人要通吃。后段工艺偏重切粒、输送、装车、产品跟踪(工厂在不断转换产品的过程中,到最后装车的时候必须确认谁是谁),需要对具体工艺和操作规程十分熟悉,否则谁到了哪里那是两眼一抹黑,产品发错了车,前面生产再高产优质也白搭。熟谙工艺就好比医生熟谙一般生理和病人具体情况一样,做不到这一点,绝对要开错药。2 T5 W: w) s0 p- L3 T1 W: E |9 n
1 u5 s! ^) c4 Y( h1 ~, K7 b( J
另一方面,自控也是很大的一个领域。有连续控制、断续控制,单变量控制、多变量控制,简单控制(线性、时不变)、复杂控制(非线性、时变),随动控制、干扰抑制,更有无穷无尽的组合情况。还有一个问题是自控不光包括传统自控,还和连锁保护高度交联。两者关系不理顺,要么互相打架,要么过程落入“两不管”的区域,最后无序漂移到被迫启动连锁保护的被动局面。自控也不光是“自”控,还要有机地结合进人机交互。不光要及时、准确、择优(指按照优先等级)报告过程信息,还要及时、可靠、无歧义地执行人工干预。计算机可以按照预设程序自动处理所有已知、已有预案的非正常情况,但对于没有预案的情况,人工判断、人工反应依然是最后一道关。这好比医生对药品的理解和熟练应用,也是必须的。
2 h h. d1 j5 b& L2 t
0 P/ W8 O( @* d- B还有一方面当然就是编程了。现代计算机控制系统通常自带很大的功能模块库,对于简单问题,可以直接套,并不需要多少编程。但这就像微软办公室软件一样,虽然提供了大量的信件、报告、电邮、宣传等标准格式,但现实远比标准格式复杂,还是有很多场合需要用户编程。我不是软件工程出身的,对于软件的理解不超过皮毛,基本上只要够用就行。一般来说,软件需要模块化,模块之间的逻辑关系要清晰,模块本身的复杂度要适度,功能增减更应该遵循模块化原则,不要撒胡椒面,到处打补丁。
: E4 W( ?7 k( ? x6 }$ f, Y$ m; X/ ^) o# I" k/ R" \, m. p) J
在三个方面都达到专业水平,这当然最好,但实际上不大可能。在理论上,学化工的、学自控的、学软件的都可以编制控制应用,但实际上没有那么简单。学化工的基本上都在大学里滚过4年,学的自控也就是一门课的事情,能记得P、I、D各自代表什么、能干什么用已经不简单了。软件也一样,不能要求比打印一句“hello world”高太多的要求。学自控的稍好,这是因为在北美,化工自控也是在化工系里,一般要学全套化工基础课,然后再加自控课。有的学校是快马加鞭,有的学校则是增加到5年毕业。学自控的编程课也要多一点,有点还要学汇编和数据结构,但更学软件的专业人士还是不能比的。学软件的人对于软件专业没得说,那也是大学4年滚出来的,但要是跟他们说精馏塔板效率、泵曲线、催化剂活性与失活,那就吃力了。罗马不是一天建成的。" f. W4 y6 b& b; F# `0 I8 s
( d* d0 v2 d6 ~5 o% }; z
另一方面,不管是喜欢也好,不喜欢也好,自控在工艺眼里就是后娘养的,自控天生就是“保障”工艺的,主从关系非常明确。这个观念一路向上,所以从公司的人事和投资结构来说,自控是“叫你干啥,你只要说一句保证完成任务就行了,别的都是多余的话。”在这样的心态下,计算机控制的必要性虽然大家都知道,但到了要投入人力、物力资源的时候,第一个要看的“你这个部门的业绩是多少?”工艺的业绩很明确:改变工艺条件或者设备挖潜改造后,今年产量提高xx,合格率提高yy。自控就难了。直接的产品质量控制或者产量最优化控制还好说,大量的保障性控制甚至连锁保护就没法计算了。我常发牢骚,哪一天把所有的控制应用都关了,看产量和质量差别多少,就知道自控的业绩了。但这当然是不可能的。由于从上倒下这样的心态,自控常常处于“你先证明你能干什么,再来提要求”的境地。所以,通常的情况是,计算机控制(尤其是先进版本)的开始不是来自于工艺的要求,而是自控的请战:“瞧啊,这xx技术上得厅堂下得厨房,咱们要不要试试?”回答是:“要钱没有,要机会可以考虑给你一个。”请专业的软件工程师是out of question,所以自控的人自己动手,搞出第一版。如果成功了,然后才有然后。这样不可避免地打上“业余”的烙印。
0 r9 E- k0 x( ?5 X+ ^4 X. Y2 B
! U( G/ i; n& I* f另一个问题是专业背景。软件工程师对于软件的工具和方法当然最在行,但对于工艺和自控就不一定在行了。在理论上,工艺和自控的人可以编写任务书,但任务书的编写是一门大学问,缺乏对软件工程的基本理解的话,从工艺和自控那边“想”的翻译成软件这边可以照着“做”的,这中间的距离不可以道里计。这有点像请中文系的人来编写产品使用手册。他们对语言的感觉和文章的组织可能非常好,但要工艺和产品这边的人把要写的东西解释清楚,这是非常艰巨的任务。事实上,是工艺和产品人员获得合格的写作技能才是一般通行的做法。
9 _, {8 ]& _) S, M8 L* R0 f# n' N# _# {( q7 j+ K5 F
出生决定品格,这对软件也是一样的。控制软件很多都出生旁门,这决定了它们业余的特质。控制软件的另一个特质是要求高度可靠。办公室电脑或者家庭电脑出了问题,IT的第一句话通常是:你重新启动过没有?重新启动可以刷新所有状态,大多数情况下,这就强迫系统退出不正常状态,在硬件、软件没有大问题的情况下,除非完全重复导致当前不正常状态的所有步骤(通常这是不可能的),再次出现同样问题的几率很小。采用品牌保证的硬件,大牌软件,通常也避免了大问题的出现。所以重启是合理的做法。但在实时控制系统里,重启是最后才可以考虑的选择。除非有特别的措施作为替补,重启期间的失控是不容许的。0 G* N" P, `: s1 W0 r( X2 ^' ^3 N4 J
+ m3 g( |. w5 z第二个问题是系统初始化。首先,系统要“理解”当前所有控制动作的位置,一切新的控制指令从当前位置开始,而不是从零开始,否则要出大乱子。所有多层控制回路都要逆向初始化,也是一样的意思。设计正确的控制系统应该打断所有控制回路,从底层向顶层逐级初始化,使当前的控制指令与控制机构的实际状态对应;然后再逐级接通,从顶层向底层发出控制指令。具体说起来,还有internal initialization和external initialization,还有PV tracking,但这说起来太罗嗦了,有兴趣的我们可以展开,否则就按下不表了。不过问题就是,初始化之后,全系统的设定值都可能发生偏移,需要人工或者应用重新校验、核对和调整一遍,才谈得上恢复正常。+ b6 q# L8 R: R7 q* W& n
& Y- f, M7 Y* r& M& _* o, G6 @. o- D控制软件不光根据当前状态动作,还根据状态历史作出控制决定。比如说,当前温度高了是一回事,在过去一段时间里,温度一直在迅速升高,这就是另一个问题了,需要紧急处理。相反,当前温度偏高,但过去一段时间里温度已经开始回落,这就可能不需要特别处理,静观其变更好。: `& a5 {' U* u( k# Q
5 h8 D( ^8 B0 P3 Y
另外的初始化问题包括所有控制参数的设定。有的参数是固化的,有的是用暂存动态存放的。控制系统都做定时备份,重启时调用最近的备份,但暂存里动态存放的参数就可能是过时的,也需要校验、核实和调整。
; F8 O6 q: s/ F( y/ M- c2 [# I; H+ E* j
总而言之,控制系统重启是一件大事,不可能轻易就重启的。这一点在后面watchdog的时候还要谈到。
( n! ? \: X$ _$ t* b
: V% \" B) _8 K7 l% R但这样高度可靠性要求的另一面就是:不要轻易改动已知可靠工作的部分,尽量做加法,减法或者重组要特别慎重。参照前面说道的核心软件的“业余”性质,隐患就不难理解了。9 r$ f* M( X" r% Y! [- \1 ~+ `( k
2 U' V5 v' o0 F8 k8 ?推到重写是有的,但这是非常慎重的事情。最重要的就是:控制软件通常“从属于”工艺项目,项目“不需要”的时候,没有控制软件独善其身的机会;项目需要的时候,时间限制放在那里,不容控制软件独善其身。这和通用软件的环境是不一样的。通用软件自身就是最终产品,除了市场竞争因素外,软件部门是可以自己控制进度和要求的。另一个问题就是,通用软件的开发任务相对单纯,周期也较长,windows不断出补丁,但基本软件要好几年才推出一个新版,尽管近10来年基本上是无事生非,为创新而创新,但这是另外一个话题了。航空航天也是一样,NASA从阿波罗到现在,中间只出过一个航天飞机。洛克希德这些年算高产了,但F-22到F-35,30年里也只是两型战斗机,算上无人机要不超过4-5中。一般工业控制软件则不一样,作为“从属”系统,需要短平快出产品。比如说,丰田一年就要推出好多种汽车。各种丰田汽车的控制系统当然有通用部分,但毕竟还是有很多不同。我不知道丰田的基本软件的身世,但要是有相对“业余”的核心,我一点也不会感到奇怪。
7 t, I( O5 N; i: Y- q- } N' g8 Q7 v$ y; p! F
控制软件还有一个问题:测试环境。通用软件的测试环境不是一个问题,只有有限人力物力的问题,否则理论上可以测试所有的情况。航空航天不惜工本,先用铁鸟测试,也可以解决大部分问题,尽管F-22试飞中依然出现PIO问题,F-35的软件研发也是问题一大堆。但工业控制软件的测试环境就很有限。有的地方还有仿真系统可以测试,但有些功能仿真系统也测试不了。仿真系统是实际系统的简化,不光在工艺上简化,在控制系统方面也是简化。以化工为例,HYSIS(现在是Honeywell的一部分)用硬件仿真,只有工艺模型用数学模型,控制系统是全套硬件,这样的系统仿真度高,但是成本受不了。Honeywell也用PC作为控制终端,只是在总线上插一块板子,但这块板子就是4万美刀,PC实际上白送。这还是控制系统里最便宜的部分,I/O柜子一个就是1.5万美刀,一个铁柜子啊!林林总总加起来,完全模拟一个化工厂的DCS,等于DCS硬件双倍投资,省掉一点现场接线的投资,这就是没有50万美刀想也不要想的事情,加上过程模型,还有每年的服务协议,这就使大部分公司打退堂鼓了。ABB(现在叫RSI)是软件仿真,省掉很多DCS硬件,但软件与实际DCS的相似度总是差那么一点点。要命的是,有些时候,仿真上通过了,实际一用,毛病来了。可以亡羊补牢的应用还不要紧,一锤子买卖的应用就要命了。有时候,特别关键的应用反而没法测试,只有“实践是检验真理的唯一标准”。问题是有些实践是可遇而不可求的,甚至是极力避免这个“遇”的。比如说,全过程紧急停车的后处理应用,这非常关键,不管保证安全,还减少设备损坏,但如果仿真不能提供100%的答案的话,工艺是不可能为了让你测试应用而给你拉闸的。; f% d, o5 H+ T6 `, _* U
" U3 s! s( @. Y# \; o, e这些不是吐糟,而是为了帮助非控制行当但对IT很熟悉的人,了解控制软件的特殊生态环境。有了这样的了解,再来看丰田汽车控制的问题,就比较容易了。9 P6 a% U% j R
! V4 o1 c# c: C& a( S% }8 P* r1 H
第一个问题:模块复杂度过高,不便于查错、修复和扩展,有的已经达到“非可维护程度”了1 @% E1 {9 u6 ^. @1 I! p( ]
# ]& K$ l* I' g& |
前面已经谈到,大部分控制软件有一个身世问题,通常出生旁门左道,在结构上不够专业,不够高瞻远瞩,好在功能简单,问题还不大。但随着经验的累积和胃口的增加,控制软件的不断复杂化,这简直就和水往低处流一样必然。
+ ^. ^" ?5 H- k
4 @. N3 \+ p+ _ }在增加功能的时候,首先考虑的通常是尽量不改动已有部分,只是净增加。这似乎是模块化的好机会,新功能整合到新模块,老功能保留在老模块。但实际上没有那么简单。控制软件的大头通常并不是核心功能部分,而是人机接口和意外处理,姑且称这些为外围功能。对于新功能来说,这部分在很大程度上是重复的。要看原始软件是怎么搭建的,如果核心功能与外围功能本来就分属不同模块,这样模块化还容易些。但考虑到“原始”控制软件大多很小、很简单,模块化程度可能不高,而新增功能只是很小的改动,最大的可能还是“就地”改动,继续享用原有外围功能,而不是另外构建新的模块。否则就要拆分原有模块,根本改动软件结构了。这不仅是编程的工作量,还有重新测试和验收问题。工艺上会不解地问:“只要那么小一个改动,为什么要重起炉灶?”问题也是显然的,这样时间长了,累计改动就积少成多,造成模块复杂度过高。/ v# ?, k1 a5 g
2 M4 V& i% m. [5 q9 {现成软件在什么时候拆分模块,这是一个艺术。太早了,没有business case,吃力不讨好,四处讨骂;太晚了,就有Michael Barr说的问题。但是具体到某一个软件,就怕Machael Barr自己也说不好,“应该”什么时候拆分,尤其是把对项目、成本、工期、风险的影响统统摆在面前的时候。写书、谈理论是容易的,但CEO从来不根据理论或者书来做business决定。
9 I6 ^( B+ T: ~# o4 ^# A7 V: O. S( }: v% M% [. v( }' O: X; x
第二个问题:全局变量过多
/ { I3 n5 Z3 z" h3 J- P3 K h, @& R9 r! U% T4 y4 Z
控制软件的对象是物理系统,尤其是大系统。大系统的行为是高度关联的。控制软件在本质上就是要与大系统的很多参数交联,否则就无法有效控制。聚合物工厂的反应器当然有温度控制、浓度控制、转化率控制等等,大这些控制上要“感知”进料情况,下要“感知”火车装车,中间更要“感知”进料纯化、催化剂制备、产物分离、未反应物料循环等等,哪一个环节脱节了,都要相应调整、减产,甚至停车。这一点与办公室软件或者小系统的专用软件有很大的不同。引文中用洗衣机(还是洗碗机?)做例子,全系统才有几个变量?
+ ~1 F1 R4 f4 H+ H0 e5 x$ ~( m% \: c
控制软件的另一个特点是,不仅要使用变量的当前值,还要使用变量的历史值。控制软件是定时反复执行的,比如说,每秒钟或者每分钟(根据控制对象的动态特性决定,慢过程还有每几分钟执行一次的,像精馏塔温度,升高个几度动辄半小时一小时,执行更快也没用;但F-16的尾翼就要每秒60次以上,否则飞机就掉下来了)执行X次,每次都要从头执行到底,或者在中途受控退出(exit)。全局变量有两种,一种是测量值,全系统都有access,这当然是全局变量,控制软件只是“调用”而已;另一种是中间数据暂存。这是因为程序内部的局部变量在每次执行结束后都被清洗掉,只有用全局变量才能在两次(或者多次)执行之间保留数值。这对历史值特别有用。
' j6 i T, Y2 _- x! v; L6 E& D, E! R4 L2 a0 \6 ]2 c
比如说,当前温度超限了,这当然是坏事,但“坏度”取决于温度在继续升高,还是已经在回落了,还有就是升高或者回落的速率。这就牵涉到历史值。历史值的另一个应用是比较当前状态和过去一段时间里的平均值。系统的工作状态是一直在漂移的,即使是“同一工况”,由于设备损耗、气候因素、物料纯度等等,具体到某一个温度、压力、电动机扭力,每时每刻都会有一点不一样。标准工况参数(SOC,standard operating condition)只是一个参照,具体到今天,这个数据可高可低,都是正常的。但要是要对异常情况监测,就不能用SOC参数比较,而要用当日平均值比较,这又要用到历史值。
6 T- E# O$ G* N6 M6 W# i% m
0 U) W/ N) S. `0 kMichael Barr说到丰田用了11000个全局变量。听起来这有点多了,但没有研究丰田的实际控制问题之前,我不能下结论这到底是多还是少。我自己的化工厂光测量值就有10万个,加上各种暂存,可能在要加几万。但化工厂和汽车的控制问题不能直接相比,只能说,控制软件“天生”就有大量的全局变量。
# }0 J* w) L9 }3 Z% [+ k# J& X5 W( i N5 P2 l) c/ b! X1 J* H7 D
第三个问题:违反丰田和行业的编程规范
1 p2 v& I) y9 l4 r1 e2 w( h: u
5 G4 E0 J4 c7 B+ l7 d6 }: m, Z丰田的汽车控制软件违反丰田和行业的编程规范,这是有可能的。这有几个可能:
2 R8 \0 m1 r5 ~% ~$ L" \1、 核心模块采用了大量legacy成分,也就是“历史流传下来”的东西。已经久经考验的,一般不会轻易放弃。但是当年编程的时候没有按照规范,留下来就一直这个样子了。工业上这叫grandfathering。重新按照规范改写当然可以,但一来需要花时间和投资,二来要重新测试和认证。在很多情况下,这样的重写属于“没事找事”。
2 x& k" S, L5 U5 Q6 C2、 核心模块不仅采用了legacy成分,而且是“打包固化”的。用科学计算程序举例,历史上流传下来很多FORTRAN程序,用于解算各种复杂科学问题。用了几十年了,可靠性是已经证明了的。但现在的程序环境早就进化了,C、VB、MATLAB或者专用环境,不再能直接使用,但可以把当年FORTRAN打包成DLL之类的东西调用。这样的话,更不可能按照新规范重新编写了。! v# x1 S; c+ g$ p& |' p9 @
- h- a8 H( g9 r: ~ K$ b0 L
一般计算机出毛病,IT的第一句话就是重启过没有,但工控可不能轻易重启。工业控制要求极端可靠。这包括两方面。第一是系统软件、硬件的无故障间隔,第二则是系统软件、硬件的出错机制已经“透明”。系统软件、硬件的无故障间隔当然是越长越好,但有时深刻理解出错机制更重要。只要能采取适当的“预防性维修”(Preventative Maintenance,简称PM),在故障间隔到期前更换部件,或者重启系统,故障间隔不可怕。但不可预测的出错隐患是大得多的威胁,不知道什么时候就咬你一下。这就是为什么要求高度可靠的应用常常使用貌似老爷的系统,主要是因为这些系统的出错机制已经熟悉,不会有意外。有些工业要求具有可靠性认证,没有足够的运行时间,这也是不可能的到的。例如,直到10年前(现在不知道是不是有改变了),核反应堆的控制如果用Honeywell DCS的话,还是TDC2000,这是80年代初的技术,连80年代后期的TDC3000都不准用。波音777上还是用8086、80286,F-22上使用PowerPC,都是这个道理。
- n1 F# }6 u; c( a* M' ?' o+ b8 `2 e' D+ C8 u2 A6 V
既然是老式计算机系统,编程环境陈旧就不奇怪了。不仅陈旧,而且是简化版。像Honeywell TDC3000上使用的CL语言,这是基于FORTRAN 4的简化版,可以IF…THEN…ELSE,但不能做嵌套IF…THEN,也就是说,不能使用6 ?* Z1 \% ]3 X' C% X
IF…THEN
: a6 o. k$ i0 \/ f+ K% x" l. ~# t IF…THEN
0 O( t1 O) d9 z: z- C8 b" p, Z这样的多层嵌套。这使得结构化的编程很困难,只有用逆逻辑和GOTO模拟与结构化相当的效果,但有时还是不能完全做到。如果丰田的编程环境有类似的问题,达不到规范要求也就不奇怪了。
% o7 Z7 y; H# S! r# ~
& X4 V: \& a% U还是那句话,原则上,规范要求是底线,必须达到;但实际上由于种种情况,不一定能做到。
' R- L6 `9 r1 N$ [6 r; M9 g# A s
- v7 |" _8 R( z h |第四个问题:使用递归) h3 G9 P/ a! O7 r/ e
: {% a9 w6 @* _* L" m5 Y' @
由于实时控制需要使用历史值,有的时候recursion是不可避免的。求数值解的时候,也常用recursion,可能这和文中提到的递归是不一样,那是函数反复调用自身?性质有所不同,但也未必不可控制。设立一个独立的计数,每调用一次就增加一次计数值,这样应该可以控制最多递归的次数,避免无穷递归。控制程序都是定时重复执行的,每一个循环开始的时候,技术需要清零。! t& F5 w) q1 c8 T3 D2 w9 a- {
3 ]. V$ s/ G3 b% O4 f
第五个问题:缺乏关键变量出错保护
; ~" E' i, i, R( o0 a5 [6 X8 Z* N9 O% c: \: n% f
变量保护分几个方面:5 \9 e. e3 i' Y; K
1、 发现变量出错,比如bad value,像传感器开路,bit reversal也属于这一类
1 Z/ f/ ~) L6 \9 p2、 变量不合理,比如flat line(数值冻结)、阶跃式数值剧变、脉冲式数值剧变等
& M2 W/ d9 d2 P, _$ z. s; F& J* x3、 发现出错后如何处理
' D1 k6 z9 y+ z$ S; w7 M3 J1 ?+ W) U( Z8 d) W' R; P
传感器开路有专门的检测手段,bit reversal也可以用类似校验码之类的办法,问题是工控的CPU有严格的时间限制,每一个时间段(一般是把一秒分划为256或者多少个等分)里,相关程序模块必须执行完全,不能“溢出”到下一个时间段里,影响其他程序模块的执行。换句话说,程序的复杂度要控制,否则可能出现超时出错(overrun)。
: `3 C( s1 X% V8 C9 m. i* T* g0 o5 c2 S* x- L
变量不合理的检测更加复杂。数值冻结需要对同一变量检测一段时间才能判定,这当然是移动窗口。阶跃式数值跳变是数值跳变后,一直停留在新的值,没有回落。连续控制作用对这样的跳变做出反应会很危险,大部分情况下这是传感器出错,而不是过程变量真的跳变了,但不采取有效措施检测,控制律是不知道不该对这样的跳变做出反应的。脉冲式跳变更常见,瞬时变化很大,但很快回落。人工控制的话,会对这样的跳变产生怀疑,通常等一等,跳变也就过去了,不至于做出错误反应。但计算机控制就比较死板,要不错误反应需要增加很多复杂逻辑,又多出来“聪明反被聪明误”的问题。总之,没有放之四海而皆准的好办法。" W, T/ Y6 ~# J0 ]
0 Z4 T# s6 `$ G: Y. K1 R5 X/ c发现变量出错后,如何处理,这也是一门学问。常用做法是使用一个固定的无害替代值,还有就是使用最近的有效值。后一个方法较好,但问题是如果变量持续出错,就要出现数值冻结问题。0 w6 H# P) \+ }# J: m, C6 g
$ G8 \ a9 D% n6 H$ {' i* Z m所有的变量保护措施都耗用CPU和I/O时间,不加区分都保护的话,CPU和I/O忙不过来。但什么是关键变量很不好确定,常常是以为不关键的变量最后要了你的命。
; A8 K; e$ ~0 }9 f7 x
/ M; o7 c- z0 b5 L2 [" j6、对操作系统的代码没有深度校核,选用的操作系统没有通过认证
. j) O% a2 f: E# f/ Y3 U) y) Q9 A8 q8 l) y. j1 P, ]- i" p$ D
操作系统应该认证。丰田使用未经认证的系统,这是自找麻烦。但使用应用软件的人,很少有本事或者工具对操作系统的代码深度校验,这个要求过分了。美国海军使用Windows NT作为宙斯盾的平台,香港赤腊角机场管理也是,早期曾出现死机问题。他们这样人力物力丰厚的地方都没有能力深度校核操作系统深层代码,一般工业公司就更不可能了。
+ \) Z" k4 v( |0 S5 H7 I+ S7 j( v, v/ E2 Z: V9 [, j
7、关键进程死后,公用变量没有保护
7 ?# a" x0 w& g# h
+ Z7 X) t9 t; ]8 R$ t如前所述,控制系统中公用变量和一般程序中有所不同,所有测量量、控制作用都是公用变量,这些公用变量不受关键进程死机的影响,它们和物理变量相连接。另一种公用变量是关键进程的计算结果,但这个数据是公用的,比如化工厂里反应器的转化率。这样的数据一般是放在专用的placeholder里,施主进程不更新,数据就保持不变;施主进程死机了,数据也就冻结了。由于数据本身是合理的(不是乱码,不超限),简单的校验是看不出数据是不是正确。“冻结检测”可以发现数据已经超过一定时间没有变化了,但这不一定可靠,有时候这数据确实就是长时间不变的;延长检测窗口最终是可以发现冻结,但要等很长时间才能确定冻结,发现的时候就太晚了。另一个办法是由施主进程在写入计算结果的时候,同时写入一个“心跳”(heartbeat)信号,现在是0,就写一个1;现在是1,就写一个0。受主进程在读用计算结果的时候,同时检测这个心跳,如果超过一定时间心跳冻结在一个数值,这就是说施主进程死机了。这时有几个办法:一个办法是不用计算结果,但有时这是不可能的;还有一个办法是降低控制增益甚至冻结控制输出,直到信号恢复;要是这不是唯一的输入的话,可以在几个同质输入中调整加权,降低冻结信号的加权,维持控制。4 E& l* [9 ~8 ]9 j" ]6 j" E" G9 x
- z( d1 L! }. V2 u; [6 q! ~* g: L8、内存分配容量不足,位置不合理,堆栈溢出造成任务分配表错乱
7 N) L8 h1 K2 Z4 i
% W9 V) n k: ~/ o9 W7 _对于这一段,很怀疑原作者对于堆栈溢出理解错误:“丰田的系统里,正好有这么两块相邻的内存块。第一块被称为“堆栈(Stack)”,这是所有Task存储它们运行状态的地方,大小为4KB。与之相邻的地 方储存了操作系统进行任务分配的记录。那么可以想象,如果很多Task给堆栈里写入太多东西,超过4KB,那么就会错误地写入与之相邻的任务分配表。这种 错误被称为“堆栈溢出”。”这样的指针管理错误实在太低级。堆栈是后进先出的,如果中断层次超过堆栈尺寸,最近的中断地址就没地方放了,程序就执行不下去了,这就是我理解的堆栈溢出,但绝不是把数据存到相邻的内存区。丰田很可能堆栈区没有设计有足够的尺寸,递归更加使得堆栈问题无法控制,但溢出到相邻内存应该是误解。6 g% q( b" m, X4 Q
& W# V1 T* n; V5 R' m6 K9、没有用task来监视task,没有用watchdog自动重启系统
8 T7 t1 I& N) o: l4 n( V1 W
. o }$ I2 }' {9 _# [用task来监视task,这就是看门狗。看门狗是实时程序中常用的东西,但看门狗最不能做的事情就是自动重启系统。系统如果当机,不弄清楚是怎么进入这个当机状态的,直接重启,很可能造成无限重启,问题更大。另外,看门狗要看性质,有时不是系统全面当机,只是局部功能死机,自动重启就是下下策。如前所述,计算机控制系统重启可不是PC机重启,这也是办公室IT和自控IT思维的关键差别。如果办公室PC出了毛病,哪怕还没有死机,IT支持经常首先要你重启一下,如果毛病没有了,就当从来没有出现过这毛病;如果毛病还在,再进一步查找。这是办公室IT的标准程序。但控制系统是24/7/365的,没有天大的事情,决不能贸然重启。不光重启期间全过程要失控,重启后的初始化更要火烛小心,否则就真的搬起石头砸自己的脚了。在工业工程中,看门狗用于提醒操作工或者系统人员:出现异常,这时就要人工按预案补偿、修复。对于不可能人工干预的情况,比如汽车的发动机-刹车控制系统,这就要考虑多余度备份,必要的时候保留模拟控制通道,保持简化的基本控制。丰田在看门狗“叫唤”的时候是怎么做的,我不知道,但自动重启是要不得的。
) c7 \9 A- _& ], D9 q$ L4 J( [! z5 Y N2 r) n( m9 ^
10、watchdog只用于监视CPU过载,但容许CPU过载1.5秒
' M! v2 I3 G7 q1 s5 D _
( m2 A* V. L; u0 {6 DCPU过载是不好的,但也要具体情况具体分析。实时系统的特点是程序按固定周期反复执行。最起码的要求是在指定周期内要完成所有计算和I/O。但具体分起来,前台(foreground)程序必须在指定周期内必须完成,否则就是overrun错误;累计overrun到一定程度,系统就认定已经无法再完成任务,或者选择性地关闭“坏程序”,但也可能的是全面崩溃。后台(background)程序则容许见缝插针,在前台程序执行空闲的间隙执行,一个周期完不成,就“溢出”到下一个周期。要是连续几个周期都完不成,那也引起overrun错误。另一方面,计算机虽然是数字式的,非黑即白,但在过载问题上,就和汽车发动机转速红线一样,这是指导性的,但不是硬性的。换句话说,发动机转速经常保持在红线上,发动机肯定要出毛病;但偶尔上红线甚至略为超过一点,并不至于损坏发动机。至于到了红线是否立刻切断油路,这要看应用场合。民用汽车发动机没有太性命交关的应用,到红线就切断油路是妥当的;飞机发动机就不一样了,有时候飞行员就是要争取这关键的几秒钟,否则就撞山了,这是你给他切断油路,还不如直接给他一枪自杀算了。控制系统CPU过载也是一样,由于不到万不得已不宜关机重启,适当容许过载一定的时间并无不妥,当然这个容许时间要小心掌握,在使用中也要时刻关注,要是经常出现进入过载但还不到容许时间极限的情况,这就要警惕了,有重大隐患,不能心存侥幸。
% v* g6 h5 M" O- P9 v4 S7 B, I1 J- z! J% _% ]
11、用硬件时钟“喂狗”
/ E* H, ^! |- Z* U* b
8 h5 I+ ]( D& t- [& Q3 D I硬件时钟喂狗是不妥的,这只监视硬件。根据不同系统,要是时钟死了,整机也就死了;心脏停跳了,还要大脑指挥手脚做反应,这就是荒唐了。& P) }# B8 Z( z
% `& P2 J j6 V) `8 E
12、Brake Echo Check
/ O# ^* |3 j. ?' G" }
$ [7 G2 a7 Z6 T) a* [# y如果我理解没错的话,brake echo check是根据刹车片位置传感器的反馈来确认刹车动作,这在化工上也常用,叫valve open/close switch,泵机等也有类似传感器。这牵涉到控制和逻辑的基本设计思路:一种是开环,根据控制意图发布指令,但发布指令后并不检查是否完成;另一种是闭环,发布指令后检查系统状态,确认指令得到完成,然后再做下一步。显然,闭环方法更好,但首先需要更多的传感器掌握系统状态,控制逻辑的复杂程度大大提高,而且执行时间更长,因为要等到确认了系统状态才能进入下一步。这也多了一个新的隐患。有的时候,第一次指令发出后,动作没有完成;控制系统根据系统状态反馈,发出下一次指令;几次下来,动作完成了。从控制逻辑的角度来说,万事大吉,达到设计要求了。但这实际上留下了一个隐患:为什么第一次没有完成动作?为什么总是要到第三次才完成?如果能确认原因,这通常引向一个系统的特质,然后针对性地改进设计,可以大大提高执行的可靠性,而不是依靠状态反馈。状态反馈是好东西,但也会掩盖深层问题,忽略了深层问题而依靠状态反馈“擦屁股”,最终是要被“踢屁股”的。有时问题是累计性的,前面几次依靠状态反馈最后完成了,但反复尝试的次数越来越多,最后再试也不管用了,这时就晚了。还有一点:多一个状态反馈,就多一个出错点。如果状态反馈传感器故障,控制动作正确执行了也不管用,控制系统还是“傻等”。开环方法还是闭环方法要看具体应用的关键性,还要看执行机构和传感器的相对可靠性,否则会自己给自己上枷锁。
) v7 k- ~9 n0 T5 k# r0 {# F
* p1 O+ c" N! ^! s$ K3 Y7 c13、刹车“触发动作”:change of state?7 G( I( M6 ~% y7 ]8 M
- c: ^: ? H9 h# V7 `
原文中对刹车“触发动作”的描述语焉不详,可能这是latched logic还是momentary logic的差别?前者根据系统状态将控制输出锁定在指定位置,后者则用脉冲信号将输出一次性推到指定位置,然后控制信号回中。两者各有优点。比如汽车车灯就是latched,而照相机快门就是momentary。还有一个可能是指根据系统状态(是0还是1)做出控制动作,还是根据系统状态变化(从0变到1或者从1变到0)做出控制动作。这一段看不懂作者在说什么,不大好评论。+ i- M! W3 A4 b6 m
: ~1 S- [4 Z- E; D14、顶层设计:没有考虑mutually exclusive action的cross check4 X. v# x1 j {
8 e/ p0 c) u/ t& t3 Z% J1 r8 a) Z$ O
原文指责丰田在顶层设计没有考虑mutually exclusive action的cross check,这确是对关键控制动作的基本检查。不过针对不同控制任务,mutually exclusive action集是不同的,有的时候绕了几个圈子后可能发生冲突,要很小心,别把自己绕住了。比如说,驾车时,右脚在油门踏板上,就不能在刹车踏板上,这在通常是对的,但飙车时是可以heel and toe的,也就是在踩刹车的时候同时拖一点油门。这是为了保持发动机转速不掉下来,在出弯的时候可以更快地加速。即使不做heel and toe,驾车人也可能错误地左脚踩刹车,右脚踩油门。对于开惯手动车的人来说,如果新换上自动车,还不习惯,左脚“找不到”离合器的时候,偏一点踩到刹车上,这是很可能出现的错误。如果控制系统死板地认定刹车和油门不可能同时踩下,而对控制逻辑做相应的设计,这就要出大问题。作者后面提到“刹车优先”,在刹车踏板踩下时,无条件关闭节气门,切断动力。认为如果这一点做到,即使上述mutually exclusive action没有做到,也可以保证安全。同样的问题,这不能解决heel and toe的问题,也容易在意外同时踩下两块踏板时过度减速,造成追尾。如果“刹车优先”在刹车踏板踩到80%以上才启动,可以解决这个问题。
) a& d- u9 z; [1 }2 j2 t" {) V; h& o; O' l* O' b/ j
15、节气门大开导致刹车助力不足
$ ?; O! u9 w" t) ]* Z1 t! [# l+ \3 \. K1 {2 j& p: P6 K8 X' R
这个不知道是Michael Barr的错误还是解读他的人的错误,汽车发动机进气系统的节气门与刹车是两个系统。轿车刹车是独立的液压系统,与发动机进气没有关系。即使是卡车上的气刹车也与发动机进气没有关系。(这一点我的理解有误,刹车的真空助力确实和节气门有关)5 S9 ?9 _4 q# L& I* K
" |* ^$ D+ b; G6 `+ _ M+ D' w
丰田的控制编程可能有很多严重问题,相信Michael Burr是有根据的。原文的解读也是花了功夫的,作者似乎是软件业内人士,至少对软件工程很熟悉,但对于实时控制软件的很多基本特点不甚了了,而是套用通用软件的概念,得出的结论就容易有偏差。但是作者的一些观点还是正确的。控制从业人员越来越借助计算机实现控制算法,编程早已不是选择之一,而是主要吃饭家伙。另一方面,控制从业人员的基本训练中,软件工程训练不足。这本来就是一个无底洞。软件发展那么快,几乎所有新颖软件都有控制应用,比如说,HTML已经广泛用于人机界面设计,JAVA也开始大量使用。随着机翼不同软件平台的MES和DCS的进一步整合,未来跨平台应用都会出现。控制从业人员一方面要不断提高自身软件工程的素质,另一方面也依赖软件行业提供更先进、有力的软件环境,帮助、鼓励甚至迫使控制从业人员采用软件工程的原则。隔行如隔山,有软件专业人员编写控制程序就像由药剂师开处方一样,说到底是十八般武艺用错了地方。对于控制软件和应用来说,软件专业人员的贡献更在于提供工具,而不在于具体解决问题,自控还是应该由自控专业人员主导,只有他们才更理解控制问题的特质。8 G4 i9 {3 r! D* c, G
|
评分
-
查看全部评分
|