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.

Get Authorization Token with Login

In the following snipet, an external application can get the authorization token using GraphiQL. Alternatively, the helyos admin can create a token using the helyos dashboard.

External applications gets authorization token.
import requests,  json
hostname = "https://helyos-server.com"
username = "myaccount"
password = "mypassword"
session = requests.Session()
session.headers.update({ "Content-Type": "application/json; charset=utf-8"})


def login(username, password):
    session.headers.pop('Authorization', '')
    graphql_request = {"operationName": "authenticate",
                    "query":""" mutation authenticate($postMessage:  AuthenticateInput!) {
                                    authenticate(input:$postMessage)  {  jwtToken }}
                            """,
                        "variables": {"postMessage": { "username": username, "password":password} }
                        }
    res = session.post(f"{hostname}/graphql", json=graphql_request)
    token = res.json()['data']['authenticate']['jwtToken']
    return token

auth_token = login(username, password)
print(f"Authorizaton token: {auth_token}")
session.headers.update({ "Authorization": f"Bearer {auth_token}"})

List the Agents in the Yard

Retrieve agents.
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

Retrieve agents sensors.
# !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

Retrieve agents status.
# !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

Mission request.
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”.

Mission request.
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.

Mission request.
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’.

Handle agent registration.
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.

Update map objects.
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.