flexsim中的重要概念及开发技术_第1页
flexsim中的重要概念及开发技术_第2页
flexsim中的重要概念及开发技术_第3页
flexsim中的重要概念及开发技术_第4页
flexsim中的重要概念及开发技术_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、-. z.第五章 Fle*sim相关的概念及关键技术研究5.1 Fle*sim软件介绍Fle*sim是由美国的Fle*sim Software Production公司出品的,是一款商业化离散事件系统仿真软件。Fle*sim采用面向对象技术,并具有三维显示功能。建模快捷方便和显示能力强大是该软件的重要特点。该软件体供了原始数据拟合、输入建模、图形化的模型构建、虚拟现实显示、运行模型进展仿真试验、对结果进展优化、生成3D动画影像文件等功能,也提供了与其他工具软件的接口。图5-1是Fle*sim软件及其构成模块的构造图7。E*pertFit等拟和分布工具E*cel等可以用作统计分析的工具模型建立与

2、调试模型有效性确认运行仿真试验3D的可视化结果动态显示生成影像文件Fle*sim仿真软件Microsoft Visual C+.NET输入建模系统仿真运行仿真试验结果统计分析图5-1 Fle*sim功能构造图Fle*sim提供了仿真模型与E*pertFit和E*cel的接口,用户可以同过E*perFit对输入数据进展分布拟合,同时可以在E*cel中方面地实现和仿真模型之间的数据交换,包括输出和运行模型过程中动态修改运行参数等。另外该软件还提供了优化模块Optquest,增加了帮助迅速建模的Microsoft Visio的接口。5.1.1 Fle*sim软件的主要特点Fle*sim仿真软件的特点

3、主要表达在采用面向对象技术,突出3D显示效果,建模和调试简单开放方便,模型的扩展性强,易于和其他软件配合使用等方面。基于面向对象技术建模Fle*sim中所有用来建立模型的资源都是对象,包括模型、表格、记录、GUI等。同时,用户可以根据自己行业和领域特点,扩展对象,构建自己的对象库。面向对象的建模技术使得Fle*sim的建模过程生产线化,对象可以重复利用,从而减少了建模人员的重复劳动。突出的3D图形显示功能Fle*sim支持OpenGL技术,也支持3ds、wrl、d*f和stl等文件格式。因此用户可以建立逼真的模型,从而可以帮助用户对模型有一个直观的认识,并帮助模型的验证。用户可以在仿真环境下很

4、容易地操控3D模型,从不同角度、放大或缩小来观测。建模和调试的方便建模过程中用户只需要从模型库中拖入已有的模型,根据模型的逻辑关系进展连接,然后设定不同对象的属性。建模的工作简单快捷,不需要编写程序。建模的扩展性强Fle*sim支持建立用户定制对象,融合了C+编程。用户完全可以将其当作一个C+的开发平台来开发一定的仿真应用程序。开放性好提供了与外部软件的接口,可以通过ODBC与外部数据库相连,通过socket接口与外部硬件设备相连,与E*cel、Visio等软件配合使用。5.2 Fle*sim的一些重要概念Fle*sim是目前国内最新的仿真软件,关于该软件的资料和使用经历还很少。作者是在不断的

5、摸索中学习的,所以希望本文能对其他人有一定的借鉴。要完全掌握好Fle*sim,并将其用到我们的工作、学习和研究当中,理解该软件的一些重要概念和思想是很重要的,本节针对集装箱码头建模仿真中用到的技术做一个梳理。5.2.1 面向对象的思想相对于目前的一些仿真软件如Witness, eM-Plant等,Fle*sim是采用面向对象思想和技术开发的,其本身更是用C+语言实现。严格地说该仿真软件包括了两局部,仿真软件和后台支持环境VC+.NET。由于C+是一种面向对象的语言,所以使用Fle*sim软件,从用户用于系统建模,或是做一些二次开发,这些工作都有面向对象思想的表达。可以这样说,没有领会面向对象的

6、思想,就不能完全发挥Fle*sim软件本身的特点,也就不能用其实现用户的目的。使用Fle*sim软件的用户需要对C+语言有一定程度的熟悉。本节主要是解释Fle*sim中所特有的一些面向对象思想,而不涉及面向对象语言的解释关于C+语言的知识请查看相关书籍。对象Object的概念在Fle*sim软件中无处不在,我们先直观的感受一下。软件的运行界面左边是一个常用的对象库如图5-1。库中的各种部件就是有特定功能的对象,这些对象是软件本身自带的,使用这些根本的部件对象用户可以完成大多数的仿真工作。我们使用Processor来解释一下对象的概念:我们日常所见的任何具体事物都可看作是对象,这里Process

7、or就是一种设备,它的作用就是对经过他的物件进展一些加工,即改变物件的状态。这里我们可以将其当作现实中的设备,如机床等。图5-1这里我们借用C+程序设计语言中的对象的概念。对象是类的实例,类是对现实对象的抽象。类中包含了对象的数据相当于现实对象的状态,以及对象的方法相当于现实对象用来处理外界所给信息的方法。对象封装了属性和方法,进一步到Fle*sim中,对于软件中可用的库对象,他们本身有自己的属性如颜色,尺寸,位置等,还有处理物件的方法。在使用软件的过程中,我们完全可以以人们平时的思维方式来思考,而无须过多的抽象化,这也就是面向对象方法的优点。5.2.2 Fle*sim的对象层次构造面向对象方

8、法的一个优点是类与类之间可以有继承关系,对象的继承性给我们提供了更大的柔性来扩展我们自己的对象,即衍生出新的对象。在Fle*sim中我们可以充分利用继承性来开发我们自己的对象,而软件本身也给用户提供了这样的机制。Fle*sim本身的库对象是高度抽象化的,具有很强的通用性,几乎涵盖了仿真中可能遇到的所有对象。这些对象之间有一定的继承关系,他们之间存在着逻辑关系。下列图图5-2是Fle*sim中对象的层次构造。Fle*simObjectFi*edResourceDispatcherNavigatorNetworkNodeSourceQueueSinkConveyorRackReservoirFi*

9、edSourceTemplateProcessorTaskE*ecuterbinerSeparatorOperatorTranspoterCraneASRSvehicleNetworkNavigatorCraneNavigatorBasicTEBasicRF从类的派生关系图中我们可以对Fle*sim中各种对象的逻辑关系一目了然。对象库中的对象分为两种,一种是从Fi*edResource中派生下来的,另一种是TaskE*ecuter中派生下来的。通过分析我们不难发现,从Fi*edResource中派生来的对象有一个共同的特点,其本身是不会运动的,他们的作用只是产生或消除物件、存储物件、加工物件等

10、等;从TaskE*ecuter中派生的对象,其本身是可以运动的,其作用是将物件从一个地点运送到另一个地点。当现有的库对象不能满足用户的需要时,用户就需要创立自己的对象。Fle*sim为用户提供了这样一种机制用户可以定制自己的库对象。在对象层次图中,我们看到有两个虚线框,这表示用户可以从Fi*edResource和TaskE*ecuter中派生出自己的对象。Fle*sim的早期版本中从这两个类中派生新的对象比拟复杂,最新的3.06版中增加了BasicFR和BasicTE类,使用户的开发工作更容易。后面的章节中将具体介绍怎样来实现一个新对象的定制。5.2.3 节点和树在介绍树构造之前,我们先来了解

11、Fle*sim中节点node的概念。节点是树构造的最根本的组成单元,他们组成了的层次。所有的节点都有一个文本缓冲区,用来保存节点的名字。节点可以是其他节点的容器,可以是用来定义一个对象属性的关键字,或是拥有一个数据项。属于一个节点的数据项类型可能是:数值number,字符串string,对象object,或指针pointer。下面列出FLe*sim中不同类型的节点标志:标准Standard:对象Object:属性/变量Attribute/Varibale:函数Function(C+):函数Function(Fle*Script):用户可以在对象的树构造中任意地操作节点,例如增加节点,删除节点,

12、改变节点所包含的值等。含有对象数据Object的节点可能包含有节点的子列表。含有对象数据的节点称之为对象节点。当你单击一个对象节点时,你会看到在节点的左边有一个大于号。单击将翻开对象数据的树分支。如果一个节点包含子节点,可以按下+按钮来展开。如果一个节点包含对象数据,可以按下来展开。下列图图5-3展示了一个队列Queue展开的对象数据树。图5-3树构造tree是一种很常用的数据构造。Fle*sim仿真模型中的对象,或对象中的属性和方法节点等都是树构造;用户甚至可以直接在树构造中操作对象。在Fle*sim中有两个主要的对象类型:模型Model或仿真对象Simulation Object和视图对象

13、View Object。两种类型都有对象数据树,包含了属性和行为控件。一个对象节点的对象数据树中的节点可以作为属性、变量或成员函数。也有只是作为简单的容器来包含节点以到达组织的目的。5.2.4 任务序列任务序列Task Sequences是Fle*sim仿真软件中的核心机制。各种复杂仿真的实现很大程度取决于怎样实现任务序列。前面介绍了Fle*sim中有两种对象,一种是派生至Fi*edResource的静态对象即对象本身不运动;另一种是派生至TaskE*ecuter的动态对象即对象本身可运动。如果用户建立的系统模型全部使用了静态对象,则就不需要任务序列的机制,但是这种情况几乎没有。使用动态对象搬

14、运物件,对象怎样运动,实现什么样的功能等,这就需要。任务序列是由TaskE*ecuter执行的一组命令序列。这里TaskE*ecuter涵盖了所有派生自他的动态对象,如Operators,Transpoters,Crane,ASRSvehicle,Robots,Elevators以及其他可运动的对象。图1-4表示一个任务序列,该任务序列有多个任务组成。P1 P2 Task1 Task2 Task3 Task4 Simulation TimeP1: Priority ValueP2: Preempt Value图1-4Fle*sim中为用户提供了功能齐备的任务类型。常用的任务序列有:TASKTY

15、PE_TRAVEL、TASKTYPE_LOAD、TASKTYPE_UNLOAD、TASKTYPE_TRAVELTOLOC等。不同的任务序列有不同的设置参数,用户可以根据需要在使用的时候查询帮助文档。 默认任务序列Fi*edResource为了将物件item移至下一个站点station,有一个创立任务序列的默认机制。Fi*edResource对象的参数对话框中一个通用的Flow选项页,选择其中的Use Transport复选框,这样就可创立默认的任务序列。对于Processor对象,还可以自动创立对Setup time/Process time/Repair operation的任

16、务序列。当仿真运行时,这些自动创立的任务序列就会传递给与其中心端口相连的动态对象来执行。这里给个简单的例子说明。假设用户选择了Queue对象参数对话框的Flow选项页中的Use Transport复选框,当系统运行时,产生了如下任务序列:P1 P2 Travel Load Break Travel Unload当Operator收到该任务序列时,顺序地执行任务序列中的每个任务,执行过程如下:Operator先移动到Queue处Travel;接着拿起物件Load;然后移动到下一个站点处Travel;最后放下物件Unload。在仿真运行的任意时刻,一个TaskE*ecuter只能执行一个任务序列,

17、而此时Fi*edResource可能创立了许多任务序列,这些未执行的任务序列被放置在缓存队列中等待执行。 定制任务序列一般情况下,默认的任务序列就可以满足仿真要求。有时候用户需要为*些特定的工艺、多个设备的组合操控灯定制任务序列。这里分三种介绍定制任务序列,第一种是创立最简单的、只分配给一个对象执行的任务序列;第二种是由多个对象协同作业的任务序列。定制简单任务序列使用3条命令来创立任务序列,命令执行的顺序如下:createemptytasksequence();inserttask();dispatchtasksequence();从函数名就可以看出创立任务序列的过程。首先创立一

18、个空的任务序列,然后在此任务序列中插入具体的任务,最后发布该任务序列。我们举个简单的例子,叉车运动到集装箱旁边,然后装载集装箱。在这个过程中,涉及了两个任务:运动TASKTYPE_TRAVEL和装载TASKTYPE_LOAD。具体实现如下:fsnode* new_ts = createemptytasksequence(forklift, 0, 0);inserttask(new_ts, TASKTYPE_TRAVEL, station);inserttask(new_ts, TASKTYPE_LOAD, item, station, 2);dispatchtasksequence(new_t

19、s);这里叉车forklift是任务序列的执行者,我们为其创立了一个新任务序列new_ts,在此任务序列中插入具体的任务TRAVEL/LOAD,最后发布任务序列。我们在创立新任务序列时,createemptytaskseqence函数的第一个参数forklift可以是该任务序列的执行者,或者是Dispatcher对象。关于Dispatcher对象的作用下一小节有具体的介绍。后两者参数决定了该任务序列的优先级别,我们可以根据任务的紧急程度来定义任务序列的执行顺序。Inserttask函数插入具体的任务类型。第一个参数表示该任务所属的任务序列。前面提过不同的任务类型有着不同的代码,以及不同的参数选

20、择。这些参数分别是:Task Type/involved1/involved2/var1/var2/var3,有些参数是选择性的,这要根据任务类型来决定。这里以TASKTYPE_LOAD为例,图1-5表示了不同参数的意义。用户可以根据所示规则查询具体的任务的参数选项。P1 P2 TRAVEL LOADTask Type: LOADInvoloved1: bject to load itemInvoloved2 : object to load from stationVar1 : output port 2Var2 : 0 默认值Var3 : 0 默认值图1-5 任务Load的参数含义协同作业

21、的任务序列协同作业的情况有很多,比方叉车作业需要一个司机来操控,或者一件物品需要两个人来同时搬运等。在Fle*sim中叉车、人都是可运动对象,要实现协同作业的任务序列相对于只对一个对象创立任务序列要复杂许多。我们以叉车和司机的协同工作为例来说明怎样实现协同作业的任务序列。我们先来分解任务的执行过程:1人运动到叉车上Travel;2人进入驾驶室这里是叉车的动作Load;3叉车运动到指定地点Travel;4叉车装载货物Load;5叉车运动到卸载点Travel;6卸载货物Unload。图1-6是叉车和人的任务序列。P P Wait Load Travel Load Travel UnloadP P

22、Travel to forklift WaitForkliftOperatort图1-6 协同任务序列从图中可以看出,叉车在人到达之后才执行任务,人进入叉车之后就随着叉车一起完成叉车的任务。人的任务序列中只有一个任务,其他时间不做任何事情。在Fle*sim中实现的代码要复杂一些,调用的函数与前面所讲的函数不同。涉及的函数主要有:createcoordinatedtasksequence();insertallocatetask();insertpro*ytask();insertsynctask();insertdeallocatetask();dispatchcoordinatedtasks

23、equence();一个协同作业的任务序列的定制是很复杂,也是很容易出错的。在开场实现之前必须分析清楚作业的过程。对于前面人操控叉车的例子我们已经将作业流程分析清楚了,下面是具体的实现,我将每个函数的功能写在程序的注释当中。/创立协同任务序列fsnode * myts = createcoordinatedtasksequence(operatorteam);/为每个执行对象分配任务int opkey = insertallocatetask(myts, operatorteam, 0, 0);int forkliftkey = insertallocatetask(myts, forklif

24、tteam, 0,0);/人的分派任务序列int traveltask = insertpro*ytask(myts, opkey, TASKTYPE_TRAVEL, forkliftkey, NULL);insertsynctask(myts, traveltask);/叉车的分派任务序列insertpro*ytask(myts, forkliftkey, TASKTYPE_MOVEOBJECT, opkey, forkliftkey);insertpro*ytask(myts, forkliftkey, TASKTYPE_TRAVEL, loadstation, NULL);insertp

25、ro*ytask(myts, forkliftkey, TASKTYPE_LOAD, item, loadstation);insertpro*ytask(myts, forkliftkey, TASKTYPE_TRAVEL, unloadstation, NULL);insertpro*ytask(myts, forkliftkey, TASKTYPE_UNLOAD, item, unloadstation);/释放分派的任务序列insertdeallocatetask(myts, forkliftkey);insertdeallocatetask(myts, opkey);/发布协同任务序

26、列dispatchcoordinatedtasksequence(myts);对象Dispatcher及任务序列的分配规则现在考虑一种较为复杂的情况:有两个Queue对象用于存放物件,三个Operator对象用于搬运物件;三个Operator是自由的,没有被分配给固定的Queue,则怎样来有效地调用这三个Operator呢?此时就要用到Dispatcher对象。Dispatcher用来控制一组Transporter或Operator。任务序列从一个静态对象发送到Dispatcher,然后Dispatcher来调配这些任务序列分配给与其输出端口相连的动态对象。动态对象接收到任务序列

27、后执行相应的命令序列。Dispatcher对象的功能就是将任务序列进展队列存储和发送任务序列。根据用户建模的逻辑,任务序列可以被排队等待或是立即传送个相应的对象。Dispatcher的参数设置对话框只有两项,当接收到一个任务序列时,调用Pass To函数。顾名思义,该函数将任务序列发送给接收对象;如果该函数返回值是0,即该任务序列不能被立即分配,则根据QueueStrategy定义的规则将任务序列放入队列中等候。QueueStrategy函数返回任务序列的相关值,然后根据优先级来确定任务序列在队列中的位置。高优先级的任务序列放在队列的前面,低优先级的放在队列的后面。如果优先级一样,则根据队列的

28、先进先出FIFO原则来处理。用户可以根据需要,动态的改变任务序列的优先级。当将队列中的任务序列进展排序时,Dispatcher执行队列策略函数,遍历取得已有任务序列的优先级值,与最新的任务序列优先级值比拟,根据比拟的结果重新进展队列排序。在Fle*sim对象层次图中,我们发现Dispatcher是所有TaskE*ecuter的父类,也就是说所有的TaskE*ecuter也是Dispatcher。这就意味着Operator或Transporter也可以担当Dispatcher的角色来分配任务序列,或者是自己执行任务序列。Dispatcher与TaskE*ecuter的区别在仿真执行

29、的任意时刻,即使任务序列的等候队列中多个任务序列,TaskE*ecuter一次只能执行一个任务序列。而Dispatcher对象的作用只是在缓存队列中存放已排序好任务序列,并将队列最前面的任务序列发送给动态对象,但并不执行任务序列。利用任务序列实现集装箱的装卸过程在集装箱码头的作业的过程中,集卡行驶到岸桥设备处等待装箱,岸桥将集装箱从船上卸下装到已等待的集卡上;装箱后的集卡行驶到堆场中,场桥将集装箱从集卡上卸下,堆放到堆场中。集装箱从船到堆场的过程中,经过了集卡、岸桥、场桥等设备的搬运,在Fle*sim中就需要使用任务序列来完成这个过程。这里涉及了三个可运动对象:集卡、岸桥和场桥。

30、这里设计的思路是这样的,集装箱的运输由集卡来实现,这样集卡就有这样一个任务序列:Travel Load Travel Unload。集装箱装入集卡的作业由岸桥设备完成,卸载放入堆场的作业由场桥设备完成,所以集卡的任务序列中Load/Unload的任务就应该由岸桥和场桥来完成。岸桥完成一次作业的过程也就是完成一个任务序列的过程,可以知道岸桥完成的任务序列应该是:Travel Load Travel Unload。岸桥在作业的过程中,集卡处于等待的状态,也就是说岸桥和集卡之间是协同作业的。场桥的情况与岸桥一致。Fle*sim中可以使用调用子任务的方法将岸桥和场桥的任务序列插入到集卡的任务序列中。图

31、1-7表示了主任务序列和子任务序列之间的关系。TravelLoadTravelUnload场桥子任务序列TravelLoadTravelUnload集卡主任务序列TravelLoadTravelUnload岸桥子任务序列图1-7 集装箱搬运过程的任务序列在Fle*sim中的实现的主要代码如下,其关键的代码在文中有注释:/获取任务序列中的任务数量int nroftasks = gettotalnroftasks(tasksequence);/查找Load/Unload任务,找到之后调用子任务来替换这两个任务for(int i=1; i=nroftasks; i+)int tasktype = g

32、ettasktype(tasksequence, i);switch(tasktype)case TASKTYPE_LOAD:case TASKTYPE_FRLOAD:int msgtype = (tasktype = TASKTYPE_LOAD 1 : 2);/changetask()函数会发出一个消息message,我们在消息的承受者的OnMessage()函/数中创立岸桥和叉车的子任务序列changetask(tasksequence, i, TASKTYPE_CALLSUBTASKS, current, NULL, msgtype, tonum(gettaskinvolved(task

33、sequence, i, 1), tonum(gettaskinvolved(tasksequence, i, 2), gettaskvariable(tasksequence, i, 1);break;case TASKTYPE_UNLOAD:case TASKTYPE_FRUNLOAD:int msgtype = (tasktype = TASKTYPE_UNLOAD 3: 4);changetask(tasksequence, i, TASKTYPE_CALLSUBTASKS, current, NULL, msgtype, tonum(gettaskinvolved(taskseque

34、nce, i, 1), tonum(gettaskinvolved(tasksequence, i, 2), gettaskvariable(tasksequence, i, 1);break;default: break;子任务序列的实现过程,关键代码有注释/由changetask()传过来的参数msgtypeint msgtype = msgparam(1);switch(msgtype)/这里只实现了岸桥子任务序列case 1:case 2:fsnode* op = msgsendingobject;fsnode* item = tonode(msgparam(2);fsnode* qu

35、eue = up(item);/queue1fsnode* active_ts = gettasksequence(op, 0); /0表示当前活动的任务序列int port = gettaskvariable(active_ts, getcurtask(active_ts), 4);fsnode* sts = centerobject(queue, 2); /注意连接时候的端口号fsnode* ts = createcoordinatedtasksequence(op);/创立协同工作序列int op_key = insertallocatetask(ts, op, 0, 0); int s

36、ync_key1 = insertpro*ytask(ts, op_key, TASKTYPE_PICKOFFSET, item, queue, 0, 1, 0); int sts_key = insertallocatetask(ts, sts, tonum(queue), 0);insertpro*ytask(ts, sts_key, TASKTYPE_TRAVEL, queue, NULL, 0); int sync_key2 = insertpro*ytask(ts, sts_key, msgtype = 1 TASKTYPE_FRLOAD : TASKTYPE_LOAD, item,

37、 queue, port);insertsynctask(ts, sync_key1);insertsynctask(ts, sync_key2);int sync_key3 = insertpro*ytask(ts, sts_key, TASKTYPE_UNLOAD, item, op, port);insertsynctask(ts, sync_key3);insertdeallocatetask(ts, op_key);insertdeallocatetask(ts, sts_key);return tonum(ts);break;具体的代码实现局部有些复杂,但是我们通过前面的分析,将思

38、路整理清楚了,实现也就相对容易了。5.3 运动学Kinematics运动学局部是Fle*sim3.06版中新引入的功能。Fle*sim软件的一大特点就是三维显示功能非常强大,除了能够处理数据统计外,还能使模型的场景中的可运动设备动起来,从而使模拟过程更接近真实。例如,对于港口设备岸边集装箱岸桥,在系统建模中如果我们只关心数据、处理时间等的话,可以用Processor来简单代替岸桥的功能。在Fle*sim中可以将岸桥完全实现,不仅在外观上,更重要的是设备处理物件的动作。要实现设备的动作,平移水平运动,或垂直运动,或是旋转运动,这些都需要用到运动学的知识。本节主要介绍运动学相关知识,例如坐标空间转

39、换,运动实现,模型的导入,尺寸大小的设定等,还将详细讲述如何在Fle*sim中创立用户自己的专门对象库。5.3.1 FLe*sim中的坐标空间运动功能允许一个对象同时实现多个移动操作,在每个运动方向都有加速度、减速度、起始速度、完毕速度以及最大速度等属性。例如集装箱岸桥的运动就是由多个部件的运动组成,即大车沿着轨道运行,小车在大车上运行,吊具在垂直方向上运行。大车、小车和吊具都有其自己的速度属性。如果有了岸桥这样一个设备对象,在仿真过程中我们就可以实现岸桥的作业过程。运动学函数的引入就是帮助用户来实现自己定制的设备的动作。运动学这局部是从3.06版才开场引入的,新版本还会对这局部进一步改良。实

40、现运动学并不难,主要是对三个函数的使用。要执行运动操作,首先要调用initkinematics命令。该命令为运动初始化数据,保存对象的起始位置、起始角度。初始化完毕之后,调用addkinematic命令为对象添加平移或旋转动作。例如,用户告诉对象在5秒钟时开场运动,给定加速度、减速度和最大速度,在*方向上平移10个单位;然后告诉对象在7秒钟时,用不同的加速度、减速度和最大速度,在y方向上移动10个单位。这两个运动的结果是:对象先在*方向上运动,然后同时在y方向上加速,最后到达目的点的运动轨迹是抛物线。每一个单独的运动通过addkinematic命令添加;然后调用updatekinematics

41、命令在运动过程中不断地刷新视图,该命令的作用就是计算对象当前的位置和旋转角度。上面的例子很简单,为了更好的解释运动学,我们先介绍坐标空间的概念。Fle*sim中最常用的坐标空间就是模型空间model。用户建立系统模型时,将许多对象放入视图中,根据不同的逻辑关系组成不同的模型。这些对象都处于模型空间中。模型空间是Fle*sim中最大的坐标空间,系统模型中的所有对象都被包含在这个空间当中。还有一种容器坐标空间container。容器对象就是可以存储物件,举例来说,对象Queue的作用是暂存物件,此时Queue就相当于一个容器。当物件置于Queue中时,物件item就处于Queue的容器空间中。当一

42、个物体处于不同的容器空间中时,他的位置坐标就是他所在容器坐标空间坐标系的值。图1-5描述了容器空间的概念。32物件itemOOZ*Y*YZModel空间Queue空间-21图1-5在上图中,Queue置于Model坐标空间中,其位置坐标是2,3;物件item置于Queue的容器空间中,其位置坐标是1,-2。用户查看对象的属性页面可以得到对象的坐标值。这里需要提示一点的是,在Fle*sim中每个被选中的对象都有一个黄色的外界矩形框,对象的坐标是以如下图的位置点来确定的。当用户定制的对象需要做的动作比拟复杂的动作时,相对运动的坐标关系常常需要在不同的容器坐标系之间作相应的转换工作。Fle*sim也

43、提供了相应的坐标转换函数,在我们后面的内容中会有详细的讲述。模型的导入及模型尺寸的调整Fle*sim可以导入多种3D媒体文件。这些文件格式包含了3ds、wrl、d*f和stl,这些都是很常用的工业标准。用户可以使用第三方的软件,如3DMa*,MAYA来构造模型,然后将模型文件转化为标准格式,最后导入Fle*sim中。这里有一些注意点,Fle*sim只支持VRML1.0版的图形,不支持2.0版本;Fle*sim只能导入stl的ascii文件,不支持stl的二进制binary文件。在对象的属性对话框中,在3D shape一项中可以更改3D模型。我们这里用一个实例来介绍一个制作的过程,以及一些技巧。

44、制作一个集装箱吊具。我们在3DMa*中按比例做出吊具的三维模型,具体的制作过程不是我们讨论的内容。在完成之后我们还需要做一些后期的处理工作,使导出的文件在导入Fle*sim中有最正确的效果。实现过程很简单,过程如下:量取模型长宽高的比例值0.5:2.5:0.6;设置3DMa*软件的最小单元的尺寸为1;将已完成的模型缩小到尺寸大小为1的正方体中图1-6;最后将模型导出,保存为3ds文件格式。图1-6我们选取BasicTE作为吊具的模板。在Fle*sim中,BasicTE对象的默认外形是一个球体。翻开该对象的属性对话框,将3D shape选项中的媒体文件改为吊具模型的文件。导入之后的外观如图1-7

45、所示。在Position, Rotation, and Size选项中,将S*/SY/SZ三项的值改为我们之前记录的外界矩形框的长宽高比例,效果如图1-8。图1-7 图1-8从图中我们看到,不管模型的尺寸怎么改变,模型始终被包含在黄色的外界框中。这么做的目的不仅是为了外观上的好看,更重要的是为了后面的运动学计算时的方便。有时候模型导入Fle*sim后,模型和外界框之间有一些偏差。此时可以使用Edit 3D Shape Factors来修正,使模型完全处于黄色的外界框之中。除了改变模型的外观和尺寸,Fle*sim中还可以改变对象外观的贴图和颜色。还有一点就是用户还可以自己编写OpenGL代码来画

46、出对象的外观,具体实现在Custom Draw Code中实现。这局部的要求比拟高,用的不是很多。制作岸边集装箱起重机对象岸桥设备是集装箱码头装卸船作业的最主要设备,在港口中有着广泛的应用。我们用一个例子来总结一下本节所讲的内容,该例子对于其他对象的开发有很多的借鉴意义。岸桥设备对象在后面的系统建模及仿真中也得到了应用。BasicTE对象我们前面提到,Fle*sim为用户提供了BasicTE/BasicFR对象来开发自己的对象。岸桥设备的实现要涉及到运动学,所以我们选择BasicTE对象。BasicTE对象的引入就是为了实现对象的运动,我们主要的工作就要实现参数对话框中OnBeginOffse

47、t/OnUpdateOffset/OnFinishOffset函数。图1-9 BasicTE参数对话框这些函数的功能是:OnBeginOffset 计算出该对象在*/Y/Z方向上要运行的距离或要旋转的角度;OnUpdateOffset 在对象运动的过程不断地计算位置或旋转的角度;OnFinishOffset 运动完毕后调用该函数。部件的层级关系这里我们将岸桥分解为三个主要运动部件:大车运行构造、小车运行机构和吊具。三者之间的关系是:小车和吊具跟随大车运动;吊具跟随小车运动。也就是说大车和小车都相当于容器,小车置于大车容器中,吊具置于小车容器中。在Fle*sim中的实现如图1-10大车运行机构小

48、车运行机构吊具BasicTEBasicTEBasicTE图1-10 岸桥部件层次关系导入三维模型我们在3DMa*中制作三维模型,调整三个部件的比例关系,记录模型外接矩形框的窗宽高比例,然后将三个部件分别导出,保存为:STS.3ds/Trolley.3ds/Grabber.3ds。将三个模型导入到各自对应的BasicTE对象。调整尺寸之后得到的如图1-11所示的效果。图1-11 三维模型导入Fle*ism后的效果运动的实现我们先来看看BasicTE是怎样来完成一次搬运的作业过程的。图1-12表示的是BasicTE与物件容器容器1是提取物件的位置,容器2是物件放下的位置的相对位置。BasicTE先

49、运动到容器1;提取物件;在运动到容器2;放下物件。这就是一个完整的作业过程。我们关心的是BasicTE两次运动的行走路线,从图中我们可以清楚地看到有两种路线:1在*/Y方向上同时有运动速度,此时从起始点到目的点的运动路线是抛物线;2将*/Y方向上的运动分解,可以先完成*方向上的运行距离,再完成Y方向上的运行距离,或反过来。*Y*y*YBasicTE容器1容器2图1-12 两种运行路线确定了运行路线后,接下来需要知道的是BasicTE对象需要运动的距离。不管是抛物线的运行路线还是直线的运动路线,都可以将分解为起始点与目的点之间在*方向上的距离和Y方向的距离。BasicTE的参数对话框的OnBeg

50、inOffset选项中为我们提供了多个有用的参数值,这是系统自动计算的,用户只要明白这些参数的含义直接拿来使用即可。下面是对这些参数含义的解释:current:BasicTE对象本身;*:BasicTE在*方向上的偏移量;其值为BasicTE与物件中心坐标在*方向的差;y:BasicTE在y方向上的偏移量;其值为BasicTE与物件中心坐标在y方向的差;z:BasicTE在z方向上的偏移量;其值为BasicTE与物件中心坐标在z方向的差;item:BasicTE所搬运的物件;endspeed:BasicTE到达目的点的速度;ma*speed:BasicTE运动过程中所能到达的最大速度;acce

51、leration:BasicTE运动过程中的加速度;deceleration:BasicTE运动过程中的减速度;我们接着来看看我们做要完成的岸桥设备该怎样运动?可以肯定岸桥不会有抛物线的运动轨迹,假设岸桥的大车STS在model坐标空间中沿着y方向运动,则小车Trolley在大车的坐标空间中沿着*方向运动,吊具Grabber在z方向上运动。小车和吊具都处于大车的坐标空间中,当我们在大车中实现运动函数时,上面所提到的距离参数需要做一些转换。这里*/y/z距离参数都是大车的BasicTE对象相对物件的距离,这个距离值只有在model坐标空间中才有意义;大车处在model的坐标空间中,大车在y方向上

52、运动,所以y参数值可以直接使用。小车处于大车的坐标空间中,需要将*参数转化到同一坐标系下,这样小车才能准确地运动到物件的正上方。吊具运行的距离也同要需要将z值转换到同一坐标系下。图1-13是对上述文字的一些解释。*Dis_Trolleydelta*YY*y*STStrolleyitemModelnew*图1-13 岸桥各部件运动距离从图中我们可以清楚地看到大车的运行距离是y。小车的运行距离*Dis_Trolley需要经过一些计算才能得到。因为小车处于大车的坐标空间中,而*参数值是大车中心与物件中心的差,是model坐标空间中的值,所以我们先将*转换到大车的坐标空间中,Fle*sim为我们提供了

53、转换函数vectorprojer*()。物件在大车坐标空间的坐标值new*:new* = vectorproject*(model, *center(current)+*, 0, 0, current);从图中可以知道delta是在大车的坐标空间中:delta = *loc(trolley) + 0.5*size(trolley);小车最终的运行距离是:*Dis_Trolley = new* delta。同样的我们可以得到吊具的运行距离z。运行距离得到之后,接下来的工作是分析岸桥在完成一次装卸作业的运动周期。我们将完成一次装卸作业的运动定义如下:1吊具运动;2大车运行;3小车运行;4吊具运行。

54、仿真过程中岸桥设备按照这样的作业周期不停地作业,直到仿真完毕或者装卸完毕。在OnBeginOffset中具体实现如下:/初始化运动initkinematics(sts_kin, current);/全局坐标initkinematics(trolley_kin, trolley);initkinematics(grabber_kin, grabber);/添加运动double time1 = addkinematic(grabber_kin, 0, 0, z, time(), KINEMATIC_TRAVEL);double time2 = addkinematic(sts_kin, 0, y,

55、 0, time1, KINEMATIC_TRAVEL);double time3 = addkinematic(trolley_kin, *, 0, 0, time2, KINEMATIC_TRAVEL);double time4 = addkinematic(grabber_kin, 0, 0, z, time3, KINEMATIC_TRAVEL);return time4 time();在OnUpdateOffset中的实现比拟简单,只要不断地更新运动过程即可,主要实现如下:if(offsettingnow)updatekinematics(label(current, sts_kin), current

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论