How to Create a New Core segment or Memory Server
See also
Write a Memory Server and Client (C++)
Todo:
Merge the information from here into Write a Memory Server and Client (C++)

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 if you want to know how to do so.

Create a new memory server

Note: If you plan to extend an existing memory server, you can skip this step.

If your data should be stored in a new memory server, follow these steps:

Create a new component, let's say MyMemory:

# In the root directory of your ArmarX package:
armarx-package add component MyMemory

Then, extend the new component by the respective component plugin.

Add the include:

Make the component derive from the component plugin user:

class MyMemory :
virtual public armarx::Component
// v Add this line ... v
// v ... or this line ... v
, virtual public armem::server::ReadOnlyPluginUser

Don't forget to add the respective library to your CMakeLists.txt:

set(COMPONENT_LIBS
...
# Add this:
armem
...
)

If the component already implements an ice interface, you have to add the memory server into face to it (otherwise, you will receive ‘no unique final overrider for 'virtual function ...’` errors by the compiler):

// memory_tutorial/source/memory_tutorial/components/object_memory/ComponentInterface.ice
#pragma once
// v either include this one (read-write) v
#include <RobotAPI/interface/armem/server/MemoryInterface.ice>
// v or this one (read-only) v
// #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.ice>
module memory_tutorial { module components { module object_memory
{
interface ComponentInterface
// v either extend from this one (read-write) v
extends armarx::armem::server::MemoryInterface
// v or this one (read-only) v
// extends armarx::armem::server::ReadingMemoryInterface
{
...
};
};};};

In this case, make sure RobotAPIInterfaces is in the Ice dependencies of your ice library:

armarx_add_component(object_memory
ICE_FILES
ComponentInterface.ice
ICE_DEPENDENCIES
...
RobotAPIInterfaces
...

You can set the memory name of the memory server in the createPropertyDefinitions():

...
armarx::PropertyDefinitionsPtr MyMemory::createPropertyDefinitions()
{
armarx::PropertyDefinitionsPtr defs = new ComponentPropertyDefinitions(getConfigIdentifier());
...
// Set the memory name:
workingMemory().name() = "My";
...
return defs;
}

Note:

  • The ReadWritePluginUser implements the ice interface MemoryInterface, which combines, among others, the ReadingMemoryInterface and the WritingMemoryInterface.
  • The ReadOnlyPluginUser only implements the ReadingMemoryInterface.
  • Both provide a working memory data storage workingMemory() (of type armem::server::wm::Memory) and an iceAdapter() (armem::server::MemoryToIceAdapter).

That's it: Your component is now a memory server.

Add a core segment with your new data type in a memory server

Wait, how does the new memory server know of my specially written ARON type?

Oh right, it doesn't. At least not yet. But this is easy to fix: We just have to add a core segment.

What on earth is a core segment?

A segment is a section of a memory (server) containing data of a specific type, i.e. they are homogeneous data containers (in contrast to heterogeneous, which would mean they contain different kinds of data) (see the Introduction).

There are two kinds of segments: core segments, and provider segments:

  • Core segments are usually added by the memory server itself with a name and the ARON data type the core segment is going to keep.
  • Provider segments are usually added by clients committing data to the memory. You can think of them as "sub-segments" of a (core) segment, providing a namespace for the provider's entities and some additional features.

... what?

Just stick with me, you'll get used to it.

Okay ... but how does the memory add the ... core segment?

A fine question! Luckily, that's very simple. All we need is your ARON type, a name and the working memory data structure.

...

Okay, okay, I'll come to the code. Adding a core segment merely alters a local data structure (it is not an ice/network operation). Thus, we can do it in onInitComponent():

void MyMemory::onInitComponent()
{
workingMemory().addCoreSegment("Data", armarx::mydata::arondto::MyData::toAronType());
}
  • workingMemory() is a function provided by the component plugin user (ReadWritePluginUser or ReadOnlyPluginUser) returning a reference to the working memory data of the type armem::server::wm::Memory.
  • addCoreSegment() adds a core segment. It takes a name and (optionally) an ARON type.
  • "Data" is the name of the core segment.
    • It should refer to a modality or concept, not to its elements (i.e. prefer "Instance" over "Instances" and "Location" over "Locations").
    • Also, try to avoid repeating the memory name, as the core segment's ID is prepended by the memory name anyway (e.g. "Object/Instance" over "Object/ObjectInstance" and "Navigation/Location" over "Navigation/NavigationLocation").
  • armarx::mydata::arondto::MyData is the C++ class generated from your MyData.xml ARON XML description file.
    • ::toAronType() creates a runtime type object describing the ARON type. This allows, e.g., the MemoryViewer GUI to show the data in a suitable manner (e.g. a pose as an affine transformation instead of a 4x4 matrix).
    • Of course, you need to include the respective header: It's located at the same path where your XML is. For example, for the ObjectInstance.xml located at RobotAPI/libraries/armem_objects/aron/ObjectInstance.xml, the include would be:
#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.h>

Note that you need to include the .h file, not the .xml. As the generated class is header-only, you do not need to link any libraries in your CMakeLists.txt.

When you now start your new memory server and the MemoryNameSystem (MNS) (e.g. using the scenario ArMemCore in RobotAPI), and open the MemoryViewer gui plugin, you should see an entry for your memory (My) and the core segment (Data under My).

Conclusion

That's it! You now have a memory server providing a place where your nice and interesting data can feel welcome, and where interested listeners would look to find it.

Next, we learn how to commit data to the memory, and query data from the memory.

ReadWritePluginUser.h
memory_definitions.h
armarx::armem::server::plugins::ReadWritePluginUser
Base class of memory server components.
Definition: ReadWritePluginUser.h:20
armarx::Component
Baseclass for all ArmarX ManagedIceObjects requiring properties.
Definition: Component.h:95
ReadOnlyPluginUser.h
IceUtil::Handle< class PropertyDefinitionContainer >