moveit2
The MoveIt Motion Planning Framework for ROS 2.
collision_matrix.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan, E. Gil Jones */
36 
38 #include <rclcpp/logger.hpp>
39 #include <rclcpp/logging.hpp>
40 #include <functional>
41 #include <iomanip>
42 #include <moveit/utils/logger.hpp>
43 
44 namespace collision_detection
45 {
46 namespace
47 {
48 rclcpp::Logger getLogger()
49 {
50  return moveit::getLogger("collision_detection_matrix");
51 }
52 } // namespace
53 
55 {
56 }
57 
58 AllowedCollisionMatrix::AllowedCollisionMatrix(const std::vector<std::string>& names, const bool allowed)
59 {
60  for (std::size_t i = 0; i < names.size(); ++i)
61  {
62  for (std::size_t j = i; j < names.size(); ++j)
63  setEntry(names[i], names[j], allowed);
64  }
65 }
66 
68 {
69  // load collision defaults
70  for (const std::string& name : srdf.getNoDefaultCollisionLinks())
72  // re-enable specific collision pairs
73  for (const auto& collision : srdf.getEnabledCollisionPairs())
74  setEntry(collision.link1_, collision.link2_, false);
75  // *finally* disable selected collision pairs
76  for (const auto& collision : srdf.getDisabledCollisionPairs())
77  setEntry(collision.link1_, collision.link2_, true);
78 }
79 
80 AllowedCollisionMatrix::AllowedCollisionMatrix(const moveit_msgs::msg::AllowedCollisionMatrix& msg)
81 {
82  if (msg.entry_names.size() != msg.entry_values.size() ||
83  msg.default_entry_names.size() != msg.default_entry_values.size())
84  {
85  RCLCPP_ERROR(getLogger(),
86  "The number of links does not match the number of entries in AllowedCollisionMatrix message");
87  return;
88  }
89  for (std::size_t i = 0; i < msg.default_entry_names.size(); ++i)
90  {
91  setDefaultEntry(msg.default_entry_names[i], msg.default_entry_values[i]);
92  }
93 
94  for (std::size_t i = 0; i < msg.entry_names.size(); ++i)
95  {
96  if (msg.entry_values[i].enabled.size() != msg.entry_names.size())
97  {
98  RCLCPP_ERROR(getLogger(), "Number of entries is incorrect for link '%s' in AllowedCollisionMatrix message",
99  msg.entry_names[i].c_str());
100  return;
101  }
102  for (std::size_t j = i + 1; j < msg.entry_values[i].enabled.size(); ++j)
103  {
104  AllowedCollision::Type allowed_default, allowed_entry;
105  if (!getDefaultEntry(msg.entry_names[i], msg.entry_names[j], allowed_default))
106  allowed_default = AllowedCollision::NEVER;
107  allowed_entry = msg.entry_values[i].enabled[j] ? AllowedCollision::ALWAYS : AllowedCollision::NEVER;
108 
109  if (allowed_entry != allowed_default)
110  setEntry(msg.entry_names[i], msg.entry_names[j], allowed_entry);
111  }
112  }
113 }
114 
115 bool AllowedCollisionMatrix::getEntry(const std::string& name1, const std::string& name2, DecideContactFn& fn) const
116 {
117  const auto it1 = allowed_contacts_.find(name1);
118  if (it1 == allowed_contacts_.end())
119  return false;
120  const auto it2 = it1->second.find(name2);
121  if (it2 == it1->second.end())
122  return false;
123  fn = it2->second;
124  return true;
125 }
126 
127 bool AllowedCollisionMatrix::getEntry(const std::string& name1, const std::string& name2,
128  AllowedCollision::Type& allowed_collision) const
129 {
130  const auto it1 = entries_.find(name1);
131  if (it1 == entries_.end())
132  return false;
133  auto it2 = it1->second.find(name2);
134  if (it2 == it1->second.end())
135  return false;
136  allowed_collision = it2->second;
137  return true;
138 }
139 
140 bool AllowedCollisionMatrix::hasEntry(const std::string& name) const
141 {
142  return entries_.find(name) != entries_.end();
143 }
144 
145 bool AllowedCollisionMatrix::hasEntry(const std::string& name1, const std::string& name2) const
146 {
147  const auto it1 = entries_.find(name1);
148  if (it1 == entries_.end())
149  return false;
150  const auto it2 = it1->second.find(name2);
151  return it2 != it1->second.end();
152 }
153 
154 void AllowedCollisionMatrix::setEntry(const std::string& name1, const std::string& name2, const bool allowed)
155 {
157  entries_[name1][name2] = entries_[name2][name1] = v;
158 
159  // remove function pointers, if any
160  auto it = allowed_contacts_.find(name1);
161  if (it != allowed_contacts_.end())
162  {
163  auto jt = it->second.find(name2);
164  if (jt != it->second.end())
165  it->second.erase(jt);
166  }
167  it = allowed_contacts_.find(name2);
168  if (it != allowed_contacts_.end())
169  {
170  auto jt = it->second.find(name1);
171  if (jt != it->second.end())
172  it->second.erase(jt);
173  }
174 }
175 
176 void AllowedCollisionMatrix::setEntry(const std::string& name1, const std::string& name2, DecideContactFn& fn)
177 {
178  entries_[name1][name2] = entries_[name2][name1] = AllowedCollision::CONDITIONAL;
179  allowed_contacts_[name1][name2] = allowed_contacts_[name2][name1] = fn;
180 }
181 
183 {
184  entries_.erase(name);
185  allowed_contacts_.erase(name);
186  for (auto& entry : entries_)
187  entry.second.erase(name);
188  for (auto& allowed_contact : allowed_contacts_)
189  allowed_contact.second.erase(name);
190 }
191 
192 void AllowedCollisionMatrix::removeEntry(const std::string& name1, const std::string& name2)
193 {
194  auto jt = entries_.find(name1);
195  if (jt != entries_.end())
196  {
197  auto it = jt->second.find(name2);
198  if (it != jt->second.end())
199  jt->second.erase(it);
200  }
201  jt = entries_.find(name2);
202  if (jt != entries_.end())
203  {
204  auto it = jt->second.find(name1);
205  if (it != jt->second.end())
206  jt->second.erase(it);
207  }
208 
209  auto it = allowed_contacts_.find(name1);
210  if (it != allowed_contacts_.end())
211  {
212  auto jt = it->second.find(name2);
213  if (jt != it->second.end())
214  it->second.erase(jt);
215  }
216  it = allowed_contacts_.find(name2);
217  if (it != allowed_contacts_.end())
218  {
219  auto jt = it->second.find(name1);
220  if (jt != it->second.end())
221  it->second.erase(jt);
222  }
223 }
224 
225 void AllowedCollisionMatrix::setEntry(const std::string& name, const std::vector<std::string>& other_names,
226  const bool allowed)
227 {
228  for (const auto& other_name : other_names)
229  {
230  if (other_name != name)
231  setEntry(other_name, name, allowed);
232  }
233 }
234 
235 void AllowedCollisionMatrix::setEntry(const std::vector<std::string>& names1, const std::vector<std::string>& names2,
236  const bool allowed)
237 {
238  for (const auto& name1 : names1)
239  setEntry(name1, names2, allowed);
240 }
241 
242 void AllowedCollisionMatrix::setEntry(const std::string& name, const bool allowed)
243 {
244  std::string last = name;
245  for (auto& entry : entries_)
246  {
247  if (name != entry.first && last != entry.first)
248  {
249  last = entry.first;
250  setEntry(name, entry.first, allowed);
251  }
252  }
253 }
254 
255 void AllowedCollisionMatrix::setEntry(const bool allowed)
256 {
258  for (auto& entry : entries_)
259  {
260  for (auto& it2 : entry.second)
261  it2.second = v;
262  }
263 }
264 
265 void AllowedCollisionMatrix::setDefaultEntry(const std::string& name, const bool allowed)
266 {
268  default_entries_[name] = v;
269  default_allowed_contacts_.erase(name);
270 }
271 
273 {
274  default_entries_[name] = AllowedCollision::CONDITIONAL;
275  default_allowed_contacts_[name] = fn;
276 }
277 
278 bool AllowedCollisionMatrix::getDefaultEntry(const std::string& name, AllowedCollision::Type& allowed_collision) const
279 {
280  auto it = default_entries_.find(name);
281  if (it == default_entries_.end())
282  return false;
283  allowed_collision = it->second;
284  return true;
285 }
286 
288 {
289  auto it = default_allowed_contacts_.find(name);
290  if (it == default_allowed_contacts_.end())
291  return false;
292  fn = it->second;
293  return true;
294 }
295 
296 static bool andDecideContact(const DecideContactFn& f1, const DecideContactFn& f2, Contact& contact)
297 {
298  return f1(contact) && f2(contact);
299 }
300 
301 bool AllowedCollisionMatrix::getAllowedCollision(const std::string& name1, const std::string& name2,
302  DecideContactFn& fn) const
303 {
304  const bool found = getEntry(name1, name2, fn);
305  if (!found)
306  {
307  DecideContactFn fn1, fn2;
308  const bool found1 = getDefaultEntry(name1, fn1);
309  const bool found2 = getDefaultEntry(name2, fn2);
310  if (found1 && !found2)
311  {
312  fn = fn1;
313  }
314  else if (!found1 && found2)
315  {
316  fn = fn2;
317  }
318  else if (found1 && found2)
319  {
320  fn = [fn1, fn2](Contact& contact) { return andDecideContact(fn1, fn2, contact); };
321  }
322  else
323  {
324  return false;
325  }
326  }
327  return true;
328 }
329 
330 bool AllowedCollisionMatrix::getDefaultEntry(const std::string& name1, const std::string& name2,
331  AllowedCollision::Type& allowed_collision) const
332 {
333  AllowedCollision::Type t1, t2;
334  const bool found1 = getDefaultEntry(name1, t1);
335  const bool found2 = getDefaultEntry(name2, t2);
336  if (!found1 && !found2)
337  {
338  return false;
339  }
340  else if (found1 && !found2)
341  {
342  allowed_collision = t1;
343  }
344  else if (!found1 && found2)
345  {
346  allowed_collision = t2;
347  }
348  else if (found1 && found2)
349  {
351  {
352  allowed_collision = AllowedCollision::NEVER;
353  }
355  {
356  allowed_collision = AllowedCollision::CONDITIONAL;
357  }
358  else
359  { // ALWAYS is the only remaining case
360  allowed_collision = AllowedCollision::ALWAYS;
361  }
362  }
363  return true;
364 }
365 
366 bool AllowedCollisionMatrix::getAllowedCollision(const std::string& name1, const std::string& name2,
367  AllowedCollision::Type& allowed_collision) const
368 {
369  return getEntry(name1, name2, allowed_collision) || getDefaultEntry(name1, name2, allowed_collision);
370 }
371 
373 {
374  entries_.clear();
375  allowed_contacts_.clear();
376  default_entries_.clear();
377  default_allowed_contacts_.clear();
378 }
379 
380 void AllowedCollisionMatrix::getAllEntryNames(std::vector<std::string>& names) const
381 {
382  names.clear();
383  for (const auto& entry : entries_)
384  names.push_back(entry.first);
385 
386  for (const auto& item : default_entries_)
387  {
388  auto it = std::lower_bound(names.begin(), names.end(), item.first);
389  if (it != names.end() && *it != item.first)
390  names.insert(it, item.first);
391  }
392 }
393 
394 void AllowedCollisionMatrix::getMessage(moveit_msgs::msg::AllowedCollisionMatrix& msg) const
395 {
396  msg.entry_names.clear();
397  msg.entry_values.clear();
398  msg.default_entry_names.clear();
399  msg.default_entry_values.clear();
400 
401  getAllEntryNames(msg.entry_names);
402 
403  msg.entry_values.resize(msg.entry_names.size());
404  for (std::size_t i = 0; i < msg.entry_names.size(); ++i)
405  msg.entry_values[i].enabled.resize(msg.entry_names.size(), false);
406 
407  // there is an approximation here: if we use a function to decide
408  // whether a collision is allowed or not, we just assume the collision is not allowed.
409  for (std::size_t i = 0; i < msg.entry_names.size(); ++i)
410  {
412  const bool dfound = getDefaultEntry(msg.entry_names[i], dtype);
413  if (dfound)
414  {
415  msg.default_entry_names.push_back(msg.entry_names[i]);
416  msg.default_entry_values.push_back(dtype == AllowedCollision::ALWAYS);
417  }
418 
419  for (std::size_t j = i; j < msg.entry_names.size(); ++j)
420  {
422  getAllowedCollision(msg.entry_names[i], msg.entry_names[j], type);
423  msg.entry_values[i].enabled[j] = msg.entry_values[j].enabled[i] = (type == AllowedCollision::ALWAYS);
424  }
425  }
426 }
427 
428 void AllowedCollisionMatrix::print(std::ostream& out) const
429 {
430  std::vector<std::string> names;
431  getAllEntryNames(names);
432 
433  std::size_t spacing = 4;
434  for (const auto& name : names)
435  {
436  const std::size_t length = name.length();
437  if (length > spacing)
438  spacing = length;
439  }
440  ++spacing;
441 
442  std::size_t number_digits = 2;
443  while (names.size() > pow(10, number_digits) - 1)
444  number_digits++;
445 
446  // print indices along the top of the matrix
447  for (std::size_t j = 0; j < number_digits; ++j)
448  {
449  out << std::setw(spacing + number_digits + 8) << "";
450  for (std::size_t i = 0; i < names.size(); ++i)
451  {
452  std::stringstream ss;
453  ss << std::setw(number_digits) << i;
454  out << std::setw(3) << ss.str().c_str()[j];
455  }
456  out << '\n';
457  }
458 
459  const char* indicator = "01?"; // ALWAYS / NEVER / CONDITIONAL
460  for (std::size_t i = 0; i < names.size(); ++i)
461  {
462  out << std::setw(spacing) << names[i];
463  out << std::setw(number_digits + 1) << i;
464  out << " | ";
465  // print default value
467  if (getDefaultEntry(names[i], type))
468  {
469  out << indicator[type];
470  }
471  else
472  {
473  out << '-';
474  }
475  out << " | ";
476  // print pairs
477  for (std::size_t j = 0; j < names.size(); ++j)
478  {
479  const bool found = getAllowedCollision(names[i], names[j], type);
480  if (found)
481  {
482  out << std::setw(3) << indicator[type];
483  }
484  else
485  {
486  out << std::setw(3) << '-';
487  }
488  }
489  out << '\n';
490  }
491 }
492 
493 } // end of namespace collision_detection
void getAllEntryNames(std::vector< std::string > &names) const
Get all the names known to the collision matrix.
void clear()
Clear the allowed collision matrix.
void setEntry(const std::string &name1, const std::string &name2, bool allowed)
Set an entry corresponding to a pair of elements.
bool getEntry(const std::string &name1, const std::string &name2, AllowedCollision::Type &allowed_collision_type) const
Get the type of the allowed collision between two elements. Return true if the entry is included in t...
bool getAllowedCollision(const std::string &name1, const std::string &name2, DecideContactFn &fn) const
Get the allowed collision predicate between two elements. Return true if a predicate for entry is inc...
void print(std::ostream &out) const
Print the allowed collision matrix.
void setDefaultEntry(const std::string &name, bool allowed)
Set the default value for entries that include name but are not set explicitly with setEntry().
void removeEntry(const std::string &name1, const std::string &name2)
Remove an entry corresponding to a pair of elements. Nothing happens if the pair does not exist in th...
bool getDefaultEntry(const std::string &name, AllowedCollision::Type &allowed_collision) const
Get the type of the allowed collision to be considered by default for an element. Return true if a de...
bool hasEntry(const std::string &name) const
Check if the allowed collision matrix has an entry at all for an element. Returns true if the element...
void getMessage(moveit_msgs::msg::AllowedCollisionMatrix &msg) const
Get the allowed collision matrix as a message.
@ CONDITIONAL
The collision is allowed depending on a predicate evaluated on the produced contact....
@ NEVER
Collisions between the pair of bodies is never ok, i.e., if two bodies are in contact in a particular...
@ ALWAYS
Collisions between a particular pair of bodies does not imply that the robot configuration is in coll...
std::function< bool(collision_detection::Contact &)> DecideContactFn
Signature of predicate that decides whether a contact is allowed or not (when AllowedCollision::Type ...
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition: logger.cpp:79
name
Definition: setup.py:7
Definition of a contact point.