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
Showing
with 390 additions and 62 deletions
[[_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)
# ARON Readers, Writers and Conversion {#aron-conversion}
\ref aron "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
(for example, 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.
For example, 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`.
# ARON Visitors {#aron-visitors}
\tableofcontents
Visitors are a useful tool to define specific methods for specific types
without specifying the `switch(): case: ...` again and again.
Further, recursive visitors offer a convenient way to iterate through the tree-like structure of any Aron object.
(Please note that right now the implementation does not check for cycles!).
Again, we will only look at data visitors since the implementation of type visitors is more or less similar.
## Non-recursive Visitors
First, there are "normal" visitors.
They are used to get rid of the big switch-case statement when getting an Aron object with unknown type.
Further, these visitors can be used to convert an Aron object from one representation into another (see \ref aron-conversion).
The `armarx::aron::data::Visitor` base class offers the following pure virtual methods which you have to implement:
```cpp
virtual data::Descriptor getDescriptor(Input&) = 0;
virtual void visitDict(Input&) {};
virtual void visitList(Input&) {};
virtual void visitNDArray(Input&) {};
virtual void visitInt(Input&) {};
virtual void visitLong(Input&) {};
virtual void visitFloat(Input&) {};
virtual void visitDouble(Input&) {};
virtual void visitBool(Input&) {};
virtual void visitString(Input&) {};
virtual void visitUnknown(Input&) { throw error::AronException(__PRETTY_FUNCTION__, "Unknown type in visitor."); }
```
`Input` is a template parameter, defining the Input-type
(e.g. `const armarx::aron::data::VariantPtr` for a `VariantVisitor` Implementation).
The method `getDescriptor(Input&)` is used for the switch case internally.
As you can see the `VariantVisitor` always gets a generic variant as input in each function.
This means that, although the Visitor guarantees that the input is correct, you have to cast the class to the correct
type.
For widely used Visitors, the Aron library offers convenience implementations
(e.g. for Variants and for nlohmann::json inputs).
The convenience class for Variants additionally adds overloads where the input is already cast correctly
(you can decide which method you want to override).
To use a Visitor, you have to use the function
```cpp
void visit(VisitorImplementation& v, typename VisitorImplementation::Input& o);
```
which takes the visitor and the input as arguments and does the switch-case.
## Recursive Visitors
Recursive visitors are similar to normal visitors, but they continue "visiting" until the object is fully visited.
For containers (e.g. dicts, lists) they offer two methods each:
```cpp
virtual void visitDictOnEnter(Input& element) {};
virtual void visitDictOnExit(Input& element) {};
virtual void visitListOnEnter(Input& element) {};
virtual void visitListOnExit(Input& element) {};
```
The `*OnEnter` method is called before iterating over all children of the container.
The `*OnExit` is called after the iteration.
Further, in order to get the elements of a container, you must implement the methods:
```cpp
virtual MapElements getDictElements(Input&) = 0;
virtual ListElements getListElements(Input&) = 0;
```
Again, Input can be any aron object (e.g. Variant or nlohmann::json).
As for normal visitors, the Aron library offers convenience implementations for Variants and nlohmann::json inputs.
To use the RecursiveVisitor, you have to use the function
```cpp
void visitRecursive(RecursiveVisitorImplementation& v, typename RecursiveVisitorImplementation::Input& o);
```
### Example
Assume you want to count how many objects of each kind you have in a Variant.
```cpp
#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
class CountingRecursiveVisitor : public RecursiveConstVariantVisitor
{
public:
int dicts = 0;
int lists = 0;
int ndarrays = 0;
int ints = 0;
int floats = 0;
int longs = 0;
int doubles = 0;
int strings = 0;
int bools = 0;
public:
void visitAronVariantOnEnter(const data::DictPtr&) override { dicts++; }
void visitAronVariantOnEnter(const data::ListPtr&) override { lists++; }
void visitAronVariant(const data::NDArrayPtr&) override { ndarrays++; }
void visitAronVariant(const data::IntPtr&) override { ints++; }
void visitAronVariant(const data::LongPtr&) override { longs++; }
void visitAronVariant(const data::FloatPtr&) override { floats++; }
void visitAronVariant(const data::DoublePtr&) override { doubles++; }
void visitAronVariant(const data::BoolPtr&) override { strings++; }
void visitAronVariant(const data::StringPtr&) override { bools++; }
};
void countHowMany(const aron::data::VariantPtr& aron)
{
CountingRecursiveVisitor visitor;
aron::data::visitRecursive(visitor, aron);
std::cout << "The aron has " << visitor.dicts << " dicts." << std::endl;
}
```
## Typed Visitors
# Lessons Learned
......@@ -18,6 +18,15 @@
# ArmarX.ApplicationName = ""
# ArmarX.AutodiscoverPackages: If enabled, will discover all ArmarX packages based on the environment variables. Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.AutodiscoverPackages = true
# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config)
# Attributes:
# - Default: mongo/.cache
......
......@@ -18,6 +18,15 @@
# ArmarX.ApplicationName = ""
# ArmarX.AutodiscoverPackages: If enabled, will discover all ArmarX packages based on the environment variables. Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.AutodiscoverPackages = true
# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config)
# Attributes:
# - Default: mongo/.cache
......
......@@ -18,6 +18,15 @@
# ArmarX.ApplicationName = ""
# ArmarX.AutodiscoverPackages: If enabled, will discover all ArmarX packages based on the environment variables. Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used.
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.AutodiscoverPackages = true
# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config)
# Attributes:
# - Default: mongo/.cache
......
......@@ -37,6 +37,8 @@
#include <ArmarXCore/core/rapidxml/wrapper/RapidXmlReader.h>
#include <ArmarXCore/core/system/ArmarXDataPath.h>
#include <ArmarXCore/core/time/TimeUtil.h>
#include <RobotAPI/components/units/RobotUnit/util/RtTiming.h>
#include <RobotAPI/components/units/RobotUnit/util/NonRtTiming.h>
using namespace Eigen;
......@@ -296,10 +298,10 @@ namespace armarx
{
if (timestamp <= 0)
{
timestamp = IceUtil::Time::now().toMicroSeconds();
timestamp = armarx::rtNow().toMicroSeconds();
}
IceUtil::Time time = IceUtil::Time::microSeconds(timestamp);
IceUtil::Time time = mapRtTimestampToNonRtTimestamp(IceUtil::Time::microSeconds(timestamp));
ARMARX_DEBUG << deactivateSpam(1) << "Got new jointangles: " << jointAngles
<< " from timestamp " << time.toDateTime()
......
......@@ -78,6 +78,7 @@ set(LIB_HEADERS
util/introspection/ClassMemberInfo.h
util/RtLogging.h
util/RtTiming.h
util/NonRtTiming.h
util/CtrlUtil.h
#robot unit modules need to be added to the list below (but not here)
......
# RobotUnit
# RobotUnit {#RobotUnit}
The RobotUnit can be used for real-time control.
The central principle is that all controllers are executed synchronously.
The controllers are arranged in a 2-layer architecture.
......
......@@ -30,6 +30,8 @@
#include <ArmarXCore/core/util/FileSystemPathBuilder.h>
#include <ArmarXCore/util/CPPUtility/trace.h>
#include "RobotAPI/components/units/RobotUnit/util/NonRtTiming.h"
#include "../util/ControlThreadOutputBuffer.h"
#include "RobotUnitModuleControlThreadDataBuffer.h"
#include "RobotUnitModuleDevices.h"
......@@ -1060,7 +1062,8 @@ namespace armarx::RobotUnitModule
auto& data = result.emplace_back(getResultElement());
data.iterationId = e.iteration;
data.timestampUSec = e.sensorValuesTimestamp.toMicroSeconds();
data.timestampUSec =
armarx::mapRtTimestampToNonRtTimestamp(e.sensorValuesTimestamp).toMicroSeconds();
data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
}
......
......@@ -35,6 +35,7 @@
#include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.h>
#include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h>
#include <RobotAPI/components/units/RobotUnit/Units/RobotUnitSubUnit.h>
#include <RobotAPI/components/units/RobotUnit/util/NonRtTiming.h>
namespace armarx::RobotUnitModule
{
......@@ -632,7 +633,10 @@ namespace armarx::RobotUnitModule
const auto requestedJointControllers =
_module<ControlThreadDataBuffer>().copyRequestedJointControllers();
lastControlThreadTimestamp = controlThreadOutputBuffer.sensorValuesTimestamp;
// controlThreadOutputBuffer.sensorValuesTimestamp is in MONOTONIC_RAW (not relative to epoch).
// We have to map it to be relative to epoch (REAL_TIME).
lastControlThreadTimestamp =
armarx::mapRtTimestampToNonRtTimestamp(controlThreadOutputBuffer.sensorValuesTimestamp);
const bool publishToObserver = !(publishIterationCount % debugObserverSkipIterations);
//publish publishing meta state
......
......@@ -34,6 +34,7 @@
#include "../Devices/SensorDevice.h"
#include "../SensorValues/SensorValueBase.h"
#include "HeterogenousContinuousContainer.h"
#include "RtTiming.h"
namespace armarx
{
......@@ -50,7 +51,7 @@ namespace armarx::detail
{
struct RtMessageLogEntryBase
{
RtMessageLogEntryBase() : time{IceUtil::Time::now()}
RtMessageLogEntryBase() : time{armarx::rtNow()}
{
}
......
/*
* This file is part of ArmarX.
*
* Copyright (C) 2011-2017, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
*
* ArmarX is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ArmarX is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package ArmarX
* @author Mirko Waechter( mirko.waechter at kit dot edu)
* @date 2018
* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
* GNU General Public License
*/
#pragma once
#include <time.h>
#include <IceUtil/Time.h>
#include "RtTiming.h"
namespace armarx
{
inline IceUtil::Time
nonRtNow()
{
using namespace rt_timing::constants;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return IceUtil::Time::microSeconds(ts.tv_sec * seconds2MicroSeconds +
ts.tv_nsec / nanoSeconds2MicroSeconds);
}
inline IceUtil::Time
mapRtTimestampToNonRtTimestamp(const IceUtil::Time& time_monotic_raw)
{
// This is the "real time" clock, i.e. NTP-synchronized and relative to epoch.
IceUtil::Time now_real_time = armarx::nonRtNow();
// This is not relative to epoch and not NTP-synchronized.
IceUtil::Time now_monotonic_raw = armarx::rtNow();
/*
* Assumption for small very small time deltas (i.e. "time" is close to "now"):
*
* time_real_time - now_real_time == time_monotic_raw - now_monotonic_raw
* =>
* time_real_time = time_monotic_raw - now_monotonic_raw + now_real_time
*/
//
IceUtil::Time time_real_time = time_monotic_raw - now_monotonic_raw + now_real_time;
ARMARX_DEBUG << VAROUT(time_monotic_raw) << " vs. " << VAROUT(time_real_time);
return time_real_time;
}
} // namespace armarx
......@@ -23,8 +23,9 @@
*/
#pragma once
#include <chrono>
#include "ControlThreadOutputBuffer.h"
#include <time.h>
#include <IceUtil/Time.h>
namespace armarx
{
......@@ -36,11 +37,11 @@ namespace armarx
} // namespace rt_timing::constants
inline IceUtil::Time
rtNow(clockid_t clockId = CLOCK_MONOTONIC_RAW)
rtNow()
{
using namespace rt_timing::constants;
struct timespec ts;
clock_gettime(clockId, &ts);
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
return IceUtil::Time::microSeconds(ts.tv_sec * seconds2MicroSeconds +
ts.tv_nsec / nanoSeconds2MicroSeconds);
}
......@@ -50,8 +51,7 @@ namespace armarx
//! \ingroup VirtualTime
//! Prints duration with comment in front of it, yet only once per second.
#define RT_TIMING_END_COMMENT(name, comment) \
printf( \
"%s - duration: %.3f ms \n", comment, (armarx::rtNow() - name).toMilliSecondsDouble());
printf("%s - duration: %.3f ms \n", comment, (armarx::rtNow() - name).toMilliSecondsDouble());
//! \ingroup VirtualTime
//! Prints duration
#define RT_TIMING_END(name) RT_TIMING_END_COMMENT(name, #name)
......
# GamepadUnit
# GamepadUnit {#GamepadUnit}
This component is used to control the robot with a gamepad.
......
<!--
Recognized and spoken names of a known object.
-->
<?xml version="1.0" encoding="UTF-8" ?>
<AronTypeDefinition>
<GenerateTypes>
<Object name="armarx::arondto::ObjectNames">
<ObjectChild key="recognizedNames">
<List>
<String/>
</List>
</ObjectChild>
<ObjectChild key="spokenNames">
<List>
<String/>
</List>
</ObjectChild>
</Object>
</GenerateTypes>
</AronTypeDefinition>