MTC
storage.h
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Hamburg University
5  * Copyright (c) 2017, Bielefeld University
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Bielefeld University nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 /* Authors: Michael Goerner, Robert Haschke
37  Desc: Classes to store and pass partial solutions between stages
38 */
39 
40 #pragma once
41 
42 #include <moveit/macros/class_forward.h>
43 #include <moveit/task_constructor/properties.h>
44 #include <moveit/task_constructor/cost_queue.h>
45 #include <moveit/task_constructor/utils.h>
46 #include <moveit_task_constructor_msgs/Solution.h>
47 #include <visualization_msgs/MarkerArray.h>
48 
49 #include <list>
50 #include <vector>
51 #include <deque>
52 #include <cassert>
53 #include <functional>
54 
55 namespace planning_scene {
56 MOVEIT_CLASS_FORWARD(PlanningScene);
57 }
58 
59 namespace robot_trajectory {
60 MOVEIT_CLASS_FORWARD(RobotTrajectory);
61 }
62 
63 namespace moveit {
64 namespace task_constructor {
65 
66 class SolutionBase;
67 MOVEIT_CLASS_FORWARD(InterfaceState);
68 MOVEIT_CLASS_FORWARD(Interface);
69 MOVEIT_CLASS_FORWARD(Stage);
70 MOVEIT_CLASS_FORWARD(Introspection);
71 
77 {
78  friend class SolutionBase; // addIncoming() / addOutgoing() should be called only by SolutionBase
79  friend class Interface; // allow Interface to set owner_ and priority_
80  friend class ContainerBasePrivate; // allow setting priority_ for pruning
81 
82 public:
83  enum Status : uint8_t
84  {
85  ENABLED, // state is actively considered during planning
86  ARMED, // disabled state in a Connecting interface that will become re-enabled with a new opposite state
87  PRUNED, // disabled state on a pruned solution branch
88  };
89  static const char* colorForStatus(unsigned int s) { return STATUS_COLOR_[s]; }
90 
95  struct Priority : std::tuple<Status, unsigned int, double>
96  {
97  Priority(unsigned int depth, double cost, Status status)
98  : std::tuple<Status, unsigned int, double>(status, depth, cost) {}
99  Priority(unsigned int depth, double cost) : Priority(depth, cost, std::isfinite(cost) ? ENABLED : PRUNED) {}
100  // Constructor copying depth and cost, but modifying its status
101  Priority(const Priority& other, Status status) : Priority(other.depth(), other.cost(), status) {}
102 
103  inline Status status() const { return std::get<0>(*this); }
104  inline bool enabled() const { return std::get<0>(*this) == ENABLED; }
105 
106  inline unsigned int depth() const { return std::get<1>(*this); }
107  inline double cost() const { return std::get<2>(*this); }
108 
109  // add priorities
110  Priority operator+(const Priority& other) const {
111  return Priority(depth() + other.depth(), cost() + other.cost(), std::min(status(), other.status()));
112  }
113  // comparison operators
114  bool operator<(const Priority& rhs) const;
115  inline bool operator>(const Priority& rhs) const { return rhs < *this; }
116  inline bool operator<=(const Priority& rhs) const { return !(rhs < *this); }
117  inline bool operator>=(const Priority& rhs) const { return !(*this < rhs); }
118  };
119  using Solutions = std::deque<SolutionBase*>;
120 
122  InterfaceState(const planning_scene::PlanningScenePtr& ps);
123  InterfaceState(const planning_scene::PlanningSceneConstPtr& ps);
124 
126  InterfaceState(const planning_scene::PlanningSceneConstPtr& ps, const Priority& p);
127 
129  InterfaceState(const InterfaceState& other);
130  InterfaceState(InterfaceState&& other) = default;
131  InterfaceState& operator=(const InterfaceState& other) = default;
132 
133  inline const planning_scene::PlanningSceneConstPtr& scene() const { return scene_; }
134  inline const Solutions& incomingTrajectories() const { return incoming_trajectories_; }
135  inline const Solutions& outgoingTrajectories() const { return outgoing_trajectories_; }
136 
137  PropertyMap& properties() { return properties_; }
138  const PropertyMap& properties() const { return properties_; }
139 
141  inline bool operator<(const InterfaceState& other) const { return this->priority_ < other.priority_; }
142 
143  inline const Priority& priority() const { return priority_; }
145  void updatePriority(const InterfaceState::Priority& priority);
147  void updateStatus(Status status);
148 
149  Interface* owner() const { return owner_; }
150 
151 private:
152  // these methods should be only called by SolutionBase::set[Start|End]State()
153  inline void addIncoming(SolutionBase* t) { incoming_trajectories_.push_back(t); }
154  inline void addOutgoing(SolutionBase* t) { outgoing_trajectories_.push_back(t); }
155  // Set new priority without updating the owning interface (USE WITH CARE)
156  inline void setPriority(const Priority& prio) { priority_ = prio; }
157 
158 private:
159  static const char* STATUS_COLOR_[];
160  planning_scene::PlanningSceneConstPtr scene_;
161  PropertyMap properties_;
163  Solutions incoming_trajectories_;
165  Solutions outgoing_trajectories_;
166 
167  // members needed for priority scheduling in Interface list
168  Priority priority_;
169  Interface* owner_ = nullptr; // allow update of priority
170 };
171 
173 class Interface : public ordered<InterfaceState*>
174 {
176 
177 public:
178  // iterators providing convinient access to stored InterfaceState
179  class iterator : public base_type::iterator
180  {
181  public:
182  iterator() = default;
183  iterator(base_type::iterator other) : base_type::iterator(other) {}
184 
185  InterfaceState& operator*() const noexcept { return *base_type::iterator::operator*(); }
186 
187  InterfaceState* operator->() const noexcept { return base_type::iterator::operator*(); }
188  };
189  class const_iterator : public base_type::const_iterator
190  {
191  public:
192  const_iterator(base_type::const_iterator other) : base_type::const_iterator(other) {}
193  const_iterator(base_type::iterator other) : base_type::const_iterator(other) {}
194 
195  const InterfaceState& operator*() const noexcept { return *base_type::const_iterator::operator*(); }
196 
197  const InterfaceState* operator->() const noexcept { return base_type::const_iterator::operator*(); }
198  };
199 
200  enum Direction : uint8_t
201  {
202  FORWARD,
203  BACKWARD,
204  };
205  enum Update : uint8_t
206  {
207  STATUS = 1 << 0,
208  PRIORITY = 1 << 1,
209  ALL = STATUS | PRIORITY,
210  };
211  using UpdateFlags = utils::Flags<Update>;
212  using NotifyFunction = std::function<void(iterator, UpdateFlags)>;
213 
215  {
216  Interface& if_;
217  Interface::NotifyFunction old_;
218 
219  public:
220  DisableNotify(Interface& i) : if_(i) { old_.swap(if_.notify_); }
221  ~DisableNotify() { old_.swap(if_.notify_); }
222  };
223  friend class DisableNotify;
224 
225  Interface(const NotifyFunction& notify = NotifyFunction());
226 
228  void add(InterfaceState& state);
229 
231  container_type remove(iterator it);
232 
234  void updatePriority(InterfaceState* state, const InterfaceState::Priority& priority);
235  inline bool notifyEnabled() const { return static_cast<bool>(notify_); }
236 
237 private:
238  NotifyFunction notify_;
239 
240  // restrict access to some functions to ensure consistency
241  // (we need to set/unset InterfaceState::owner_)
242  using base_type::erase;
243  using base_type::insert;
244  using base_type::moveFrom;
245  using base_type::moveTo;
246  using base_type::remove_if;
247 };
248 
249 std::ostream& operator<<(std::ostream& os, const InterfaceState::Priority& prio);
250 std::ostream& operator<<(std::ostream& os, const Interface& interface);
251 std::ostream& operator<<(std::ostream& os, Interface::Direction dir);
252 
254 template <typename T>
255 size_t getIndex(const T& container, typename T::const_iterator search) {
256  size_t index = 1;
257  for (typename T::const_iterator it = container.begin(), end = container.end(); it != end; ++it, ++index)
258  if (it == search)
259  return index;
260  return 0;
261 }
262 
263 class CostTerm;
264 class StagePrivate;
265 class ContainerBasePrivate;
266 struct TmpSolutionContext;
269 {
270  friend ContainerBasePrivate;
271  friend TmpSolutionContext;
272 
273 public:
274  virtual ~SolutionBase() = default;
275 
276  inline const InterfaceState* start() const { return start_; }
277  inline const InterfaceState* end() const { return end_; }
278 
283  inline void setStartState(const InterfaceState& state) {
284  assert(start_ == nullptr);
285  start_ = &state;
286  const_cast<InterfaceState&>(state).addOutgoing(this);
287  }
288 
293  inline void setEndState(const InterfaceState& state) {
294  assert(end_ == nullptr);
295  end_ = &state;
296  const_cast<InterfaceState&>(state).addIncoming(this);
297  }
298 
299  inline const Stage* creator() const { return creator_; }
300  void setCreator(Stage* creator);
301 
302  inline double cost() const { return cost_; }
303  void setCost(double cost);
304  void markAsFailure(const std::string& msg = std::string());
305  inline bool isFailure() const { return !std::isfinite(cost_); }
306 
307  const std::string& comment() const { return comment_; }
308  void setComment(const std::string& comment) { comment_ = comment; }
309 
310  auto& markers() { return markers_; }
311  const auto& markers() const { return markers_; }
312 
314  void toMsg(moveit_task_constructor_msgs::Solution& solution, Introspection* introspection = nullptr) const;
316  virtual void appendTo(moveit_task_constructor_msgs::Solution& solution,
317  Introspection* introspection = nullptr) const = 0;
318  void fillInfo(moveit_task_constructor_msgs::SolutionInfo& info, Introspection* introspection = nullptr) const;
319 
321  virtual double computeCost(const CostTerm& cost, std::string& comment) const = 0;
322 
324  bool operator<(const SolutionBase& other) const { return this->cost_ < other.cost_; }
325 
326 protected:
327  SolutionBase(Stage* creator = nullptr, double cost = 0.0, std::string comment = "")
328  : creator_(creator), cost_(cost), comment_(std::move(comment)) {}
329 
330 private:
331  // back-pointer to creating stage, allows to access sub-solutions
332  Stage* creator_;
333  // associated cost
334  double cost_;
335  // comment for this solution, e.g. explanation of failure
336  std::string comment_;
337  // markers for this solution, e.g. target frame or collision indicators
338  std::deque<visualization_msgs::Marker> markers_;
339 
340  // begin and end InterfaceState of this solution/trajectory
341  const InterfaceState* start_ = nullptr;
342  const InterfaceState* end_ = nullptr;
343 };
344 MOVEIT_CLASS_FORWARD(SolutionBase);
345 
348 {
349 public:
351  const robot_trajectory::RobotTrajectoryConstPtr& trajectory = robot_trajectory::RobotTrajectoryConstPtr(),
352  double cost = 0.0, std::string comment = "")
353  : SolutionBase(nullptr, cost, std::move(comment)), trajectory_(trajectory) {}
354 
355  robot_trajectory::RobotTrajectoryConstPtr trajectory() const { return trajectory_; }
356  void setTrajectory(const robot_trajectory::RobotTrajectoryPtr& t) { trajectory_ = t; }
357 
358  void appendTo(moveit_task_constructor_msgs::Solution& msg, Introspection* introspection = nullptr) const override;
359 
360  double computeCost(const CostTerm& cost, std::string& comment) const override;
361 
362  static SubTrajectory failure(const std::string& msg) {
363  SubTrajectory s;
364  s.markAsFailure(msg);
365  return s;
366  }
367 
368 private:
369  // actual trajectory, might be empty
370  robot_trajectory::RobotTrajectoryConstPtr trajectory_;
371 };
372 MOVEIT_CLASS_FORWARD(SubTrajectory);
373 
380 {
381 public:
382  using container_type = std::vector<const SolutionBase*>;
383 
384  explicit SolutionSequence() : SolutionBase() {}
385  SolutionSequence(container_type&& subsolutions, double cost = 0.0, Stage* creator = nullptr)
386  : SolutionBase(creator, cost), subsolutions_(std::move(subsolutions)) {}
387 
388  void push_back(const SolutionBase& solution);
389 
391  void appendTo(moveit_task_constructor_msgs::Solution& msg, Introspection* introspection) const override;
392 
393  double computeCost(const CostTerm& cost, std::string& comment) const override;
394 
395  const container_type& solutions() const { return subsolutions_; }
396 
397  inline const InterfaceState* internalStart() const { return subsolutions_.front()->start(); }
398  inline const InterfaceState* internalEnd() const { return subsolutions_.back()->end(); }
399 
400 private:
402  container_type subsolutions_;
403 };
404 MOVEIT_CLASS_FORWARD(SolutionSequence);
405 
414 {
415 public:
416  explicit WrappedSolution(Stage* creator, const SolutionBase* wrapped, double cost, std::string comment)
417  : SolutionBase(creator, cost, std::move(comment)), wrapped_(wrapped) {}
418  explicit WrappedSolution(Stage* creator, const SolutionBase* wrapped, double cost)
419  : SolutionBase(creator, cost), wrapped_(wrapped) {}
420  explicit WrappedSolution(Stage* creator, const SolutionBase* wrapped)
421  : WrappedSolution(creator, wrapped, wrapped->cost()) {}
422  void appendTo(moveit_task_constructor_msgs::Solution& solution,
423  Introspection* introspection = nullptr) const override;
424 
425  double computeCost(const CostTerm& cost, std::string& comment) const override;
426 
427  const SolutionBase* wrapped() const { return wrapped_; }
428 
429 private:
430  const SolutionBase* wrapped_;
431 };
432 
434 template <Interface::Direction dir>
435 const InterfaceState* state(const SolutionBase& solution);
436 template <>
437 inline const InterfaceState* state<Interface::FORWARD>(const SolutionBase& solution) {
438  return solution.end();
439 }
440 template <>
441 inline const InterfaceState* state<Interface::BACKWARD>(const SolutionBase& solution) {
442  return solution.start();
443 }
444 
446 template <Interface::Direction dir>
447 const InterfaceState::Solutions& trajectories(const InterfaceState& state);
448 template <>
449 inline const InterfaceState::Solutions& trajectories<Interface::FORWARD>(const InterfaceState& state) {
450  return state.outgoingTrajectories();
451 }
452 template <>
453 inline const InterfaceState::Solutions& trajectories<Interface::BACKWARD>(const InterfaceState& state) {
454  return state.incomingTrajectories();
455 }
456 
458 template <Interface::Direction dir>
459 constexpr Interface::Direction opposite();
460 template <>
461 inline constexpr Interface::Direction opposite<Interface::FORWARD>() {
462  return Interface::BACKWARD;
463 }
464 template <>
465 inline constexpr Interface::Direction opposite<Interface::BACKWARD>() {
466  return Interface::FORWARD;
467 }
468 } // namespace task_constructor
469 } // namespace moveit
470 
471 namespace std {
472 // comparison for pointers to SolutionBase: compare based on value
473 template <>
474 struct less<moveit::task_constructor::SolutionBase*>
475 {
477  return *x < *y;
478  }
479 };
480 } // namespace std
Definition: cost_terms.h:56
InterfaceState(const planning_scene::PlanningScenePtr &ps)
create an InterfaceState from a planning scene
Definition: storage.cpp:56
void updatePriority(const InterfaceState::Priority &priority)
Update priority and call owner's notify() if possible.
Definition: storage.cpp:85
bool operator<(const InterfaceState &other) const
states are ordered by priority
Definition: storage.h:141
void updateStatus(Status status)
Update status, but keep current priority.
Definition: storage.cpp:96
Definition: storage.h:174
void add(InterfaceState &state)
add a new InterfaceState
Definition: storage.cpp:103
void updatePriority(InterfaceState *state, const InterfaceState::Priority &priority)
update state's priority (and call notify_ if it really has changed)
Definition: storage.cpp:143
container_type remove(iterator it)
remove a state from the interface and return it as a one-element list
Definition: storage.cpp:136
Definition: introspection.h:66
abstract base class for solutions (primitive and sequences)
Definition: storage.h:269
void setEndState(const InterfaceState &state)
Definition: storage.h:293
bool operator<(const SolutionBase &other) const
order solutions by their cost
Definition: storage.h:324
virtual double computeCost(const CostTerm &cost, std::string &comment) const =0
required to dispatch to type-specific CostTerm methods via vtable
void setStartState(const InterfaceState &state)
Definition: storage.h:283
virtual void appendTo(moveit_task_constructor_msgs::Solution &solution, Introspection *introspection=nullptr) const =0
append this solution to Solution msg
void toMsg(moveit_task_constructor_msgs::Solution &solution, Introspection *introspection=nullptr) const
convert solution to message
Definition: storage.cpp:207
double computeCost(const CostTerm &cost, std::string &comment) const override
required to dispatch to type-specific CostTerm methods via vtable
Definition: storage.cpp:283
void appendTo(moveit_task_constructor_msgs::Solution &msg, Introspection *introspection) const override
append all subsolutions to solution
Definition: storage.cpp:248
Definition: stage.h:147
SubTrajectory connects interface states of ComputeStages.
Definition: storage.h:348
void appendTo(moveit_task_constructor_msgs::Solution &msg, Introspection *introspection=nullptr) const override
append this solution to Solution msg
Definition: storage.cpp:224
double computeCost(const CostTerm &cost, std::string &comment) const override
required to dispatch to type-specific CostTerm methods via vtable
Definition: storage.cpp:240
double computeCost(const CostTerm &cost, std::string &comment) const override
required to dispatch to type-specific CostTerm methods via vtable
Definition: storage.cpp:297
void appendTo(moveit_task_constructor_msgs::Solution &solution, Introspection *introspection=nullptr) const override
append this solution to Solution msg
Definition: storage.cpp:287
ordered<ValueType> provides an adapter for a std::list to allow sorting.
Definition: cost_queue.h:30
iterator moveTo(iterator pos, container_type &other, iterator other_pos)
move element pos from this to other container, inserting before other_pos
Definition: cost_queue.h:114
iterator moveFrom(iterator pos, container_type &other)
move element pos from other container into this one (sorted)
Definition: cost_queue.h:119