FlexSim Knowledge Base
Announcements, articles, and guides to help you take your simulations to the next level.
Sort by:
I was recently asked how a user can implement jerk, i.e. a rate of acceleration change, in the AGV module. The AGV module uses FlexSim's kinematics API to define the motion of AGVs along paths. The kinematics API does not natively support jerk. However, the AGV module has included a hook to allow developers, and audacious end users :-), to customize the kinematics that drive AGVs on paths. Using this hook, you can approximate jerk by breaking what would otherwise be a single kinematic, with a single acceleration/deceleration, into multiple smaller kinematics that gradually change the acceleration/deceleration of the object as it progresses. There are two ways to do this. The first option is to simply do it as an end user, confining your changes to your model, by customizing nodes in the tree. The second option is to do it as a module developer, using the module SDK. Adding Jerk as a User The AGV network uses an "AGV Customization Delegate" to allow for hooks to be placed at certain points in the AGV navigation logic. There is a default customization delegate that the AGV network uses, but you can override the logic of this default delegate by adding and configuring a special node at MODEL:/AGVNetwork>variables/customizationDelegate. But before I tell you how to do it, I want to explain a little more about how it works. I've attached three C++ files. The main ones you'll want to look at are AGVCustomizationDelegate.h and AGVCustomizationDelegate.cpp. These show the definition of the customization delegate class. In the header file, you'll see the definition of AGVCustomizationDelegate class. This class includes several methods, but the main method relevant here is addKinematics(). This method takes several parameters defining the context. Its responsibility is to add one or more kinematics, in the positive X direction, that will move the AGV the target distance along a path. The AGVCustomizationDelegate class is the default customization delegate used by the AGV network. The C++ files also define a subclass called UserAGVCustomizationDelegate, which overrides the methods of its parent class by delegating the logic to FlexScript code that the user can write in the model. So, now for actually doing it in the model. We want to instantiate an instance of UserCustomizationDelegate at the node MODEL:/AGVNetwork>variables/customizationDelegate, so that we can write FlexScript code to add the kinematics. Navigate in the tree to MODEL:/AGVNetwork>variables/customizationDelegate Right click on that node, and choose Edit > Designate this Node (so) In a script window execute the script: nodeadddata(so(), DATATYPE_SIMPLE) Add a subnode to that node named sdt::attributetree and give it the text: AGV::UserAGVCustomizationDelegate. Copy the node and then paste it onto itself. This will instantiate the UserAGVCustomizationDelegate. Right-click on the addKinematics subnode and choose Build > Toggle Node as FlexScript. Right-click on the addKinematics node and choose Explore > As Code. This will allow you to edit the code for adding kinematics. The header for field should be as follows (note this is determined by the evaluate() command in AGVCustomizationDelegate.cpp at line 71). treenode kinematics = param(1); // the kinematics node to call addkinematic()/getkinematics() on treenode section = param(2); // the associated travel path section double startAtTravelDist = param(3); // the agv cumulative travel distance at this point double distance = param(4); // the distance to travel on the path section (your addkinematics() calls should add up to this distance) double startTime = param(5); // the start time for the first addkinematic() call double startSpeed = param(6); // the initial speed to start at double endSpeed = param(7); // the target end speed (should be going this speed at the end) int reason = param(8); // reason for adding the kinematic (see AGVCustomizationDelegate.h) treenode endSpeedOut = param(9); // if target end speed cannot be reached, update this node's value with the actual end speed double peakSpeed = param(10); double acc = param(11); double dec = param(12); TaskExecuter agv = ownerobject(tonode(get(kinematics.up))); // the agv At this point you can customize how kinematics are added to the kinematics node in this code. To approximate jerk you would break it up into small addkinematic() commands that each change the acceleration/deceleration. Please refer to the kinematics api for more information on how to manipulate kinematics. Note that you should only use the addkinematic() and getkinematics() commands in this field (not initkinematics() or updatekinematics()), and the addkinematic() command should only tell the AGV to move forward in the X direction. Y and Z directions are ignored by the AGV travel logic. In other words, from a kinematics perspective, the AGV network "flattens" an AGV's path into movement in a straight line along the x axis. When you're finished adding kinematics, you should return the end time of the last added kinematic. This will be the same as the return value of the last called addkinematic() command. Adding Jerk as a Module Developer To implement jerk as a module developer, you would first create a module using the module SDK. Then you would include AGVClasses.h and AGVCustomizationDelegate.h in your project (do not include AGVCustomizationDelegate.cpp as it won't compile properly. I'm including that file just to be informative in this article). Then you would subclass AGVCustomizationDelegate with your own class that overrides the appropriate methods, specifically the addKinematics() method. Once you've done that, you would replace MODEL:/AGVNetwork>variables/customizationDelegate with an instance of your customized class, using the same steps described above, but using your own class name instead of AGV::UserAGVCustomizationDelegate. If you need more header files so you can access more information, i.e. the definition of TravelPathSection, the let us know and we can get them to you. agvheaderfiles.zip
View full article
A number of questions on the forum involve racks being service by a combination of shuttles and elevators. There are solutions involving network, Astar and AGV navigators, but for this example we’re just going to use TaskExecuter FlowItems and conveyors. The elevator system in particular, as described to me, seemed it would benefit from the flexibility conveyors offer – particularly spacing options, and the possibility of having dog/power-and-free based travel. For the pick face we can just use the slot and item locations to give the task executers travel command, and we can use kinematics for loading and unloading tasks. This removes the need for network nodes or control points at each location and allows fine positioning of a ‘two spot’ shuttle in front of the slot. The system has been put into a container to represent the cell/aisle and it is this object that is the instance member of the ShuttleSystemProcess process flow. The cell is designed to be duplicated with each cell becoming a new member instance of the single process flow. It comprises two racks, two elevators (conveyor loops), and a shuttle return queue (also a conveyor but with no roller visual). The system assumes that by the time an inbound item arrives at the pickup position it has been assigned a slot in one of the racks in the cell – so you should assign a slot in the normal way before it reaches a shuttle. You can additionally request items for picking out of the racks by pushing the item to the global list ItemsToPick. Currently each shuttle will store and/or pick one item in one trip with a dedicated position for each. When doing both in a single trip, the order in which this happens will depend where along the level the slots are located. In the event that there are no remaining tasks but items still need to exit the cell, the shuttles at the front of the queue will be asked to circulate empty through the system, thereby allowing the outbound items to advance to the exit position. The number of shuttles in the system is a process flow variable. In the example system there are elevators at each end of the rack(s) with a number of carriers to transport shuttles to the levels. Both elevators have a process flow variable for the number of carriers to be generated. Shuttles are not allowed to pick from the same level at the same time but in order to keep the up-elevator moving the carriers can unload the shuttle to the level even if another is active on that level. The shuttles only travel along the face of the rack in one direction towards the down-elevator and once are collected by a carrier the next shuttle on that level can start its operations. It is possible to run the system with only one rack should you wish to view the operations without the second rack obscuring your view. Since different applications will use different rack dimensions the cell has a label method called “configureToRack” which will align the conveyors and decision points to Rack1 based on the level heights and size of the racks that the user has set for Rack1. There may be some limits to very small sizes when the conveyor decision points overlap. The second rack will be configured during this method call to mirror Rack1. Here’s an example invocation of this method for an instance of the cell: Model.find("RackShuttleSystem").as(Object).configureToRack The shuttles need levels to be the same height along the length of the rack. Some effort was made to configure the system based on the shuttle and carrier sizes, so you can try adjusting those to suit your needs and hopefully the alignment will work as needed. The elevator conveyor and shuttle speeds are not set by the alignment method so you can edit those in the usual way. This is an example for both learning and perhaps as a starting point for any project should you find the approach suits your application, modelling style and skills. ShuttleLiftAndRack.fsm Time taken: 1 day to build the working model - plus another to work around holes api for auto-alignment code. 17Nov Updated: to initalize shuttles at the load point (via fast entry) added shuttleQheight label for use to set the returnQ height in the cell (used by the alignment method) added a process flow variable 'shuttleLoadTime' for the time to un/load items. aligned shuttle kinematics to the speed and acceleration of the TE FlowItem.
View full article
FlexSim 2022 Beta is now available. (Updated November 23) To get the beta, log in to your account at https://account.flexsim.com, then go to the Downloads section, and click on More Versions. It will be at the top of the list. The More Versions button does not appear when logged in as a guest account. Subsequently the beta is available only to licensed accounts and accounts that have a license shared with them. Learn more about downloading the best version of FlexSim for your license here. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. FlexSim 22.0.0 Release Notes Added several new features to the Experimenter including: Experimenter can define and run multiple different jobs. Experimenter results are stored in a database file. Additional replications of a scenario can be run without needing to rerun previous replications. Improved visuals for status of replications. Added a Reinforcement Learning tool. Added Label charts. Added Tracked Variable charts. Standardized charts created by Pin buttons. Added sort options to table views. Updated MTBF/MTTR time fields to show unit conversion options. Added InObjectsInternal and OutObjectsInternal properties to the Visual Tool class. Backwards Compatibility Note: The following changes may slightly change the way updated models behave. Deprecated the optquest() command. It no longer executes any logic when called. The associated OPT_* macros have been removed. FlexSim now interacts with OptQuest through the Optimization Job object. Changed the default query handlers that deal with the Experimenter in MAIN:/project/exec/globals/serverinterface/queryhandlers. Custom applications that create web queries may need to be updated. Process Flow Added Process Flow Activity Statistics charts.
View full article
Attached is a simple model that implements functionality for "pallet moles." These are small vehicles that move pallets forward in a racking system. The targeted behavior is a FIFO storage mechanism like what you would see in gravity flow racks. However, for incredibly deep storage, a gravity flow mechanism would result in unacceptable pressures exerted on the pallets at the front of the rack, especially when pallets collide with each other as they roll down the slot. These pallet moles solve these issues. They provide the forward movement that enables FIFO storage, without the unacceptable pressures that come with gravity flow. The functionality is implemented as two object process flows, one for the rack, and one for the pallet mole. As such, it is scalable to higher numbers of racks and moles. Just add the set of racks/moles that your model uses, and then make sure those objects are attached as instances of their respective object process flow. Moles can be moved between different slots in the racking system. If a mole needs to move to a different slot, it will request transport from a team of fork lifts. The fork lift picks the mole up from the slot, and moves it to the destination slot. RackMole.fsm
View full article
FlexSim Answers is designed to make information available to the FlexSim community. However, there are times when you will need help with a model or project that contains proprietary or otherwise confidential information. Here are a couple ways of getting the help you need while protecting sensitive information. Private Questions When you create a question you can mark it as Private. The question is then only viewable to FlexSim employees. A lock icon will show up next to the question for those who can see the question Comment Visibility (Currently this option is only available to moderators, but moderators may use it to make comments visible only to you and other FlexSim employees) You can also post private comments by setting the visibility level of your comment. Setting the visibility of the comment to Viewable by Moderators will make the comment visible only to FlexSim employees. Posting private comments is useful for posting confidential information to questions that aren't private.
View full article
I'm attaching a user library and an example model that contains process flows for two types of merge controller. The main advantage of both of these is that the release strategy is consolidated into a single list pull query, so that you can have incredible flexibility in defining custom release strategies just by adjusting a single query. Several query examples are included and explained. The DPClearingMergeController uses the standard merge controller mechanism that utilizes decision points and the merge controller's lane clear table to determine when slug lanes are clear for release. Alternatively, the FixedGapMergeController customizes lane release times for an optimal target gap between released slugs. This, combined with a good release strategy, can maximize total merge throughput. Here's a view of the fixed gap merge control running. Notice how it tries to time the releases so the slugs line up pretty close on the take away lane (the target gap here is 3 feet). And below is a screenshot of the fixed gap merge control process flow. mergecontrollerprocessflows.zip This model and library were created in 16.1.0.
View full article
FlexSim 2017 Update 1 Beta is available. (updated 5 Apr 2017) To get the beta, log in to your account at www.flexsim.com, then go to the Downloads section, and click on More Versions. It will be at the top of the list. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Release Notes Changed FlexSim to store strings using UTF-8 encoding. Added support for Oculus Touch controllers. Implemented OpenVR for HTC Vive compatibility. Improved the shadow frustum calculation in VR so that shadows look better. Added a global preference for changing the resolution of the shadow map. Added support for nested queries in SQL. Added ROW_NUMBER as a SQL keyword. Implemented F2 and Esc functionality in tables. Updated the table view and labels tab to be more robust with different datatypes. Added Table(name) method for referencing Global Tables. Added more FlexScript classes, including List, AGV, Conveyor, and TrackedVariable. Added more properties and methods to existing FlexScript classes, including Object stats and additional string methods. Improved scientific notation for literals in FlexScript. Added a start value to tracked variables. All tracked variables in the model now reset on model reset. Changed itemtype references to referencing an item's type label instead. Improved the Person flowitem's 3D shape. Added repeating events to time tables. Added a short description field to user commands. Made the gantt charts and time charts scroll with a fixed time window. Removed the global table Clear on Reset checkbox and replaced it with a reset trigger. Added new visualization options for the Rack. Added duplicate buttons to the Excel Interface window. Added a duplicate option to the Toolbox's context menu. Taskbar now shows experimenter/optimizer status and runtime based upon stop time. Disabled deleting objects while the model is running. Fixed an issue with the undo history when pasting over nodes with pointer data. Fixed issues with using the ternary operator after properties. Fixed an issue with writing to Access databases with read-only fields. Included fixes listed in 17.0.3. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. Removed the FlexSim WebServer application from the default installation and developed a new WebServer application using Node.js that streams the 3D view much faster. The new WebServer can be downloaded through FlexSim's Online Content. Existing models will continue to work with itemtype, but new models should be built using a type label instead of the itemtype attribute and commands. Process Flow Added an Assign Released Resource(s) To field on the Release Resource activity. Added functionality to allow you to Ctrl+Drag activities in an activity block. Added a right-click menu option and Alt+Click to open the Token View. Added a sampler to the assign labels Label Name field so you can sample other activities or tokens to get label names. Added a right-click menu option to open multiple views of a Process Flow. Added an Assign To property to the Create Tokens activity. Added a Make Array label aggregation type to the Batch. Added Center in View buttons for fields with pointer data. Added a name property to the Token FlexScript class. Fixed a bug with duplicating Process Flows using the Toolbox. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. Updated the Pull From List activity so it does not assign a null label when nothing was pulled or the token was released early (manually). Previously, if you used a Max Wait Timer or Max Idle Timer (or some other mechanism) to release a token from a Pull from List prematurely, the label specified in the Assign To field would be created with a value of NULL. Now, the label will not be created. This may break other models that are checking to see if the label value exists. For example, saying objectexists(token.pulled) will throw an exception if the pulled label is never created. This can be easily remedied by changing the code to objectexists(token.pulled?). The ? will cause the value returned to be nullvar when the pulled label does not exist. Universal Edit fields are now more strict when accessing labels on a token. Previously, typing token.labelThatDoesNotExist would happily return NULL and move on. Now the Universal Edit will throw an exception if the label doesn't exist. This does not include Universal Edit fields that assert labels, for example the Assign To fields.
View full article
[ FlexSim 16.1.0 ] Attached is an example model that uses both of the new template process flows for AGV and AGV elevator control, available in FlexSim 2016 Update 1. Thanks @Katharina Albert (I believe), who provided the seed model, which I adjusted/extended as I implemented these process flows. This model enumerates many of the control point connections and path configurations you might use in an AGV model when using these template process flows.
View full article
FlexSim 2019 is available. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Release Notes Added support for importing JT files. Added a way to directly animate 3D shapes with bones. Added a way to parent subcomponents to a bone on a 3D shape. Updated calculated tables and chart templates to be able to save their data during an experiment. Added support for SQL keywords UNION, UNION ALL, INTERSECT, and EXCEPT. Updated the time table's weekly and daily modes to use a graphical display. Improved the time table's user interface. Added options for stacking bars on a histogram and added more bar modes. Added a Column Sets feature to statistics collectors. Added more options for event listening in statistics collectors. Added an option to statistics collectors and calculated tables for object path display depth. Added an option to statistics collectors to stop tracking row values after specified events. Added an option to milestone collectors to start new entries on the next milestone. Added options to record more data in additional columns on a milestone collector. Added enable/disable right-click menu options to statistics collectors in the toolbox. Improved the performance of calculated tables in certain configurations. Fixed a bug with Always Leave Entries on List when reevaluating multiple back orders. Fixed a bug with color spilling from one mesh to another when using shape data overrides. Fixed scaling issues and a crashing bug when loading certain STEP and IGES files. Process Flow Improved the Token.create() method to be able to create child tokens. Added a new Person Flow type of Process Flow. Fixed a bug with a resource connected to a global list deleting the list when the resource was in an instanced flow. People Added a Process activity. Added a Remove Person activity. Added various activity sets to quickly create common groups of activities. Added a priority value to resource objects that is used for acquiring and preempting resources. Added advanced options to the Process activity for handling preemption. Added functionality for simulating shift schedules with time tables and down behaviors. Improved the UI for how people objects are added to groups. AGV Improved control point selection on paths in the 3D view. A* Added a way to draw a heat map based on a node's percentage of total traversals. Added a Two Way option to preferred paths and dividers. Added a Condition option to A* objects to optionally disable them under certain circumstances. Added a Mandatory Path object used for defining sets of paths where certain connected objects can travel. Updated the Barrier object to be able to specify patterns to determine how it affects the grid. Added a FlexScript API for A* objects and data. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. Fixed a bug with A* barriers blocking space larger than their actual size.
View full article
One of the most powerful features of Process Flow is the ability to easily define a Task Sequence. However, many real-life situations require the coordination of multiple workers and machines to do a single task. This article demonstrates one approach you can use with Process Flow to coordinate multiple Task Executers, or in other words, to create a coordinated task sequence. This article talks about an example model (handoff.fsm). It might be easiest to open that model, watch it run, and perhaps read this article with the model open. The Example Scenario Here is a screenshot of the demo model used in this article: Items enter the system on the left. The yellow operator must carry each item to the queue in the middle, and then wait for the purple operator to arrive. Once the two operators are both at the middle queue, then the yellow operator can unload the box, and the purple operator can take it. After this point, the yellow operator is free to load another item from the left queue. The purple operator takes the item, waits for a while, and then puts the item in the sink on the right. The interesting part of this model is the hand off. The yellow operator must wait for the purple operator, and vice versa. This is the synchronization point, and it requires coordination of both operators. The approach used in this model allows you to add more operators to the yellow side, and more to the purple side. But it still maintains that a yellow operator must wait for a purple operator before unloading the box. The Example Model In addition to to the 3D layout shown previously, there are 5 process flows in the example model. The first is a general flow, and defines the logic for each task. The second is a Task Executor flow, and defines the logic for the yellow operator. The third is also a Task Executor flow, and defines the logic for the purple operator. The remaining two flows are synchronization flows, for synchronizing between the other three flows. Synchronizing on a Task The basic approach in this model uses the Synchronize activity. This activity waits for one token from each incoming connector, before it allows any of the tokens to move on. Here is the Yellow Purple Sync flow (a global Sub Flow) from the example model: The flows for the yellow and purple operators each use the Run Sub Flow activity to send a token to this flow, to their respective start activities (you can use the sampler on the Run Sub Flow activity to sample a specific start activity in a sub flow). This is what allows both the yellow and purple operators to wait for each other. However, it is important that the yellow and purple operators are both doing the same task. In this model, there is a token that represents each item that needs to be moved. Both operators get a reference to this task token. The Synchronize activity is set up to partition by that Task token. That means that a yellow and purple operators must both call this sub flow with the same task token, ensuring that each task has its own synchronization. In the example model, this kind of synchronization happens between operators, and it happens between each task and an operator. Basically, the task must wait for the operator to finish that operator's part. The Task Flow A task token is created every time an item enters the first queue. The tasks flow puts that task on both the Yellow and Purple lists. In both cases, the task token does not wait to be pulled, but keeps itself on the list. Then, the task token waits for a yellow operator to finish with it, and then for the purple operator to finish with it. There is a zone in this flow, but its only purpose it to gather statistics for how long the whole task took. The Yellow and Purple Flows These flows are easiest to understand when viewed side by side: Recall that each task is put on both the Yellow and Purple lists at the exact same model time. The yellow operator waits to get a task (at the Get Task activity). Then the operator travels to the first queue, gets the item, and travels to the second queue. At this point, the yellow operator waits. At the same time, the purple operator is also waiting for the task. The purple operator just has to travel to the second queue before waiting for the yellow. Once the yellow operator arrives, the purple operator also has to wait for the yellow operator to unload the box. On the yellow side, once the purple operator arrives, the yellow operator unloads the box, and then synchronizes with the purple operator, allowing the purple operator to load the box. Summary The purpose of this article is to show one method for synchronizing token in separate flows. That method is as follows: Have a token for each task. As each task executor (or fixed resource) needs to synchronize, they each use a Run Sub Flow activity, putting the token in a specific Start activity. The Sub Flow (a global Sub Flow) has a synchronize activity, that requires a token from each participant for that task before releasing the tokens. This is certainly not the only way to create this model. However, there are some advantages: By forcing the task to synchronize, you can gather stats on how long each phase of the task took, as well as how long the complete task took. You can add more yellow or purple operators by copy/paste. They simply follow their own logic Each set of logic is separated; tasks, yellow operators, and purple operators each have their own flows, making each one much simpler. The exact approach used in the example model will not work exactly as it is for each model. However, you can apply the general principles, and adapt them to your own situation.
View full article
FlexSim 2018 is available. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Release Notes Added a new People module. (Try out the Sample Models.) Added new dashboard chart templates to quickly collect and display statistics. Legacy charts are hidden by default in the Library and can be enabled through Global Preferences. Removed the basic Person flowitem and renamed the TaskExecuterFlowItem to Person. Added functionality to the List's pull method to allow you to pull an object/node directly (without writing SQL). Updated ODA to be compatible with DWG 2018 shapes. Updated Assimp to be compatible with the latest FBX file format. Added a RegExResult class for iterating over the matches in a regular expression. Lists can now use arrays as partition ids. Added a mechanism for automatically setting the reset position of objects after moving them by setting their resetposition variable to 1. Added a By Lazy Interval update mode to the calculated table. Improved calculated table performance by reducing the amount of table updates. Improved statistics collector performance by reducing the number of updates to Always columns. Table views can now be set as read-only using the grayed attribute. Added an Ignore Warmup option to statistics collectors. Updated OptQuest so that it can run more than 10,000 solutions. Added a pick option for restoring default values in the Global Table's On Reset trigger. The Query test field is now a multi-line text box. The Source now adds labels to items before calling the OnCreation trigger. Updated the table selection for the Excel Import/Export. Improved color options in various dashboard charts. Changed the model update dialog to be able to autosave the model with an incremented number. Added many new animations for the operator and the person flowitem. Updated many stochastic pick options to use getstream() as the default stream parameter. Updated the TaskExecuter to connect to the DefaultNavigator when created. Improved the Group UI. Updated the Library view to not change when clicking on the User Manual view. Changed the Tree view's Explore > As Code so that it closes the tree's edit view. Fixed a bug with list initial contents having old values in label fields. Fixed a bug with the statistics collector chart interface checkboxes. Fixed an OnDropWindow exception. Fixed some exceptions in the Table View when viewing an Array that no longer exists. Process Flow Added a Date Time Source activity. Added a Wait for Simultaneous Arrivals Before Entry option to the Zone. Added autocomplete for instanced flow labels (current). Added a zoneistokeninsubset() command. Conveyor Added a Round Robin destination option to the Send Item pick option. AStar Added a visual option to show the travel threshold for objects. Improved the draw performance and fixed the timing of some graphical updates. AGV Fixed a bug with redirecting AGVs at times other than On Pre-Arrival of way points.
View full article
Nesse exemplo nós vamos construir um modelo que usa listas para relações básicas de roteamento de itens. Os itens serão enviados de três filas para um dos quatro processos. Nós vamos usar uma Lista de itens (item list). As filas irão empurrar os itens para a lista e os processos irão puxar os itens da lista e processa-los. Inicialmente, vamos implementar um simples puxado, mas depois iremos experimentar o puxado com restrições e priorizações. Passo 1. Montar Layout Para esse exemplo, criaremos um novo layout. A Figura 1 mostra quais objetos devem estar presentes nesse layout. Observe que NÃO há ligação entre as filas e os processos. Figura 1- Layout exemplo 2 Passo 2. Configurar source Na janela de propriedades do source, em inter-Arrivaltime coloque exponential (0 ,2.5,0). Figura 2- Inserir inter- arrival time 2.Na aba FLOW, em send to port abra a lista de opções e escolha a opção random port. Figura 3- Sent to port 3.Na aba trigger, adicionar uma Oncreation trigger para configurar o tipo e a cor. OnCreation> Data > Set item type and color Figura 4- Configurar tipo e cor Passo 3. Adicionar lists Para adicionar a lógica é preciso criar um item list. Em Toolbox> > Global list> Item list(Figura 5). Figura 5- Adicionar item list Ao clicar em Item list irá abrir janela de propriedades da lista (Figura 6), por agora apenas feche a aba. A sua lista está nomeada como ItemList1. Figura 6- Janela de propriedades Itemlist Não é necessário definir nenhuma das configurações agora. Apenas feche a janela de propriedades. Passo 4. Configurar queue Para configurar a queue para empurrar os itens para a lista, clique sobre cada uma das filas> Aba Flow> Send to port> abra a lista de opções> Escolha use list> Push to item list. CONFIRA se o o nome da lista corresponde ao nome da lista que você criou. Figura 7- Push to item list OBS: Fazer o Passo 4 para (((TODAS))) as filas Passo 5. Configurar Processos Para fazer com que os processos puxem da lista, nós precisamos configurar cada input de processos para todos os 4 processos. Clique em um dos processos, na aba Flow vá na parte de input, marque a opção pull strategy. Na aba de escolha da estratégia >Use list>Pull from item list. Você pode deixar o campo QUERY em branco. E confira se o nome da lista escolhida é o mesmo da lista que você criou no Passo 3. Figura 8- Estratégia puxada Obs: Não esqueça de fazer o passo 5 para todos os processors. Salve seu modelo como Exemplo 2 e ele está pronto para ser executado. Mas antes de fazer isso vamos dar uma olhada no que está na lista. Para verificar se até aqui as coisas estão funcionando da maneira correta. Vamos fazer um test rápido. Nas propriedades do ItemList1, vá na aba General e clique no botão a esquerda “ Back Orders”, sua lista deve estar parecida com a da Figura 9. Mudando apenas os nomes dos processos de acordo como os seus estão nomeados. Figura 9- Janela de pedidos pendentes A Figura 9 representa que os processos começaram a puxar da lista, mas como não há itens que foram empurrados para a lista, eles estão aguardando para poderem puxar e se tornarem fulfilled(preenchidos). Execute o modelo e você perceberá os itens vão entrar nas filas e serão empurrados para a lista (View entries) fazendo com que os pedidos pendentes sejam atendidos e então começam a ser processados. Quando um item é empurrado para a lista e existe pedidos pendentes o item será imediatamente puxado da lista. Dessa forma o pedido pendente irá se tornar Fulfilled e será removido da lista de pedidos pendentes. Eventualmente, todos os processos irão puxar os itens e dessa forma a lista de pedidos pendentes se tornará vazia, já que todos estão em operação. Então a lista de entradas vai crescendo(Figura 10) até que um dos processos termine o processamento e requisite puxar um item da lista. Figura 10- Entradas na lista aguardando serem puxadas Quando os itens são empurrados para a lista, eles são adicionados no fim da lista. Assim se o sistema puxado não utilizar prioridades como parte da sua tomada de decisão, os itens irão ser puxados como FIFO( first-in-first-out), ou seja, seguindo uma ordem de quem chegou primeiro sai primeiro. O mesmo acontece com os pedidos pendentes pendentes. A primeira máquina que ficar disponível irá puxar o primeiro item que entrar na lista. exemplo2.fsm Experimentos Agora vamos experimentar diferentes configurações das operações puxadas. Cenário 1- Filtrar por tipo de item Vamos considerar que um dos processos pode apenas processar o tipo de item 2. Nós podemos vincular essa lógica na simulação utilizando uma simples Query nesse processo. Clique sobre o processo que deseja restringir a entrada ao tipo 2 de item, na janela de propriedades, vá em FLOW > >Pull strategy >em Query digite a restrição WHERE itemtype == 2 (Figura 11). Figura 11- Adicionar query para tipo de item Salve o modelo como Exemplo2_cenario1. Reset seu modelo e execute. exemplo2-cenario1.fsm Cenário 2- Puxar pelo LIFO Vamos supor que agora queremos que todos os processos puxem seguindo a ordem último a chegar primeiro a sair (LIFO) ao invés do padrão FIFO, o que significa que o item mais recentemente adicionado na lista deve ser o primento a ser puxado da lista. Nós podemos criar essa lógica na simulação, implementando uma simples puxada Query. Abra o arquivo do exemplo 2, e salve como exemplo2_cenario2. Para cada um dos 4 processos faça o seguinte: 1)Clique no processo >vá em FLOW > Pull strategy > em Query digite a restrição ORDER BY age ASC (Figura 12). Figura 12- Lógica LIFO Repita 1) para TODOS os processos. Salve o modelo e coloque para executar. exemplo2-cenario2.fsm Use a ferramenta avançada view entry Nessa ferramenta você pode verificar se o seu modelo está rodando de acordo com a lógica planejada. Por exemplo, se você quiser testar o seu query de order by age asc para você ter certeza de o que você quer antes de implementar no modelo. Você pode usar a ferramenta avançada para fazer isso. Execute o modelo até que tenha um número significativo de itens na lista. Nas propriedades do ItemList1, vá na aba General e clique no botão a esquerda “ View entries”. Pressione botão para mostra as ferramentas avançadas (Figura 13). Figura 13- Ferramentas avançadas view entry Agora teste colocar a Query por ORDER BY age ASC e pressione enter (Figura 14). Figura 14- Itens ordenados por tempo Na Figura 14 você pode notar que os itens na lista estão agora reorganizados com as idades ascendentes. A ordem puxada que usa a query order by age asc, vai puxar do topo dessa lista. No caso o primeiro a ser puxado seria o Queue5/Box~3 com itemtype de 3 e age de 0. 18, o último a entrar na fila.
View full article
FloWorks 24.2.0 is now available (6 August). This version of FloWorks is intended for use with FlexSim 2024 Update 2. If you are using FloWorks with FlexSim 2024 (LTS), please update to FloWorks version 24.0.5 (LTS). If you are using FloWorks with FlexSim 2024 Update 1, please update to FloWorks version 24.1.1. All versions can be found in the Downloads section of your FlexSim account on the 3rd party modules tab. Please do not hesitate to report any bugs, usability improvements and feature requests to support@talumis.com. About FloWorks FloWorks is a 3rd party module developed and maintained by Talumis BV (talumis.com). It provides faster and more accurate modelling and calculation of fluid systems than the default FlexSim fluid library. It is especially useful within the oil, gas, and bulk industry both for production and supply chain optimization. This module requires a FloWorks license with active maintenance. For any questions, please email support@talumis.com. Release notes View the full release notes in the online documentation. FloWorks 24.2.0 (6 August 2024) Bug fix: removed flicker due to unnecessary repaint in ApplyImpactFactor QuickProperties panel. All bug fixes in FloWorks 24.0.4 below. FloWorks 24.1.1 (6 August 2024) Bug fix: removed flicker due to unnecessary repaint in ApplyImpactFactor QuickProperties panel. All bug fixes in FloWorks 24.0.4 below. FloWorks 24.1.0 (17 April 2024) Feature: new "Apply Impact Factor" activity in ProcessFlow. Feature: new "Connect Flow Objects" and "Disconnect Flow Objects" activities in ProcessFlow. All bug fixes in FloWorks 24.0.3 below. FloWorks 24.0.5 (27 August 2024) Bug fix: Version 24.0.4 installer contained an incorrect module (.t) file Bug fix: Removed ProcessFlow activities which are only available from 24.1 from the drag/drop library FloWorks 24.0.4 (6 August 2024) Bug fix: FlowToItem was not behaving correctly when an item buffer was used. Bug fix: Fixed a timing issue when FlowToItem got starved while an item was being released. Bug fix: Fixed some rounding issues in event scheduling. Bug fix: Fixed Quick Properties product combo when product has been deleted. Bug fix: Missing states 19 and 20 added to state profile. Bug fix: Fixed several issues in FlowConveyor visualization. Bug fix: Invalid curved FlowConveyor animation fixed. Bug fix: Invalid initial content for Segmented Pipe fixed. Bug fix: "FlowConveyor content changes are not allowed" error (and subsequent exception) fixed. Improvment: Curved conveyor now also supports FlowConveyor length property. Improvement: Tank label hidden in FlowItems (FlowVessel and FlowTruck). Improvement: Cleaned up the variables in the FlowItems' model tree. Improvement: Tank size/position and max content changed for FlowTruck, also as FlowTaskExecuter. Improvement: Slight optimization in preventing unnecessary FlowControl events. Improvement: Added SetMaxContent for FlowToItem and improved handling for Flow Tanks. FloWorks 24.0.3 (17 April 2024) QuickProperties behavior improved. Fixed invalid manual references. Fixed missing code completion documentation. FloWorks 24.0.2 (6 March 2024) Made activity path references in warning message more clear. Restore missing Flow Trigger Process Flow activities to the library. Fixed Tank level indicator settings for some tank shapes. Add Accumulating checkbox to the Conveyor properties. FloWorks 24.0.1 (5 February 2024) Added vertical splitter to Mixer recipe editor and other small layout improvements. Fixed missing icons in statistics panel pin menus. Flow Polygon Tank property panels fixed and documentation updated. Added "Fill Sideways" property for Flow Polygon Tank. IsMultiProduct setting on Flow Tank is now a proper property. Renamed Flow Tank shapes from Cylindric and Rectangular to Tank and Container, respectively. Fixed "Copy Production Plan" button in Flow To Item properties. Some objects were not correctly reset. ItemToFlow statistics were accessible through .output instead of .input . Breaking changes: Deprecated the input.triggerAmount , input.triggerInterval , output.triggerAmount , and output.triggerInterval properties. FlowObject.stats.input and FlowObject.stats.output now return a Tracked Variable. Cylindric level indicator now expects size of bounding box instead of center and radius. The update script will try to convert these for you. FloWorks 24.0.0 (14 January 2024) All bug fixes in FloWorks 23.0.5 below. Improved warning and error messages throughout Fixed rounding issue in Mass Flow Conveyor
View full article
Attached is an example model that shows how you can use reversible conveyors for routing/sorting of items. ReversibleRoutingConveyor.fsm Traditionally we've sort of warned against using reversible conveyors for purposes other than accumulation buffers. The main reason I've been hesitant to promote alternative uses is that the routing system for conveyors is, and will continue to be, static. In other words, the path finding algorithm to send an item through a network of conveyors to a destination point does not change when one or more conveyors in the system is reversed. Put another way, "for routing purposes, ..., the conveyor is always assumed to be conveying in its original direction." This naturally makes using reversible conveyors for routing more complex. However, as long as you can still work within those constraints, you can actually get the desired outcome. The attached model does this by 'shortening' the routing decision so that it can always route onto conveyors in their forward direction. The attached model sorts items by color by moving them between two conveyor via a reversible conveyor that conveys in either direction as needed. In order to still work within the 'static routing' rule, I split the reversible conveyor into two separate conveyors that are directed into each other. This way, I can route items onto the reversible section by referencing a conveyor whose primary forward direction always diverts from the line a given item is on. The critical element is that I have to always make sure that when one conveyor is moving forward, the other is reversed, and vice versa. I also have to implement some mutual exclusion, blocking some items so they aren't sent to conveyors in opposite directions. This all is done in the process flow. I honestly don't know how close this example is to a real life situation. We've just received some requests for a reversible conveyor that can do more than just accumulation buffers, and routing/sorting is the main alternate example I can think of. This is one way you can achieve such a result.
View full article
This article explores an example model. In this model, items on downstream lanes are able to reserve dogs so that items on upstream lanes cannot use them: reservedogdemo.fsm About Dogs in FlexSim FlexSim simulates dogs on a power-and-free system in an extremely abstract and minimal way. A dog isn't a persistent entity at all. Instead, FlexSim calculates where dogs would be, given the speed, and when they would interact with items. This has a huge performance benefit. But if your logic needs items to interact with specific dogs, this can pose a problem: how do you interact with such an abstract entity? The Catch Condition The only time you can "see" a dog in FlexSim is during the Conveyor's Catch Condition: https://docs.flexsim.com/en/23.1/Reference/PropertiesPanels/ConveyorPanels/ConveyorBehavior/ConveyorBehavior.html#powerAndFree The catch condition fires when a dog passes by an item. If the catch condition returns a 1, the item catches the dog and transfers to the power and free conveyor. If the catch condition returns a 0, the item does not catch the dog. During the catch condition (and only during a catch condition), you can learn many things about a dog: ID - each dog has an ID. The ID is derived from the length of the conveyor and by the distance the conveyor has travelled. If a conveyor is 26 dogs long, the dogs will have IDs 1 through 26. Location - Since an item is trying to catch the given dog, you can derive the dog's location from the items location. Speed - The conveyor that owns the dog is "current" in the catch condition. So you can get the speed of the conveyor at that point. We'll use all these pieces of information in a moment. Creating Tokens to Represent Dogs The first real insight into this model is to make a dummy item. The purpose of this dummy item is to cause the Catch Condition to fire. It never gets on the conveyor. But when the catch condition fires, it makes a token that represents the dog. In this example, that item has a label called "DogFinder" Here is the relevant code from the catch condition: if (item.DogFinder?) { Object pe = current.DogPE; if (pe.stats.state(1).value == PE_STATE_BLOCKED) { return 0; } double dist = current.MaxDogDist; double speed = current.targetSpeed; double duration = dist / speed; if (!item.labels["DistAlong"]) { item.DistAlong = Vec3(item.getLocation(1, 0, 0).x, 0, 0).project(item.up, current).x; } Token token = Token.create(0, current.DogHandler); token.DistAlong = item.DistAlong; token.Conveyor = current.as(treenode); token.Duration = duration; token.DogNum = dogNum; token.Speed = speed; token.DetectTime = Model.time; token.release(1); return 0; } There's a lot going on in this code: This logic only fires for the fake dog finder item If the photo eye just upstream from the dog is blocked, that means there is an item, and this dog is not available. Return here if that's the case. Figure out how long this dog will last (the duration), assuming the conveyor runs at the same speed. In this model, there's a label on the conveyor called MaxDogDist. This is the distance from the PE to the end of the conveyor, minus 2 meters. If this is the first dog ever, calculate the position of the dog, given the position of the item. Store that on a label. Create a token with all kinds of labels. We'll need all this information to estimate where the dog is later, and to estimate how far it is from other items. Pushing Dog Tokens to a List Once the token is made, we need to push it to a list, so that items can pull them. If all your items are the same size, you can just push the token to a list directly. In this model, however, there are larger items that require two dogs. So there's a batch activity first. The dummy item is far enough back that it can detect two dogs and still push the first dog to the list in time for the first lane. So it holds the dog back in a Batch activity until one of two things happen: Either the next dog token appears, completing the batch. Or the max wait timer on the batch expires, indicating that the next dog is not available. Otherwise, there would have been a token. This duration is based on the conveyor's speed and dog interval. If the batch is complete, the first dog in the batch can be marked as a "double", meaning the dog behind it is also available. Once the flow has determined whether the dog is a single or double, it then pushes it to the list. Creating the DistToDog Field When pulling the dog from the list, an item needs to know the position of the dog relative to the item. Is it 0.3 meters upstream? Or is it 2 meters downstream? When we query the set of dogs, we need to filter out downstream dogs and order by upstream dogs, to reserve the closest one: WHERE DistToDog >= 0 ORDER BY DistToDog Here, DistToDog is positive if the dog is upstream, and negative if the dog is downstream. The code for this field is as follows: /**Custom Code*/ Variant value = param(1); Variant puller = param(2); treenode entry = param(3); double pushTime = param(4); double distAlong = Vec3(puller.getLocation(1, 0, 0).x, 0, 0).project(puller.up, value.Conveyor).x; double dt = Model.time - value.DetectTime; double dx = value.Speed * dt; double dogDistAlong = value.DistAlong + dx; return distAlong - dogDistAlong; This code assumes that the item waiting to merge is the puller. So we calculate the item's "dist along" the main conveyor. Then we estimate the location of the dog since the DogFinder item created the token. Then we can find the difference between the item's position and the dog's position. Pulling Dogs from the List Each incoming lane has a Decision Point. The main process flow creates a token when an item arrives there. At a high level, this token just needs to do something simple: pull an available downstream token. If all the items are the same size, it's that simple. But this example is more complicated! If the item is large, we also need to pull the upstream dog behind the dog we got, so that no other item can get that dog. And it gets even more complicated! It can happen that an item acquires the dog after a double dog. In that case, we need to mark the downstream dog as "not double", so that big items won't try to get it. So most of the logic in the ConveyorLogic flow is handling that case. Using the Dog Finally, the item must be assigned to that dog. The ConveyorLogic flow sets the DogNum label on the item. Then, the catch condition checks to see if the dog matches the item's DogNum. Upstream Items The final piece of this model is allowing upstream items to catch a dog on this conveyor. This model adds a special label to those items called "ForceCatch". The catch condition always returns true for those items.
View full article
If you've ever tried to nest groups of objects inside a hierarchy of planes, you may find the drawing of the planes suboptimal and lacking information: Using the container (modified plane) in the attached user library you can represent the container with just an outline. A settings dashboard is installed with the library along with some user commands and global variables. Corner prisms show the nesting layers under the prism: The option 'Use the container center' allows you to use it as either a plane as before or, when unselected, a bordered frame where dropping an object or clicking and dragging within the borders will behave as though you are dropping onto or clicking/dragging the model floor. You can also choose to hide the containers entirely for the cleanest visuals. I hope this will encourage users to use containers more, since when coupled with Templates and Object Process Flows they can increase the scaleability and make your developed assets more manageable. ( In those cases the container becomes the member instance of the process flow or template master and references to its components are made through pointer labels on the container rather than names which you may want to alter for reporting purposes. The pointer labels are updated automatically when creating a new instance of the container.) ContainerMarkers_v1.fsl If you want planes you already have in your model to adopt this style just add this to their draw code: return containerdraw(view,current);
View full article
This article describes an example of Reinforcement Learning being used to solve scheduling problems. See the model and python files in the attached zip file. SchedulingRL.zip Problem Description This model represents a generic sheet metal processing plant. There are four machines in series. Each job requires time on all four machines. Jobs come in batches of 10. A poor sequence of jobs will cause blocking between items, lowering throughput. If the time between batches is long, such as a shift or a day, you could use the optimizer to determine the best sequence. If the time between batches is short, however, the optimizer may not be feasible. For real sequencing problems, the time to find a good sequence can be anywhere from 5 minutes to an hour, or even longer. This makes it impractical for high-velocity situations. The attached model requests a decision every time the first machine in the series is available. The only action is an index for the Nth available job. So the decision can be interpreted as "which job should I do next?" Solution The general solution is to use reinforcement learning. However, this problem required customized python scripts: The model uses custom parameters for observations. This allows arbitrary values for observations. The model uses a custom observation space. The observations include a table of the required times at each station for the remaining jobs. They also include an array of the in-progress jobs and their predicted remaining times. By using a Dict space, the python scripts can combine all the observations into a single space. The model uses an Action Mask. An Action Mask is a binary array with one value per value of the action. This tells the RL algorithm about invalid options. The python scripts require the sb3-contrib package. Use pip install sb3-contrib to install it. Results After training for 500k time-steps, the agent learns to choose jobs moderately well. If you run the inference script, you can use the experimenter to compare a random policy to a trained agent:
View full article
This model shows a simple way of bringing together all the separate picks in an order to be consolidated in a putwall. It also shows a great way of tracking flowitems while on a conveyor through the use of tracked variable labels. A side concept is that the order reserves a slot in a rack for all of the picks. Conveyor-Routing-Order-Consolidation.fsm
View full article
FlexSim 2017 Update 1 or later is compatible with Windows Mixed Reality headsets and controllers, such as the Samsung HMD Odyssey. To configure such devices, you use the Windows Mixed Reality Portal app in Windows 10 and SteamVR. FlexSim uses SteamVR's OpenVR API to communicate with these devices. Microsoft provides instructions for how to Play SteamVR games in Windows Mixed Reality. I will provide additional summarized steps below: 1. Configure your hardware with the Windows Mixed Reality Portal app in Windows 10. 2. Install Steam. 3. Within Steam, install SteamVR and Windows Mixed Reality for SteamVR. 4. If you are able to do the SteamVR tutorial with your headset, then you should now be able to use VR Mode in FlexSim: Note: While using a Windows Mixed Reality HMD (head-mounted display), pressing the Windows button on the controllers may take you to the Windows Mixed Reality Portal Home: If you end up here, you can take the headset off and put it back on to transfer back to FlexSim: Also, if you appear to be floating far above the ground, you can recenter the headset pose with this script, which you could map to a Custom Button on your toolbar: applicationcommand("recenteroculusrift");
View full article
Cams Module flexcon-cams v17.0.zip This module permits to place cameras in the model and so to follow an object using the nearest camera. How to install it: put the "Cams Module" folder into the Flexsim "modules" folder run Flexsim This module adds: the "Camera"object into the "Visual" section of the Flexsim standard library "Cams" menu button How to use it: insert cameras into your model where you want and adjust z locations (it's not important where camera is looking) highlight the object (maily a task executer) you want to follow click on the Cams menu voice: "Set Cam focus to highlighted" click on the Cams menu voice: "Camera activate" run the model the nearest camera to the focused object follows it click on the Cams menu voice: "Hide Cams and Camera Manager" to hide or unhide cameras Example:
View full article
Top Contributors