FlexSim实战练习(二)
提示:这里需要用到脚本函数有两个
- Array.splic(int fromindex,int count)
- Array.splic(int fromindex,int count,Array insert())
Array cars = ["Volvo","BMW","Audi","Ford"];
cars.splice(2,2); // ["Volvo", "Ford"]
cars.splice(3, 1, ["Lotus", "Kia"]); // ["Volvo", "BMW", "Lotus", "Kia", "Ford"]
Array.append(Array otherArray)
Array myArray = [1,2,3,4,5];
myArray.append([7,8,9]); //[1,2,3,4,5,7,8,9]
以上FlexSim软件版本为19版。
1、案例背景及3D布局说明
如图所示,系统会按照时间表(Arrival Schedule)生成不同类型的产品。
首先,根据产品类型分别进入对应的两个传送带上;
然后,根据产品的批次在合成器上进行合成;
最后,进入到一个暂存区进行缓存,等待订单计划下达。
产品到达
其中,ID表示产品编号,Type表示产品类型,B_ID表示产品一批次的数量。
这张图表示,一共有4种类型的订单(该全局表名称“info”),其中类型1订单需要{ST101,ST102,ST103,ST104}共4种产品组成,类型2,、类型3以及类型4订单如图所示。
2、详细流程图文解释
在整个仿真项目流程中,一共可以分为三个部分:
- 产品在发生器上产生,通过传送带进入合成器进行合成批次,最后进入缓存区等待订单下达;
- 订单下达指令;
- 订单下达后,操作员就会前往缓存区,对缓存区上的产品进行刷选,选择下达订单需要的产品搬运至放有tote的暂存区上进行订单组成。当满足订单需求后,操作员就会搬运该订单前往中转场。
第一步
完成后,你的模型布局应该类似于上图。
具体操作如下:
- 从Library模型库中拖出3个Source,4个Queue,2个Straight Conveyor,2个Combiner;
- 按照图中连线方式进行"A"链接;
注意,2个Source、2个Queue与2个Combiner链接时,必须要Source首先链接到Combiner,且2个Source都产生Pallet.
- 2个Conveyor的上游Queue,双击打开,找到send to port,并选择By Expression>item.Type;
- 选择一个Combiner,在进入触发和离开触发中,写上代码如下:
//进入触发
if (port == 2)
{
int de=item.B_ID;
Table thelist = getvarnode(current, "componentlist");
treenode thesum = getvarnode(current, "targetcomponentsum");
// thesum.value = 0;
for(int index = 1; index <= thelist.numRows; index++)
{
thelist[index][1] = item.B_ID;
//inc(thesum, item.B_ID);
}
}
//离开触发
item.labels.assert("B_ID").value = item.first.B_ID;
item.labels.assert("ID").value = item.first.ID;
//把产品上的标识赋值给下面的托盘。
- 对combiner下游的Queue,在进入触发里设置Push to List1,并打开List1列表,进行如下的设置;
以上是"第一部分"流程的所有活动。
第二步
具体操作如下:
- 从库中将以下实体添加到model中:
(1)1个 Source
(2)1个Queue
(3) 1个"Operator1" - 将Source和Queue进行"A"链接;
- 在Queue的进入触发上,写上如下代码:
treenode OP=Model.find("Operator1");
senddelayedmessage(OP,0,current,item.Order,0,0);//item.Order对应的是订单编号
应该会有人问,这第二步的作用是什么。它的作用就是:利用发生器按时间间隔发送一个Box到Queue上,使进入触发的代码被触发,这一个流程来模拟"订单下发"动作。
Source的设置可以参考我的,当然,你也可以自己编写。
以上是"第二部分"流程的所有活动。
第三步
- 从库中将以下实体添加到"model中:
(1)1个 Source;
(2)12个Queu;
(3)1个BasicFR; - 按照文章第一张图布局的样子,对Source与1个Queue进行"A"链接,同时,Queue与另外10个Queue进行"A"链接;
- 对下游10个Queue的进入触发中设置Push to List1:
if(true)
{
string listName = "List1";
List(listName).push(item,2);
}
- Process Flow>Add a general Process Flow,最终流程图样如下:
以下操作都将在Process Flow 上进行:
(1)拉入1个事件监听的发生器,并用吸管吸取操作员的On Message,同时在Msg Param1这一行,写入"Order",并选择assign,Order表示订单编号。
(2)拉入1个Pull form List 和1个List,通过Pull form List右边的感叹号与List进行链接。打开Pull form List,在Assign to 中写入token.Pallet,并在Partition ID填入2,表示为拉入的token.Pallet是10个Queue进入的Tote。
(3)拉入2个Assign Labels,并分别命名为“goal_01”和“Array”。goal_01的作用是获取当前下达订单对应需要几种产品,因此,代码为Table("info").cell(token.Order,1).as(Table).numRows
。Array的作用是将当前订单对应的产品编号,通过数组的形式存储到对应的Queue上,即up(token.Pallet)。代码如下:
Table dd=Table("info").cell(token.Order,1);
Array Save =up(token.Pallet).as(Object).save;
for(int i=1;i<=token.goal;i++)
{
string name=dd.cell(i,1).value;
Save.append([name]);
}
return Save;
- 拉入1个Assign Labels,并命名为“OP”,用于将model中的操作员以及中转场进行赋值。
- 拉入1个Assign Labels:“goal_02”,1个Wait for event,1个Delay,1个Decide,并进行连线,如图所示。
这里,goal_02的作用是获取进入缓存区的产品数量Queue_Num=token.Q_01.subnodes.length
,在Decide中进行判断token.Queue_Num >=1
,如果成立,token就会顺着直线往下走;否则,token就会前往Wait for event等待并监听缓存区有产品进入后,再次判断token.Queue_Num >=1
是否成立。 - 拉入1个Custom Code,1个Assign Labels,1个Delay,1个Decide,并进行连线,如图所示。
其中Custom Code的代码如下:
treenode BF=Model.find("BasicFR1");//就是之前拉入的BasicFR,这边需要注意名字要一样,或者改成你model中BF的名字;
int Queue_num=token.Q_01.subnodes.length;//再次获取缓存区中产品的数量值,确定for循环的次数。
Array save_item=Model.find("BasicFR1").save_item;//获取BF上的Array数组(以下简称BF);
Array Save=up(token.Pallet).save;//获取Tote存放的Queue上的Array数组(以下简称Qu);
for(int i=1;i<=Queue_num;i++)
{
treenode item=token.Q_01.subnodes[i];
string item_id=item.ID;
for(int j=1;j<=Save.length;j++)
{
string order_id=Save[j];
if(item_id==order_id)//如果缓存区中有产品属于当前订单组成部分,则把Qu中该产品编号从数组中剔除出去,并在BF中添加被剔除的产品编号
{
Save.splice(j,1);
save_item.append([order_id]);
break;
}
}
}
int array_num=save_item.length;
if(array_num == 4)//获取BF数组长度,如果长度==4,说明目前产品已满足订单需求;如果长度==0,说明目前产品不属于该订单;
{
BF.panduan = 1;
}
else if(array_num ==0)
{
BF.panduan = 3;
}
else
{
BF.panduan = 2;
}
判断完毕后,将判断结果赋值给BasicFR的panduan标签。最后通过Decide把token送到对应的下游去。
8. 这一步没有什么好讲的,主要是从BF上save_item存着需要搬运的订单组,以及订单组的长度save_item_L;
9. 这里的代码需要注意的是,把BF上存放订单的Array("save_item ")清空,用于下个token进入时的保存。
以上是第三步的所有活动。
总结
由于篇幅的限制,许多知识点无法详细说明,而且其中一些代码只适用于订单数量为4个的时候,存在优化的空间。