Skip to content

Latest commit

 

History

History
482 lines (349 loc) · 21.5 KB

README.md

File metadata and controls

482 lines (349 loc) · 21.5 KB

Material Flow Plugin for the PFDL

mf_plugin_logo

DISCLAIMER: This project is not intended for everyday use and made available without any support. However, we welcome any kind of feedback via the issue tracker or by e-mail.


The Material Flow (MF)-Plugin is a plugin for the Production Flow Description Language (PFDL) Domain Specific Language. It enables the user to describe advanced transportation tasks included in a material flow. Such a material flow consists of 1..N transport orders. A transport order represents an operation of a pickup of a good at location A and a delivery of the good at a dedicated location B. In general, a transport order can be executed by a human, by an automated guided vehicle (AGV), an autonomous mobile robot (AMR), or in collaborative mode. In the following, the executor/executing entity will be addressed in general with mobile robot (MR).

This repository contains the grammar specification for the MF-Plugin and provides an own scheduler that supports the extended syntax. The grammar is realized with the help of ANTLR.

Table of Contents

MF-Plugin grammar extension

The MF-Plugin extends the PFDL to enable the definition of transports in a declarative way. It contains

All of the additionally defined grammar contained in the MF-Plugin can be used aside the grammar and functionalitites the PFDL defines. Therefore, the MF-Plugin comes with an own Scheduler, which expands the PFDL Scheduler by adding some new functionalities and editing/overwriting some others. A mainTask is always required to contain the main program (like the productionTask for pure PFDL programs).

Intralogistic Primitives

The MF-Plugin contains of predefined structs describing intralogistic primitives, that are essential in the domain of intralogistics. Currently three primitves exist in the context of the MF-Plugin:

Note that each created Struct in the context of the MF-Plugin will automatically have an id and time parameter assigned that can be accessed, e.g., for comparisons. Therefore each Struct will have the following structure:

Struct <Struct name>
    id: string
    time: number
    <additional attribute definitions>
End

For simplicity, the two base attributes are not shown in the following Struct definitions and can be left out when defining own Struct definitions.

Location

A transport is a movement of goods placed in a container (or bin) from one location to another location. In the MF-Plugin, a Location is defined as follows:

Struct Location
    type: ""
End

Inside a program using the MF-PLugin syntax, an instance of Location can directly be used without declaring the Struct manually. See an example below. Note that the field id is not required and will be set automatically if no value is passed (as time as well).

Location goodsPallet
    id: "productionArea_palletPlace"
    type: "pallet"
End

Location warehousePos1
    id: "warehouseArea_pos1"
    type: "pallet"
End

Figure 1 illustrates this Scenario.

Figure 1: Production hall with two Locations.

Event

Sometimes it is necessary to determine the flow control, for example, when an action depends on an interaction with an user or a physical sensor. The primitive Struct Event is introduced to represent those dependencies, which is defined as follows:

Struct Event
    value: boolean | number | string
End

The value represents the event status and can be either a boolean, a number or a string. See an example of an Event manualLoadingConfirmation below. The Event's value here might be set to true after a button was pressed to confirm that a mobile robot has been loaded.

Event manualLoadingConfirmation
    id : "buttonMRIsLoaded"
    value : false
End

Time

The primitive Time is linked to the UNIX cron job time. This primitive enables the scheduling of a Task in the future.

Struct Time
    timing: string # Unix crontab Format
    value: bool # is set to true if the time in timing was reached
End

A Task's time of execution can, for example, be set to 6:30am by creating a Time instance like startOfProduction in the example below and passing it to the Task. The value of startOfProduction will be set to true when the wanted timestamp is reached.

Time startOfProduction
    timing: "30 6 * * *"
    value: false
End

Additional Task options

With the MF-Plugin, the Task functionality is expanded. Beneath Tasks and Services, any number of Order statements can be called from inside a Task. With the help of Orders, a Task in the MF-Plugin is able to describe that an item should be picked up at some location and be delivered to another location.

The example below builds upon the two Locations which were defined through goodsPallet and warehousePos1. To transport a good from goodsPallet to warehousePos1, two TransportOrderSteps, which define the corresponding location, are needed. Each TransportOrderStep is then included in the Task’s Transport statement. See Figure 2 for an illustration of the MF-Plugin code.

TransportOrderStep loadGoodsPallet
    Location: goodsPallet
End

TransportOrderStep unloadGoodsPallet
    Location: warehousePos1
End

Task transportGoodsPallet
    Transport
    From    loadGoodsPallet
    To      unloadGoodsPallet
End

Figure 2: A simple Transport with one pickup location.

There are also some additional options that can be defined once in a Task. These statements are:

  • StartedBy
  • FinishedBy
  • Constraints

The StartedBy and FinishedBy statements are able to restrict the start or finish of a Task, respectively, depending on a passed condition. This could either be the truth value of a Time instance or an expression that might be realized by a Rule. Note that the mainTask ignores these statements because it is meant to be wrapped around the whole program.

See an example of a Task taskWithEvent that contains a StartedBy statement that is linked to the Event manualLoadingConfirmationdescribed here. The Task is started after the condition was met, which happens by pressing the button connected to the Event. An illustration of this logic can be found in Figure 3.

Task taskWithEvent
    StartedBy manualLoadingConfirmation.value

    Transport
    From loadGoodsPallet
    To unloadGoodsPallet
End

Figure 3: A transportation Task that is started when a specific Event is triggered.

Transports that need to fulfill certain constraints can be defined with the help of the Constraint keyword. In the following example, a time span is defined using the JSON inline syntax. Here the transport should take place in the period from 14:05 to 14:45pm. This restriction is taken into account during the order assignment, either by the process itself, or by the MRs that apply for the order.

Task transportGoodsPallet
    Transport
    From        loadGoodsPallet
    To          unloadGoodsPallet

    Constraints: {"TransportStart" : "05 14 * * *", "TransportFinished" : "45 14 * * *"}
End

Orders

In the simplest form, a Task in the MF-Plugin describes that an item should be picked up at some location and be delivered to another location. Furthermore, actions can be executed at specified locations. There are three additional operations available in a Task to tell a mobile robot what to do: Transport, Move and Action.

A Transport Order (indicated by the Transport keyword) is made up of at least two TransportOrderSteps. A TransportOrderStep inherently consists of a Move Order or an Action Order or both. A Move Order is defined as the movement from the current location to a specific destination. An Action Order is defined as an action of manual or automatic loading or unloading of a mobile robot.

To allow more flexibility, besides the Transport, there also exist a Move and Action statement, representing the Move and Action Order. However, these statements can only appear in a Task after a Transport was executed. Otherwise, for example with only an Action Order in a Task, it would make no sense that a random MR executes an action, as this Action in general depends on a specific Location, which might not be similar to the MR's location. Instead, each Transport, Action or Move included in a Task is meant to be executed by the same mobile robot. To provide coherence, a MoveOrderStep and ActionOrderStep is included, which works like the TransportOrderStep.

Transport Order

A Transport Order is indicated by the Transport keyword and consists of at least one TransportOrderStep describing the pickup Location and exactly one TransportOrderStep for the delivery Location. Additional options are also possible for one TransportOrderStep, as explained here. For the pickup indicated by the From keyword, multiple TransportOrderSteps are also possible. The syntax looks like the following:

Transport
From        {transportOrderStepPickup1, ..., transportOrderStepPickupN}
To          {transportOrderStepDelivery}

See an example of a Task transportGoodsPallet describing a Transport Order containing two pickup TransportOrderSteps below:

Location goodsPallet2
    id: "productionArea_palletPlace"
    type: "pallet"
End

TransportOrderStep loadGoodsPallet
    Location: goodsPallet
End

TransportOrderStep loadgoodsPallet2
    Location: goodsPallet2
End

TransportOrderStep unloadGoodsPallet
    Location: warehousePos1
End

Task transportGoodsPallet
    Transport
    From    loadGoodsPallet, loadgoodsPallet2
    To      unloadGoodsPallet
End

Note, that the order of the pallets inside the From statement is not necessarily the pickup order. The solution of this problem is solved internally, by a so called execution engine. It is only important to define the pickup locations, respectively where the goods should be transported to and not how it is done. In the example scenario shown in Figure 4, goodsPallet2 is visited before goodsPallet by the MR.

Figure 4: A Transport with two pickup locations.

Move Order

A Move Order is called by the Move keyword and takes only one MoveOrderStep to set the Location for the mobile robot to drive towards.

Move
To {moveOrderStep}

As mentioned, a Move Order can only appear in a Task if there was at least one Transport Order (and therefore a MR assigned) before. See an example below. Here, the mobile robot that executes the transport in transportGoodsPallet should drive to a specific parking location afterwards. The following program is illustrated in Figure 5.

Location parkingPos
    id: "parkingPos_1"
End

MoveOrderStep moveToParkingPos
    Location: parkingPos
End

Task transportGoodsPallet
    Transport
    From        loadGoodsPallet
    To          unloadGoodsPallet

    Move
    To          moveToParkingPos
End

Figure 5: A Transport with an additional Move Order.

Action Order

An Action Order can be used to specify an Action that the MR should perform at its current position. An ActionOrderStep is necessary for that.

Action
Do {actionOrderStep}

As for the Move Order, an Action Order can only appear in a Task if there was at least one Transport Order (and therefore a MR assigned) before. In the example below, the MR is instructed to load a specific pallet at the Location of unloadGoodsPallet by using an Action statement.

ActionOrderStep loadAdditionalGood
    Parameters: {"load": "pallet2"}
End

Task transportGoodsPallet
    Transport
    From        loadGoodsPallet
    To          unloadGoodsPallet

    Action
    Do          loadAdditionalGood
End

OrderSteps

OrderSteps are used to specify the Order statements Transport, Move and Action. For each of them, there exists an OrderStep with different options for the specific usecase. Additionally, each OrderStep type can also optionally contain a StartedBy and FinishedBy statement, which work as for a Task. Furthermore, an OnDone statement can be defined once per OrderStep. This statement takes a Task name. The corresponding Task is executed when the OrderStep containing the OnDone statement finishes. With that use, more complex material flows can be realized. Note that the MR that is assigned to a possible followUp Task defined in the OnDone statement does not have to be the same as the one that executes the original Task.

TransportOrderStep

A TransportOrderStep (TOS) is mainly described by a Location (representation of a Move Order) and optionally the action to be performed there. Here, the optional statement Parameters is used to define or specify the execution of an action. For example, this action could be either loading at a source or unloading at a sink. This corresponds to an Action Order, which is the execution of a specific action at the current position.

TransportOrderStep {name}
    # required
    Location: {Instance_Location}

    # optional
    Parameters: {json_object, expression}
    StartedBy: {Rule(...), expression}
    FinishedBy: {Rule(...), expression}
    OnDone: {Task} # follow up task
End

The following example Task transportgoodsPallet2 consists of two TransportOrderSteps. The TransportOrderStep loadGoodsPallet defines a Location (required) and an optional FinishedBy condition that has to be fullfilled before the Task can be continued. unloadGoodsPallet contains an optional Parameters statement to specify the exact pallet where to unload the goods, here the second one.

Event mrLoaded
    value: false
End

TransportOrderStep loadGoodsPallet
    Location: goodsPallet
    FinishedBy: mrLoaded.value
End

TransportOrderStep unloadGoodsPallet
    Location: warehousePos1
    Parameters: {"palletNumber" : 2}
End

Task transportgoodsPallet2
    Transport
    From loadGoodsPallet
    To unloadGoodsPallet
End

The scenario is depicted in Figure 6.

Figure 6: A Transport with two TransportOrderSteps, one with a FinishedBy option and one with a Parameters statement to explicitly define the pallet where to unload the goods.

MoveOrderStep and ActionOrderStep

The MoveOrderStep and ActionOrderStep are defined similarly to the TransportOrderStep. The only difference is, that a MoveOrderStep do not contain a Parameter statement and the ActionOrderStep do not contain a Location statement and needs to specify a Parameter statement instead. See the definitions below.

MoveOrderStep {name}
    # required
    Location: {Instance_Location}

    # optional
    StartedBy: {Rule(...), expression}
    FinishedBy: {Rule(...), expression}
    OnDone: {Task} # follow up task
End
ActionOrderStep {name}
    # required
    Parameters: {json_object, expression}

    # optional
    StartedBy: {Rule(...), expression}
    FinishedBy: {Rule(...), expression}
    OnDone: {Task} # follow up task
End

Rules

With the help of Rules, the values of instances can be evaluated in a more advanced manner. It enables an event-driven program control with more comprehensive expressions. Within Rules, the logical operators for comparisons (<, ≤, ==, !=, ≥, >) and concatenation (AND, OR, NOT(represented by !)), as well as the mathematical basic arithmetic operations (+, -, ∗, /) can be used. Dependencies, sequences or even temporal properties can be realized by using Rules. Expressions in Rules are only evaluated, so the values are not changed. If all expressions within a rule evaluate to true the value true is returned, otherwise this rule is invalid and false is returned. Moreover, a Rule call can also consist of other Rules.

Parameters or default values can be passed into a Rule. The following example has the three parameters event1, event2 and offset. The first two parameters have to be passed at runtime while the third, if it is not assigned a value manually, is assigned a default value (here 0).

Rule beforeWithOffset(event1, event2, offset = 0)
    (event1.time + offset < event2.time) And (event1.value == 5)
End

Note that, if there are several expressions in multiple lines, it is implicitly assumed that all expressions of the Rule are linked with an AND. The Rule beforeWithOffset2 defined in the following example is equivalent to the previously defined Rule beforeWithOffset.

Rule beforeWithOffset2(event1, event2, offset = 0)
    event1.time + offset < event2.time
    event1.value == 5
End

Installation

As this plugin is specified to complement the PFDL, the code needs to be inside the plugins directory of the PFDL Scheduler. The MF-Plugin scheduler can then be accessed via the following commands:

import pfdl_scheduler.plugins as plugins

mf_plugin_scheduler = plugins.load("mf_plugin.mf_plugin.scheduler", "pfdl_scheduler")

You can find a full demonstrator of the MF-Plugin Scheduler here. Note that this file has to be placed on top of the project structure (of the PFDL repository) in order to work as expected. Please also have a look at the several example files that use the MF-Plugin grammar!

Requirements

All requirements are listed in requirements.txt and can be installed via pip install -r requirements.txt.

Generate ANTLR files from the grammar

After changing the MF-Plugin grammar, you will need to regenerate the respective generated ANTLR classes (Lexer, Parser, Visitor and Listener) from the grammar specification:

Make sure to first install ANTLR correctly. Follow the guide on the official ANTLR site to install it. To generate the Lexer and Parser with an additional visitor as Python classes, run the following command inside the grammar directory:

antlr4 -v 4.9.3 -Dlanguage=Python3 -visitor PFDLLexer.g4 PFDLParser.g4

Now, the generated classes can be used within a Python script. Within the original project structure, it is necessary to move/copy the generated files into the mf_plugin/parser directory.

Unit and Integrationtests

The project uses a pipeline to run different unit and integration tests. If you want to execute the tests locally, run it via VSCode (Python Extension) or via the following command in the projects root directory (in the PFDL directory):

python3 -m unittest discover -v

This will give a detailed overview over all test results. If you want to run the test isolated use something like the following:

python3 -m unittest discover -v pfdl_scheduler/plugins/mf_plugin/tests

License

Material Flow (MF)-Plugin is licensed under the MIT License. See LICENSE for details on the licensing terms.

Academic Attribution

If you use the MF-Plugin for research, please include the following reference in any resulting publication.

@INPROCEEDINGS{10710795,
  author={Gödeke, Jana and Horstrup, Maximilian and Detzner, Peter},
  booktitle={2024 IEEE 29th International Conference on Emerging Technologies and Factory Automation (ETFA)}, 
  title={Towards a Unified Flow Description Language for CPPSs: An Example with Material Flows}, 
  year={2024},
  volume={},
  number={},
  pages={1-8},
  keywords={Concurrent computing;Production systems;DSL;Synchronization;Manufacturing automation;Domain specific languages;Convergence;Logistics;Cyber-Physical Production System;Domain-Specific Language},
  doi={10.1109/ETFA61755.2024.10710795}}