Component.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 control::ArmarXObjects::collision_avoidance_skill_provider
17 * @author Meixner ( andre dot meixner at kit dot edu )
18 * @date 2025
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23
24#include "Component.h"
25
26// Include headers you only need in function definitions in the .cpp.
27
28// #include <Eigen/Core>
29
30// #include <SimoxUtility/color/Color.h>
31
33
34// Skill libraries
36
39
41{
42
43 const std::string Component::defaultName = "collision_avoidance";
44
46 {
47 //
48 }
49
52 {
54 new ::armarx::ComponentPropertyDefinitions(getConfigIdentifier());
55
56 // Publish to a topic (passing the TopicListenerPrx).
57 // def->topic(myTopicListener);
58
59 // Subscribe to a topic (passing the topic name).
60 // def->topic<PlatformUnitListener>("MyTopic");
61
62 // Use (and depend on) another component (passing the ComponentInterfacePrx).
63 // def->component(myComponentProxy)
64 //def->required(properties.robotUnitName, "RobotUnitName", "Name of the robot unit.");
65
66 def->required(
67 properties.controllerNames,
68 "p.controllerNames",
69 "Names of controllers to send the collision objects to. E.g. \"col:right,col:left\"");
70
71
72 // Add a required property. (The component won't start without a value being set.)
73 // def->required(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
74
75 // Add an optional property.
76 // def->optional(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
77 // def->optional(properties.numBoxes, "p.box.Number", "Number of boxes to draw in ArViz.");
78
79 return def;
80 }
81
82 void
84 {
85 // Topics and properties defined above are automagically registered.
86
87 // Keep debug observer data until calling `sendDebugObserverBatch()`.
88 // (Requires the armarx::DebugObserverComponentPluginUser.)
89 // setDebugObserverBatchModeEnabled(true);
90 }
91
92 void
94 {
95 // Do things after connecting to topics and components.
96
97 //skills::CollisionAvoidance::Properties properties;
99 robotStateReader.connect(memoryNameSystem());
100 ::armarx::control::client::ComponentPlugin* controlComponentPluginUser =
102 robotUnit = controlComponentPluginUser->getRobotUnitPlugin().getRobotUnit();
103
104 objectClassReader.connect(memoryNameSystem());
105 objectInstanceReader.connect(memoryNameSystem());
106 articulatedObjectReader.connect(memoryNameSystem());
107
108 /* (Requires the armarx::DebugObserverComponentPluginUser.)
109 // Use the debug observer to log data over time.
110 // The data can be viewed in the ObserverView and the LivePlotter.
111 // (Before starting any threads, we don't need to lock mutexes.)
112 {
113 setDebugObserverDatafield("numBoxes", properties.numBoxes);
114 setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
115 sendDebugObserverBatch();
116 }
117 */
118
119 /* (Requires the armarx::ArVizComponentPluginUser.)
120 // Draw boxes in ArViz.
121 // (Before starting any threads, we don't need to lock mutexes.)
122 drawBoxes(properties, arviz);
123 */
124
125 /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
126 // Setup the remote GUI.
127 {
128 createRemoteGuiTab();
129 RemoteGui_startRunningTask();
130 }
131 */
132 }
133
134 void
138
139 void
143
144 std::string
146 {
147 return Component::defaultName;
148 }
149
150 std::string
152 {
153 return Component::defaultName;
154 }
155
156 std::vector<std::vector<std::string>>
157 parseColumnConfig(const std::string& config)
158 {
159 std::vector<std::vector<std::string>> result;
160
161 std::stringstream ss(config);
162 std::string pair;
163
164 while (std::getline(ss, pair, ','))
165 {
166 std::vector<std::string> parts;
167 std::stringstream pairStream(pair);
168 std::string part;
169
170 while (std::getline(pairStream, part, ':'))
171 {
172 parts.push_back(part);
173 }
174 result.push_back(parts);
175 }
176 return result;
177 }
178
179 std::string
180 toLower(const std::string& str)
181 {
182 std::string result = str;
183 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
184 return result;
185 }
186
187 bool
188 containsAll(std::string name, std::vector<std::string> list)
189 {
190 std::string lowerCaseName = toLower(name);
191 return std::all_of(list.begin(),
192 list.end(),
193 [&lowerCaseName](const std::string& item)
194 {
195 std::string lowerCaseItem = toLower(item);
196 return lowerCaseName.find(lowerCaseItem) != std::string::npos;
197 });
198 }
199
200 void
201 Component::sendCollisionObjectsToController(const Ice::StringSeq& objectIDs,
202 const Ice::Current&)
203 {
204 auto names = robotUnit->getActivatedNJointControllerNames();
205 // find the controllers containing "controllerNames" in their name
206 auto controllerNamePatterns = parseColumnConfig(properties.controllerNames);
207 std::vector<std::string> controllerNames;
208
209 for (const auto& pattern : controllerNamePatterns)
210 {
211 bool controllerFound = false;
212 for (const auto& name : names)
213 {
214 if (containsAll(name, pattern))
215 {
216 controllerNames.push_back(name);
217 ARMARX_LOG << "found controller name: " << name;
218 controllerFound = true;
219 break;
220 }
221 }
222 if (!controllerFound)
223 {
224 ARMARX_ERROR_S << "No matching controller for pattern " << pattern;
225 }
226 }
227 if (controllerNames.size() != 0)
228 {
230 objectIDs,
231 objectClassReader,
232 objectInstanceReader,
233 articulatedObjectReader);
234
235 for (const auto& name : controllerNames)
236 {
237 controller = Ice::checkedCast<armarx::control::TSColAvoidCtrlInterfacePrx>(
238 robotUnit->getNJointController(name));
239
240 controller->updateCollisionObjects("CollisionAvoidanceSkill", scene.toAronDTO());
241 }
242 }
243 }
244
245 void
247 {
248 auto names = robotUnit->getActivatedNJointControllerNames();
249 // find the controllers containing "controllerNames" in their name
250 auto controllerNamePatterns = parseColumnConfig(properties.controllerNames);
251 std::vector<std::string> controllerNames;
252
253 for (const auto& pattern : controllerNamePatterns)
254 {
255 bool controllerFound = false;
256 for (const auto& name : names)
257 {
258 if (containsAll(name, pattern))
259 {
260 controllerNames.push_back(name);
261 ARMARX_LOG << "found controller name: " << name;
262 controllerFound = true;
263 break;
264 }
265 }
266 if (!controllerFound)
267 {
268 ARMARX_ERROR_S << "No matching controller for pattern " << pattern;
269 }
270 }
271 if (controllerNames.size() != 0)
272 {
273 for (const auto& name : controllerNames)
274 {
275 controller = Ice::checkedCast<armarx::control::TSColAvoidCtrlInterfacePrx>(
276 robotUnit->getNJointController(name));
277
278 controller->deleteCollisionObjects();
279 }
280 }
281 }
282
283 /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
284 void
285 Component::createRemoteGuiTab()
286 {
287 using namespace armarx::RemoteGui::Client;
288
289 // Setup the widgets.
290
291 tab.boxLayerName.setValue(properties.boxLayerName);
292
293 tab.numBoxes.setValue(properties.numBoxes);
294 tab.numBoxes.setRange(0, 100);
295
296 tab.drawBoxes.setLabel("Draw Boxes");
297
298 // Setup the layout.
299
300 GridLayout grid;
301 int row = 0;
302 {
303 grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1});
304 ++row;
305
306 grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1});
307 ++row;
308
309 grid.add(tab.drawBoxes, {row, 0}, {2, 1});
310 ++row;
311 }
312
313 VBoxLayout root = {grid, VSpacer()};
314 RemoteGui_createTab(getName(), root, &tab);
315 }
316
317
318 void
319 Component::RemoteGui_update()
320 {
321 if (tab.boxLayerName.hasValueChanged() || tab.numBoxes.hasValueChanged())
322 {
323 std::scoped_lock lock(propertiesMutex);
324 properties.boxLayerName = tab.boxLayerName.getValue();
325 properties.numBoxes = tab.numBoxes.getValue();
326
327 {
328 setDebugObserverDatafield("numBoxes", properties.numBoxes);
329 setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
330 sendDebugObserverBatch();
331 }
332 }
333 if (tab.drawBoxes.wasClicked())
334 {
335 // Lock shared variables in methods running in separate threads
336 // and pass them to functions. This way, the called functions do
337 // not need to think about locking.
338 std::scoped_lock lock(propertiesMutex);
339 drawBoxes(properties, arviz);
340 }
341 }
342 */
343
344
345 /* (Requires the armarx::ArVizComponentPluginUser.)
346 void
347 Component::drawBoxes(const Component::Properties& p, viz::Client& arviz)
348 {
349 // Draw something in ArViz (requires the armarx::ArVizComponentPluginUser.
350 // See the ArVizExample in RobotAPI for more examples.
351
352 viz::Layer layer = arviz.layer(p.boxLayerName);
353 for (int i = 0; i < p.numBoxes; ++i)
354 {
355 layer.add(viz::Box("box_" + std::to_string(i))
356 .position(Eigen::Vector3f(i * 100, 0, 0))
357 .size(20).color(simox::Color::blue()));
358 }
359 arviz.commit(layer);
360 }
361 */
362
363
365
366} // namespace armarx::control::components::collision_avoidance
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
std::string str(const T &t)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
virtual void connect(armem::client::MemoryNameSystem &memoryNameSystem)
armarx::plugins::RobotUnitComponentPlugin & getRobotUnitPlugin()
::armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition Component.cpp:51
void sendCollisionObjectsToController(const Ice::StringSeq &objectIDs, const Ice::Current &)
static std::string GetDefaultName()
Get the component's default name.
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_LOG
Definition Logging.h:165
armarx::control::common::control_law::arondto::CollisionScene getCollisionSceneFromMemory(const std::vector< armarx::ObjectID > &objectIDs, armarx::armem::obj::clazz::ClassReader &objectClassReader, armarx::armem::obj::instance::Reader &objectInstanceReader, armarx::armem::articulated_object::ArticulatedObjectReader &articulatedObjectReader)
bool containsAll(std::string name, std::vector< std::string > list)
std::vector< std::vector< std::string > > parseColumnConfig(const std::string &config)
std::string toLower(const std::string &str)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.