ArmarX Object Notation (ARON) / Interpretable Data Format (IDF)
See also

ARON (ArmarX Object Notation) is the ArmarX implementation of variants which can be transferred over the network via ZeroC Ice. It is our instantiation of an Interpretable Data Format (IDF). Further, ARON is the data representation used in the ArmarX Memory System.

When sending data over the network we distinguish between different representations: The Ice object, which is the object transferred over the network, the Aron Data Transfer Object (ARON DTO) and the Business Object (BO).

Overview of Aron

We also distinguish between different types of objects: data objects and type objects.

ARON Data Objects vs. ARON Type Objects

To support easier conversion of ARON Data Objects - which hold actual informational data - we use ARON Type Objects, which explain what kind of data is stored in a transferred object. If we want to send a PointCloud over the network, the data will be represented as an NDArray, but the additional information that this ARON Data Object should be interpreted as a point cloud is useful for conversion in business objects. The Aron Type Objects we support are listed at aron_specification . As a user working with ARON you can use those Aron Type Objects to define your own - more complex - Aron Data Transfer Objects. They can consist of Dictionaries containing List, Floats, Strings etc. and can be nested as needed.

Lifecycle of Data Send over the Network

If you want to send data over the network, e.g. because you want to send data to the memory, the data will be converted several times. You start out with the Business Object, which you defined yourself as a C++ or Python class and contains all business logic, as well as the data itself. This is not connected to Aron in any way. Then it will be converted to an ARON Data Transfer Object, using the toAron(arondto::YourType& dto, const YourType& bo) method, which is defined by hand (usually in a aron_conversions.h\.cpp file) and is not part of the arondto:: namespace. If you are developing in C++ the class of the ARON Data Transfer Object is generated automatically from an Ice Definition (and ususally resides in an arondto:: namespace), if you are developing in Python, this class has to be written by hand. Once you have the ARON Data Transfer Object it needs to be converted to an actual Ice Object so it can be transferred over the network in a language independent format. For this we use toAron() functions in the arondto:: namespace, defined as part of the automatically generated ARON Data Transfer Object. The resulting object can now be transferred over the network using Ice.

An example of this can be seen in the following:

#include <memory_tutorial/object_instance/aron_conversions.h> // this is the conversion file in which toAron(arondto::YourType& dto, const YourType& bo) is defined
#include <memory_tutorial/object_instance/ObjectInstance.h> // this is the file which defines the business object
#include <memory_tutorial/object_instance/aron/ObjectInstance.aron.generated.h> // this is the autogenerated file from the xml file
// 1. call some method to generate a new business object
object_instance::ObjectInstance bo = ObjectInstance();
// 2. Convert the data to a aron data transfer object (DTO).
object_instance::arondto::ObjectInstance dto;
toAron(dto, bo); // this is the method defined in aron_conversions.h
// 3. Convert the dto to an object transferrable over ice
dto.toAron();

In Python an example looks like this:

# 1. get the business object
bo = BusinessObject()
# 2. convert your business object to its aron representation
aron_dto = bo.toAron() # this is a method defined in your business object class and converts everything to aron dto objects
# 3. convert the aron dto to its ice transferrable version
ice_dto = aron_dto.to_aron_ice() # this is a method defined in your aron dto class
# alternatively, if you have a dictionary with only primitive types:
from armarx_memory.aron.conversion import pythonic_from_to_aron_ice
data = some_dict
ice_dto = pythonic_from_to_aron_ice.pythonic_to_aron_ice(data)

Once it was received somewhere the whole process is repeated the other way around. We use arondto::fromAron() methods to get the C++/Python Wrapper of the ARON Data Transfer Object out of the Ice object we received. Then we use the fromAron(const arondto::YourType& dto, YourType& bo) methods to get the actual Business Object in C++/Python.

Defining a new Object Class in C++

While we already support a wide range of possible Data Types we can send over the network, they might not fit your need 100%, especially if you write a new memory segment or entity. To deal with this you can define a new ARON Type using xml. There are two steps involved:

  1. create the aron defintion as an xml file
  2. define your C++ Business Object
  3. define conversions from ARON DTOs to Business Objects
  4. add the xml file and the conversions to your CMakeLists.txt

Aron Definitions as xml files

All Definitions follow the same pattern.

<!-- MyData containing all accepted members once -->
<?xml version="1.0" encoding="UTF-8" ?>
<AronTypeDefinition>
<AronIncludes>
<Include include="path_to_other_xml_file_you_want_to_include" />
...
</AronIncludes>
<GenerateTypes>
<Object name="datatypeOfObject">
<ObjectChild key="nameOfChildObject">
<String />
</ObjectChild>
</Object>
...
</GenerateTypes>
</AronTypeDefinition>

You can add an arbitrary amount of other ARON types you want to include and use, you can define ARON types and use them in the same xml, you can use dictionaries and lists of other ARON types...

For a more detailed example and explanation on how to write such a new xml file see code_generation .

Defining your Business Object

Define a normal C++ class containing the data and the business logic of the object. Add the .cpp/.h files to your CMakeLists.txt

(Optional) Define Forward Declarations

An optional but recommended step consists of adding forward declarations. A forward declaration is a declaration of a class without definition of its implementation. This tells the compiler that the symbol YourType is a class, but not how it is comprised (i.e. which member variables and methods it has). Even without the definition, the class name can already be used as reference, pointer, function argument and function return type. Using forward declarations can heavily reduce the amount of includes the users of a class or header file pull into their code, and thus can heavily speed up compilation.

You file should look something like this:

#pragma once
namespace yournamespace::your_type
{
class YourType;
}
namespace yournamespace::your_type::arondto
{
class YourType;
}

Defining Conversions

Following conventions we define conversions from ARON DTOs to C++ BOs in a specific C++ file called aron_conversions.cpp/.h. To do so, first add the files to your SOURCES and HEADERS in your CMakeLists.txt. Then add the definition of two methods per AronTypeDefinition you wrote to the aron_conversions.h file.

Your file should look something like this:

#pragma once
#include <memory_tutorial/object_instance/forward_declarations.h> // if you added such a file, otherwise include the files containing the namespaces for YourType and arondto::YourType
namespace yournamespace
{
void toAron(arondto::YourType& dto, const YourType& bo);
void fromAron(const arondto::YourType& dto, YourType& bo);
}

Next implement the conversion functions in aron_conversions.cpp:

#include "aron_conversions.h"
// the following conversions can be used to convert types like poses, locations etc; only include if needed
// include the header files to your business object and the generated file for the ARON DTO
#include <memory_tutorial/object_instance/YourType.h>
#include <memory_tutorial/object_instance/aron/YourType.aron.generated.h>
namespace yournamespace
{
void your_type::toAron(arondto::YourType& dto, const YourType& bo){
//now convert the child elements
//primitive types can be assigned
dto.name = bo.name; // assuming name is a string
// more complex types which have their own aron conversion methods:
toAron(dto.pose, bo.pose); // assuming this conversion method is defined in one of the included files above
}
void your_type::fromAron(const arondto::YourType& dto, YourType& bo){
//now convert the child elements
//primitive types can be assigned
bo.name = dto.name; // assuming name is a string
// more complex types which have their own aron conversion methods:
fromAron(dto.pose, bo.pose); // assuming this conversion method is defined in one of the included files above
}
}

Make sure your CMakeLists.txt contains all relevant information

You CMakeLists.txt file should contain:

  • aron_conversions.cpp/h in SOURCES/HEADERS
  • your_type_aronin DEPENDENCIES
  • aroncommonin DEPENDENCIES if you use common aron conversions
  • forward_declarations.h in HEADERS if you use forward declarations
  • aron/YourType.xml in ARON_FILES in armarx_add_aron_library(your_type_aron)
  • YourType.cpp/.hin SOURCES/HEADERS for your business object

Example:

armarx_add_aron_library(your_type_aron
ARON_FILES
aron/YourType.xml
)
SOURCES
YourType.cpp
aron_conversions.cpp
HEADERS
YourType.h
forward_declarations.h
aron_conversions.h
DEPENDENCIES
ArmarXCoreInterfaces
ArmarXCore
aroncommon # For common converters, if needed
your_type_aron # To generate aron classes
)

Defining a new Object Class in Python

To be able to use defined Data Types in Python similar steps as in C++ are needed. If you have not yet done all the steps to use the new type in C++ you can start from step 1, otherwise start from step 2 and leave out step 4.

  1. create the aron defintion as an xml file (see sections above)
  2. define your Python Business Object
  3. define your Aron DTO and define conversions from ARON DTOs to Business Objects
  4. add the xml file to your CMakeLists.txt

Defining your Business Object

Define your business object, for example:

class TheType:
def __init__(some_attribute: int, some_optional_attribute: float or None = None):
self.some_attribute: int = some_attribute
self.some_optional_attribute: float or None = some_optional_attribute
# not all variables of the bo need to be reflected in the dataclass, e.g.:
is_ready: bool = False
def do_something():
# the BO includes logic
pass

Defining your ARON DTO and Conversions

There is no exact standard of where to put your ARON DTO, but for Python you need to define it by hand, as it is not generated automatically yet. The ARON DTO is a python class inheriting from AronDataclass defined in armarx_memory.aron.aron_dataclass. The class also needs the methods from_aron() and to_aron() as classmethods. These methods convert from business object to ARON DTO and vice versa. AronDataClass itself defines methods converting the objects from AROn DTOs to Aron Ice objects (from_aron_ice() and to_aron_ice()).

An example corresponding to the business object above could look like this:

# if the following is impossible in your python version, leave it out and
# put type annotations referring to the own class in "quotation" marks
from __future__ import annotations
from dataclasses import dataclass
from armarx_memory.aron.aron_dataclass import AronDataclass
# "as ...Bo" is recommended for clarity
from path.of.the.bo_module import TheType as TheTypeBo
@dataclass
class TheTypeDto(AronDataclass):
# for optionals, it is important to use the Union notation here, not `or`!
some_attribute: int
some_optional_attribute: Union[float, None]
@classmethod
def from_aron(cls, dto: TheTypeDto) -> TheTypeBo:
bo = TheTypeBo(
dto.some_attribute,
dto.some_optional_attribute
# if a parameter is a complex type itself, use something like:
# TheOtherTypeDto.from_aron(dto.the_complex_attribute)
)
return bo
@classmethod
def to_aron(cls, bo: TheTypeBo) -> TheTypeDto:
dto = cls(
bo.some_attribute,
bo.some_optional_attribute
)
return dto

Lessons Learned

  • There is a difference between ARON data and ARON type
  • There is a difference between ARON (business) objects and ARON DTOs
  • How to use the ARON objects
  • How to define new ARON types and provide functions to help others use them
  • How objects are transferred over the network

Detailed Explanations

See

Examples

For an example on how to use aron type definitions in python together with the memory see (Example)

cpp
IceStorm Admin cpp
Definition: CMakeLists.txt:87
armarx_add_library
DMPController armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") if(DMP_FOUND) target_include_directories("$
Definition: _CMakeLists.txt:52
simox.h
armarx.h
aron_conversions.h
armarx::fromAron
void fromAron(const arondto::PackagePath &dto, PackageFileLocation &bo)
armarx::toAron
void toAron(arondto::PackagePath &dto, const PackageFileLocation &bo)
armarx::navigation::qt_plugins::location_graph_editor::utils::EdgeDirection::To
@ To
armarx::aron::bo
const std::optional< BoT > & bo
Definition: aron_conversions.h:174