VDA5050 Messages with Meili FMS #
VDA5050 denfines specific json-schema for messages that can be sent or received by the robot.
Meili FMS is designed to use the information contained in the state messages to update position, battery and progress of the mission assigned to the robot. Whenever a robot attempts to alter the status of an assigned mission, we check the “orderId” to see if it’s valid, only then we will update the status of its mission. A subtask in the Meili FMS is a sub-part of a Mission, it includes an action or movement. When converting to VDA5050 order message, Meili performs a distinction between actions and movements, meaning that there are different ways of progressing a move-to-point subtask and an action subtask. These are described below.
Setting a Move-to-point Subtask in Progress #
To set a Move-to-point subtask as “in progress” we use the “nodeStates” sent from the robot and the “lastNodeId”. We check where the robot is using the “lastNodeId” and check the next nodes if they include the node which would complete the move-to-point subtask. In case the robot is manually paused, the “paused” field will be checked and the mission will appear as paused in the UI.
Orders sent from Meili include the whole path to the final node of that move-to-point subtask. Nodes that are intermediate between the starting station and the final station are denominated “intermediate” while the final node will have a unique UUID as “nodeID” that Meili uses to process the specific subtask. Once the robot starts sending the state message containing the “nodeStates” and the “lastNodeId” with “intermediate” prefix then the subtask will be set in progress.
Completing a Move-to-point Subtask #
The Meili system uses the “orderId” and “lastNodeId” to complete a move-to-point subtask: when the robot is on the final station, we expect to receive the “lastNodeId” that matches the “NodeId” of the last node in the “nodeStates” list.
As an example, here is the basic structure of an order message that contains the “orderId” and one node in the “nodes” list:
{
"headerId": 0,
"timestamp": "2019-04-30T15:07:02.698931656Z",
"version": "2.0.0",
"manufacturer": "meili",
"serialNumber": "serial_number",
"orderId": "04576bad742140f7bc76fa3a709a3674",
"orderUpdateId": 0,
"nodes": [
{
"nodeId": "66a03c63d294461d94a3b11a49189cca",
"description": "",
"sequenceId": 0,
"released": true,
"nodePosition": {
"x": 0.0,
"y": 0.0,
"theta": 0.0,
"allowedDeviationXY": 0.1,
"allowedDeviationTheta": 1,
"mapId": ""
},
"actions": []
}
]
}
The information contained in the order message can then be used by the robot to update the state message to set the progress of task in the state message sent by the robot to the FMS. When the robot is in the last node of the mission, we check that the “lastNodeId” sent by the robot matches the “nodeId” sent in the order. Impotrtant fields in the state message sent by the robot that have to match the order message are eg:
"orderId":"04576bad742140f7bc76fa3a709a3674"
and
"lastNodeId":"66a03c63d294461d94a3b11a49189cca"
Completing Action and Setting Action in Progress #
Everything other than a “move-to-point” action in the Meili system, will be sent to the robot as an action on a node. Currently a robot has to be on a station to perform an action. The status of this action is then sent from the robot in the “actionStates” field of the state message. Below is the conversion table from VDA5050 action states into Meili subtask status:
VDA5050 action state | Meili status |
---|---|
WAITING | PENDING |
INITIALIZING | IN_PROGRESS |
RUNNING | IN_PROGRESS |
PAUSED | PAUSED |
FINISHED | COMPLETED |
FAILED | FAILED |
Errors from the Robot #
The robot can also send errors which can send notifications to the user or fail a task that has been sent to the robot. The errors are sent in the “Errors” field of the state message from the robot.
The behaviour in the Meili FMS depends on the level of the error.
- WARNING: it will send a notification to the user with the information included in the error.
- FATAL: will send a notification, and fail the current task that is assigned to the robot.
Messages details #
Meili FMS uses three types of messages: “order”, “state” and “instantActions” to manage missions, robot states and traffic. Meili also provides the “factsheet” message to directly import from the robot essential information and “connection” topic to notify of an unexpected robot disconnection.
State message #
The state message is sent from the robot to the mqtt-broker and contains all the information that represent the current status and position of the robot. Not all the field defined by VDA5050 are used by Meili, the mandatory ones are shown in thr following table:
Field | Required subfield | Required by Meili |
---|---|---|
agvPosition | x, y, theta, positionInitialized | YES |
batteryState | batteryCharge | YES |
driving | YES | |
operatingMode | YES | |
serialNumber | YES | |
manufacturer | YES | |
nodeStates | YES* | |
headerId | NO | |
newBasedRequested | NO | |
paused | YES | |
timestamp | NO | |
version | NO | |
velocity | vx, vy, omega | YES |
orderID | YES* | |
orderUpdateID | YES* | |
errors | YES | |
safetyState | YES | |
actionStates | YES* | |
information | NO | |
lastNodeSequenceId | NO | |
newBaseRequest | NO | |
distanceSinceLastNode | NO | |
loads | NO |
the fields with “YES*” are applicable only after the robot has received an order and omitted when the robot is idle.
It is important to know that agvPosition, paused, driving and safetyState are essential parameters that are used by the system to check the state of the robot: when the robot is in emergency-stop no mission will be sent and the current mission will be paused. When a mission is cancelled or paused by the user directly from the UI, Meili FMS checks if the robot is responding to the command, specifically if it is driving or paused and if the actionState is updated coorectly. If the conditions are not met, the system will send the message again to make sure that it has been received by the robot.
Order message #
The order message is sent from the Meili FMS to the mqtt-client and contains information such as the “orderId”, “nodes” and “edges”. The “orderId” contained in the state message is used by Meili to update the progress of the task based on the status of the actions and the node reached by the robot. The “lastNodeId” in the state message defines what node the robot has reached.
The “auto-confirmation” setting is available for each mission, this determines if the subtasks (move-to-point or action) of a mission need to be confirmed by the user. With auto-confirmation switched off the user must confirm the subtask in the UI. If auto-confirmation is on all the nodes in the task are released when the order is sent for the first time.
instantActions message #
Instant actions are specific actions that have higher priority than the mission the robot is performing. The messages are sent on a separate topic and can be triggered by the user from the UI or by the FMS in specific situations such as traffic control and collision avoidance.
There are three types of messages currently supported by Meili FMS that are published on instantAction topic: “cancelOrder”, “startPause” and “stopPause”. The first one can be triggered by the user when cancelling/deleting a mission. The pause instant actions are possible to trigger manually by pressing the “pause” and “play” icons in the mission tab next to the mission name. The pause instant actions are also used for traffic control. When an instantAction is received, Meili FMS expect the robot to update the state message with the instantAction in the actionStates. If the state of the action is “FAILED”, Meili will send the instantAction again and will notify the user.
In addition there is a fourth type of instantAction message: “factsheetRequest” that is triggered when requesting a factsheet message
Factsheet message #
The factsheet contains basic information about a specific AGV type series. The JSON structure of the factsheet message is defined here: VDA5050 factsheet documentation.
This file is directly stored in the robot’s internal memory and contains information that can be imported directly from the robot to Meili FMS such as physical dimensions of the robot and actions that it can perform.
By clicking the “factsheet request” button in the vehicle page (click on the edit icon for the vehicle and then factsheet tab), a factsheetRequest instant action message will be sent to the robot.
The FMS expects a factsheet message to be published on the topic: meili/v2/{manufacturer}/{serial_numer}/factsheet
. Once the message is received and elaborated, the relevant fields and properties will be automatically updated in Meili FMS. This feature facilitates the process of integrating a robot in a new team/organisation.
Currently Meili imports only dimensions and action definitions which are defined in the JSON schema as:
-
"physicalParameters"
and specifically"heightMax"
,"width"
and"length"
. -
"protocolFeatures"
, specifically"agvActions"
which is a list containing theactionType
(name),actionDescription
and a list ofactionParameters
that will be used by Meili to define the actions.
Note: Actions that have the same name (actionType
) as the preset ones or as already created custom actions, will not be imported. We suggest to define theactionType
as “Robot series/category - Action name” or “Action name - Robot series/category” to avoid conflicts.
An example of factsheet message is shown in the example message. Fields that are not necessary can be left empty.
Connection message #
The connection topic is used to inform Meili FMS of an unexpected disconnection of a vehicle. During the connection of a vehicle to the Meili broker, a “Last Will Topic” and “Last Will Message” can be set up which will be published by the broker upon unexpected disconnection of the AGV. This functionality is described in the VDA5050 standard, the JSON encapsulated message fields are described here: VDA5050 connection message spec
When an unexpected disconnection happens, the FMS will cancel the current task and will set it offline. The robot, depending on its capabilities, could continue to perform the task offline on it’s own. It won’t receive any new orders as long as it is not back online. The connection topic and message can be set using different MQTT libraries. Here is an example using Eclipse paho-mqtt library in python and it has to be set before connecting to the broker.
client.will_clear()
message = {
"headerId": 0,
"timestamp": datetime.now(),
"version": "2.0",
"manufacturer": manufacturer,
"serialNumber": vehicle_uuid,
"connectionState": "CONNECTIONBROKEN"
}
client.will_set(
topic = f"meili/v2/{manufacturer}/{vehicle_uuid}/connection",
payload = (json.dumps(message, default=str)).encode('utf-8'),
qos=1,
retain=True
)
Message examples #
State message #
{
"agvPosition": {
"positionInitialized": true,
"theta": 30,
"x": 0.7,
"y": -0.5
},
"batteryState": {
"batteryCharge": 10,
"batteryHealth": 1,
"batteryVoltage": 12,
"charging": true
},
"driving": true,
"headerId": 189,
"manufacturer": "Meili",
"newBaseRequested": false,
"lastNodeId": "intermediate_node__0_1",
"manufacturer": "meili",
"nodeStates": [
{
"nodeId": "intermediate_node__0_1",
"description": "intermediate point 1 of task subtask index 0 ",
"nodePosition": {
"theta": 1.5707964,
"x": 0.7,
"y": -0.5,
"allowedDeviationXY": 0.1,
"mapId": "floor 0"
},
"released": true,
"sequenceId": 1,
"actions": []
},
{
"nodeId": "66a03c63d294461d94a3b11a49189cca",
"description": "we are in 2 Subtask of 20240801_0001 at index 0 ",
"nodePosition": {
"theta": 1.5707964,
"x": 0.8,
"y": -0.6,
"allowedDeviationXY": 0.1,
"mapId": "floor 0"
},
"released": false,
"sequenceId": 2,
"actions": []
}
],
"operatingMode": "AUTOMATIC",
"orderId": "0d9961951d3a48d4b762b6959219ff86",
"paused": false,
"safetyState": {
"eStop": "NONE",
"fieldViolation": false
},
"serialNumber": "serial_number",
"timestamp": "2019-04-30T15:07:02.698931656Z",
"velocity": {
"omega": 0,
"vx": 0.05,
"vy": 0.75
},
"version": "2.0.0"
}
Order message #
{
"headerId": 3,
"timestamp": "2019-04-30T15:07:02.698931656Z",
"version": "2.0.0",
"manufacturer": "meili",
"serialNumber": "serial_number",
"orderId": "217368b19ece4317a2abeba81ebe4937",
"orderUpdateId": 0,
"nodes": [
{
"nodeId": "intermediate_node_0_0",
"description": "intermediate point 0 of task wed subtask index 0 ",
"sequenceId": 0,
"released": true,
"nodePosition": {
"x": 4.3,
"y": -5.15,
"theta": 2.3561945,
"allowedDeviationXY": 0.1,
"allowedDeviationTheta": 1
}
},
{
"nodeId": "89bd6a888a8947e2a5fa07e697c2cc83",
"description": "we are in 2 Subtask of wed at index 0",
"sequenceId": 2,
"released": true,
"nodePosition": {
"x": 4.05,
"y": -1.75,
"theta": 0,
"allowedDeviationXY": 0.1,
"allowedDeviationTheta": 1
},
"actions": [
{
"actionType": "Pick shelf",
"actionId": "c2c78d6286fb4df5bd814a2e6ca57588",
"actionDescription": "Start detection routine and pick a shelf",
"blockingType": "NONE",
"actionParameters": [
{
"key": "shelf_id",
"value": "3"
},
{
"key": "sub_area",
"value": "4"
}
]
}
]
}
],
"edges": [
{
"edgeId": "edge_0",
"sequenceId": 1,
"released": true,
"startNodeId": "intermediate_node_0_0",
"endNodeId": "89bd6a888a8947e2a5fa07e697c2cc83",
"maxSpeed": 5
}
]
}
instantActions message #
{
"headerId": 26,
"timestamp": "2019-04-30T15:07:02.698931656Z",
"version": "2.0.0",
"manufacturer": "meili",
"serialNumber": "serial_number",
"actions": [
{
"actionType": "stopPause",
"actionId": "ea5615a50019477f9c53a88a2f90f881",
"blockingType": "HARD",
"actionParameters": []
}
]
}
factsheet message #
{
"headerId": 0,
"timestamp": "",
"version": "2.0.0",
"manufacturer": "meili",
"serialNumber": "serial_number",
"typeSpecification": {
"seriesName": "Robot series",
"seriesDescription": "This is a description of the robot series",
"agvKinematics": "DIFF",
"agvClass": "CARRIER",
"maxLoadMass": 100,
"localizationTypes": ["NATURAL"],
"navigationTypes": ["AUTONOMOUS"]
},
"physicalParameters": {
"speedMin": 0.1,
"speedMax": 3,
"accelerationMax": 1,
"decelerationMax": 2,
"heightMin": 0.1,
"heightMax": 0.2,
"width": 0.8,
"length": 0.8
},
"protocolLimits": {},
"protocolFeatures": {
"optionalParameters": [],
"agvActions": [
{
"actionType": "Robot New - Test factsheet 1",
"actionDescription": "This is a description of the action",
"actionScopes": ["NODE"],
"actionParameters": [
{
"key": "variable name",
"valueDataType": "INTEGER",
"description": "This is a description of the parameter",
"isOptional": false
}
],
"resultDescription": "This is a description of the result"
},
{
"actionType": "Robot New - Test factsheet 2",
"actionDescription": "This is a description of the action",
"actionScopes": ["NODE"],
"actionParameters": [
{
"key": "param_1",
"valueDataType": "FLOAT",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_2",
"valueDataType": "BOOL",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_3",
"valueDataType": "STRING",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_4",
"valueDataType": "INTEGER",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_5",
"valueDataType": "NUMBER",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_6",
"valueDataType": "ARRAY",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_7",
"valueDataType": "TIME",
"description": "This is a description of the parameter",
"isOptional": false
},
{
"key": "param_8",
"valueDataType": "DATETIME",
"description": "This is a description of the parameter",
"isOptional": false
}
],
"resultDescription": "This is a description of the result"
}
]
},
"agvGeometry": {}
}