FlexSim Knowledge Base
Announcements, articles, and guides to help you take your simulations to the next level.
Sort by:
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
We recently had a customer ask how to draw a flow item label on the flow item object. I thought that this information would be useful to other FlexSim users as well. In the 3D model, drag and drop a Text visual from the Library. Select the text in the 3D model, then copy it to the clipboard using Ctl + C Go to the Toolbox tab, open the FlowItem Bin, and double click the Flow Item of interest. Right click the 3D flow object, and click "Explore Tree" Click in the white space underneath the Flow Item's node, and use Ctl + V to paste the text as a subnode to the flow item. If you zoom out in the Flow Item's 3D view, you will see the text. You can double click on the text and use the General tab to position it wherever you would like. Double click the 3D Flow Item. Underneath the Labels tab, select the green plus sign to add your label. In my example, I added a number label called "Type" with a default setting of 0. Click "OK". Double click the text that you added in step 5 and 6. Underneath the Display tab, click the custom code button next to Text Display. Within the custom code type something like the following: /**Custom Code*/ Object current = ownerobject(c); treenode textnode = param(1); textnode.value = "Type: " + string.fromNum(current.up.Type); //Note: If your label is called something other than "Type", make sure to replace it in both places. Click out of the "FlowItem Bin" tab and back into the "Model" tab. Double click the source where your Flow Item is being created. Underneath the Triggers tab, add an On Creation trigger. Click the green plus next to the On Creation trigger. Hover over Data and select "Set Label". Make sure the text next to the Label field matches the text of the label you set in step 7 and 8. By following these steps, each Flow Item will have a text label that displays the Flow Item label next to the Flow Item object. Please see the attached gif for a demonstration. flowitem-label.gif
View full article
Here on Answers it's often helpful to post code in a question or an answer. When you do so, there are certain steps that should be taken to avoid being blocked by Answers' internal security mechanisms. This article describes the proper way to submit code without arousing suspicion from our threat detection software. Some of our customers are all too familiar with the screen below after asking a question or adding a comment that includes code. What is Cloudflare? Cloudflare is a 3rd party threat detection software specifically designed to detect malicious code/software that may threaten a website. Once you've seen this screen above, there is no way for us to un-block you, as it is an automated 3rd party software. Unfortunately, at this point you have to wait a variable amount of time until Cloudflare decides your IP address is no longer a threat and you will again be allowed access to answers.flexsim.com. What am I doing wrong? This warning usually presents itself when code has been typed or pasted directly into the body of your post, like this: How do I properly format my code? First paste or type your code into the body of your post. Then, highlight your code and click the Code button in the toolbar. It looks like this: < > How can I tell if my code is properly formatted? After highlighting your code and clicking the code < > button, you will see that your code now has a border and light background: Remember, if you have multiple blocks of code, you can select just the code you want to be grouped together in the first block, hit the code button in the toolbar, and then select the second group of code and again hit the code button to make the second code block, etc. After you submit your post, you will see your code formatted with syntax highlighting, a mono-spaced font, and the lines numbered, like this: Conclusion Adding code to your post is an essential task for many of our customers. If you follow these guidelines, you should be able to avoid being blocked and ensure you have uninterrupted service on our answers site. If you feel you have properly entered code and are still being blocked, please inform us and include the code and method of formatting you were using when you were blocked. We'll gladly look into it. As a fallback, you can take a screenshot of your code and add it to your post as an image, but still let us know there was an issue, and we'll look into it. Finally, if you're in a hurry and Answers troubles are keeping you from getting the help you need, remember to contact your local FlexSim representative directly by phone or email.
View full article
One of the most powerful commands in FlexSim is the query() command. It allows you to run SQL-like queries on virtually any data structure in the tree. If you don't know what that means, or what SQL is, or why it would be good to have SQL in FlexSim, this article is for you. If you have general ideas, but you would like to know more, then this article is for you. This article is not about connecting FlexSim to an external database. If that is your goal, then this article is not for you. Basics - Tables Data is often arranged in a table, which very loosely means that data is organized into rows and columns. However, SQL (and therefore the query() command) was designed to work only on certain kinds of tables, that look something like this: Name Age Fur Color Scooter 6 Brown Spot 3 Brown Whizby 4 Black Notice the following points about this table: Each column has a unique name There are no row headers (although if your table in FlexSim has data in the row header, that's okay; we'll get to that later) The table is a list of things, and each row in the table represents a single thing. The columns tell you the data that is stored about each thing. In this table, each thing is a pet, and each row stores the name, age, and hair color (the columns) of each pet. If our data included another pet, it would make another row in the table. In database lingo, a row in a table is called a record. One other thing you need to know about this table is that it has a name (in this case, "Pets"). All tables in SQL have a name, and follow the format described previously. Basics - Tables In FlexSim FlexSim has several different ways you can store data. Most users employ Global Tables and Lists (found in the toolbox) to manage data in their model. More advanced users sometimes create tables or bundles on labels. Then there's the model itself, which stores your object's locations in a tree data structure. All the data about where and object is, and how big it is, is stored in the model tree. So which of these data structures meet the standards for a SQL table? As far as the query() command is concerned, all of them do. The query() command is flexible enough to handle any data structure. The trick is to imagine your data as a table. To do this, you need to be able to answer the following questions: How many rows are there? What columns will the table have? How do you get the data for each cell? Phrased another way, given a row and a column, how do you put data in the table cell? If you can answer these questions, you can use the query() command. Let's apply these questions to two data structures in FlexSim: the Global Table, and the Global List. For the Global Table, the answers are very straightforward, but follow along to get the hang of it: Q: How many rows are there? A: The number of rows in the Global Table. Q: What columns with the table have? A: The same columns as in the Global Table. Q: How do you get the data for each cell? A: Given the row and column, look up the value in the Global Table For the Global List, things get a little more interesting: Q: How many rows are there? A: The number of entries on the list. Q: What columns with the table have? A: There is a value column, and there is a column for each field on the list. Q: How do you get the data for each cell? A: Remember that each row represents an entry on the list. For the value column, I get the value that was pushed on to the list to create the entry. For each field column, I get the value of the field for that entry. For example, suppose you have this list: Then supposed that you pushed a 5, 23, -12, 7, and 2 on to this list. When you view the entries on the list, you can see the data on this list laid out as a table: Notice that the value column has the values that were pushed on the list. The field columns (Doubled, Tripled, OddOrEven, and IsNegative) are each filled with the values of that field. The query() command has built-in support for Global Tables and Global Lists. However, it is always important to remember that to the query() command, the data is laid out in a table. If the data is not laid out in a table, you can still use the query() command, but you will need to use the methods explained in the Explicitly Defined Tables section. Basics - Queries SQL stands for Structured Query Language, so we can guess that it is a language for making queries. So what is a query? In a general sense, a query is a question. In SQL, a query is a question with two parts: who are you asking, and what do you want to know? There is a general answer to both parts of the question, and this is where tables come in. The answer to the first part (who are you asking?) is always a table. A SQL query is always directed at one (or more) tables. The answer to the second second part (what do you want to know?) is usually a new table. A SQL query takes in a table, and gives back a new table. The power in SQL comes from the new tables you can make. You can make a table that is a sorted version of the old table, like sorting data in excel. For example, if you have a list of items that need to be processed, you can sort that list by the item's priority. You can also make a table that is a filtered version of the old table, meaning you only kept certain rows. For example, if certain operators can only do certain tasks, you can make sure to only include the tasks that operator can do. In fact, you can make a table that is filtered, sorted, and modified in several other ways all with one query statement. Basics - Queries in FlexSim Let's look at examples of the query() command. You can follow along using the attached model ( numberlist.fsm). That model has a script that pushes values on to the list, and then queries the list. It also puts the result into the Global Table called QueryResult. Let's look at the line of that script with the query() command: int newTableRows = query("SELECT value FROM NumberList"); This line has a lot of new material. You can see that the query() command takes at least one argument, which is the text of a SQL query. We'll discuss the query itself in a moment. The query() command takes in the SQL query, and creates an internal (and invisible) temporary table that contains the result of the SQL query. It then returns the number of rows in the temporary table. Since you can't readily see the new table made by the query() command, you may want to copy the temporary table to a global table, using the dumpquery() command, as the script does: dumpquery(reftable("QueryResult"), 1); The temporary table lasts until you run the query() command again. Now for the query itself. You can see two parts of this query. The question "What do you want to know?" is answered by the SELECT statement. The question "Who are you asking?" is answered by the FROM clause. In this case, the FROM clause just lists one table, the NumberList. Recall that even though the NumberList isn't technically a table, you can visualize it's data as a table, which is what the query() command does (you can always right-click the NumberList in the Toolbox and choose the "View Entries" option to see the data as a table). In this example, the SELECT statement lists a column name. This means that the resulting table will have 1 column, because only one is required by the SELECT statement. When you run the script, it will put the result of the query in the QueryResult table: Notice that this table has only one column, the value column. If you look at the NumberList entries, you will see that this column is identical to the value column in that table. Examples To give you a general idea of what you can do with queries, these examples show a few common tasks. The examples all query the NumberList, which can be visualized as the following table: Selecting Multiple Columns SELECT value, IsNegative FROM NumberList Filtering SELECT value, IsNegative FROM NumberList WHERE IsNegative == 1 SELECT value, OddOrEven FROM NumberList WHERE value >= 5 Sorting SELECT value, Doubled FROM NumberList WHERE value >= 5 ORDER BY value Advanced - Callback Values It is often necessary to create a dynamic query. In FlexSim (not in regular SQL), you can do this by replacing a value in a query with a $n variable. This variable corresponds to additional parameters in the query() command. If you specify $1, then the value in the query will be the first additional parameter in the query() command, $2 will correspond to the second, and so on, up to $9. For example: query("SELECT Col1, Col2 FROM MyTable WHERE Col1 > $1 AND Col2 < $2", 10, 20) This query creates a table with Col1 and Col2, but only the rows where Col1 is greater than 10, and Col2 is less than 20. It is possible to include the values 10 and 20 in the query text. However, the $ variables allows you to easily change the value in the query, and replace them with more complicated expressions. Note that using callback values in a query where the FROM value is a Global List is not supported before versions 16.0.6/16.2.1. Advanced - Explicitly Defined Tables and the $iter() command Another FlexSim-specific feature of the query() command is the ability to explicitly define a table. This means you can query data that isn't arranged in the table format. In order to do so, you will need to answer the questions posed above, but shown again here: How many rows are there? What columns will the table have? How do you get the data for each cell? Once these questions are answered, the query() command can treat your data like a table. Each of the following subsections will answer these questions in detail. Defining the Number of Rows Let's start with a simple example: query("SELECT 1 FROM $1", 5) Notice that we are selecting from a number, not a Global Table or Global List. When the query() command sees a number instead of a table in the from statement, it assumes that you are querying a table with that number of rows. The statement above yields the following table (after a call to the dumpquery() command): This table has five rows, because $1 (the first additional parameter) evaluates to 5. All the rows have the value 1 because SELECT can handle expressions as well as column names (or expressions involving column names). Note that defining a table will only work if you use callback variables. A from statement like FROM 5 is not valid. To determine the number of rows in the table, use callback variables in the FROM statement. Defining the Columns To define the columns of your table, use the SELECT statement. Each expression in the SELECT statement will result in a column. When you are explicitly defining a table, you will often use callback variables as columns. This is where we can take advantage of the query() command. The query() command is very different from most other commands, because most commands only evaluate their parameters once. The query() command, however, can evaluate its parameters as many times as it needs to. Let's look at another example: query("SELECT $2 FROM $1", 5, normal(0, 1)) The result of this query is the following table: Notice that the second parameter, corresponding to $2, was re-evaluated as many times as the query needed it. Getting the Value in Each Cell Finally, we need a way to access the correct value for a given row and column. To do that, we need a way to know which row we are currently dealing with. This is where the $iter() command comes in. For example: query("SELECT $2 FROM $1", 5, $iter(1)) The $iter() command accepts an argument. That argument should match the value of the callback variable, e.g. if you used FROM $1, then the $iter() command should take a one as an argument. The $iter() command is linked to the query() command, so that its return value depends on which row is being evaluated. The above query results in the following table: Notice that $iter(1) returned the row number for each row. Now we can begin to query the tree, as if it were a table. Let's start with a simple example. Suppose you wanted a table of all the names of the first-level subnodes of the model tree. Let's start by answering the three questions: Q: How many rows are there? A: The number of first-level subnodes of the model Q: What columns with the table have? A: A column for the name of each of those subnodes Q: How do you get the data for each cell? A: Given the row number, get the name of that object Let's translate those answers into a query. First, we need to query something that isn't in table format already, so we know we need to use callback variables in the FROM statement: query("SELECT ... FROM $1", ..., ...) Next, we need a column for the names of all the subnodes, so we add one to the select statement: query("SELECT $2 FROM $1", ..., ...) Next, we need to answer the question of how many rows there are. Since this is the number of subnodes, you can write that as content(model()): query("SELECT $2 FROM $1", content(model()), ...) Finally, we need a way to get the name of each of the subnodes. We know that $iter(1) will give us the values from 1 to content(model()), so we can use those values in the rank() command, and we can pass the result of the rank() command to the getname() command: query("SELECT $2 FROM $1", content(model()), getname(rank(model(), $iter(1))) ) After dragging in a few random objects into the model, you can run that query. If you use the dumpquery() command, you can get a table like this: In the previous example, we used the value from $iter(1), and passed it in to rank(), and from rank() to getname(), all to get the name of the nth subnode of the model. Since querying a node in this way is fairly common, the query() command also allows you to specify a node as a table, rather than a number. In this case, $iter(1) will iterate over all the subnodes of $1, rather than the values 1 to $1. This makes our query much simpler: query("SELECT $2 FROM $1", model(), getname($iter(1))) Advanced - Flattening Data There is another option for what you can query in a FROM statement. If you use a callback variable (like $1) as your table, then you can use flattening syntax, shown in the following example: query("SELECT $3, $4 FROM $1x$2", 3, 2, $iter(1), $iter(2)) This query makes the following table: Notice that for every possible value of $1, there is a row for every possible value of $2. That is the purpose of the x (called the flattening operator); it ensures that there is a row for each permutation of all the callback variables involved. A query containing FROM $1x$2x$3x$4 would produce a table with enough rows for each unique combination of $iter(1), $iter(2), $iter(3), and $iter(4), and then execute the query on that table. The user manual contains an excellent example of when flattening syntax might be helpful, shown in the help manual in Miscellaneous Concepts > SQL Queries > Example.
View full article
Neste Tutorial iremos demonstrar como funciona a ferramenta Model Layouts no FlexSim. Esta ferramenta permite que você crie e edite diferentes Layouts para um mesmo modelo. Você pode modificar a posição dos objetos e criar uma nova opção de Layout. Por exemplo você pode salvar um Layout inicial de seu processo e após montar propostas a serem estudadas, como um Layout com diferentes posições, redução de transporte, etc... O Model Layouts permite que você possa fazer isso. modellayouts-example-model.fsm Ferramenta útil para estudar comparativamente os resultados gráficos dos Layouts criados apenas rodando o modelo para cada um dos Layouts, e ou para criar a variável Layout para inclusão das opções de Layouts em um experimento. As informações de Layout são armazenadas em cada um dos objetos individuais. Um nó é adicionado aos atributos de objeto chamados Layouts. Para cada Layout criado, uma cópia das informações espaciais atuais do objeto (posição, tamanho, rotação) é armazenada. Janela Model Layout Esta janela pode ser acessada em: View Menu / Model Layouts Layout List - Exibe a lista de Layouts atuais. Selecione um layout para atualizar imediatamente o modelo desse Layout. Você pode renomear um Layout digitando um novo nome neste campo. Add Layout - Adiciona um novo Layout. Quando você adiciona um Layout, ele salva o Layout atual do modelo. Delete Layout - Remove o Layout selecionado. Set - Opção para atualizar o Layout do modelo selecionado para corresponder ao Layout atual do modelo indicado na lista (Layout List).
View full article
Playing Multiplayer Tag in FlexSim! TagServer.fsm TagClient.fsm This is a side project to show off some fun things FlexSim can do using sockets. Sockets are just one possible way that one instance of FlexSim can communicate with another. In its simplest sense, a socket is just a port number and an IP address that computers use to send information to each other. For example, whenever a computer visits a website, it uses sockets to create a connection to the webserver's IP address on port 80 (HTTP) or port 443 (HTTPS). All of this occurs within the framework of the TCP/IP network. Similarly, FlexSim can establish socket connections to communicate with another FlexSim as long as you know the IP address and choose a port for both instances to connect on. Establish Socket Connection In this game of tag, the model that acts as the server uses these commands to set up socket connection with the client: socketinit(); servercreatemain(8002); serveraccept(0); Note: All of the commands in this article can be found in the documentation The client then runs the following to connect to the server. The HostIP should be the IP address of the device running the server model (or 127.0.0.1 if running both client and server on the same machine). socketinit(); int a = clientcreate(); int a_con = clientconnect(a, HostIP, 8002); On both the client model and server model, these commands are in the OnRunStart trigger and the server creates 5 socket connections for each player. 4 for inputs (up, down, left, right) and 1 for passing in their player name from the client. The server model will freeze and wait for all sockets to be set up. For example, if there are 3 players, the server model will wait until 3 clients have successfully ran the client model and connected. After all clients have connected to the server, we can use clientsend() and serverreceive() to send information from client to server. An example of this is sending movement inputs from client to server. This is what that looks like: Client // MOVE if (iskeydown(87)){ clientsend(2, "up"); } if (iskeydown(83)){ clientsend(3, "down"); } if (iskeydown(65)){ clientsend(4, "left"); } if (iskeydown(68)){ clientsend(5, "right"); } Server string up1 = serverreceive(token.Rank * 5 - 3, NULL, 100, 1); string down1 = serverreceive(token.Rank * 5 - 2, NULL, 100, 1); string left1 = serverreceive(token.Rank * 5 - 1, NULL, 100, 1); string right1 = serverreceive(token.Rank * 5, NULL, 100, 1); // token.Rank is the number of the player (1,2,3 etc.) and is used to reference the right // socket for each player's inputs //reset coordinates te.X = 0; te.Y = 0; te.Stop = 0; if (up1 != ""){ // up W meaning the server received an input on this socket te.Y = 1; // this accounts for getting multiple messages from client like "upupup" } if (down1 != ""){ // down S te.Y = -1; // this label is later used in a travel activity } if (left1 != ""){ // left A te.X = -1; } if (right1 != ""){ // right D te.X = 1; } Note: In a typical game environment, the server is also sending information back to the clients, but in this example, all visuals and logic occur on the server. Game Logic All game logic is found on the server process flow. Setup and Order of Models To play Tag, follow these steps: Note: If there are certain firewalls or security groups on your network that doesn't allow traffic into FlexSim outside local networks you may be limited on who can connect to play tag 1. Open TagServer model and change NumPlayers parameter to the desired number of players 2. Open TagClient model and change both global variables (HostIP and EnterNameHere). Again, if everything is running on the same device, use 127.0.0.1 as the HostIP global variable value. 3. Reset and Run the TagServer model first 4. Reset and Run the TagClient model. You should get this output if connection was successful 5. Run clients one at a time for each player until all players have connected and the server will run automatically. This is the output on the server upon successful connection 6. Enjoy!
View full article
Changing the packing method for task executers can be tricky and also can vary widely between types. In this article we'll explore the default packing method for each TE and how to alter it to suit the model's needs. Attached is a model which demonstrates the default packing method and the comparison. The model is also the best place to get premade code for the ASRS, the crane, and the Robot: TEStackingNew.fsm Default Stacking on Task Executers There are two types of default stacking methods on the TE's. AGV's, operators, forklifts, ASRS, and basicTE's all use a simple up and down stacking method: The other TE's (elevator, robot, and crane) don't separate the boxes at all so they all look like they're on top of each other (this is because they're mostly meant to only carry one item at a time): Changing the Stacking Pattern: AGV, Operator, & BasicTE: For these objects, changing the stacking method is relatively simple. Add 5 labels to the object: numx, numy, xshift, yshift, and zshift Add an OnLoad trigger in the properties panel Set the trigger by going to Visual->Set Location Type in this code current.xshift+item.size.x*((item.rank-1)%current.numx) -current.yshift+item.size.y*(Math.floor(((item.rank-1)/current.numx)%current.numy) - (current.numy-1)/2) current.zshift+item.size.z*Math.floor((item.rank-1)/current.numx/current.numy) The only thing that differs between these 3 objects are the label values. The labels "numx" and "numy" sets the number of objects in the x direction and how many in the y direction. For example a 3x3 grid on the AGV would set "numx" be 3 and "numy" be 3 xshift yshift zshift AGV 1 .5 .5 Operator .75 .29 1.10 BasicTE 0 0 .85 Elevator, Robot, & Crane: These objects are very similar to the TE's above. You'll follow the same steps above, except on the On Load trigger, choose to just paste custom code in the box. They have slightly different code (due to the different direction/ways of stacking) that you can copy from the model above. However, you will still add the labels to the TE's. You can set them using labels like these: xshift yshift zshift Elevator .7 1 .095 Robot .34 .35 .2 Crane .2 .5 -.25 Forklift: This is the easiest object to change because it is already built into the TE. To change the stacking pattern just add an OnEntry trigger and select Transporter Stacking Method, then just change the values to be what you would like. ASRS: For this one, you can change the stacking method by editing the model tree. The steps to change it are simple but specific: Open the model tree for the object by right clicking and selecting Explore Tree Find the behaviour node beneath the ASRS Node Add an node underneath called "eventfunctions" Beneath the node you just created add a node called "OnPreDraw" Paste in that node the code below (you can edit this to alter the stacking method how you would like): inheritcode(); TaskExecuter current = c; Object followingObj = first(current); double numx = 1; double numy = 4; double xshift = .95; double yshift = 1.45; double zshift = .1; while(objectexists(followingObj)){ double x = xshift+followingObj.size.x*((followingObj.rank-1)%numx); double y = -yshift+yloc(node(">visual/drawsurrogate/Lift/Slide", current))+followingObj.size.y*(Math.floor(((followingObj.rank-1)/numx)%numy) - (numy-1)/2); double z = zshift+followingObj.size.z*Math.floor((followingObj.rank-1)/numx/numy); double xFactor = 0.5; double yFactor = 0.5; double zFactor = 0; setloc(followingObj, x, y, z, xFactor, yFactor, zFactor); followingObj = next(followingObj); } Some things to keep in mind: Each TE is completely customizable by the user so the offset I considered to look right may not look right to you, the good thing is it's very changeable!
View full article
Cycle time per process.fsm When we create simulation models, sometimes we limit ourselves to modeling a process or a part number, in which we have problems. But what happens when we run a complete production plan with different part numbers, which in turn run at different cycle times? This is a way that allows you to run different part numbers in as many different processes as you want, each with its own cycle time. What do we need? 1.- Label on each item that identifies what part number it is. For example • Label: IDpart Value: ABC12 2.-Label on each machine that identifies the process that it runs. For example • Label: Station Value: Processor1 3.- Global table that contains in the columns the different processes that you have in your production line and in the rows the different part numbers that can run in your line. The information contained in this table will refer to the cycle times of each part number in each process. For example: Processor1 Processor2 Processor3 ABC12 20 10 13 BAC21 11 30 20 4.-You must configure the processing time of your processor referring to your global table and placing the following: With this, we will obtain weighted usage statistics for the equipment. Benefits: 1. You can run different part numbers on the same line with their respective cycle time each. 2. More accurate use of equipment and operators. 3. Modifying cycle times in a global table is easier and more controlled than directly in the processes. 4. Calculation of the capacity of your line running a real production plan will be accurate. 5. You can add and remove processes or even modify the flow of your line without affecting the cycle time that processor runs. Since it is referenced by its label to the global table.
View full article
MQTT is a communication protocol designed for IoT devices. Clients (the devices) connect to a Broker which allows them to publish (send) and subscribe (receive) messages. Each message is associated with a Topic. Each client can choose which topics to use for publishing and subscribing. Usually, the MQTT broker discards messages once they are sent to all subscribers. However, a publisher can mark a message as "retained." This means the broker will keep the last message for that topic and make it available to other subscribers. Only the most recent message is retained. When developing a digital twin, you may need to access these retained messages. This article describes how to do that using FlexSim's Python connection. This article is not meant as a comprehensive guide, but as a starting point, which you certainly will modify for your circumstances. Here are the python scripts and FlexSim model used in this example: MQTT.zip A quick note: since MQTT is a device communication protocol, support for MQTT in the Emulation module is in progress. This article describes how to import data from an MQTT broker like any other file/database/http server, rather than connecting for Emulation purposes. Step 1: Gaining Access to an MQTT Broker Your facility may already have an MQTT Broker running. In the end, your digital twin will need to connect to that broker to retrieve the latest retained messages. However, for testing, or if you don't have an MQTT Broker yet, you can easily get one. One possibility is to use Docker to run the EMQX Broker. However, there are dozens of brokers and installation steps You can download Docker Desktop here: https://www.docker.com/products/docker-desktop/ Once docker is running, you can use the following command in a terminal to download and run the EMQX Broker: docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx Note that this command runs a Linux container, so if Docker is in Windows mode, you'll need to switch before running this command. Step 2: Publishing Messages to an MQTT Broker A real facility will have many publishers and subscribers. However, for testing, it can be convenient to create publishers and subscribers that you control. Once your broker is running, you can use code like the following to create a publishing client: https://github.com/emqx/MQTT-Client-Examples/blob/master/mqtt-client-Python3/pub_sub_tcp.py For this example, I created two clients that publish tabular data: one that publishes a set of "raw materials" available for use in the process, and another that publishes a set of "finished goods" available to fulfill orders. To create some data, run the finished_goods_client.py and raw_materials_client.py files for a few seconds each. Note that both of these clients mark the messages to be retained, so FlexSim can access the latest message, even if neither client is actively running. Step 3: Writing a Python Script to Retrieve Messages This approach is demonstrated in fs_client.py, shown here: import paho.mqtt.subscribe as subscribe import json def get_retained_msgs(topics): auth = { 'username': 'emqx', 'password': 'public', } msgs = subscribe.simple( topics, qos=0, msg_count=len(topics), retained=True, hostname="localhost", port=1883, client_id=None, auth=auth, keepalive=5) if type(msgs) == list: return [json.loads(m.payload) for m in msgs] else: return [json.loads(msgs.payload)] if __name__ == "__main__": topics = ["python-mqtt/raw-materials", "python-mqtt/finished-goods"] print(get_retained_msgs(topics)) Run this script to verify that it returns the latest data from the two publishers. When FlexSim calls this function, FlexSim can convert python Lists and Dictionaries into FlexSim Arrays and Maps. So you can return complex data structures directly to FlexSim. Step 4: Writing a User Command to Call the Python Command In FlexSim, create a new user command, and edit the code. Be sure to toggle the node for external use, and set it to the following: /**external python: */ /**/"fs_client"/**/ /** \nfunction name:*/ /**/"get_retained_msgs"/**/ To use Python like this, you need python installed on the path. You also need the paho-mqtt package installed globally. Finally, you need to verify that your global preferences indicate the correct version of Python. For more information on connecting to python functions, see FlexSim's documentation: https://docs.flexsim.com/en/23.2/Reference/DeveloperAdvancedUser/ConnectingToExternalCode/ConnectingToExternalCode.html Step 5: Writing a User Command to Write Messages to Global Tables In this example, the messages we are interested in store tabular data, so it makes sense to store the data in Global Tables: Array tables = ; Array topics = ["python-mqtt/raw-materials", "python-mqtt/finished-goods" Array msgs = getRetainedMessages(topics); for (int m = 1; m <= msgs.length; m++) { Table fsTable = tables[m // header code elided; see example Array msgData = msgs .data; Table msgTable = Table(msgData); msgTable.cloneTo(fsTable); // header code elided; see example } If you run this new user command, you can see the latest data pulled in to FlexSim. Conclusion This example shows just one way you could import data from an MQTT broker into FlexSim. In addition, the kind of data you import or what you do with that data is up to you as the user.
View full article
This article borrows from @jordan.johnson's original guide for deploying a distributed experiment/optimization with Amazon. Distributed Terminology Please be familiar with the terminology related to experiments and optimizations. Replication - a distinct model run. We'll use this term below for both replications (experimenter) and solutions (optimizer). Instance - a system, whether virtual or bare-metal, local or remote, meeting FlexSim's recommended requirements, and used for running distributed replications. Main PC - the system from which the user configures and initiates the distributed experiment or optimization. The Cloud - a shorthand term for remote servers/systems hosted in a data center, sometimes by a 3rd party such as Amazon, Microsoft, Google, or others. Background Concepts In discussing distributed experiments or optimization, you should start with a good understanding of both the Experimenter and the Optimizer. Please read and understand this user manual entry which includes explanations of key concepts that will be important as you continue. Other user manual articles provide additional guidance on configuring your own experiments or optimizations. Search the online user manual and this community if you have additional questions regarding experiments or optimizations, as needed. Using the experimenter requires a FlexSim license. The optimizer requires a license for the OptQuest add-on. Please contact your local distributor for more information or to request a test license for FlexSim and/or OptQuest. What are distributed experiments or optimizations? Experiments or optimizations can create dozens, hundreds, or even thousands of distinct model runs (or replications) to test various scenarios, build confidence intervals of the results, or zero-in on an optimal solution. A distributed experiment or optimization takes those individual model runs and assigns them (distributes them) to run across a group of computers. If you needed to run 1000 replications, and you have 4 computers available, each computer could run 250 replications, getting your results 4 times faster. When should you distribute? Using distributed replications can significantly reduce the required time to run an experiment if: The single-run time for your model is high (a couple minutes or more) You anticipate running a high number of replications If the time per replication is short, then the increased communication overhead may outweigh the benefit of using distributed replications. The communication overhead increases because all distributed replications still report results to a single FlexSim process on the Main PC, and that communication occurs over the network (local instances) or internet (remote instances), rather than on a single computer. If an experiment or optimization completes in an acceptable amount of time, you may not need to use distributed replications. Financial Costs 3rd party cloud providers such as Amazon, Microsoft, Google, and others, charge for their services. Your cost is usually based on the hardware you provision for your Windows instances, and the length of time those instances are live. Typically you only run your instances when running your experiment or optimization, and cancel or decommission your instances when your replications are complete. In this way you minimize the cost of your distributed experiment or optimization. The costs and process of decommissioning your provisioned instances differ based on which 3rd party cloud provider you use. You may have access to local computing resources that could be configured for use in your FlexSim experiments or optimizations. In this case you may avoid additional costs relating to 3rd party cloud providers by using your own on-premises computers. Licensing for distributed Windows instances Windows instances used solely for distributed replications DO NOT need an individual FlexSim license. Only the FlexSim installation on the Main PC must be licensed. System requirements for distributed Windows instances Graphics A Windows instance should meet or exceed FlexSim's recommended requirements. However, because replications run as background processes without graphics, they need not meet the graphics requirements and do not need hardware accelerated graphics. CPU An instance can run as many concurrent replications as it has CPU cores. If, for example, an instance has 32 CPU cores, it can run 32 replications of your model simultaneously. RAM For this example of a 32-CPU Windows instance, if you want FlexSim to run 32 replications simultaneously - one on each core - then the instance must also have enough RAM to handle 32 concurrent model runs. On your Main PC, use Windows Task Manager to watch a single model run's RAM usage to determine its peak RAM utilization. If your model's RAM utilization peaks at 3GB throughout the course of a model run, you should make sure your 32-CPU system has at least 32*3 = 96GB of RAM for replications alone, along with a good ~10% more for additional overhead used for the Webserver and the statistics gathering and reporting from all the replications (this number could be more or less, depending on the model's stats gathering). In addition, you must account for your system's baseline RAM utilization - how much RAM it uses just to run the operating system and all its background processes. You can find this baseline by checking the Task Manager at a moment when you're not running any simulations. Add all these together to see how much RAM would be necessary to run a replication on each core of the instance. If your instance doesn't have enough RAM to handle that many simultaneous replications, you'll need to limit the number of CPUs FlexSim will use when configuring your Cloud Computing settings from the Main PC. Disk Disk space is usually not an issue. However, if you are using the Store Data on Hard Drive option in the Statistics Collector, you will need to be sure that there is enough disk space to run the model to completion on the hard drive, multiplied by the number of cores. The amount of disk space on each instance may affect the total cost of using a 3rd party cloud provider. More information See the related sections in the article Recommended System Requirements for a more in-depth discussion of system components such as CPU and RAM, and how they relate to running your simulations and experiments. Provisioning distributed Windows instances The process of provisioning 3rd party cloud instances for running distributed FlexSim replications will differ from provider to provider. FlexSim has guides for the following cloud providers: Amazon Web Services Wherever you decide to host your instances, the important part is that eventually you end up with a group of Windows instances, each with a unique IPv4 address accessible from the Main PC. A custom Windows image Your 3rd party cloud provider probably allows you to save a custom Windows image that can include software and settings that you need for each Windows instance. Doing this once for a custom Windows image saves you time when starting new instances - each instance will start with the software and settings preconfigured for your purpose. On your custom image, do the following Download and install FlexSim. Use the same version of FlexSim as is licensed on the Main PC. Remember, you DO NOT need to activate a license. Run FlexSim. This creates a directory that is needed later. After FlexSim finishes its first start, close FlexSim. Download and install the FlexSim Webserver for your installed version of FlexSim. Edit the Webserver's configuration file appropriately for your situation. Default location is here: "C:\Program Files (x86)\FlexSim Web Server\flexsim webserver configuration.txt" Start the FlexSim Webserver from your Windows Start menu, or manually from the default location here: "C:\Program Files (x86)\FlexSim Web Server\flexsimserver.bat". The Webserver will download necessary files the first time it is run. Close the Webserver after it has completed its initial startup. Allow both FlexSim and node.js through the Windows Firewall. To do so, use Windows' Allow an App through the Windows Firewall tool. You will need to browse for both FlexSim and Node.js. Example locations (exact locations may vary by version): C:\Program Files\FlexSim 2023\program\flexsim.exe C:\Program Files\nodejs\node.exe If you are not familiar with the FlexSim Webserver, please review its documentation and test it out on a local machine to understand what it does, its configuration options, etc. If you cannot configure a custom Windows image, you will need to do the above on each instance individually. Initialize instances Launch your instances. On each instance, do the following: Log in to the instance with Remote Desktop or some other solution. Start the FlexSim Webserver from your Windows Start menu, or manually from the default location here: "C:\Program Files (x86)\FlexSim Web Server\flexsimserver.bat". Note the instance's IPv4 address. Once all instances are running the Webserver, you are ready to configure a distributed experiment or optimization from the Main PC. Author's Note: There is probably a way to make it so that when instances start up, they automatically run the Webserver, so that you don't have to manually connect to each one. I welcome any suggestions or steps for how to make that happen. Configuring a distributed experiment or optimization Once you have a list of running instances available, launch FlexSim on the Main PC. Open the experimenter interface from FlexSim's Main Menu > Statistics > Experimenter. Configure your experiment. As part of your configuration, under the Advanced tab, select the option to Use Distributed CPUs. Press the button to Configure Cloud Nodes. This will open the Global Preferences' Environment tab. Enter the IP addresses of your instances into FlexSim. Enter the port numbers you configured in their FlexSim Webservers. If your instances will max out RAM before CPUs, enter a CPU count representing the maximum number of concurrent replications your instance can handle. For more information on using remote computers for Experiment Jobs, see Running Jobs on the Cloud for more information.
View full article
Neste Tutorial iremos demonstrar como importar um Layout do AutoCad no FlexSim. Desenhos do AutoCAD e outras imagens podem ser usadas como planta baixa para a montagem do modelo de simulação no FlexSim, sendo facilmente importadas usando o Background Drawing Wizard. Isto facilita a construção do modelo de simulação fazendo com que o modelador possa posicionar os objetos de forma rápida e em escala. O Background Drawing Wizard pode ser acessado clicando em: Tools / Visual / Model Background , ou na Biblioteca de Objetos / Visual / Background arrastando o objeto para o plano. O assistente abre uma nova janela, e irá pergunta-lo se você quer importar um desenho CAD ou um arquivo de imagem. Assegure-se que "AutoCAD Drawing" está selecionado e então clique em "Next". A próxima tela irá pedir a você que especifique o caminho do arquivo CAD que você quer usar; busque o arquivo em seu computador e clique em "Open". Veja que você está usando um arquivo .dwg; arquivos .dxf e .dwg podem ser importados para o FlexSim. Clique em "Next" novamente para ir para a próxima tela. Nesta tela você poderá definir detalhes sobre o posicionamento do seu layout no plano de trabalho do FlexSim. Existem três colunas representando os eixos X, Y e Z e três linhas para cada um que correspondem a posição, rotação e tamanho ao longo de cada eixo. Configure a posição para cada eixo em "0" e você verá a posição original do desenho, localizado no canto esquerdo inferior, mostrando exatamente que está no centro do seu modelo. Clique em "Next" para seguir para a próxima tela. Nesta tela você pode customizar qual layers de seu desenho CAD estarão visíveis, e ainda alterar a cor de cada layer. Se você tiver algum recurso no desenho que não é necessário para o modelo de simulação, como por exemplo, uma parede ou uma porta, talvez possa ser uma boa idéia fazer com que estes layers fiquem invisíveis e então o espaço visual não se torne confuso. Clique em "Next" para ir para a tela final. Clique em Finish e pronto! Agora você já pode começar a montar seu modelo utilizando o Layout em AutoCad como planta baixa.
View full article
O link que segue leva a um vídeo no qual é apresentado um exemplo de modelagem utilizando-se o módulo FloWorks FlexSim. No vídeo, modela-se um processo de fabricação de Suco de Laranja, desde sua extração até seu envase. Recursos do FloWorks utilizados no vídeo: ItemToFlow: Extração do suco FlowPipe: Transporte do fluido FlowTank: Armazenamento FlowMixer: Processo de mistura de conservantes Vídeo Tutorial: FloWorks Exemplo de Modelagem Esperamos que aproveitem mais este vídeo tutorial.
View full article
Nesse vídeo demonstramos como importar modelos de animações para os executadores de tarefas ou recursos através de arquivos criados em software específicos para modelagem de animações e disponíveis em repositórios como o Mixamo. Veja o passo clicando em BoneAnimationVideo Também descrevemos o passo a passo de uma parte, logo abaixo. Estes são os passos que seguimos para criar os operadores com bone animation no FlexSim. (opção disponível a partir da versão 7.7) Copie o conteúdo deste diretório "Pasta Operador" para o seu diretório FlexSim/ fs3d / Operator para que ele tenha 5 opções de operadores ao invés de apenas 3; Abra o FlexSim; Arraste um Operador; Clique duas vezes nele para editar suas propriedades; Selecionar Masculino - High Res ou Feminino - High Res na opção do Shape na guia Operador; Pressione Aplicar; Reinicialize o modelo (Isso é necessário para atualizar as animações porque esses arquivos possuem mais animações do que o padrão); Clique com o botão direito do mouse no Operador na vista 3D e selecione Editar> Animações Existem agora 12 animações disponíveis; Execute estas animações usando listas de seleção, utilizando um Triggers para Iniciar e ou Parar a Animação eu sua Modelagem no 3D ou então use a atividade Run Animation na criação da sua lógica com o ProcessFlow. Abaixo você encontra os arquivos necessários para incluir os operadores em alta resolução em seu FlexSim e também uma grande quantidade de animações de dança extras adicionadas! Faça o download aqui do material explicando sobre o bone animation. Faça o download aqui do material usado no passo a passo do vídeo deste artigo. Inscreva-se e acompanhe nosso canal de videos no YouTube FlexSim Brasil -------------------------------------------------------------------------------------------
View full article
Neste modelo anexo simples mostramos como usar TrackedVariable para conseguir alguns outputs customizáveis dentro do FlexSim e uma das funções do recurso Global Variables, outro recurso que pode ser usado durante a modelagem para customizar os trabalhos de criação de lógicas e também customizar alguns outputs de seu sistema. O passo a passo como elaborar esse modelo encontra-se no vídeo em Passo a Passo TrackedVariable e Global Variable trackedvariables-e-global-variable.fsm somente na versão 2017 do FlexSim.
View full article
Introduction Several times per year we release a new feature-version of FlexSim Simulation Software. In order for your PCs to be able to run a licensed version of the upgraded software, you'll need to upgrade your standalone FlexSim license. Licenses with a current maintenance subscription are eligible to be upgraded to the new version. If you don't understand how licensing works for different FlexSim versions, please review our Answers article FlexSim Version Numbering. Overview After installing your new version of FlexSim, there are 3 main steps to upgrading your standalone license: Return the licenses you intend to upgrade Upgrade your licenses Activate the upgraded license Several of these steps have their own fully documented procedures. We'll link you to those resources below. 1. Return the licenses you intend to upgrade The steps to return a standalone license are fully documented. Choose the link below that best matches your needs, depending on whether your PC can connect to the Internet: Standalone - Return - Online Standalone - Return - XML / Offline Be sure to return ALL licenses you wish to upgrade. 2. Upgrade your licenses NOTE: Licenses with expired maintenance will not upgrade. Timed licenses do not upgrade. Only permanent (not timed) licenses under current maintenance can be upgraded. Log in to your FlexSim Account. If you were already logged in to your FlexSim Account, in the top navigation menu hover over your initials icon and choose Reload Account. Now in the top navigation menu, choose Licenses > List. Check that the available seat count is equal to the total. All of a license’s seats should be returned for it to upgrade. Click on the Upgrade Licenses button. If you have several licenses to upgrade and all are owned by or shared with your FlexSim Account, they will all be upgraded at once. Please be patient while the upgrade process works in the background. When the page refreshes, eligible licenses will have a new activation ID for the latest version of the software. Your license code indicates its version at the end of the code to help you know what versions your license will properly activate. Review license code format. You'll be able to use the upgraded license codes in the next step. 3. Activate the upgraded licenses The steps to activate a standalone license are fully documented. Choose the link below that best matches your needs, depending on whether your PC can connect to the Internet: Standalone - Activation - Online Standalone - Activation - XML / Offline If you have any questions or problems, please search our Answers Community for possible solutions. There is a good chance someone else has already asked your question. Still not finding what you're looking for? Submit a new question and we'll check it out. If you're including any confidential information, such as license codes, be sure to mark your question as private! You can also contact your local FlexSim distributor for live phone, web, or email help.
View full article
Neste Tutorial iremos demonstrar em um exemplo como funciona a biblioteca AStar Navigator no FlexSim. O AStar Navigator, também conhecido como A*, é um algoritmo de busca usado para encontrar um caminho entre pontos, e serve para determinarmos o trajeto pelo qual os executores de tarefas podem se movimentar pelo modelo. Esta biblioteca permite que você crie e defina barreiras físicas para a correta movimentação dos executores de tarefas em seu modelo. Nós iremos usar o seguinte modelo para mostrar como o A* Navigator pode ser usado em um modelo simples. astar-example-model.fsm Crie o A* Navigator Primeiro, um objeto AStarNavigator deve ser adicionado ao modelo. Somente um objeto AStarNavigator faz-se necessário e permitido por modelo. Crie um objeto AStarNavigator ao clicar e arrastar da biblioteca para qualquer posição na superfície de simulação em 3D. Conectando os Membros Neste modelo, existe apenas um objeto executador de tarefa (TaskExecuter), no entanto, nós também queremos incluir o Rack como uma barreira. Faça um conexão com o 'A' entre o AStarNavigator e o operador. Isto pode ser feito mantendo a tecla A pressionada e clicando/arrastando do AStarNavigator para o operador, ou do operador para o AStarNavigator (não importando a ordem ou sequência de onde tem que partir a conexão). Um círculo em azul irá aparecer abaixo do operador. Faça uma conexão com o 'A' entre o AStarNavigator e o Rack. Um retângulo em azul irá aparecer abaixo do Rack. Adicione um Source e um Queue próximo ao operador conforme você pode visualizar em outra imagem mais abaixo. Criando Barreiras (Barriers) Junto com o Rack, vamos também criar um par de barreiras para representar paredes ou obstáculos que o operador não pode caminhar através. Clique no ícone do Divider na biblioteca para entrar no modo de criação. Clique em algum lugar ao lado direito do Queue (buffer) para criar um novo Divider. Clique duas vezes mais próximo dos pontos para mostrar a imagem abaixo para finalizar o Divider. Clique com o botão direito do mouse para sair do modo de criação. Adicione os Processors e um Sink conforme imagens abaixo. Faça a conexão deste o Source até o Sink usando a conexão com “A”. Clique sobre o ícone Barrier na biblioteca para entrar no modo de criação. Clique uma vez onde o canto esquerdo inferior do Barrier estará como mostrado abaixo. Clique novamente no canto direito superior para completar a configuração do Barrier. Clique com o botão direito para sair do modo de criação. Coloque o Barrier abaixo do Rack. Execute o Modelo Você pode agora resetar e executar o modelo para ver como será a performance do operador. Lembre-se, se você fizer qualquer mudança nas suas barreiras, o modelo obrigatoriamente deve ser resetado antes de ser executado novamente. Note que o operador encontrou o menor caminho para movimentar-se por cima e por fora do Divider. Embora exista diversas formas de alterar os caminhos do operador (por exemplo, estender ainda mais o tamanho do Divider), nós iremos modificar o caminho percorrido pelo operador, usando o Preferred Path. Crie Preferred Paths Preferred paths não são caminhos “configuráveis”, em vez disso, dará aos nodes associados com o caminho preferido, um peso maior no algoritmo de busca. Isso vai nos afetar, e puxar o operador para o caminho preferido. Clique sobre o ícone Preferred Path na biblioteca para entrar no modo de criação. Crie os dois seguintes Preferred Paths conforme mostrado na imagem abaixo. Preferred paths são unidirecionais e além do mais precisa ser posicionado no layout na ordem correta. Clique com o botão direito do mouse para sair do modo de criação. Execute o Modelo Resete e execute o modelo. Se o seu operador continuar a movimentar para cima e fora do Divider, você pode ou movimentar o Preferred Path ou alterar o Preferred Path weight na janela de propriedades do objeto AStarNavigator. Os Resultados do seu modelo podem variar deste exemplo conforme você posiciona suas barreiras e objetos, o que pode fazer a diferença no cálculo dos caminhos do operador. AStar Navigator Library O AStar é acessado na Biblioteca principal a esquerda: View Menu / Drag-Drop Library Existem 5 tipos de barreiras usada pelo A* Navigator. Estas barreiras modificam a grade usada no algoritmo de busca. Nota: Uma vez que as barreiras são criadas ou modificadas, o modelo precisa ser Resetado para recalcular o node table. Solid Barrier A mais simples das barreiras, a barreira sólida modifica a grade para remover uma área retangular, prevenindo os membros de viajar e (travel members) se movimentarem dentro da barreira. Divider Dividers desconectam os nodes ao longo de seu caminho, prevenindo os travel members de atravessarem o divider. Dividers podem ser modificados na superfície de simulação 3D ao arrastar o ponto final e intermediário. Qualquer número de pontos pode ser adicionado ao divider. One-Way Divider O One-way divider funciona de forma muito similar ao divider, no entanto, travel members são permitidos se movimentarem através do divider na direção das flechas em verde, neste caso, em direção ao topo da página. O one-way dividers pode ser modificado na superfície de simulação em 3D ao arrastar os pontos finais ou intermediários. Qualquer número de pontos podem ser adicionados em um one-way divider. Preferred Path Embora o preferred path não é uma barreira real, ele funciona da mesma forma que as barreiras fazem para modificar a tabela de nodes do A* Navigator. Em vez de modificar os nodes removendo os seus indicadores de direção, o caminho preferencial dá um peso maior a todos os nós associados com o percurso. Este valor de Path Weight pode ser alterado através da janela de propriedades do A * Navigator. O Path Weight tem de ser maior do que 0 e menor que 1, a fim de funcionar adequadamente. Valores acima ou abaixo deste podem causar resultados não intencionais. Os preferred paths podem ser modificados na visualização em 3D, arrastando os pontos do fim ou do meio. Preferred paths são unidirecionais. Qualquer número de pontos pode ser adicionado a um preferred path.
View full article
O artigo "Using Fixed Resource Process Flows" que descreve algumas funções do Fixed Resource Process Flow tem um modelo de exemplo. O exemplo está em anexo e mostra como podemos utilizar do Fixed Resource Process Flow para multiplicar lógicas de fluxo e de trabalho. Esse representa uma área de despacho de produtos onde o produto vem de um estoque transportado pelo empacotador (Packer) e é preparado em uma paleteadora. Depois o produto é levado em lotes pelo empacotador para uma estação e dali ele vai ser despachado pelo carregador (Shipper). A função do Fixed Resource Process Flow facilita a replicação da lógica dessas paleteadoras e dos funcionários envolvidos. Alguns teste como se aumentássemos o número de recursos conseguiríamos suprir melhor a demanda podem ser realizados por esse recurso. Nesse artigo descreveremos o passo a passo desse modelo. A descrição segue no arquivo exemplo FR Flow em anexo.
View full article
Cycle time per process.fsm Cuando creamos modelos de simulación en ocasiones nos limitamos a modelar un proceso o un numero de parte, en el cual tenemos problemas. Pero ¿Qué pasa cuando corremos un plan de producción completo con distintos números de parte, que ha su vez corren a diferente tiempo ciclo? Este es una manera que permite correr diferentes números de parte en diferentes procesos tantos como tu desees, cada uno con su tiempo ciclo. ¿Qué necesitamos? 1.- Etiqueta en cada ítem que identifique que numero de parte es. Por ejemplo Label: IDpart Value: ABC12 2.-Etiqueta en cada máquina que identifique el proceso que este corre. Por ejemplo Label: Station Value: Processor1 3.- Tabla global que contenga en las columnas los diferentes procesos que tienes en tu línea de producción y en los renglones los diferentes números de parte que pueden correr en tu línea. La información que contenga esta tabla será referente a los tiempos de ciclo de cada numero de parte en cada proceso. Por ejemplo: Processor1 Processor2 Processor3 ABC12 20 10 13 BAC21 11 30 20 4.-Deberas configurar el tiempo de procesamiento de tu processor haciendo referencia a tu tabla global y colocando lo siguiente: Con esto, obtendremos estadísticos ponderados de utilización para los equipos. Beneficios: Puedes correr diferentes números de parte en una misma línea con su respectivo tiempo ciclo cada una. Utilización de equipos y operadores mas exacta. Modificar tiempos ciclos en una tabla global es más fácil y controlado que directo en los procesos. Cálculo de capacidad de tu línea más exacta corriendo un plan de producción real. Puedes agregar y quitar procesos o incluso modificar el flujo de tu línea sin afectar el tiempo de ciclo que corra ese procesador. Ya que esta referenciado por su etiqueta a la tabla global.
View full article
RailWorks 25.0.1 is now available (19 March 2025). This version of RailWorks is intended for use with FlexSim 2025. 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 developmentbrflexsim@flexsbr.com.br. Rail Network: New feature in RailWorks The Rail Network feature provides users with an intuitive and efficient way to design and connect railway systems. With a user-friendly interface, this tool enables seamless track placement, automatic node linking, and real-time validation to ensure smooth rail operations. Users can quickly define routes, junctions, and stations while leveraging smart snapping and alignment aids to simplify complex track layouts. This feature is designed for both beginners and advanced users, offering powerful tools to build scalable and efficient rail networks with minimal effort. New Speed Table: New feature in RailWorks Offering more speed possibilities to configurate all the movement parameters, the new speed table covers all movement speeds, acceleration and deceleration parameters, making the model more plausible and adherent to the real world process. About Railworks The FlexSim Brazil RailWorks module consists of premade custom objects, designed to represent a real environment for the Rail problem modeling, with less configuration. Our approach is to unite 3D modeling with the Process Flow functionality, allowing object configuration and visualization through the native 3D FlexSim solution, and the rail system events to be triggered by the Process Flow, using not only defaults FlexSim Process Flow activities, but also new ones developed by our team. Release Notes View the full release notes in the online documentation. RailWorks 25.0.1 (19 March 2025) Features Feature: Rail Network A new way to create and connect your rails into the model. Simple as network nodes, now you can connect the RailNetwork nodes and easily create your own rail tracks. Feature: New Speed table Offering more speed possibilities to configurate all the movement parameters, the new speed table covers all movement speeds, acceleration and deceleration parameters, making the model more plausible and adherent to the real world process. Bug-Fixes Fixed moveWagon auto decouple operation. Fixed a bug where SendToPortal was not freeing rails. RailWorks 24.2.7 (17 January 2025) Bug-Fixes Fixed moveWagon auto decouple operation. Fixed a bug where SendToPortal was not freeing rails. RailWorks 24.2.6 (17 October 2024) Bug-Fixes Improved couple and decouple internal operations. Improved offset calculations internal operations. Fixed a bug where all flowItem classes was the same in different stations. Fixed a bug with passenger locomotive. RailWorks 24.2.5 (25 September 2024) Bug-Fixes Fixed a bug on creating Station object.
View full article
Requirements FlexSim 25.0 or later (found in the downloads page) NVIDIA's Omniverse USD Composer Background Historically, users have used USD Stages in FlexSim to create a live connection with an Omniverse application to be able to simulate animations in Omniverse. However, this relies on a live connection between FlexSim and Omniverse. Sometimes this type of connection is sub-optimal for a user's situation. This article will explain a workflow for writing animation data to a USD file to play in an Omniverse application independent from FlexSim. Disclaimer All the data we record during this example is meant to help us write meaningful data into a .usd file so we can generate an animation in USD Composer. When I say "animation", I mean positional and rotational data along with showing/hiding flowitems. If you want to see Operator Skeletal Animations, I'll post a similar article with a few tweaks later to showcase how to do that using USD Composer's Sequencer, which uses Tracks and Asset Clips to handle small-scale skeletal animations. Example Model I've built a sample model demonstrating the changes to the USD API and how to use them. This example model is just one way to use the API -- there are other ways that users are free to explore. example_model.zip Explaining the Model When you open the model, you'll see a few different windowpanes. In the top-right corner, you'll see a Global Table. If you reset the model, you'll see column headings appear. Each column is a different piece of data we'll be writing to the USD Stage. Each row is a different entry of data to write. In the center views, you'll have a 3D view on the left side and a Process Flow (PF) on the right. At the bottom, there's a script window with a few lines of code. Those lines of code are User Commands I defined to summarize the functionality they encapsulate. The 3D View In the 3D view, you should see some queues, processors, operators, and conveyors. This is a simple workflow where items come into the queues, operators move them into the processors for processing, and then the operators send them down the conveyor lines. With this model, we'll demonstrate (1) operator movement and (2) flowitem movement on conveyors. Setting Up the USD Stage There should be a "USD Stage1" present in the model. If you click on the USD Stage, its properties will appear on the right-side of the screen. In it, you'll see a blank edit field. This is where you put the path to the USD file you want to work on have appear. If you want to save a fresh one, while the edit field is blank, click the "Save" icon next to it. Once you select where you want to place the file, name it, and close the file explorer popup, the edit field should populate with the full path to the .usd file. For more info, you can check out the docs page on the USD Stage object. Viewing the Model in USD Composer Once you've saved your USD Stage, you can open the .usd file in any software that can view .usd files. For this demonstration, we'll be using NVIDIA's Omniverse application which as a USD Composer module. The Process Flow Open up the Process Flow tab to view the simple setup. I'll walk through each part of the PF to give you an idea of how it works. Operator Movement This block of PF is in charge of recording information about Operator positions and rotations. It records information whenever an Operator starts and ends a task. You can expound on this concept and record information when specific triggers or events happen, but for this example I kept it simple and record when any task happens. User Command: RecordInfoToTable Within the "Record Info" Activity, it calls a User Command to record information to the table. This function simply takes a token as the first parameter. This is what the code looks like: Token token = param(1); // Setup row for this iteration Table animInfo = Table("AnimationInfo"); animInfo.addRow(); int curRow = animInfo.numRows; token.labels.assert("Row", 1).value = curRow; animInfo[curRow]["Object"] = token.operator; animInfo[curRow]["AnimTime"] = Model.time; animInfo[curRow]["TaskType"] = token.taskType; // Record positional and rotational data Object operator = token.operator.as(Object); animInfo[curRow]["PosX"] = operator.location.x; animInfo[curRow]["PosY"] = operator.location.y; animInfo[curRow]["PosZ"] = operator.location.z; double Z = Math.fmod(operator.rotation.z, 360); if (Z < 0) Z += 360; animInfo[curRow]["RotX"] = operator.rotation.x; animInfo[curRow]["RotY"] = operator.rotation.y; animInfo[curRow]["RotZ"] = Z; To summarize: Start by assigning the value of the token (parameter 1) to the local variable "token" We get a reference to the Global Table (AnimationInfo) and add a row for the data we're about to write Record (1) which operator this data is for, (2) what time this is happening, (3) and the type of task they're performing. The task type isn't as important - it's for finer details and debugging if necessary. Then we record the positional data of the operator. We previously saved the "operator" label onto the token, so we can use that and "cast" it to be an Object. We do this because the Object class has a "location" property which holds the x, y, z coordinates of the object. Lastly, we do the same thing with "rotation", except we need to bound the rotation to be a positive number between 0 and 360. To do this, we call Math.fmod() to get the reminder after dividing by 360. If the value is negative, we add 360 to get a positive value. Running the Model If you reset and run the model to the stop time at 200, you'll see the Global Table populate with data. There should be valid data for all the columns except the last 3. The "BoxNum", "EntryConveyor", and "Show" columns are for recording flowitem data. We'll discuss that later. Once you've got data in the table, we can run the User Commands in the script window at the bottom of the screen. They should be: ClearTimestampedData(); return WriteToUsd(); The first one "ClearTimestampedData()" is used to loop through the operators and clear all their time-sampled data. We do this so no old data is used if you change things in the FlexSim model and export new data. The second one "WriteToUsd()" is what reads the Global Table line by line, defines and finds prims, writes time-sampled data to them, and saves the information to the .usd file. View the Animation in USD Composer After running these scripts, you should get a prompt in USD Composer to "Fetch Changes". Fetch the changes. Then, open the Timeline feature (Window > Animation > Timeline). This opens an animation timeline at the bottom of the screen. You can save predefined start and end times for the whole stage using the Flexscript API if you choose. Otherwise, you can change the settings manually in USD Composer. (I've color-coded the image below to help explain the tool.) On the far-left (green circle) is the starting frame of the animation while the far-right (red circle) is the ending frame. The inner numbers allow you to set specific sections of the animation to play. If not set, it will play the whole animation. The top-right value and blue "scrubber" (blue circle and arrow) denote the current frame. When you hit your space-bar (or click the "Play" button), that scrubber should move. The value next to FPS (yellow circle) represents the "Frames per Second" the animation runs at. If you want it to play faster, then you can set it to a higher FPS. Note that this example model is built assuming 24 FPS. There is a User Command "TimeToFPS" that simply multiples the given Model time by a desired FPS, defaulting to 24 FPS. If you want to change that rate, you can set it in the code. Now that we've got the animation timeline setup, hit play and watch the animation. You may need to adjust the animation range to be 850 to 4800 so you can see the movements. Like I mentioned in the Disclaimer, if you want to see skeletal animations in the Operator, I'll have another article explaining how to add that functionality. Add Flowitem Movement on the Conveyor Let's go back to FlexSim and check out the Process Flow again. I have two other containers labeled "Box Movement: Time-based" and "Box Movement: DPs". These flows represent two different ways to record this data: either based on a time interval or based on Decision Point positions. The time-based way can be more accurate, but it adds much more time-sample data than the DP version. Choose one of the versions to test out, open the properties of their Source, and then Enable it. If you reset and run the model, you'll start seeing entries for Flowitems. They'll utilize the last 3 columns of the Global Table to keep track of (1) the Box# they are, (2) the Conveyor they entered on, and (3) whether or not to "show" their prim. Click here to learn more about prim visibility. Run the scripts to export and save the model. Then, fetch and view the changes in USD Composer. Conclusion We've covered how to use some of the new features of the USD API in FlexSim 25.0 to create stand-alone animations in .usd files. We used FlexSim to record and export data to .usd files to then display in USD Composer. You can now play a standalone animation in USD Composer without a live connection to FlexSim.
View full article
Top Contributors