ArmarDEConverter.cpp
Go to the documentation of this file.
1#include "ArmarDEConverter.h"
2
3#include <cmath>
4#include <cstddef>
5#include <map>
6#include <set>
7#include <string>
8#include <vector>
9
10#include <SimoxUtility/algorithm/string/string_tools.h>
11
13
14#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h>
15#include <RobotAPI/libraries/armem_robot_state/aron/Exteroception.aron.generated.h>
17
18#include "ConverterTools.h"
19
21{
22
23 ArmarDEConverter::ArmarDEConverter(const Properties& properties) : properties_(properties)
24 {
25 }
26
28
30 ArmarDEConverter::convert(const RobotUnitDataStreaming::TimeStep& data,
31 const RobotUnitDataStreaming::DataStreamingDescription& description)
32 {
33 arondto::Exteroception dto;
34 dto.iterationID = data.iterationId;
35
36 // initialize fields
37 const std::size_t singleDimSize = static_cast<std::size_t>(std::sqrt(properties_.tofSize));
38 ARMARX_CHECK_EQUAL(singleDimSize * singleDimSize, properties_.tofSize);
39
40 // initialize empty
41 for (const auto& id : {"Left", "Right"})
42 {
43 // FIXME change if unsigned
44 dto.tof[id].depth.resize(singleDimSize, singleDimSize);
45 dto.tof[id].depth.setConstant(-1); // in order to unset fields faults
46
47 // FIXME change if unsigned
48 dto.tof[id].sigma.resize(singleDimSize, singleDimSize);
49 dto.tof[id].sigma.setConstant(-1); // in order to unset fields faults
50
51 // FIXME change if unsigned
52 dto.tof[id].targetDetected.resize(singleDimSize, singleDimSize);
53 dto.tof[id].targetDetected.setConstant(-1); // in order to unset fields faults
54 }
55
56
57 for (const auto& [dataEntryName, dataEntry] : description.entries)
58 {
59 process(dto, dataEntryName, {.data = data, .entry = dataEntry});
60 }
61
62 // Ensure that we only generate updates if data has changed. As the ToF sensors might only generate data at a lower rate (e.g., 15Hz) and the
63 // read loop in the unit might run at a higher rate, we might end up with a lot of duplicate data. Therefore, we check if the data is still
64 // the same and remove those entries from the update.
65 {
66 std::vector<std::string> keysToRemove;
67 for (const auto& [id, data] : dto.tof)
68 {
69 // Check if this is the first time we got data
70 if (lastData.count(id) == 0)
71 {
72 lastData.emplace(id, data);
73
74 {
75 // This is a robust HACK: as it might happen that the connection to the ToF sensor was lost at some point, the robot unit streaming
76 // might report some old data which does not change. Therefore, we initialize lastData and do not report it unless there is a change.
77 keysToRemove.push_back(id);
78 }
79
80 continue; // new data can be kept
81 }
82
83 // Check if the data is similar and remove it from the update. Here, we maintain a separate vector to avoid interference with the for loop
84 if (data == lastData.at(id))
85 {
86 keysToRemove.push_back(id);
87 }
88
89 // Update the history
90 lastData[id] = data;
91 }
92
93 // remove the found elements from the update
94 for (const auto& key : keysToRemove)
95 {
96 dto.tof.erase(key);
97 }
98 }
99
100
101 // If the data has not changed at all, we indicate this by a nullptr
102 if (dto.tof.empty())
103 {
104 return nullptr;
105 }
106
107
108 // resize to square
109 // for (auto& [_, tof] : dto.tof)
110 // {
111 // const int sr = std::sqrt(tof.array.size());
112 // const bool isSquare = (sr * sr == tof.array.size());
113
114 // if (tof.array.size() > 0 and isSquare)
115 // {
116 // tof.array.resize(sr, sr);
117 // }
118 // }
119
120
121 return dto.toAron();
122 }
123
124 void
125 ArmarDEConverter::process(arondto::Exteroception& dto,
126 const std::string& entryName,
127 const ConverterValue& value)
128 {
129 const std::vector<std::string> split = simox::alg::split(entryName, ".", false, false);
131 const std::set<size_t> acceptedSizes{3, 4, 5};
132 ARMARX_CHECK_GREATER(acceptedSizes.count(split.size()), 0)
133 << "Data entry name could not be parsed (exected 3 or 4 or 5 components between '.'): "
134 << "\n- split: '" << split << "'";
135
136 const std::string& category = split.at(0);
137 // const std::string& name = split.at(1);
138 const std::string& field = split.at(2);
139 ARMARX_CHECK_EQUAL(category, "sens") << category << " | " << entryName;
140
141 if (simox::alg::contains(field, "tofDepth"))
142 {
143 // ARMARX_DEBUG << "Processing ToF sensor data";
144 processToFDepthEntry(dto.tof, split, value);
145 }
146
147 if (simox::alg::contains(field, "tofSigma"))
148 {
149 // ARMARX_DEBUG << "Processing ToF sensor data";
150 processToFSigmaEntry(dto.tof, split, value);
151 }
152
153 if (simox::alg::contains(field, "tofTargetDetected"))
154 {
155 // ARMARX_DEBUG << "Processing ToF sensor data";
156 processToFTargetDetectedEntry(dto.tof, split, value);
157 }
158 }
159
160 void
161 ArmarDEConverter::processToFDepthEntry(
162 std::map<std::string, armarx::armem::exteroception::arondto::ToF>& tofs,
163 const std::vector<std::string>& split,
164 const ConverterValue& value)
165 {
166 // split e.g. "sens.LeftHand.tofDepth.element_15" (split at dot)
167
168 ARMARX_CHECK_EQUAL(split.size(), 4);
169 ARMARX_CHECK_EQUAL(split.at(2), "tofDepth");
170
171 const std::string& name = split.at(1);
172
173 // element 0 sens
174 // element 1 is either LeftHand or RightHand
175
176 const std::map<std::string, std::string> sidePrefixMap{{"LeftHand", "Left"},
177 {"RightHand", "Right"}};
178
179 auto it = sidePrefixMap.find(name);
180 ARMARX_CHECK(it != sidePrefixMap.end()) << name;
181
182 const std::string& side = it->second;
183 processToFDepthEntry(tofs[side], split, value);
184 }
185
186 void
187 ArmarDEConverter::processToFDepthEntry(armarx::armem::exteroception::arondto::ToF& tof,
188 const std::vector<std::string>& split,
189 const ConverterValue& value)
190 {
191 // split, e.g., element_12
192 const std::vector<std::string> elements = simox::alg::split(split.back(), "_");
193 ARMARX_CHECK_EQUAL(elements.size(), 2);
194
195 const int idx = std::stoi(elements.at(1));
196
197 ARMARX_CHECK_LESS(idx, tof.depth.size());
198
199 // we don't allow dynamic ToF size atm
200 // if (tof.array.size() < (idx + 1))
201 // {
202 // tof.array.resize(idx + 1, 1);
203 // }
204
205 tof.depth(idx) = getValueAs<float>(value);
206 }
207
208 void
209 ArmarDEConverter::processToFSigmaEntry(
210 std::map<std::string, armarx::armem::exteroception::arondto::ToF>& tofs,
211 const std::vector<std::string>& split,
212 const ConverterValue& value)
213 {
214 // split e.g. "sens.LeftHand.tofDepth.element_15" (split at dot)
215
216 ARMARX_CHECK_EQUAL(split.size(), 4);
217 ARMARX_CHECK_EQUAL(split.at(2), "tofSigma");
218
219 const std::string& name = split.at(1);
220
221 // element 0 sens
222 // element 1 is either LeftHand or RightHand
223
224 const std::map<std::string, std::string> sidePrefixMap{{"LeftHand", "Left"},
225 {"RightHand", "Right"}};
226
227 auto it = sidePrefixMap.find(name);
228 ARMARX_CHECK(it != sidePrefixMap.end()) << name;
229
230 const std::string& side = it->second;
231 processToFSigmaEntry(tofs[side], split, value);
232 }
233
234 void
235 ArmarDEConverter::processToFSigmaEntry(armarx::armem::exteroception::arondto::ToF& tof,
236 const std::vector<std::string>& split,
237 const ConverterValue& value)
238 {
239 // split, e.g., element_12
240 const std::vector<std::string> elements = simox::alg::split(split.back(), "_");
241 ARMARX_CHECK_EQUAL(elements.size(), 2);
242
243 const int idx = std::stoi(elements.at(1));
244
245 ARMARX_CHECK_LESS(idx, tof.sigma.size());
246
247 // we don't allow dynamic ToF size atm
248 // if (tof.array.size() < (idx + 1))
249 // {
250 // tof.array.resize(idx + 1, 1);
251 // }
252
253 tof.sigma(idx) = getValueAs<float>(value);
254 }
255
256 void
257 ArmarDEConverter::processToFTargetDetectedEntry(
258 std::map<std::string, armarx::armem::exteroception::arondto::ToF>& tofs,
259 const std::vector<std::string>& split,
260 const ConverterValue& value)
261 {
262 // split e.g. "sens.LeftHand.tofDepth.element_15" (split at dot)
263
264 ARMARX_CHECK_EQUAL(split.size(), 4);
265 ARMARX_CHECK_EQUAL(split.at(2), "tofTargetDetected");
266
267 const std::string& name = split.at(1);
268
269 // element 0 sens
270 // element 1 is either LeftHand or RightHand
271
272 const std::map<std::string, std::string> sidePrefixMap{{"LeftHand", "Left"},
273 {"RightHand", "Right"}};
274
275 auto it = sidePrefixMap.find(name);
276 ARMARX_CHECK(it != sidePrefixMap.end()) << name;
277
278 const std::string& side = it->second;
279 processToFTargetDetectedEntry(tofs[side], split, value);
280 }
281
282 void
283 ArmarDEConverter::processToFTargetDetectedEntry(armarx::armem::exteroception::arondto::ToF& tof,
284 const std::vector<std::string>& split,
285 const ConverterValue& value)
286 {
287 // split, e.g., element_12
288 const std::vector<std::string> elements = simox::alg::split(split.back(), "_");
289 ARMARX_CHECK_EQUAL(elements.size(), 2);
290
291 const int idx = std::stoi(elements.at(1));
292
293 ARMARX_CHECK_LESS(idx, tof.targetDetected.size());
294
295 // we don't allow dynamic ToF size atm
296 // if (tof.array.size() < (idx + 1))
297 // {
298 // tof.array.resize(idx + 1, 1);
299 // }
300
301 tof.targetDetected(idx) = getValueAs<float>(value);
302 }
303
304
305} // namespace armarx::armem::server::robot_state::exteroception
void process(arondto::Exteroception &dtoExteroception, const std::string &entryName, const ConverterValue &value)
aron::data::DictPtr convert(const RobotUnitDataStreaming::TimeStep &data, const RobotUnitDataStreaming::DataStreamingDescription &description) override
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
#define ARMARX_CHECK_GREATER_EQUAL(lhs, rhs)
This macro evaluates whether lhs is greater or equal (>=) rhs and if it turns out to be false it will...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)