一、问题背景
IF 是 KUKA 机器人编程语言 KRL 使用的语句,可以判断当一个条件满足时执行某种结果,而不满足时执行另一种结果。它的最大好处是符合自然语言习惯,易于阅读。
例如下面代码:
IF (input==TRUE) THEN output = TRUE ELSE output = FALSE ENDIF
它表示:当输入变量input为1时,输出变量output输出值为1,当输入变量input为0时,输出变量output变为0。
如果有两个输入输入条件串联的话,可以这么写
IF ((input1==TRUE) AND (input2==TRUE)) THEN output = TRUE ELSE output = FALSE ENDIF
它表示:只有当input1和input2都为1的话,output才会为1,否则为0。
如果有三个输入条件串联的话呢,你会说可以这么写:
IF ((input1==TRUE) AND (input2==TRUE) AND (input3==TRUE)) THEN output = TRUE ELSE output = FALSE ENDIF
如果有20个输入条件串联呢 ,你会说这么写么:
IF ((input1==TRUE) AND (input2==TRUE) AND (input3==TRUE) AND (input4==TRUE) AND (input5==TRUE) AND (input6==TRUE) AND (input7==TRUE) AND (input8==TRUE) AND (input9==TRUE) AND (input10==TRUE) AND (input11==TRUE) AND (input12==TRUE) AND (input13==TRUE) AND (input14==TRUE) AND (input15==TRUE) AND (input16==TRUE) AND (input17==TRUE) AND (input18==TRUE) AND (input19==TRUE) AND (input20==TRUE)) THEN output = TRUE ELSE output = FALSE ENDIF
请重新审视上面这段代码,它易于阅读么,感觉是不是眼前一团糟,如果想更改其中一个条件,是不是定位这个变量很费劲?
那么,问题来了:要怎样组织这20个条件的IF语句才优雅呢? LT 打算将这个问题发到网上,看看大家都有怎样的妙招来解决这个问题?
二、网上众筹
于是 LT 就在 weibo 上@一些朋友,看看他们如何看待这个问题
@DAVIDROBOT_INDUSTRY: IF 是高级语言编程中使用的语句,可以判断当一个条件满足时执行某种结果,而不满足时执行另一种结果。……如果有20个输入条件串联呢 ,你会说这么写么…O网页链接 @linuxsand @拉面小新 @shumaojie @Huigens @机械葫芦娃 @工控人-在路上 @于仁颇黎 各位大侠,请发表发表看法?
这一部分将是众筹的解决方案,这样,解决问题的思路将不会仅局限于个人,各种想法可以交叉碰撞。
收到 @机械葫芦娃 的回复
@机械葫芦娃: 个人想法:for遍历20个变量,只要有一个变量是false,就输出”false”,如果没有false,就输出true【for(i in 20个变量 ) if i==false than output=false】.或者用位运算(一个字节8个bit),每个变量占一个bit,按位异或:input ^ test【如同 01101101 xor 1111111】结果不==0就输出false。#求其它更好解答#
收到 @Huigens 的回复
@Huigens:我仍然会这么写,但会排列整齐,该回车换行就换行嘛,一样可以赏心悦目
@DAVIDROBOT_INDUSTRY:回复@Huigens:假如不支持换行呢
@Huigens:回复@DAVIDROBOT_INDUSTRY:你…太险恶了竟然剥夺回车换行权利。那我就用cross connection ,每6个做成一个组合变量,然后将新创建的4个组合变量作为IF条件
@DAVIDROBOT_INDUSTRY:回复@Huigens:这是个办法[哈哈]
收到 @shumaojie 的回复
@shumaojie:回复@机械葫芦娃:同意。一个32位bit,每个赋值,然后转化为double,看看是否大于零就可以了。
收到 @linuxsand 的回复
@linuxsand:和葫芦娃兄的第一种想法相同,但是实现上我不会选择bit那么细粒度的办法,因为也许今后代码会有比我更业余的人来维护;我会用一眼就能看明白但往往是性能较差的办法,让后来者把脑力集中理解到业务逻辑上。
收到 @AB_机器人 的回复
@AB_机器人:如果做现场程序的的话,现场的变量应该都可以分类,比如和气体相关的,和安全相关的传感器信号,和标定相关的,分类操作,20个变量的可以分作几类,这样便于后面的人维护;如果是同一类信号,如果吸盘数据,可以按区域分成几组,按组操作判别信号变量。如果是我自己写程序,我倾向于位操作
收到 @工控人-在路上 的回复
@工控人-在路上:如果是我,肯定用递归来写 $i=0; $var=array(1,1,1,1,1,0…);//判断条件,输入0或1,有多少输入多少 function judge($j,$a,$var){ if ($a==true){$j++; if($j>=20){//可以写成自动数组判断 return 1; } return(judge($j,$var[$j],$var)); }else{ return 0; }大致这样,没测试
收到 @于仁颇黎 的回复
@于仁颇黎:用二进制组合变成10进制数如何?
三、我的经历
IF 语句,其实不仅仅局限于C++ 编程。在采用C++语言时,如果有很多个串联条件,LT 的做法确实是采用回车换行的做法,这样,阅读代码比较清晰,就像 @Huigens 所说。
if(input1 == true && input2 == true && input3 == true && input4 == true ){ // output = true; }else{ // output = false; }
本文开篇提到的问题,源于LT 在 KUKA 机器人上的编程,KUKA机器人采用的编程语言是KRL。最初,LT确实写了3、4个AND在一起的条件判断,不过,也还好,阅读也还清晰。
但是关键点在于两点:
- KRL 代码不支持回车换行,所以不能像 C++ 一样通过换行来使代码清晰。
- KUKA机器人示教盒显示屏一行显示的字数有限,这样长代码就会被自动换行,看起来就不分明。即使在电脑上查看也不分明。后期修改不方便。
于是,LT 想把条件分开,于是就有了下面的变形,举例来说,如果有3个条件串联
IF (input1==TRUE) THEN IF(input2==TRUE) THEN IF(input2==TRUE)THEN ;the last output=TRUE ELSE output==FALSE ENDIF ELSE output==FALSE ENDIF ELSE output = FALSE ENDIF
如果input1满足,进而再判断input2,如此类推。如果要新增加条件,只需要在后面添加类似的代码就行了,这样在有限的屏幕上能看到大部分代码。
后面一个应用,LT 确实按照这个思路开始写程序了,比如下面这个样子:
DEF TEST_IF_10( ) BOOL input[14] BOOL output ; INT I FOR I =1 TO 14 input[i]=FALSE ENDFOR ; IF(input[1]==TRUE) THEN IF(input[2]==TRUE)THEN IF(input[3]==TRUE)THEN IF(input[4]==TRUE)THEN IF(input[5]==TRUE)THEN IF(input[6]==TRUE)THEN IF(input[7]==TRUE)THEN IF(input[8]==TRUE)THEN IF(input[9]==TRUE)THEN IF(input[10]==TRUE)THEN IF(input[11]==TRUE)THEN ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF ELSE output=FALSE ENDIF END
虽然看起来有点怪怪的,但是还好,一个屏幕能看到11个条件,如果缩进使用2个空格,兴许还可以更多。下面的图片就是示教盒上看到的样子(取消了换行)。
事情到此似乎结束了,可是当 LT 保存后,出现了报错!意思是嵌套达到最大深度了!
LT 当时就惊呆了,原来 KRL 还有嵌套深度的限制!于是 LT 又重新测试确认了下,没错,IF-ELSE 嵌套只能10层,到第11层就会报错,也就是说,采用目前这个结构形式,只能写10个条件。那11个条件以后的怎么办?显然,问题没有解决。
后来 robotforum 浏览时,忽然看到 SkyeFire 一种奇怪的写法,登时恍然大悟,加以吸收改善。这种写法的原理就是,将条件拆散!回顾一下上面的代码,IF-ELSE其实就是只判断了结果,如果IF后面只有一个结果,那么代码就简洁了。于是,有了下面的代码结构:
DEF TSET_IF( ) BOOL input[14] BOOL output ; INT I FOR I =1 TO 14 input[i]=FALSE ENDFOR ; output = TRUE output = output AND input[1] output = output AND input[2] output = output AND input[3] output = output AND input[4] output = output AND input[5] output = output AND input[6] output = output AND input[7] output = output AND input[8] output = output AND input[9] output = output AND input[10] output = output AND input[11] output = output AND input[12] output = output AND input[13] output = output AND input[14] ; END
在示教器界面上看起来很分明! 完美!在后面再加上 20个条件也不成问题!
四、深度分析
上面最后一种写法,其实与前面网友的想法一致,是对某个位进行操作,再把所有的位的操作集合起来再进行判断,只不过上面的写法更为特例而已。
@Huigens 提出的,就是把多个信号拆分,并利用其它并行处理的程序对其进行处理后再组合。也是一个很常见的处理方法。
在处理复杂条件时,最好把条件分类拆分判断,再将各个组合的结果再次组合,不要试图在一行代码里面写完所有的条件。
感谢众网友的思想火花!
五、扩展阅读
- S7-SCL 编程
http://www.ad.siemens.com.cn/download/OnlineReading.aspx?DocId=2757 - 在西门子PLC中使用SCL语言编程的技巧
http://wenku.baidu.com/view/e13065232f60ddccda38a064.html - Anti-If The missing patterns
http://code.joejag.com/2016/anti-if-the-missing-patterns.html
关键字: KRL, IF-ELSE, IF, 嵌套
很好的方法啊。库卡没有 ElseIf这一用法,这点很不好。
这个也是没有办法的办法。用的时候要自己组织起始逻辑和逐行逻辑关系
问一下您,KUKA中编程时可以同时给两个信号发脉冲信号吗,我改写试了很多次,都不行
你是怎么尝试的?