connect.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Bielefeld University
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 Bielefeld University 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 /* Authors: Michael Goerner, Robert Haschke
36  Desc: Connect arbitrary states by motion planning
37 */
38 
43 
46 
47 using namespace trajectory_processing;
48 
49 namespace moveit {
50 namespace task_constructor {
51 namespace stages {
52 
53 Connect::Connect(const std::string& name, const GroupPlannerVector& planners) : Connecting(name), planner_(planners) {
54  setTimeout(1.0);
55  setCostTerm(std::make_unique<cost::PathLength>());
56 
57  auto& p = properties();
58  p.declare<MergeMode>("merge_mode", WAYPOINTS, "merge mode");
59  p.declare<double>("max_distance", 1e-2,
60  "maximally accepted joint configuration distance between trajectory endpoint and goal state");
61  p.declare<moveit_msgs::Constraints>("path_constraints", moveit_msgs::Constraints(),
62  "constraints to maintain during trajectory");
63  properties().declare<TimeParameterizationPtr>("merge_time_parameterization",
64  std::make_shared<TimeOptimalTrajectoryGeneration>());
65 }
66 
69  merged_jmg_.reset();
70  subsolutions_.clear();
71  states_.clear();
72 }
73 
74 void Connect::init(const core::RobotModelConstPtr& robot_model) {
75  Connecting::init(robot_model);
76 
77  InitStageException errors;
78  if (planner_.empty())
79  errors.push_back(*this, "empty set of groups");
80 
81  std::vector<const moveit::core::JointModelGroup*> groups;
82  for (const GroupPlannerVector::value_type& pair : planner_) {
83  if (!robot_model->hasJointModelGroup(pair.first))
84  errors.push_back(*this, "invalid group: " + pair.first);
85  else if (!pair.second)
86  errors.push_back(*this, "invalid planner for group: " + pair.first);
87  else {
88  pair.second->init(robot_model);
89 
90  auto jmg = robot_model->getJointModelGroup(pair.first);
91  groups.push_back(jmg);
92  }
93  }
94 
95  if (!errors && groups.size() >= 2 && !merged_jmg_) { // enable merging?
96  try {
97  merged_jmg_.reset(task_constructor::merge(groups));
98  } catch (const std::runtime_error& e) {
99  ROS_INFO_STREAM_NAMED("Connect", fmt::format("{}: {}. Disabling merging.", this->name(), e.what()));
100  }
101  }
102 
103  if (errors)
104  throw errors;
105 }
106 
107 bool Connect::compatible(const InterfaceState& from_state, const InterfaceState& to_state) const {
108  if (!Connecting::compatible(from_state, to_state))
109  return false;
110 
111  const moveit::core::RobotState& from = from_state.scene()->getCurrentState();
112  const moveit::core::RobotState& to = to_state.scene()->getCurrentState();
113 
114  // compose set of joint names we plan for
115  std::set<std::string> planned_joint_names;
116  for (const GroupPlannerVector::value_type& pair : planner_) {
117  const moveit::core::JointModelGroup* jmg = from.getJointModelGroup(pair.first);
118  const auto& names = jmg->getJointModelNames();
119  planned_joint_names.insert(names.begin(), names.end());
120  }
121  // all active joints that we don't plan for should match
122  for (const moveit::core::JointModel* jm : from.getRobotModel()->getJointModels()) {
123  if (planned_joint_names.count(jm->getName()))
124  continue; // ignore joints we plan for
125 
126  const unsigned int num = jm->getVariableCount();
127  Eigen::Map<const Eigen::VectorXd> positions_from(from.getJointPositions(jm), num);
128  Eigen::Map<const Eigen::VectorXd> positions_to(to.getJointPositions(jm), num);
129  if (!(positions_from - positions_to).isZero(1e-4)) {
130  ROS_INFO_STREAM_NAMED("Connect", fmt::format("Deviation in joint {}: [{}] != [{}]", jm->getName(),
131  positions_from.transpose(), positions_to.transpose()));
132  return false;
133  }
134  }
135  return true;
136 }
137 
138 void Connect::compute(const InterfaceState& from, const InterfaceState& to) {
139  const auto& props = properties();
140  double timeout = this->timeout();
141  MergeMode mode = props.get<MergeMode>("merge_mode");
142  double max_distance = props.get<double>("max_distance");
143  const auto& path_constraints = props.get<moveit_msgs::Constraints>("path_constraints");
144 
145  const moveit::core::RobotState& final_goal_state = to.scene()->getCurrentState();
146  std::vector<robot_trajectory::RobotTrajectoryConstPtr> sub_trajectories;
147 
148  std::vector<planning_scene::PlanningSceneConstPtr> intermediate_scenes;
149  planning_scene::PlanningSceneConstPtr start = from.scene();
150  intermediate_scenes.push_back(start);
151 
152  bool success = false;
153  std::string comment = "No planners specified";
154  std::vector<double> positions;
155  for (const GroupPlannerVector::value_type& pair : planner_) {
156  // set intermediate goal state
157  planning_scene::PlanningScenePtr end = start->diff();
158  const moveit::core::JointModelGroup* jmg = final_goal_state.getJointModelGroup(pair.first);
159  final_goal_state.copyJointGroupPositions(jmg, positions);
160  moveit::core::RobotState& goal_state = end->getCurrentStateNonConst();
161  goal_state.setJointGroupPositions(jmg, positions);
162  goal_state.update();
163  intermediate_scenes.push_back(end);
164 
165  robot_trajectory::RobotTrajectoryPtr trajectory;
166  auto result = pair.second->plan(start, end, jmg, timeout, trajectory, path_constraints);
167  success = bool(result);
168  sub_trajectories.push_back(trajectory); // include failed trajectory
169 
170  if (!success) {
171  comment = result.message;
172  break;
173  }
174 
175  if (trajectory->getLastWayPoint().distance(goal_state, jmg) > max_distance) {
176  success = false;
177  comment = "Trajectory end-point deviates too much from goal state";
178  break;
179  }
180 
181  // continue from reached state
182  start = end;
183  }
184 
185  SolutionBasePtr solution;
186  if (success && mode != SEQUENTIAL) // try to merge
187  solution = merge(sub_trajectories, intermediate_scenes, from.scene()->getCurrentState());
188  if (!solution) // success == false or merging failed: store sequentially
189  solution = makeSequential(sub_trajectories, intermediate_scenes, from, to);
190  if (!success) // error during sequential planning
191  solution->markAsFailure(comment);
192  connect(from, to, solution);
193 }
194 
195 SolutionSequencePtr
196 Connect::makeSequential(const std::vector<robot_trajectory::RobotTrajectoryConstPtr>& sub_trajectories,
197  const std::vector<planning_scene::PlanningSceneConstPtr>& intermediate_scenes,
198  const InterfaceState& from, const InterfaceState& to) {
199  assert(!sub_trajectories.empty());
200  assert(sub_trajectories.size() + 1 == intermediate_scenes.size());
201 
202  /* We need to decouple the sequence of subsolutions, created here, from the external from and to states.
203  Hence, we create new interface states for all subsolutions. */
204  const InterfaceState* start = &*states_.insert(states_.end(), InterfaceState(from.scene()));
205 
206  auto scene_it = intermediate_scenes.begin();
207  SolutionSequence::container_type sub_solutions;
208  for (const auto& sub : sub_trajectories) {
209  // persistently store sub solution
210  auto inserted = subsolutions_.insert(subsolutions_.end(), SubTrajectory(sub));
211  inserted->setCreator(this);
212  if (!sub) // a null RobotTrajectoryPtr indicates a failure
213  inserted->markAsFailure();
214  // push back solution pointer
215  sub_solutions.push_back(&*inserted);
216 
217  // create a new end state, either from intermediate or final planning scene
218  planning_scene::PlanningSceneConstPtr end_ps =
219  (sub_solutions.size() < sub_trajectories.size()) ? *++scene_it : to.scene();
220  const InterfaceState* end = &*states_.insert(states_.end(), InterfaceState(end_ps));
221 
222  // provide newly created start/end states
223  subsolutions_.back().setStartState(*start);
224  subsolutions_.back().setEndState(*end);
225 
226  start = end; // end state becomes next start state
227  }
228 
229  return std::make_shared<SolutionSequence>(std::move(sub_solutions));
230 }
231 
232 SubTrajectoryPtr Connect::merge(const std::vector<robot_trajectory::RobotTrajectoryConstPtr>& sub_trajectories,
233  const std::vector<planning_scene::PlanningSceneConstPtr>& intermediate_scenes,
235  // no need to merge if there is only a single sub trajectory
236  if (sub_trajectories.size() == 1)
237  return std::make_shared<SubTrajectory>(sub_trajectories[0]);
238 
239  auto jmg = merged_jmg_.get();
240  assert(jmg);
241  auto timing = properties().get<TimeParameterizationPtr>("merge_time_parameterization");
242  robot_trajectory::RobotTrajectoryPtr trajectory = task_constructor::merge(sub_trajectories, state, jmg, *timing);
243  if (!trajectory)
244  return SubTrajectoryPtr();
245 
246  // check merged trajectory for collisions
247  if (!intermediate_scenes.front()->isPathValid(*trajectory,
248  properties().get<moveit_msgs::Constraints>("path_constraints")))
249  return SubTrajectoryPtr();
250 
251  return std::make_shared<SubTrajectory>(trajectory);
252 }
253 } // namespace stages
254 } // namespace task_constructor
255 } // namespace moveit
moveit::task_constructor::Connecting
Definition: stage.h:405
moveit::task_constructor::InterfaceState::scene
const planning_scene::PlanningSceneConstPtr & scene() const
Definition: storage.h:133
fmt_p.h
moveit::task_constructor::InitStageException
Definition: stage.h:119
moveit::task_constructor::stages::Connect::GroupPlannerVector
std::vector< std::pair< std::string, solvers::PlannerInterfacePtr > > GroupPlannerVector
Definition: connect.h:76
moveit::task_constructor::stages::Connect::WAYPOINTS
@ WAYPOINTS
Definition: connect.h:73
moveit::task_constructor::InitStageException::push_back
void push_back(const Stage &stage, const std::string &msg)
push_back a single new error in stage
Definition: stage.cpp:145
moveit::task_constructor::Stage::properties
PropertyMap & properties()
Get the stage's property map.
Definition: stage.cpp:505
moveit::task_constructor::stages::Connect::states_
std::list< InterfaceState > states_
Definition: connect.h:100
moveit::task_constructor::PropertyMap::declare
Property & declare(const std::string &name, const Property::type_info &type_info, const std::string &description, const boost::any &default_value)
implementation of declare methods
Definition: properties.cpp:258
moveit::task_constructor::Stage::timeout
double timeout() const
timeout of stage per computation
Definition: stage.h:196
moveit::core::RobotState
moveit::task_constructor::stages::Connect::merge
SubTrajectoryPtr merge(const std::vector< robot_trajectory::RobotTrajectoryConstPtr > &sub_trajectories, const std::vector< planning_scene::PlanningSceneConstPtr > &intermediate_scenes, const moveit::core::RobotState &state)
Definition: connect.cpp:232
moveit::task_constructor::stages::Connect::planner_
GroupPlannerVector planner_
Definition: connect.h:97
moveit::task_constructor::Connecting::reset
void reset() override
reset stage, clearing all solutions, interfaces, inherited properties.
Definition: stage.cpp:967
moveit::task_constructor::SubTrajectory
SubTrajectory connects interface states of ComputeStages.
Definition: storage.h:347
moveit::task_constructor::stages::Connect::reset
void reset() override
reset stage, clearing all solutions, interfaces, inherited properties.
Definition: connect.cpp:67
moveit::core::RobotState::update
void update(bool force=false)
moveit::task_constructor::stages::Connect::makeSequential
SolutionSequencePtr makeSequential(const std::vector< robot_trajectory::RobotTrajectoryConstPtr > &sub_trajectories, const std::vector< planning_scene::PlanningSceneConstPtr > &intermediate_scenes, const InterfaceState &from, const InterfaceState &to)
Definition: connect.cpp:196
moveit::task_constructor::stages::Connect::subsolutions_
std::list< SubTrajectory > subsolutions_
Definition: connect.h:99
connect.h
moveit::task_constructor::PropertyMap::get
const boost::any & get(const std::string &name) const
Get the value of a property. Throws undeclared if unknown name.
Definition: properties.cpp:318
moveit::core::JointModelGroup::getJointModelNames
const std::vector< std::string > & getJointModelNames() const
moveit::task_constructor::Stage::init
virtual void init(const moveit::core::RobotModelConstPtr &robot_model)
Definition: stage.cpp:419
moveit::core::RobotState::getRobotModel
const RobotModelConstPtr & getRobotModel() const
moveit::task_constructor::Stage::setTimeout
void setTimeout(double timeout)
Definition: stage.h:194
moveit::task_constructor::stages::Connect::init
void init(const moveit::core::RobotModelConstPtr &robot_model) override
Definition: connect.cpp:74
moveit::task_constructor::SolutionSequence::container_type
std::vector< const SolutionBase * > container_type
Definition: storage.h:382
trajectory_processing
moveit::task_constructor::state
const InterfaceState * state(const SolutionBase &solution)
Trait to retrieve the end (FORWARD) or start (BACKWARD) state of a given solution.
name
name
time_optimal_trajectory_generation.h
start
ROSCPP_DECL void start()
planning_scene.h
moveit
moveit::task_constructor::merge
moveit::core::JointModelGroup * merge(const std::vector< const moveit::core::JointModelGroup * > &groups)
Definition: merge.cpp:67
moveit::task_constructor::Stage::name
const std::string & name() const
Definition: stage.cpp:442
moveit::core::RobotState::getJointPositions
const double * getJointPositions(const std::string &joint_name) const
moveit::task_constructor::success
bool success
Definition: container.cpp:61
moveit::task_constructor::stages::Connect::compute
void compute(const InterfaceState &from, const InterfaceState &to) override
Definition: connect.cpp:138
moveit::core::JointModelGroup
moveit::task_constructor::Connecting::connect
void connect(const InterfaceState &from, const InterfaceState &to, const SolutionBasePtr &solution)
register solution as a solution connecting states from -> to
Definition: stage.cpp:1041
ROS_INFO_STREAM_NAMED
#define ROS_INFO_STREAM_NAMED(name, args)
moveit::task_constructor::stages::Connect::MergeMode
MergeMode
Definition: connect.h:70
cost_terms.h
merge.h
moveit::core::RobotState::setJointGroupPositions
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
moveit::task_constructor::Stage::setCostTerm
void setCostTerm(const CostTermConstPtr &term)
Definition: stage.cpp:478
moveit::core::RobotState::getJointModelGroup
const JointModelGroup * getJointModelGroup(const std::string &group) const
moveit::task_constructor::InterfaceState
Definition: storage.h:76
moveit::task_constructor::stages::Connect::compatible
bool compatible(const InterfaceState &from_state, const InterfaceState &to_state) const override
compare consistency of planning scenes
Definition: connect.cpp:107
moveit::task_constructor::Connecting::compatible
virtual bool compatible(const InterfaceState &from_state, const InterfaceState &to_state) const
compare consistency of planning scenes
Definition: stage.cpp:973
moveit::task_constructor::stages::Connect::SEQUENTIAL
@ SEQUENTIAL
Definition: connect.h:72
moveit::core::JointModel
moveit::task_constructor::stages::Connect::merged_jmg_
moveit::core::JointModelGroupPtr merged_jmg_
Definition: connect.h:98


core
Author(s):
autogenerated on Sat May 3 2025 02:40:11