Examples
The following examples illustrate common actions in an autonomous driving application. They are written in Python, but if you code in JavaScript, you can utilize our helyosjs-sdk package. Check the webapp tutorial to learn how to use the helyosjs-sdk.
List the Agents in the Yard
def list_agents(condition={}):
graphql_request = {"operationName": "allAgents",
"query":"""
query allAgents($condition: AgentCondition!) {
allAgents (condition: $condition){
nodes {id, uuid, geometry}
}
}
""",
"variables": {"condition": condition }
}
res = session.post(f"{hostname}/graphql", json=graphql_request)
return res.json()['data']['allAgents']['nodes']
print(list_agents({"yardId":3}))
Check also the query agentById in the graphiql dashboard: http://localhost:5000/graphiql.
Subscribe to the Position and Sensors Data Stream
# !pip install "python-socketio[client]"
import socketio
hostname = "https://helyos-server.com" # or wss://helyos-sever.com
authToken = login(username, password) # see previous example
headers = {"Content-Type": "application/json; charset=utf-8"}
auth = {"token": authToken}
sio = socketio.Client()
sio.connect(hostname, headers=headers, auth=auth, transports="websocket")
@sio.event
def connect():
print('connection established')
@sio.on('new_agent_poses')
def get_agent_data(data):
"""Get all agent sensors. """
print(data)
sio.wait() # block thread until disconnection
# Message stream:
# [{'agentId': '1', 'lastMessageTime': '2024-06-04T16:04:22.760Z', 'uuid': 'Bb34069fc5-fdgs-434b-b87e-f19c5435113',
# 'x': -30000, 'y': 10000, 'z': 0, 'orientation': 0.329, 'orientations': [0.329, 0], 'sensors': {...}]
# [{'agentId': '1', 'lastMessageTime': '2024-06-04T16:04:22.964Z', 'uuid': 'Bb34069fc5-fdgs-434b-b87e-f19c5435113',
# 'x': -30000, 'y': 10000, 'z': 0, 'orientation': 0.329, 'orientations': [0.329, 0], 'sensors': {...}]
Subscribe to the agent status update event via WebSocket
# !pip install "python-socketio[client]"
import socketio
hostname = "https://helyos-server.com" # or wss://helyos-sever.com
authToken = login(username, password) # see previous example
headers = {"Content-Type": "application/json; charset=utf-8"}
auth = {"token": authToken}
sio = socketio.Client()
sio.connect(hostname, headers=headers, auth=auth, transports="websocket")
@sio.event
def connect():
print('connection established')
@sio.on('change_agent_status')
def get_agent_status(data):
"""Get agent status when it changes. """
print(data)
sio.wait() # block thread until disconnection
Request mission and subscribe to the status updates via WebSocket
import requests, json
import socketio
# Login: request to the Authorization token should come here
#
auth = {"token": authToken}
sio = socketio.Client()
sio.connect(hostname, auth=auth, transports="websocket")
@sio.on('work_processes_update')
def get_mission_status(data):
"""Get agent status when it changes. """
for event in data:
print(f"mission id #{event['id']} status: {event['status']}")
def request_mission(mission_type, agents, data={}):
graphql_request = {
"operationName": "createWorkProcess",
"query": """mutation createWorkProcess($postMessage: CreateWorkProcessInput!){
createWorkProcess(input: $postMessage) {
workProcess {id, status }
}
}
""",
"variables": {"postMessage" : {"clientMutationId": "not_used",
"workProcess": {
"status": "dispatched",
"yardUid":"DACHSER_SIM",
"workProcessTypeName": mission_type,
"data": json.dumps(data),
"agentUuids": json.dumps([agents])
}
}
}
}
response = session.post(f"{hostname}/graphql", json=graphql_request)
return response.json()['data']['createWorkProcess']['workProcess']
mission = request_mission("driving", ["4353452-452355-56346"], {"to": [50.12343, 10.3442]})
print(mission)
sio.wait()
# Output
# {'id': '13', 'status': 'dispatched'}
# mission id #13 status: preparing resources
# mission id #13 status: preparing resources
# mission id #13 status: calculating
# mission id #13 status: planning_failed
# mission id #13 status: failed
Request the Canceling of a Mission
To cancel a mission, you need just to change the work process status to “canceling”.
import requests, json
import socketio
# Login: request to the Authorization token should come here
#
auth = {"token": authToken}
sio = socketio.Client()
sio.connect(hostname, auth=auth, transports="websocket")
@sio.on('work_processes_update')
def get_mission_status(data):
"""Get agent status when it changes. """
for event in data:
print(f"mission id #{event['id']} status: {event['status']}")
def cancel_mission(missionId):
graphql_request = {
"operationName": "updateWorkProcessById",
"query":"""
mutation updateWorkProcessById($postMessage: UpdateWorkProcessByIdInput!){
updateWorkProcessById(input:$postMessage) {
workProcess {id status }
}
}
""",
"variables": {"postMessage": {"id":missionId, "workProcessPatch": { "status": "canceling"}} }
}
response = session.post(f"{hostname}/graphql", json=graphql_request)
return response.json()['data']['updateWorkProcessById']['workProcess']
mission = cancel_mission(14)
print(mission)
sio.wait()
# Output
# {'id': '14', 'status': 'canceling'}
# mission id #14 status: canceling
# mission id #14 status: canceled
Send instant actions to agents
Instant actions allow external applications to directly communicate requests to the agent. They can be used to change agent settings or to influence or pause running assignments.
def create_instant_action(instant_action):
graphql_request = {
"operationName": "createInstantAction",
"query": """
mutation createInstantAction($postMessage: CreateInstantActionInput!) {
createInstantAction(input: $postMessage) {
instantAction {
id,
createdAt,
agentUuid,
error,
}
}
}
""",
"variables": {
"postMessage":{"clientMutationId": "not_used", "instantAction": instant_action }
}
}
response = session.post(f"{hostname}/graphql", json=graphql_request)
result = response.json()
return result['data']['createInstantAction']['instantAction']
create_instant_action({"agentUuid":"Ab34069fc5-fdgs-434b-b87e-f19c5435113", "command":"my custom command here..."} )
Advanced Commands
All commands issued by the helyOS Dasboard can be performed via GraphQL. Those are some examples:
Create and update agents programatically
There are four classes of agents: ‘vehicle’, ‘assistant’, ‘tool’, ‘charge_station’.
def create_agent(uuid, name, pose, geometry, status, agentClass="vehicle", agentType="truck"):
agent_data = {'uuid':uuid,
'name': name,
'geometry': json.dumps(geometry),
'status': status,
'agentClass': agentClass,
'agentType': agentType}
agent_data['x']=pose['x']
agent_data['y']=pose['y']
agent_data['orientations']=pose['orientations']
graphql_request = {"operationName": "createAgent",
"query":"""
mutation createAgent($postMessage: CreateAgentInput!){
createAgent(input:$postMessage) { agent{id} }
}""",
"variables": {"postMessage": {"agent": agent_data} }
}
response = session.post(f"{hostname}/graphql", json=graphql_request)
return response.json()
def update_agent(uuid, name, pose, geometry, status, agentClass="vehicle", agentType="truck"):
agent_data = {'uuid':uuid,
'name': name,
'geometry': json.dumps(geometry),
'status': status,
'agentClass': agentClass,
'agentType': agentType}
agent_data['x']=pose['x']
agent_data['y']=pose['y']
agent_data['orientations']=pose['orientations']
graphql_request = {"operationName": "updateAgentByUuid",
"query":"""
mutation updateAgentByUuid($postMessage: UpdateAgentByUuidInput!){
updateAgentByUuid(input:$postMessage) { agent{id} }
}""",
"variables": {"postMessage": { "uuid": uuid, "agentPatch": agent_data} }
}
response = session.post(f"{hostname}/graphql", json=graphql_request)
return response.json()
Updating multiple map objects
This example demonstrates how to insert multiple mutations into a single GraphQL query. This approach should be used to minimize latency when updating many instances. For applications where updates to map objects are very frequent, such as dynamic objects (over 1 Hz), consider performing the updates via RabbitMQ using an agent assistant.
def update_map_objects(map_objects):
# Start building the query and variables
query_parts = []
variable_definitions = []
variables = {}
for i, map_object in enumerate(map_objects):
mobj_id = map_object['id']
mobj_patch = map_object
# Create a unique alias and variable name for each mutation
alias = f"mutation{i}"
variable_name = f"postMessage{i}"
# Append the mutation part for this object
query_parts.append(f"""
{alias}: updateMapObjectById(input: ${variable_name}) {{
mapObject {{ id }}
}}
""")
# Add the variable definition for this object
variable_definitions.append(f"${variable_name}: UpdateMapObjectByIdInput!")
# Add the variables for this object
variables[variable_name] = {"mapObjectPatch": mobj_patch, "id": mobj_id}
# Combine the query parts into a single query string
query = "mutation updateMapObjects(" + ", ".join(variable_definitions) + ") {" + "\n".join(query_parts) + "\n}"
graphql_request = {
"operationName": "updateMapObjects",
"query": query,
"variables": variables
}
print(query)
response = session.post(f"{hostname}/graphql", json=graphql_request)
return response.json()
res = update_map_objects([
{"data": json.dumps({
"top":9999,
"bottom":0,
"points":[[21145.495567237958,-25642.97220017761]]
}),
"type": "obstacle",
"dataFormat": "trucktrix",
"yardId": 3,
"id":5,
},
{"data": json.dumps({
"top":9999,
"bottom":0,
"points":[[11145.495567237958,-25642.97220017761]]
}),
"type": "obstacle",
"dataFormat": "trucktrix",
"yardId": 3,
"id":6,
}
])
print(res)
# Output:
# mutation updateMapObjects($postMessage0: UpdateMapObjectByIdInput!, $postMessage1: UpdateMapObjectByIdInput!) {
# mutation0: updateMapObjectById(input: $postMessage0) {
# mapObject { id }
# }
# mutation1: updateMapObjectById(input: $postMessage1) {
# mapObject { id }
# }
#}
#{'data': {'mutation0': {'mapObject': {'id': '5'}}, 'mutation1': {'mapObject': {'id': '6'}}}}
Updating a microservice registration
In very special cases, the external application can change a microservice parameter or even rewrite a mission recipe. The application must have admin permissions.