13 minute read
During the production process a lot of data is generated (e.g., process values like temperature or images), but typically not linked to specific products. When investigating product returns, one needs to gather data from various data sources to understand what exactly happened, which might take so much time that it is not done at all.
The life would be much easier for a quality inspector if he would be able to enter the ID of the defect product and then receive all related information to it - from temperatures during the production to test results to product images.
Solution: We’ve expanded the United Manufacturing Hub so that the end-user only needs to do two things:
To allow this to happen the backend has been modified to support multiple new MQTT message types in mqtt-to-postgresql and to provide more endpoints to fetch Digital Shadow related data from the database factoryinsight.
(right click on the image and open it for a better resolution)
This is the overview of the digital shadow concept. It follows the general design principles of the United Manufacturing Hub by sending all raw sensor data first to an MQTT broker and then continuously processing it.
The following chapters are going through the concept from left to right (from the inputs of the digital shadow to the outputs).
Data sources are connected by sending their data to the central MQTT broker. UMH recommends to stick to the data definition of the UMH datamodel for the topics and messages, but the implementation is client specific and can be modeled for the individual problem.
This example is acquired using barcodereader
Topic: ia/rawBarcode/2020-0102/210-156
Topic structure: ia/rawBarcode/<transmitterID>/<barcodeReaderID>
{
"timestamp_ms": 1588879689394,
"barcode": "1284ABCtestbarcode"
}
Now the information is available at the MQTT broker because of that to all subscribed services.
In the next step this raw data is contextualized, which means to link it to specific products. To identify a product two different type of IDs are used: AID’s and UID’s (identifiers are later explained in detail).
The raw data from the data sources needs to be converted to four different MQTT message types:
To do that we recommend writing microservices. You can do that either in Node-RED (our recommendation) or in a programming language of your choice. These microservices convert messages under a raw
topic into messages under processValue or processValueString.
This typically only requires resending the message under the appropriate topic or breaking messages with multiple values apart into single ones.
The goal is to convert messages under the processValue and the processValueString topics, containing all relevant data, into messages under the topic productTag, productTagString and addParentToChild. The latter messages contain AID’s which hold the contextualization information - they are tied to a single product.
The implementation of the generation of the above mentioned messages with contextualized information is up to the user and depends heavily on the specific process. To help with this we want to present a general logic and talk about the advantages and disadvantages of it:
Example of generating a message under productTagString topic containing the measured torque value for the Example process:
{
"timestamp_ms":
"AID":
"name": "torque",
"value":
}
{
"timestamp_ms": 13498435234,
"AID":
"name": "torque",
"value": 1.458
}
{
"timestamp_ms": 13498435234,
"AID": "34258349857",
"name": "torque",
"value": 1.458
}
Now the container is full: send it away.
Important: always send the uniqueProduct message first and afterwards the messages for the related productTag/productTagString and messages on the addParentToChild topic.
Pro | Con |
---|---|
simple | not stateless |
general usability good | might need a lot of different containers if the number of e.g. productTag messages gets to big |
The explaination of the IDs can be found in the UMH datamodel (especially the definition of the terms AID and UID)
If we can move a product from point “A” in the production to point “B” or back without causing problems from a process perspective, the UID of the product should stay the same. (For example if the product only gets transported between point “A” and “B”).
If moving the object produces problems (e.g. moving a not yet tested object in the bin “tested products”), the object should have gotten a new UID on its regular way.
Even though testing a product doesn’t change the part itself, it changes its state in the production process:
-> Make a new UID.
Monitored Transport from China to Germany (This would be a significant distance: transport data would be useful to include into digital shadow)
-> Make a new UID
Type | creation UID | death UID |
---|---|---|
without inheritance at creation | topic: storage/uniqueProduct | /addParentToChild (UID is parent) |
with inheritance at creation | topic: <asset>/uniqueProduct + addParentToChild (UID is child) | /addParentToChild (UID is parent) |
MQTT messages under the productTag topic should not be used to indicate transport of a part. If transport is relevant, change the UID (-> send a new MQTT message to mqtt-to-postgresql under the uniqueProduct topic).
Assembly Station 1:
MQTT messages to send at Assembly 1:
uniqueProduct message for ProductA origin, with asset = storage, under the topic:
ia/testcustomer/testlocation/storage/uniqueProduct
{
"begin_timestamp_ms": 1611171012717,
"end_timestamp_ms": 1611171016443,
"product_id": "test123",
"is_scrap": false,
"uniqueProductAlternativeID": "A"
}
uniqueProduct message for ProductB origin, with asset = storage, under the topic:
ia/testcustomer/testlocation/storage/uniqueProduct
{
"begin_timestamp_ms": 1611171012717,
"end_timestamp_ms": 1611171016443,
"product_id": "test124",
"is_scrap": false,
"uniqueProductAlternativeID": "B"
}
uniqueProduct message for ProductC, with asset = Assy1, under the topic:
ia/testcustomer/testlocation/Assy1/uniqueProduct
{
"begin_timestamp_ms": 1611171012717,
"end_timestamp_ms": 1611171016443,
"product_id": "test125",
"is_scrap": false,
"uniqueProductAlternativeID": "A"
}
addParentToChild message describing the inheritance from ProductA to ProductC, under the topic:
ia/testcustomer/testlocation/Assy1/addParentToChild
{
"timestamp_ms": 124387,
"childAID": "A",
"parentAID": "A"
}
addParentToChild message describing the inheritance from ProductB to ProductC, under the topic:
ia/testcustomer/testlocation/Assy1/addParentToChild
{
"timestamp_ms": 124387,
"childAID": "A",
"parentAID": "B"
}
productTag message for e.g. a measured process value like the temperature,under the topic:
ia/testcustomer/testlocation/Assy1/productTag
{
"timestamp_ms": 1243204549,
"AID": "A",
"name": "temperature",
"value": 35.4
}
Now the ProductC is transported to Assembly Station 2. Because it is a short transport, doesn’t add value etc. we do not need to produce a new UID after the transport of ProductA.
Assembly Station 2:
Assembly Station 3:
Note that the uniqueProduct MQTT message for ProductD would not be under the Topic of Assembly2 as asset but for example under storage. The convention is, that every part never seen by digital shadow “comes” from storage even though the UID and the related uniqueProduct message is created at the current station.
If for example a batch of screws is supplied to one asset with only one datamatrix code (one AID) for all screws together, there will only be one MQTT message under the topic uniqueProduct created for the batch with one AID, a newly generated UID and with the default supply asset storage
.
The mqtt-to-postgresql microservice now uses the MQTT messages it gets from the broker and writes the information in the database. The microservice is not use-case specific, so the user just needs to send it the correct MQTT messages.
mqtt-to-postgresql now needs to generate UID’s and save the information in the database, because the database uses UID’s to store and link all the generated data efficiently. Remember that the incoming MQTT messages are contextualized with AID’s.
We can divide the task of mqtt-to-postgresql in three (regarding the digital shadow):
Use the MQTT message under the Topic uniqueProduct which gives us the AID and the Asset and make an entry in the uniqueProduct table containing the AID and a newly generated UID.
uniqueProductTable
Use productTag and productTagString topic MQTT messages. The AID and the AssetId is used to look for the uniqueProduct the messages belong to. The value information is then stored with the UID in the TimescaleDB
uniqueProductTable
for the uniqueProduct with the same Asset and AID from the productTag message (the child)Use the addParentToChild message. Retrieve the child UID by using the child AID and the Asset. Get the parent UID’s by finding the last time the parents AID’s were stored in the uniqueProductTable.
uniqueProductTable
for the uniqueProduct with the same Asset and AID as written in the child of the /addParentToChild messageuniqueProductTable
for all other assets for the last time the AID of the parent was used and get the UIDproductInheritanceTable
Possible Problems:
storage
) before.The structure of the database might be changed in the future.
Four tables are especially relevant:
uniqueProductTable
contains entries with a pair of one UID and one AID and other data.productTagTable
and productTagStringTable
store information referenced to the UID’s in the uniqueProductTable
.
Stored is everything from individual measurements to quality classes.productInheritanceTable
contains pairs of child and parent UID’s. The table as a whole thereby contains the complete
inheritance information of each individual part. One entry describes one edge of the inheritance graph.The new relevant tables are dotted, the uniqueProductTable
changes are bold in the timescaleDB structure visualization.
To make the relevant data from digital shadow available we need to provide new REST API’s. factoryinsight is the microservice doing that task. It accepts specific requests, accesses the timescale database and returns the data in the desired format.
The following function returns all uniqueProducts for that specific asset in a specified time range. One datapoint contains one childUID, AID and all parentAID’s regarding the asset. All uniqueProductTags and uniqueProductTagStrings (value and timestamp) for the childUID are returned to the same datapoint.
get /{customer}/{location}/{asset}/uniqueProductsWithTags
from <timestamp1>
to <timestamp2>
(in RFC 3999 Format).
Example Return with two data points:
{
"columnNames":
[
"UID",
"AID",
"TimestampBegin",
"TimestampEnd",
"ProductID",
"IsScrap",
"torque2",
"torque1",
"torque3",
"torque4",
"VH_Type123",
"Gasket_Type123"
],
"datapoints":
[
[
2,
"57000458",
1629807326485,
null,
15,
false,
5.694793469033914,
5.500782656464146,
5.868141105450906,
5.780416969961664,
"57000458",
"12000459"
],
[
6,
"57000459",
1629807443961,
null,
15,
false,
5.835010327979067,
5.9666619086350945,
5.425482064635844,
5.6943075975030535,
"57000459",
"12000460"
]
]
}
uniqueProductTable
within the specified time and from the specified asset.productInheritanceTable
for each of the selected UID’s.uniqueProductTable
.productTagTable
and productTagStringTable
for the in step 1 selected UID’s.This is currently not included in the stack
For the digital shadow functionality we need to give the tableau server access to the data. Because the tableau server can’t directly connect to the REST API, we need to either use a database in between, or a tableau web data connector. We were advised against the tableau web data connector (general info about tableau webdata connectors: https://help.tableau.com/current/pro/desktop/en-us/examples_web_data_connector.htm ).
Because of that we implemented a SQL database in combination with Node-RED. Node-RED requests data from the REST API in regular intervals and pushes it into the SQL database. From there on we can access the data with the Tableau server.
To test the digital shadow functionality and display its advantages we implemented the solution in a model factory.
We plan to integrate further functionalities to the digital shadow. Possible candidates are: