MemoryToDebugObserver.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::MemoryToDebugObserver
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2023
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <SimoxUtility/algorithm/string/string_tools.h>
26
32
34{
35
37 const Services& services) :
38 properties(properties), services(services)
39 {
40 services.debugObserver.setDebugObserverBatchModeEnabled(true);
41 }
42
44 {
45 public:
49
50 // void visitAronVariant(const data::DictPtr&) override;
51 // void visitAronVariant(const data::ListPtr&) override;
52 // void visitAronVariant(const data::NDArrayPtr&) override;
53 void
55 {
56 setDatafield(v->getValue());
57 }
58
59 void
61 {
62 setDatafield(v->getValue());
63 }
64
65 void
67 {
68 setDatafield(v->getValue());
69 }
70
71 void
73 {
74 setDatafield(v->getValue());
75 }
76
77 void
79 {
80 setDatafield(v->getValue());
81 }
82
83 void
85 {
86 setDatafield(v->getValue());
87 }
88
89 template <class ValueT>
90 void
91 setDatafield(const ValueT& value)
92 {
93 debugObserver.setDebugObserverDatafield(channelName, datafieldName, value);
94 ++count;
95 }
96
98 std::string channelName;
99 std::string datafieldName;
100
101 int count = 0;
102 };
103
104 void
106 {
107 Visitor visitor(services.debugObserver);
108
109 std::stringstream log;
110
111 // Group by memory segment to reduce number of queries.
112 std::map<MemoryID, std::vector<const MemoryValueID*>> valuesPerProviderSegment;
113 for (const MemoryValueID& valueId : properties.plottedValues)
114 {
115 valuesPerProviderSegment[valueId.entityID.getProviderSegmentID()].push_back(&valueId);
116 }
117
118 for (const auto& [providerSegmentID, values] : valuesPerProviderSegment)
119 {
120 armem::client::Reader* reader = nullptr;
121 try
122 {
123 reader = getReader(providerSegmentID);
124 }
126 {
127 log << "\n" << e.what();
128 continue;
129 }
130 ARMARX_CHECK_NOT_NULL(reader);
131
132 const QueryResult result = reader->getLatestSnapshotsIn(providerSegmentID);
133 if (not result.success)
134 {
135 log << "Query to provider segment " << providerSegmentID
136 << " failed: " << result.errorMessage;
137 continue;
138 }
139
140 for (const MemoryValueID* valueId : values)
141 {
142 const wm::Entity* entity = result.memory.findEntity(valueId->entityID);
143 if (entity == nullptr)
144 {
145 log << "\nDid not find entity " << valueId->entityID << " in provider segment "
146 << providerSegmentID << ".";
147 continue;
148 }
149
150 // Use the non-throwing findLatestInstance() variant: an
151 // entity may exist but have no snapshots (e.g. just
152 // created, or all snapshots truncated by maxHistorySize),
153 // or its latest snapshot may carry no instances. In both
154 // cases getLatestInstance() throws NoSuchEntries, which
155 // would propagate uncaught out of pollOnce() and abort
156 // the polling thread.
157 const wm::EntityInstance* instance = entity->findLatestInstance();
158 if (instance == nullptr)
159 {
160 log << "\nEntity " << valueId->entityID
161 << " has no latest instance (yet) in provider segment "
162 << providerSegmentID << ".";
163 continue;
164 }
165
166 aron::data::VariantPtr valueVariant =
167 instance->data()->navigateAbsolute(valueId->aronPath);
168 if (not valueVariant)
169 {
170 log << "\nDid not find " << valueId->aronPath.toString()
171 << " in entity instance " << instance->id() << ".";
172 continue;
173 }
174
175 visitor.channelName = makeChannelName(valueId->entityID);
176 visitor.datafieldName = makeDatafieldName(valueId->aronPath);
177
178 aron::data::visit(visitor, valueVariant);
179 }
180 }
181
182 services.debugObserver.sendDebugObserverBatch();
183
184 if (not log.str().empty())
185 {
187 << "Encountered issues while sending memory values to the debug observer "
188 "for plotting: "
189 << log.str();
190 }
191 }
192
193 std::string
194 MemoryToDebugObserver::makeChannelName(const MemoryID& memoryID)
195 {
196 return simox::alg::replace_all(memoryID.str(), "/", ">");
197 }
198
199 std::string
200 MemoryToDebugObserver::makeDatafieldName(const aron::Path& path)
201 {
202 // The first element is always "ARON->", which we can discard for readability.
203 std::string str = path.toString();
204 str = simox::alg::remove_prefix(str, path.getRootIdentifier() + path.getDelimeter());
205 str = simox::alg::replace_all(str, path.getDelimeter(), ">");
206 return str;
207 }
208
209 Reader*
210 MemoryToDebugObserver::getReader(const MemoryID& memoryID)
211 {
212 auto it = memoryReaders.find(memoryID);
213 if (it != memoryReaders.end())
214 {
215 return &it->second;
216 }
217 else
218 {
219 armem::client::Reader reader = services.memoryNameSystem.getReader(memoryID);
220
221 auto [it, _] = memoryReaders.emplace(memoryID, reader);
222 return &it->second;
223 }
224 }
225
226} // namespace armarx::armem::client::util
227
228namespace armarx::armem::client
229{
230
231 void
232 util::to_json(simox::json::json& j, const MemoryValueID& id)
233 {
234 j["entityID"] = id.entityID.getItems();
235 j["aronPath"] = id.aronPath.getPath();
236 }
237
238 void
239 util::from_json(const simox::json::json& j, MemoryValueID& id)
240 {
241 id.entityID = MemoryID::fromItems(j.at("entityID").get<std::vector<std::string>>());
242 id.aronPath = {j.at("aronPath").get<std::vector<std::string>>()};
243 }
244
245 void
246 util::to_json(simox::json::json& j, const MemoryToDebugObserver::Properties& p)
247 {
248 j["plottedValues"] = p.plottedValues;
249 }
250
251 void
253 {
254 j.at("plottedValues").get_to(p.plottedValues);
255 }
256
257
258} // namespace armarx::armem::client
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
std::string str(const T &t)
Brief description of class DebugObserverHelper.
static MemoryID fromItems(const std::vector< std::string > &items)
Constructor memory ID from items as returned by getItems().
Definition MemoryID.cpp:194
MemoryID getProviderSegmentID() const
Definition MemoryID.cpp:302
std::string str(bool escapeDelimiters=true) const
Get a string representation of this memory ID.
Definition MemoryID.cpp:102
auto * findLatestInstance(int instanceIndex=0)
Definition EntityBase.h:356
Reader getReader(const MemoryID &memoryID)
Get a reader to the given memory name.
Reads data from a memory server.
Definition Reader.h:25
QueryResult getLatestSnapshotsIn(const MemoryID &id, armem::query::DataMode dataMode=armem::query::DataMode::WithData) const
Get the latest snapshots under the given memory ID.
Definition Reader.cpp:427
void pollOnce()
Query values from the memory and send them to the debug observer.
MemoryToDebugObserver(const Properties &properties, const Services &services)
Constructor.
Visitor(armarx::DebugObserverHelper &debugObserver)
armarx::DebugObserverHelper & debugObserver
void visitAronVariant(const aron::data::LongPtr &v) override
void visitAronVariant(const aron::data::IntPtr &v) override
void visitAronVariant(const aron::data::DoublePtr &v) override
void visitAronVariant(const aron::data::StringPtr &v) override
void visitAronVariant(const aron::data::FloatPtr &v) override
void visitAronVariant(const aron::data::BoolPtr &v) override
Indicates that a query to the Memory Name System failed.
Definition mns.h:25
The Path class.
Definition Path.h:36
std::string toString() const
Definition Path.cpp:127
std::string getDelimeter() const
Definition Path.cpp:75
std::string getRootIdentifier() const
Definition Path.cpp:63
#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
void from_json(const simox::json::json &j, MemoryValueID &id)
void to_json(simox::json::json &j, const MemoryValueID &id)
armem::wm::EntityInstance EntityInstance
std::shared_ptr< Bool > BoolPtr
std::shared_ptr< Float > FloatPtr
std::shared_ptr< Variant > VariantPtr
std::shared_ptr< Long > LongPtr
std::shared_ptr< Int > IntPtr
void visit(VisitorImplementation &v, typename VisitorImplementation::Input &o)
Definition Visitor.h:136
std::shared_ptr< Double > DoublePtr
std::shared_ptr< String > StringPtr
auto * findEntity(const MemoryID &entityID)
Find an entity.
Result of a QueryInput.
Definition Query.h:51
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58