Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • sw/armarx/robot-api
  • uwkce_singer/robot-api
  • untcg_hofmann/robot-api
  • ulqba_korosakov/RobotAPI
4 results
Show changes
Commits on Source (941)
Showing
with 2303 additions and 2085 deletions
# ARON
/source/RobotAPI/libraries/aron/ @peller @dreher
/source/RobotAPI/libraries/aron/ @plewnia @hyseni
/source/RobotAPI/interface/aron/ @peller @dreher
/source/RobotAPI/interface/aron.ice @peller @dreher
/source/RobotAPI/interface/aron/ @plewnia @hyseni
/source/RobotAPI/interface/aron.ice @plewnia @hyseni @dreher
# ArMem
/source/RobotAPI/components/armem/ @peller @kartmann @dreher
/source/RobotAPI/components/armem/ @plenwia
/source/RobotAPI/libraries/armem/ @peller @kartmann @dreher
/source/RobotAPI/libraries/armem/ @plewnia
/source/RobotAPI/libraries/armem_robot_localization/ @reister
/source/RobotAPI/libraries/armem_robot_mapping/ @reister
/source/RobotAPI/interface/armem/ @fratty @RainerKartmann @dreher
/source/RobotAPI/interface/armem.ice @fratty @RainerKartmann @dreher
/source/RobotAPI/interface/armem/ @plewnia
/source/RobotAPI/interface/armem.ice @plewnia @dreher
# Skill framework
/source/RobotAPI/interface/skills @meixner @rietsch
/source/RobotAPI/libraries/skills @meixner @rietsch
# RobotAPI
## Documentation
[Wiki](docs)
[Online Documentation](https://armarx.humanoids.kit.edu/RobotAPI-Overview.html),
in particular on
[ARON ("ArmarX Object Notation") / IDF (Interpretable Data Format)](https://armarx.humanoids.kit.edu/aron.html)
and
[ArMem ("ArmarX Memory Framework")](https://armarx.humanoids.kit.edu/memory_system.html)
\ No newline at end of file
Stub to make the package tool work.
This diff is collapsed.
# Copyright (c) 2015, Georgia Tech Graphics Lab and Humanoid Robotics Lab
# This file is provided under the "BSD-style" License
# Find NLOPT
#
# This sets the following variables:
# NLOPT_FOUND
# NLOPT_INCLUDE_DIRS
# NLOPT_LIBRARIES
# NLOPT_DEFINITIONS
# NLOPT_VERSION
find_package(PkgConfig QUIET)
# Check to see if pkgconfig is installed.
pkg_check_modules(PC_NLOPT nlopt QUIET)
# Definitions
set(NLOPT_DEFINITIONS ${PC_NLOPT_CFLAGS_OTHER})
# Include directories
find_path(NLOPT_INCLUDE_DIRS
NAMES nlopt.h
HINTS ${PC_NLOPT_INCLUDEDIR}
PATHS "${CMAKE_INSTALL_PREFIX}/include")
# Libraries
find_library(NLOPT_LIBRARIES
NAMES nlopt nlopt_cxx
HINTS ${PC_NLOPT_LIBDIR})
# Version
set(NLOPT_VERSION ${PC_NLOPT_VERSION})
# Set (NAME)_FOUND if all the variables and the version are satisfied.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NLOPT
FAIL_MESSAGE DEFAULT_MSG
REQUIRED_VARS NLOPT_INCLUDE_DIRS NLOPT_LIBRARIES
VERSION_VAR NLOPT_VERSION)
# - Try to find OptoForceOMD
# Once done this will define
#
# OptoForceOMD_FOUND - OptoForceOMD found
# OptoForceOMD_INCLUDE_DIR - the OptoForceOMD include directory
# OptoForceOMD_LIBRARIES - OptoForceOMD library
#
FIND_PATH(OptoForceOMD_INCLUDE_DIR NAMES opto.h
PATHS
$ENV{OptoForceOMD_DIR}/include/
$ENV{OptoForceOMD_DIR}/include/OptoForceOMD/
${OptoForceOMD_DIR}/include/
${OptoForceOMD_DIR}/include/OptoForceOMD/
ENV CPATH
/usr/include/OptoForceOMD/
/usr/local/include/OptoForceOMD/
/opt/local/include/OptoForceOMD/
NO_DEFAULT_PATH
)
FIND_LIBRARY(OptoForceOMD_LIBRARIES NAMES libOMD.so
PATHS
$ENV{OptoForceOMD_DIR}/lib
${OptoForceOMD_DIR}/lib
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib
/usr/local/lib
/opt/local/lib
NO_DEFAULT_PATH
)
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set OODL_YOUBOT_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(OptoForceOMD DEFAULT_MSG
OptoForceOMD_LIBRARIES OptoForceOMD_INCLUDE_DIR)
set(OptoForceOMD_FOUND ${OPTOFORCEOMD_FOUND}) # CMake UPPERCASE-FUNTIME!
#message( "OptoForceOMD_FOUND:" ${OptoForceOMD_FOUND})
#message( "OPTOFORCEOMD_FOUND:" ${OPTOFORCEOMD_FOUND})
#message( "OptoForceOMD_LIBRARIES:" ${OptoForceOMD_LIBRARIES})
#message( "OptoForceOMD_INCLUDE_DIR:" ${OptoForceOMD_INCLUDE_DIR})
# show the OptoForceOMD_INCLUDE_DIR and OptoForceOMD_LIBRARY_DIR variables only in the advanced view
MARK_AS_ADVANCED(OptoForceOMD_INCLUDE_DIR OptoForceOMD_LIBRARIES)
# see https://github.com/intersvyaz/zerod/blob/master/cmake/modules/FindLibbson.cmake
# - Find libbson
# Find the native libbson includes and library.
# Once done this will define
#
# LIBBSON_INCLUDE_DIRS - where to find bson.h, etc.
# LIBBSON_LIBRARIES - List of libraries when using libbson.
# LIBBSON_FOUND - True if libbson found.
#
# LIBBSON_VERSION_STRING - The version of libbson found (x.y.z)
# LIBBSON_VERSION_MAJOR - The major version
# LIBBSON_VERSION_MINOR - The minor version
# LIBBSON_VERSION_MICRO - The micro version
FIND_PATH(LIBBSON_INCLUDE_DIR NAMES bson.h PATH_SUFFIXES libbson-1.0)
FIND_LIBRARY(LIBBSON_LIBRARY NAMES bson-1.0)
MARK_AS_ADVANCED(LIBBSON_LIBRARY LIBBSON_INCLUDE_DIR)
IF(LIBBSON_INCLUDE_DIR AND EXISTS "${LIBBSON_INCLUDE_DIR}/bson-version.h")
# Read and parse version header file for version number
file(READ "${LIBBSON_INCLUDE_DIR}/bson-version.h" _libbson_HEADER_CONTENTS)
IF(_libbson_HEADER_CONTENTS MATCHES ".*BSON_MAJOR_VERSION.*")
#define BSON_MAJOR_VERSION
string(REGEX REPLACE ".*#define +BSON_MAJOR_VERSION +\\(([0-9]+)\\).*" "\\1" LIBBSON_VERSION_MAJOR "${_libbson_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define +BSON_MINOR_VERSION +\\(([0-9]+)\\).*" "\\1" LIBBSON_VERSION_MINOR "${_libbson_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define +BSON_MICRO_VERSION +\\(([0-9]+)\\).*" "\\1" LIBBSON_VERSION_MICRO "${_libbson_HEADER_CONTENTS}")
ELSE()
SET(LIBBSON_VERSION_MAJOR 0)
SET(LIBBSON_VERSION_MINOR 0)
SET(LIBBSON_VERSION_MICRO 0)
ENDIF()
SET(LIBBSON_VERSION_STRING "${LIBBSON_VERSION_MAJOR}.${LIBBSON_VERSION_MINOR}.${LIBBSON_VERSION_MICRO}")
ENDIF()
# handle the QUIETLY and REQUIRED arguments and set LIBBSON_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(libbson-1.0
REQUIRED_VARS LIBBSON_LIBRARY LIBBSON_INCLUDE_DIR
VERSION_VAR LIBBSON_VERSION_STRING
)
IF(LIBBSON_FOUND)
SET(LIBBSON_INCLUDE_DIRS ${LIBBSON_INCLUDE_DIR})
SET(LIBBSON_LIBRARIES ${LIBBSON_LIBRARY})
ENDIF()
# see https://github.com/intersvyaz/freeradius-mongodb/blob/master/cmake/modules/FindLibmongoc.cmake
# - Find libmongoc
# Find the native libmongoc includes and library.
# Once done this will define
#
# LIBMONGOC_INCLUDE_DIRS - where to find mongoc.h, etc.
# LIBMONGOC_LIBRARIES - List of libraries when using libmongoc.
# LIBMONGOC_FOUND - True if libmongoc found.
#
# LIBMONGOC_VERSION_STRING - The version of libmongoc found (x.y.z)
# LIBMONGOC_VERSION_MAJOR - The major version
# LIBMONGOC_VERSION_MINOR - The minor version
# LIBMONGOC_VERSION_MICRO - The micro version
FIND_PATH(LIBMONGOC_INCLUDE_DIR NAMES mongoc.h PATH_SUFFIXES libmongoc-1.0)
FIND_LIBRARY(LIBMONGOC_LIBRARY NAMES mongoc-1.0)
MARK_AS_ADVANCED(LIBMONGOC_LIBRARY LIBMONGOC_INCLUDE_DIR)
IF(LIBMONGOC_INCLUDE_DIR AND EXISTS "${LIBMONGOC_INCLUDE_DIR}/mongoc-version.h")
# Read and parse version header file for version number
file(READ "${LIBMONGOC_INCLUDE_DIR}/mongoc-version.h" _libmongoc_HEADER_CONTENTS)
IF(_libmongoc_HEADER_CONTENTS MATCHES ".*MONGOC_MAJOR_VERSION.*")
string(REGEX REPLACE ".*#define +MONGOC_MAJOR_VERSION +\\(([0-9]+)\\).*" "\\1" LIBMONGOC_VERSION_MAJOR "${_libmongoc_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define +MONGOC_MINOR_VERSION +\\(([0-9]+)\\).*" "\\1" LIBMONGOC_VERSION_MINOR "${_libmongoc_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define +MONGOC_MICRO_VERSION +\\(([0-9]+)\\).*" "\\1" LIBMONGOC_VERSION_MICRO "${_libmongoc_HEADER_CONTENTS}")
ELSE()
SET(LIBMONGOC_VERSION_MAJOR 0)
SET(LIBMONGOC_VERSION_MINOR 0)
SET(LIBMONGOC_VERSION_MICRO 0)
ENDIF()
SET(LIBMONGOC_VERSION_STRING "${LIBMONGOC_VERSION_MAJOR}.${LIBMONGOC_VERSION_MINOR}.${LIBMONGOC_VERSION_MICRO}")
ENDIF()
# handle the QUIETLY and REQUIRED arguments and set LIBMONGOC_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Libmongoc
REQUIRED_VARS LIBMONGOC_LIBRARY LIBMONGOC_INCLUDE_DIR
VERSION_VAR LIBMONGOC_VERSION_STRING
)
IF(LIBMONGOC_FOUND)
SET(LIBMONGOC_INCLUDE_DIRS ${LIBMONGOC_INCLUDE_DIR})
SET(LIBMONGOC_LIBRARIES ${LIBMONGOC_LIBRARY})
ENDIF()
......@@ -63,6 +63,13 @@ RobotAPI also provides a GUI-plugin for robot visualization.
\par
\link RobotAPI-GuiPlugins Read more \endlink
\par RobotUnit
\subpage RobotUnit
\par GamepadUnit
\subpage GamepadUnit
\defgroup RobotAPI RobotAPI
\copydoc RobotAPI-Overview
......
......@@ -4,7 +4,7 @@
\ref tutorials_120_memory_server_and_client_cpp
\todo
Merge the information from here into the tutorial
Merge the information from here into \ref tutorials_120_memory_server_and_client_cpp
In order to make a new type of data available in the memory system, you first need to create an ARON XML file. Please refer to [Aron/CodeGeneration](Aron/CodeGeneration) if you want to know how to do so.
......
# Memory System {#memory_system}
# ArmarX Memory System {#memory_system}
\tableofcontents
@see
- \ref tutorials_120_memory_server_and_client_cpp
- \subpage memory_system-how_to_create_a_new_core_segment_or_memory_server
## Introduction to the Memory System {#memory_system-introduction}
......@@ -20,7 +22,7 @@ special data types, which are defined in ArmarX packages further down in the dep
All memory servers follow the same hierarchical data structure and self-describing data format.
The data structure consists of several levels, storing histories/timelines of different entities stored in different
segments (see "Memory Levels" below).
The common data format is \ref Aron, which is a self-describing, hierarchical data format,
The common data format is \ref aron, which is a self-describing, hierarchical data format,
allowing extensive introspection as well as general storage.
Each item in the memory (i.e. entries in all levels) can be identified with a **Memory ID**, which contains the keys
of each (specified) level. For example, a core segment ID specifies the memory name and core segment name, while an
......
# ArmarX Object Notation (ARON) / Interpretable Data Format (IDF) {#Aron}
# ArmarX Object Notation (ARON) / Interpretable Data Format (IDF) {#aron}
* [Introduction](introduction)
* [Code Generation](code_generation)
* [Visitors](visitors)
* [Readers, Writers and Conversion](conversion)
\tableofcontents
\see
- \subpage aron-code_generation
- \subpage aron-visitors
- \subpage aron-conversion
ARON (ArmarX Object Notation) is the ArmarX implementation of variants which can be transferred over the network via
ZeroC Ice.
Further, ARON is the data representation used in the \ref memory_system.
We distinguish between:
- type specification vs. data information
- data transfer object (in the following called "ARON DTO") vs. its corresponding C++ wrapper
(in the following called "ARON object").
The DTO specification is done in ice so that every ARON object can be transferred via ice.
## ARON Type specification
An ARON type specification defines the static type for an ARON data DTO or an ARON data object. It does not contain any
data (e.g. an ARON type list only knows the accepted type, not the list members).
Since ARON supports maybe types (raw ptr, smart ptr, optional), every ARON type DTO contains a special member.
It can only consist of the following types and information (ARONVariant means any Type):
```cpp
Object { // dto called armarx::aron::type::dto::AronObject
string name;
AronVariant extends;
map<string, AronVariant> memberTypes;
}
Dict { // dto called armarx::aron::type::dto::Dict
AronVariant acceptedType;
}
List { // dto called armarx::aron::type::dto::List
AronVariant acceptedType;
}
Pair { // ...
AronVariant acceptedType1;
AronVariant acceptedType2;
}
Tuple {
vector<AronVariant> acceptedTypes;
}
IntEnum {
string name;
map<string, int> acceptedValues;
}
NDArray {
int ndim;
type type; // in [uint8, int8, uint16, int16, uint32, int32, float32, float64]
}
Matrix {
int rows, cols;
type type; // in [int16, int32, int64, float32, float64]
}
Quaternion {
type type; // in [float32, float64]
}
Position {
}
Orientation {
}
Pose {
}
Image {
pixelType type; // in [rgb24, depth32]
}
PointCloud {
voxelType type; // in [PointXYZ, PointXYZI, PointXYZL, PointXYZRGB, PointXYZRGBA, PointXYZRGBL, PointXYZHSV]
}
Int { // dto called armarx::aron::type::dto::AronInt
}
Long { // dto called armarx::aron::type::dto::AronLong
}
Float { // dto called armarx::aron::type::dto::AronFloat
}
Double { // dto called armarx::aron::type::dto::AronDouble
}
String { // dto called armarx::aron::type::dto::AronString
}
Bool { // dto called armarx::aron::type::dto::AronBool
}
Time { // dto called armarx::aron::type::dto::AronTime
}
```
## ARON Data specification
ARON data objects and ARON data DTOs are similar structured to type objects and type DTOs.
However, there are fewer classes for data objects and data DTOs.
ARON data is completely decoupled from the static types and contains the data members
(e.g. an aron data list only contains the list members (as ARONVariants) and not the accepted type):
```cpp
Dict { // dto called armarx::aron::data::dto::Dict
map<string, AronVariant> members;
}
List { // dto called armarx::aron::data::dto::List
vector<AronVariant> elements;
}
NDArray { // ...
vector<int> shape;
string type;
vector<byte> data;
}
Int { // dto called armarx::aron::data::dto::AronInt
int value;
}
Long { // dto called armarx::aron::data::dto::AronLong
long value;
}
Float { // dto called armarx::aron::data::dto::AronFloat
float value;
}
Double { // dto called armarx::aron::data::dto::AronDouble
double value;
}
String { // dto called armarx::aron::data::dto::AronString
string value;
}
Bool { // dto called armarx::aron::data::dto::AronBool
bool value;
}
```
\note
Note that every ARON data object or DTO can be `nullptr`!
The reason is that if the type supports maybe types and a member is, for example, optional,
the data must support maybetype as well.
If a generated ARON class (We come to the code generation later) has an optional member,
this member will be translated into a NULL ARON object and DTO.
## Connection of ARON data and ARON type
ARON data contains fewer classes than ARON type.
Because ARON data objects and DTOs do not check the type of the members (they can be any aron data (ARONVariant)),
we can only validate an aron data object or DTO if we have the type information. The following mapping describes,
how data and types correspond.
| ARON Type | ARON Data |
|-------------|-----------|
| Object | Dict |
| Dict | Dict |
| List | List |
| Pair | List |
| Tuple | List |
| NDArray | NDArray |
| Matrix | NDArray |
| Quaternion | NDArray |
| Position | NDArray |
| Orientation | NDArray |
| Pose | NDArray |
| Image | NDArray |
| PointCloud | NDArray |
| IntEnum | Int |
| Int | Int |
| Long | Long |
| Float | Float |
| Double | Double |
| String | String |
| Bool | Bool |
| Time | Long |
If no type object or DTO is available, we can at least derive some information from the data object
(e.g. "it is a data dict, so the type cant be list").
To differ between data and type makes it easier to work with these Variants.
In most cases, the type information is not relevant.
Then you only have to check for the data type.
## ARON Data and Type Objects
As already mentioned, we implemented wrapper classes around the DTO.
These classes offer convenience methods and conversions and make lots things easier when working directly with ARON.
These classes can be found at `aron/core/{data,type}/variant/Variant.h`.
The ARON objects have more or less the same structure as the DTOs (see above).
Everything is stored as a `std::shared_ptr` (e.g. members, elements, acceptedTypes, ...).
If you want to implement a method which takes any ARON data object as input,
you can use the base class of every ARON data object:
```cpp
void myFancyMethod(const armarx::aron::data::VariantPtr& variant);
```
If you want to check, what a variant really is, you can use the descriptor of the object:
```cpp
armarx::aron::data::VariantPtr variant; // <-- the variant
auto desc = variant->getDescriptor();
switch(desc)
{
case armarx::aron::data::Descriptor::eDict: ...
case armarx::aron::data::Descriptor::eList: ...
...
}
```
If you have a DTO, you do not know the exact type,
but you want to have a ARON object you can make use of the static construction methods:
```cpp
armarx::aron::data::dto::GenericData dto; // <-- the DTO variant
auto aron = armarx::aron::data::Variant::FromAronDTO(dto);
```
If you know the type, you can use the constructor the specific ARON object.
### Example to Create an ARON Data Dict from Scratch
Goal: Have an ARON dict with a list as member "the_list" and some values in it.
Then echo the members and their descriptor as a string.
```cpp
using namespace armarx;
// setup aron object
auto dict = std::make_shared<aron::data::Dict>();
{
auto list = std::make_shared<aron::data::List>();
for (unsigned int i = 0; i < 10; ++i)
{
list->addElement(std::make_shared<aron::data::Int>(i));
}
dict->addElement("the_list", list);
}
// echo
auto listVariant = dict->getElement("the_list"); // will return a aron::data::VariantPtr
auto list = aron::data::List::DynamicCastAndCheck(listVariant); // cast and check whether the cast was successful
for (const auto& intVar : list->getElements())
{
auto i = aron::data::Int::DynamicCastAndCheck(intVar);
std::cout << "The value is: " << i->getValue() << std::endl;
std::cout << "The descriptor is: " << aron::data::defaultconversion::string::Descriptor2String.at(i->getDescriptor()) << std::endl;
}
```
Please note that we might add more methods or make the current ones more flexible (e.g. such as nlohmann::json).
## Lessons Learned
- There is a difference between ARON data and ARON type
- There is a difference between ARON objects and ARON DTOs
- How are ARON DTOs structured
- How do ARON data and ARON types correspond
- How to use the ARON objects
[[_TOC_]]
# ARON Code Generation {#aron-code_generation}
# Aron Type Reading
\tableofcontents
As already mention in the introduction, aron supports code generation in order to create a c++ (other languages also possible) class with plain c++ members which you can use for convenience. Further, the generated class offers methods to convert itself to a Aron object and to set the members from a Aron object. Code generation only makes sense for Aron data, however we need an Aron type specification in order to generate the class.
## Aron Type Reading
As already mention in the introduction, aron supports code generation in order to create a C++
(other languages also possible) class with plain C++ members which you can use for convenience.
Further, the generated class offers methods to convert itself to an Aron object and to set the members from an Aron
object.
Code generation only makes sense for Aron data,
however we need an Aron type specification in order to generate the class.
In the following we will describe how to specify Aron types in XML and how the generated code looks like.
## XML type description and creation
### XML type description and creation
In order to make Aron generate a c++ class for you, you first have to tell the program how the object should look like. Second you need to add the file to cmake in order to create the code generation target.
In order to make Aron generate a C++ class for you, you first have to tell the program how the object should look like.
Second you need to add the file to cmake in order to create the code generation target.
### XML type description
#### XML type description
Consider you want to use a data type called `MyData` (in the namespace `armarx::mydata`).
* Choose a library in an ArmarX package where your data type will be defined (or create a new one). Here, we will call it `MyDataLib`.
* In the directory `MyDataLib/`, create a directory `aron/` (if necessary). Inside, add a file `MyData.xml`. The directory structure should now look like this:
* Choose a library in an ArmarX package where your data type will be defined (or create a new one).
Here, we will call it `MyDataLib`.
* In the directory `MyDataLib/`, create a directory `aron/` (if necessary). Inside, add a file `MyData.xml`.
The directory structure should now look like this:
```
.../libraries/
......@@ -45,7 +55,13 @@ Then start defining your data in ARON. A hello world example could look like thi
</AronTypeDefinition>
```
Every type specification must have the top-level-tag `AronTypeDefinition` and must at least define one type in `GenerateTypes`. In the `GenerateTypes`-tag you can add as many `Object` or `IntEnum` definitions as you want. `<Object>` defines a new ARON object type (generating a C++ class) containing a number of children. Inside the `Object`-tag you can add as many members as you want through the `ObjectChild`-tag (generating a public member variable of the generated C++ class, with `key` specifying the member's name). If a member should be e.g. optional you have to add the attribute `optional="true"` to the member:
Every type specification must have the top-level tag `AronTypeDefinition`
and must at least define one type in `GenerateTypes`.
In the `GenerateTypes` tag you can add as many `Object` or `IntEnum` definitions as you want.
`<Object>` defines a new ARON object type (generating a C++ class) containing a number of children.
Inside the `Object`-tag you can add as many members as you want through the `ObjectChild`-tag
(generating a public member variable of the generated C++ class, with `key` specifying the member's name).
If a member should be e.g. optional you have to add the attribute `optional="true"` to the member:
```xml
<ObjectChild key="helloWorld">
<String optional="true" />
......@@ -54,34 +70,29 @@ Every type specification must have the top-level-tag `AronTypeDefinition` and mu
The same way you can define `raw_ptr`, `shared_ptr` or `unique_ptr` members.
Conventions:
- Put your ARON object type into a `arondto::` namespace inside your usual namespace (e.g., `armarx::mydata::arondto::MyData`), where "DTO" stands for "Data Transfer Object". This way, you can define or use a custom or existing C++ type with more methods/intelligence in the usual namespace in your business logic code (e.g. `armarx::mydata::MyData`).
- Put your ARON object type into a `arondto::` namespace inside your usual namespace
(e.g., `armarx::mydata::arondto::MyData`), where "DTO" stands for "Data Transfer Object".
This way, you can define or use a custom or existing C++ type with more methods/intelligence in the usual namespace
in your business logic code (e.g. `armarx::mydata::MyData`).
If you want to use a definition of another Aron file, you can include the file using the `AronIncludes`-section. Simply add the files you want to include using a `include`-tag:
If you want to use a definition of another Aron file, you can include the file using the `AronIncludes` section.
Simply add the files you want to include using a `include` tag:
```xml
<AronIncludes>
<Include include="<RobotAPI/libraries/aron/common/aron/PackagePath.xml>" autoinclude="true" />
...
</AronIncludes>
<AronIncludes>
<Include include="RobotAPI/libraries/aron/common/aron/PackagePath.xml" />
...
</AronIncludes>
```
The option `autoinclude` automatically adds the generated class of the Aron xml file to the c++ class.
After that, you can use the type definitions in your current xml file (you must specify the full namespace):
```xml
<ObjectChild key="referenceToMemoryID">
<armarx::arondto::PackagePath />
</ObjectChild>
<ObjectChild key="referenceToMemoryID">
<armarx::arondto::PackagePath />
</ObjectChild>
```
(At the moment), you need to specify `<CodeIncludes>` to Eigen to use `Pose`, `Position` and `Orientation` (which are translated to `Eigen::Matrix4f`, `Eigen::Vector3f`, and `Eigen::Quaternionf` in C++). In that section, you can add includes in your target language (right now only C++), e.g.:
```xml
<CodeIncludes>
<Include include="<Eigen/Core>" />
</CodeIncludes>
```
If you do not need the `CodeIncludes` and `AronIncludes` you can remove these tags.
### Examples
#### Examples
In the following we define a class that uses all more complex types once:
```xml
......@@ -158,9 +169,10 @@ In the following we define a class that uses all more complex types once:
</AronTypeDefinition>
```
### CMake specification
#### CMake Specification
In the `CMakeLists.txt`, add or extend after the definition of the target (e.g. through add_library or add_component):
In the `CMakeLists.txt`, add or extend after the definition of the target
(e.g. through `add_library` or `add_component`):
```cmake
armarx_enable_aron_file_generation_for_target(
......@@ -171,9 +183,10 @@ armarx_enable_aron_file_generation_for_target(
)
```
### Important changes
#### Important changes
- I changed the xml type reader so that embedded classes are not allowed anymore! Before that you were able to define a new class inside an existing one, e.g.:
- I changed the xml type reader so that embedded classes are not allowed anymore!
Before that you were able to define a new class inside an existing one, e.g.:
```xml
<!-- MyData containing a helloWorld member -->
<?xml version="1.0" encoding="UTF-8" ?>
......@@ -191,7 +204,8 @@ armarx_enable_aron_file_generation_for_target(
```
This is not supported anymore!
## Full example
### Full example
Say you have the following Aron XML type description:
```xml
......@@ -223,7 +237,7 @@ Say you have the following Aron XML type description:
</AronTypeDefinition>
```
The generated c++ file looks like:
The generated C++ file looks like:
```cpp
#pragma once
......@@ -651,29 +665,45 @@ namespace armarx
```
As you see, the code generation creates a class for the `NaturalIKControlMode` enum. This special class provides convenience methods compared to normal c++ enums.
As you see, the code generation creates a class for the `NaturalIKControlMode` enum.
This special class provides convenience methods compared to normal C++ enums.
Further, it creates a class for the `NaturalIKResult` object.
Both, the enum and the object provide methods for reading and writing. The `read` method is used to parse a Aron object in an arbitrary representation (e.g. Aron variant or nlohmann::json) and to set the c++ members to the same values as the Aron object. To do so it uses a ReaderInterface implementation (See [Converter](Aron/Converter)). The `write` method is used to create an Aron object in an arbitrary representation with the same values as the c++ object. This method uses a WriterInterface implementation.
For convenience, the `toAron()` and `fromAron()` methods, which internally use the `read` and `write` methods, are created. To get the structure of the c++ class as an Aron type object you can use the static `toAronType()` method which internally uses the `writeType` method.
Both, the enum and the object provide methods for reading and writing.
The `read` method is used to parse a Aron object in an arbitrary representation
(e.g. Aron variant or nlohmann::json) and to set the C++ members to the same values as the Aron object.
To do so it uses a ReaderInterface implementation (see \ref aron-conversion).
The `write` method is used to create an Aron object in an arbitrary representation with the same values as the C++
object.
This method uses a WriterInterface implementation.
Futher, the code generation creates methods to compare two classes with each other (right now only operator==).
For convenience, the `toAron()` and `fromAron()` methods, which internally use the `read` and `write` methods,
are created.
To get the structure of the C++ class as an Aron type object you can use the static `toAronType()` method which
internally uses the `writeType` method.
This means, when using Aron, you don't need to mess around with the Aron DTOs and Aron objects, you only have to set and use plain c++ members of a generated class!
Further, the code generation creates methods to compare two classes with each other (right now only operator==).
This means, when using Aron, you don't need to mess around with the Aron DTOs and Aron objects, you only have to set
and use plain C++ members of a generated class!
## (Optional) Add conversions to existing (potentially more intelligent) C++ types
# (Optional) Add conversions to existing (potentially more intelligent) C++ types
Consider the case of `simox::OrientedBoxf` and `simox::arondto::OrientedBox`. The former is the business object (BO),
used in daily business logic code (as it offers useful methods to construct and manipulate it).
The latter is a mere data storage used to transfer the data, which is called a data transfer object (DTO).
Consider the case of `simox::OrientedBoxf` and `simox::arondto::OrientedBox`. The former is the business object (BO), used in daily business logic code (as it offers useful methods to construct and manipulate it). The latter is a mere data storage used to transfer the data, which is called a data transfer object (DTO).
Therefore, you usually want to convert a `simox::arondto::OrientedBox` to a `simox::OrientedBoxf` as soon as you want to do things other than passing it around over network (e.g., at the beginning of a component method or after reading it from the working memory). Likewise, you want to convert a `simox::OrientedBoxf` to a `simox::arondto::OrientedBox` when you send the information over network or store it in the memory.
Therefore, you usually want to convert a `simox::arondto::OrientedBox` to a `simox::OrientedBoxf` as soon as you want
to do things other than passing it around over network (e.g., at the beginning of a component method or after reading
it from the working memory).
Likewise, you want to convert a `simox::OrientedBoxf` to a `simox::arondto::OrientedBox` when you send the information
over network or store it in the memory.
To allow this conversion, follow these steps:
- In your library, add a file pair `aron_conversions.{h, cpp}` next to your `aron/` directory and add them to the `CMakeLists.txt`
- In your library, add a file pair `aron_conversions.{h, cpp}` next to your `aron/` directory and add them to
the `CMakeLists.txt`
- In the header, declare functions following this form:
```cpp
......@@ -723,11 +753,14 @@ void simox::toAron(arondto::OrientedBox& dto, const OrientedBoxf& bo)
}
```
Note:
\note
The implementation depends on your data.
It might be as simple as copying all members, or require more complex conversions.
Especially, you might use `fromAron()` for `toAron()` for other ARON object types.
- The implementation depends on your data. It might be as simple as copying all members, or require more complex conversions. Especially, you might use `fromAron()` for `toAron()` for other ARON object types.
## Lessons learned
# Lessons learned
- How to create a XML file with a valid Aron specification
- How to add this file to CMake
- How to use the generated class and how to convert it to an Aron object (e.g. for sending it to the memory)
\ No newline at end of file
- How to use the generated class and how to convert it to an Aron object (e.g. for sending it to the memory)
This diff is collapsed.
# Aron conversion
Aron offers ways to simply convert any aron object into another representation (e.g. from variant to nlohmann::json or vice versa). To do so, it makes use of specific readers and writers. In the following we will only describe the readers, writers and converters for Aron data, not for types (but the principle is the same).
## Readers
An Aron reader is used to get information of an Aron object in a specific representation. Assume you have an nlohmann::json aron object which contains some information (E.g. it is a dict, containing some members, ...). We need this information to create another object in another representation with the same content.
To do so, you only have to implement the armarx::aron::data::ReaderInterface class. It needs one template parameter for your InputType (e.g. here const nlohmann::json).
The interface provides the following pure virtual methods:
```cpp
virtual void readList(InputType& input, std::vector<InputTypeNonConst>& elements) = 0;
virtual void readDict(InputType& input, std::map<std::string, InputTypeNonConst>& elements) = 0;
virtual void readNDArray(InputType& input, std::vector<int>& shape, std::string& typeAsString, std::vector<unsigned char>& data) = 0;
virtual void readInt(InputType& input, int& i) = 0;
virtual void readLong(InputType& input, long& i) = 0;
virtual void readFloat(InputType& input, float& i) = 0;
virtual void readDouble(InputType& input, double& i) = 0;
virtual void readString(InputType& input, std::string& s) = 0;
virtual void readBool(InputType& input, bool& i) = 0;
```
You have to implement the function so that the non-const arguments of the method will be filled with the values of the input. E.g. the implementation of the readString method for the nlohmann::json reader would be:
```cpp
void NlohmannJSONReader::readString(const nlohmann::json& input, std::string& i)
{
if (input[rw::json::constantes::TYPE_SLUG] != expectedType)
{
throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Wrong type in json encountered.", input[rw::json::constantes::TYPE_SLUG], expectedType);
}
i = input[rw::json::constantes::VALUE_SLUG];
}
```
Of course, the way to get the member depend on the way how to construct (writer) the nlohmann::json.
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<scenario name="FamiliarObjectDetectionExample" creation="1970-01-01.01:00:00" globalConfigName="./config/global.cfg" package="RobotAPI" nodeName="NodeMain">
<application name="FamiliarObjectDetectionExample" instance="" package="RobotAPI" nodeName="" enabled="true"/>
</scenario>