RobotStateWriter.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::RobotSensorMemory
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2020
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "RobotStateWriter.h"
24
25// STL
26#include <chrono>
27
28// Simox
29#include <SimoxUtility/math/convert/rpy_to_mat3f.h>
30
31// ArmarX
35
38#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
42
44{
45
46 void
48 {
49 // Thread-local copy of debug observer helper.
50 this->debugObserver =
51 DebugObserverHelper(Logging::tag.tagName, debugObserverPlugin.getDebugObserver(), true);
52 }
53
54 static float
55 toDurationMs(std::chrono::high_resolution_clock::time_point start,
56 std::chrono::high_resolution_clock::time_point end)
57 {
58 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
59 return duration.count() / 1000.f;
60 }
61
62 void
63 RobotStateWriter::run(float pollFrequency,
64 Queue& dataBuffer,
66 localization::Segment& localizationSegment)
67 {
68 while (isRunning())
69 {
70 if (debugObserver)
71 {
72 // This locks the queue, but I did not find an interface to lock the queue,
73 // get the size and wait_pull().
74 size_t dataBufferSize = dataBuffer.size();
75 debugObserver->setDebugObserverDatafield("RobotStateWriter | Queue Size",
76 static_cast<long>(dataBufferSize));
77
78 if (static_cast<long>(dataBufferSize) > properties.queueSizeWarningThreshold)
79 {
81 << "RobotStateWriter queue size (" << dataBufferSize
82 << ") exceeds threshold ("
83 << properties.queueSizeWarningThreshold
84 << "). The writer is not keeping up with incoming data.";
85 }
86 }
87
88 RobotUnitData robotUnitData;
89 if (const auto status = dataBuffer.wait_pull(robotUnitData);
90 status == boost::queue_op_status::success)
91 {
92 auto start = std::chrono::high_resolution_clock::now();
93 auto endBuildUpdate = start, endProprioception = start, endLocalization = start;
94
95 Update update = buildUpdate(robotUnitData);
96 endBuildUpdate = std::chrono::high_resolution_clock::now();
97
98 // Commits lock the core segments.
99
100 // Proprioception + Exteroception
101 armem::CommitResult resultProprioception =
102 memory.commitLocking(update.proprioception);
103
104 ARMARX_DEBUG << deactivateSpam(1) << VAROUT(update.exteroception.updates.size());
105 armem::CommitResult resultExteroception =
106 memory.commitLocking(update.exteroception);
107 endProprioception = std::chrono::high_resolution_clock::now();
108
109 // Localization
111 update.localization)
112 {
113 localizationSegment.commitTransformLocking(transform);
114 }
115 endLocalization = std::chrono::high_resolution_clock::now();
116
117 if (not resultProprioception.allSuccess())
118 {
119 ARMARX_WARNING << "Could not commit data to proprioception segment in memory. "
120 "Error message: "
121 << resultProprioception.allErrorMessages();
122 }
123
124 if (not resultExteroception.allSuccess())
125 {
126 ARMARX_WARNING << "Could not commit data to exteroception segment in memory. "
127 "Error message: "
128 << resultExteroception.allErrorMessages();
129 }
130
131 if (debugObserver)
132 {
133 auto end = std::chrono::high_resolution_clock::now();
134
135 debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit (ms)",
136 toDurationMs(start, end));
137 debugObserver->setDebugObserverDatafield(
138 "RobotStateWriter | t Commit 1. Build Update (ms)",
139 toDurationMs(start, endBuildUpdate));
140 debugObserver->setDebugObserverDatafield(
141 "RobotStateWriter | t Commit 2. Proprioception (ms)",
142 toDurationMs(endBuildUpdate, endProprioception));
143 debugObserver->setDebugObserverDatafield(
144 "RobotStateWriter | t Commit 3. Localization (ms)",
145 toDurationMs(endProprioception, endLocalization));
146 }
147 }
148 else
149 {
150 ARMARX_WARNING << "Queue pull was not successful. "
151 << static_cast<std::underlying_type<boost::queue_op_status>::type>(
152 status);
153 }
154
155 if (debugObserver)
156 {
157 debugObserver->sendDebugObserverBatch();
158 }
159 }
160 }
161
162 bool
163 RobotStateWriter::isRunning()
164 {
165 return task and not task->isStopped();
166 }
167
168 RobotStateWriter::Update
170 {
171 // Send batch to memory
172 Update update;
173
174 if (data.proprioception)
175 {
176 armem::EntityUpdate& up = update.proprioception.add();
177 up.entityID = properties.robotUnitProviderID.withEntityName(
178 properties.robotUnitProviderID.providerSegmentName);
179 up.entityID.coreSegmentName =
181 up.referencedTime = data.timestamp;
182 up.arrivedTime = data.timestampArrived;
183 up.instancesData = {data.proprioception};
184 }
185
186 // Exteroception
187 if (data.exteroception)
188 {
189 armem::EntityUpdate& up = update.exteroception.add();
190 up.entityID = properties.robotUnitProviderID.withEntityName(
191 properties.robotUnitProviderID.providerSegmentName);
192 up.entityID.coreSegmentName =
194 up.referencedTime = data.timestamp;
195 up.instancesData = {data.exteroception};
196 }
197
198 // Extract odometry data.
199 ARMARX_CHECK_NOT_NULL(data.proprioception);
200 const std::string platformKey = "platform";
201 if (data.proprioception->hasElement(platformKey))
202 {
203 ARMARX_DEBUG << "Found odometry data.";
204 auto platformData =
205 aron::data::Dict::DynamicCastAndCheck(data.proprioception->getElement(platformKey));
206 update.localization.emplace_back(getTransform(platformData, data.timestamp));
207 }
208 else
209 {
210 ARMARX_INFO << "No odometry data! "
211 << "(No element '" << platformKey << "' in proprioception data.)"
212 << "\nIf you are using a mobile platform this should not have happened."
213 << "\nThis error is only logged once."
214 << "\nThese keys exist: " << data.proprioception->getAllKeys();
215 noOdometryDataLogged = true;
216 }
217
218 return update;
219 }
220
222 RobotStateWriter::getTransform(const aron::data::DictPtr& platformData,
223 const Time& timestamp) const
224 {
225 prop::arondto::Platform platform;
226 platform.fromAron(platformData);
227
228 const Eigen::Vector3f& relPose = platform.relativePosition;
229
230 Eigen::Isometry3f odometryPose = Eigen::Isometry3f::Identity();
231 odometryPose.translation() << relPose.x(), relPose.y(), 0; // TODO set height
232 odometryPose.linear() = simox::math::rpy_to_mat3f(0.f, 0.f, relPose.z());
233
235 transform.header.parentFrame = armarx::OdometryFrame;
238 transform.header.timestamp = timestamp;
239 transform.transform = odometryPose;
240
241 return transform;
242 }
243
244} // namespace armarx::armem::server::robot_state::proprioception
std::string timestamp()
#define VAROUT(x)
Brief description of class DebugObserverHelper.
const DebugObserverInterfacePrx & getDebugObserver() const
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
bool isStopped()
Retrieve whether stop() has been called.
std::string providerSegmentName
Definition MemoryID.h:52
Helps connecting a Memory server to the Ice interface.
bool commitTransformLocking(const armem::robot_state::localization::Transform &transform)
Definition Segment.cpp:155
void connect(armarx::plugins::DebugObserverComponentPlugin &debugObserverPlugin)
void run(float pollFrequency, Queue &dataBuffer, MemoryToIceAdapter &memory, localization::Segment &localizationSegment)
Reads data from dataQueue and commits to the memory.
armarx::armem::server::robot_state::proprioception::Queue Queue
Brief description of class memory.
Definition memory.h:39
Brief description of class DebugObserverComponentPlugin.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
const std::string proprioceptionCoreSegment
Definition constants.h:30
const std::string exteroceptionCoreSegment
Definition constants.h:31
armarx::core::time::DateTime Time
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
std::string const OdometryFrame
Definition FramedPose.h:66
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT > >
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition algorithm.h:351
Result of a Commit.
Definition Commit.h:111
std::vector< std::string > allErrorMessages() const
Definition Commit.cpp:73
An update of an entity for a specific point in time.
Definition Commit.h:26