moveit2
The MoveIt Motion Planning Framework for ROS 2.
pose_model_state_space.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, 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 */
36 
38 #include <ompl/base/spaces/SE3StateSpace.h>
39 
40 #include <utility>
41 
42 namespace ompl_interface
43 {
44 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit.ompl_planning.pose_model_state_space");
45 } // namespace ompl_interface
46 
48 
50  : ModelBasedStateSpace(spec)
51 {
52  jump_factor_ = 3; // \todo make this a param
53 
54  if (spec.joint_model_group_->getGroupKinematics().first)
55  poses_.emplace_back(spec.joint_model_group_, spec.joint_model_group_->getGroupKinematics().first);
56  else if (!spec.joint_model_group_->getGroupKinematics().second.empty())
57  {
59  for (const auto& it : m)
60  poses_.emplace_back(it.first, it.second);
61  }
62  if (poses_.empty())
63  RCLCPP_ERROR(LOGGER, "No kinematics solvers specified. Unable to construct a "
64  "PoseModelStateSpace");
65  else
66  std::sort(poses_.begin(), poses_.end());
67  setName(getName() + "_" + PARAMETERIZATION_TYPE);
68 }
69 
71 
72 double ompl_interface::PoseModelStateSpace::distance(const ompl::base::State* state1,
73  const ompl::base::State* state2) const
74 {
75  double total = 0;
76  for (std::size_t i = 0; i < poses_.size(); ++i)
77  total += poses_[i].state_space_->distance(state1->as<StateType>()->poses[i], state2->as<StateType>()->poses[i]);
78  return total;
79 }
80 
82 {
83  double total = 0.0;
84  for (const auto& pose : poses_)
85  total += pose.state_space_->getMaximumExtent();
86  return total;
87 }
88 
90 {
91  auto* state = new StateType();
92  state->values =
93  new double[variable_count_]; // need to allocate this here since ModelBasedStateSpace::allocState() is not called
94  state->poses = new ompl::base::SE3StateSpace::StateType*[poses_.size()];
95  for (std::size_t i = 0; i < poses_.size(); ++i)
96  state->poses[i] = poses_[i].state_space_->allocState()->as<ompl::base::SE3StateSpace::StateType>();
97  return state;
98 }
99 
100 void ompl_interface::PoseModelStateSpace::freeState(ompl::base::State* state) const
101 {
102  for (std::size_t i = 0; i < poses_.size(); ++i)
103  poses_[i].state_space_->freeState(state->as<StateType>()->poses[i]);
104  delete[] state->as<StateType>()->poses;
106 }
107 
108 void ompl_interface::PoseModelStateSpace::copyState(ompl::base::State* destination,
109  const ompl::base::State* source) const
110 {
111  // copy the state data
112  ModelBasedStateSpace::copyState(destination, source);
113 
114  for (std::size_t i = 0; i < poses_.size(); ++i)
115  poses_[i].state_space_->copyState(destination->as<StateType>()->poses[i], source->as<StateType>()->poses[i]);
116 
117  // compute additional stuff if needed
118  computeStateK(destination);
119 }
120 
122 {
123  ModelBasedStateSpace::sanityChecks(std::numeric_limits<double>::epsilon(), std::numeric_limits<float>::epsilon(),
124  ~ompl::base::StateSpace::STATESPACE_TRIANGLE_INEQUALITY);
125 }
126 
127 void ompl_interface::PoseModelStateSpace::interpolate(const ompl::base::State* from, const ompl::base::State* to,
128  const double t, ompl::base::State* state) const
129 {
130  // we want to interpolate in Cartesian space; we do not have a guarantee that from and to
131  // have their poses computed, but this is very unlikely to happen (depends how the planner gets its input states)
132 
133  // interpolate in joint space
134  ModelBasedStateSpace::interpolate(from, to, t, state);
135 
136  // interpolate SE3 components
137  for (std::size_t i = 0; i < poses_.size(); ++i)
138  poses_[i].state_space_->interpolate(from->as<StateType>()->poses[i], to->as<StateType>()->poses[i], t,
139  state->as<StateType>()->poses[i]);
140 
141  // the call above may reset all flags for state; but we know the pose we want flag should be set
142  state->as<StateType>()->setPoseComputed(true);
143 
144  /*
145  std::cout << "*********** interpolate\n";
146  printState(from, std::cout);
147  printState(to, std::cout);
148  printState(state, std::cout);
149  std::cout << "\n\n";
150  */
151 
152  // after interpolation we cannot be sure about the joint values (we use them as seed only)
153  // so we recompute IK if needed
154  if (computeStateIK(state))
155  {
156  double dj = jump_factor_ * ModelBasedStateSpace::distance(from, to);
157  double d_from = ModelBasedStateSpace::distance(from, state);
158  double d_to = ModelBasedStateSpace::distance(state, to);
159 
160  // if the joint value jumped too much
161  if (d_from + d_to > std::max(0.2, dj)) // \todo make 0.2 a param
162  state->as<StateType>()->markInvalid();
163  }
164 }
165 
166 void ompl_interface::PoseModelStateSpace::setPlanningVolume(double minX, double maxX, double minY, double maxY,
167  double minZ, double maxZ)
168 {
169  ModelBasedStateSpace::setPlanningVolume(minX, maxX, minY, maxY, minZ, maxZ);
170  ompl::base::RealVectorBounds b(3);
171  b.low[0] = minX;
172  b.low[1] = minY;
173  b.low[2] = minZ;
174  b.high[0] = maxX;
175  b.high[1] = maxY;
176  b.high[2] = maxZ;
177  for (auto& pose : poses_)
178  pose.state_space_->as<ompl::base::SE3StateSpace>()->setBounds(b);
179 }
180 
181 ompl_interface::PoseModelStateSpace::PoseComponent::PoseComponent(
183  : subgroup_(subgroup), kinematics_solver_(k.allocator_(subgroup)), bijection_(k.bijection_)
184 {
185  state_space_ = std::make_shared<ompl::base::SE3StateSpace>();
186  state_space_->setName(subgroup_->getName() + "_Workspace");
187  fk_link_.resize(1, kinematics_solver_->getTipFrame());
188  if (!fk_link_[0].empty() && fk_link_[0][0] == '/')
189  fk_link_[0] = fk_link_[0].substr(1);
190 }
191 
192 bool ompl_interface::PoseModelStateSpace::PoseComponent::computeStateFK(StateType* full_state, unsigned int idx) const
193 {
194  // read the values from the joint state, in the order expected by the kinematics solver
195  std::vector<double> values(bijection_.size());
196  for (unsigned int i = 0; i < bijection_.size(); ++i)
197  values[i] = full_state->values[bijection_[i]];
198 
199  // compute forward kinematics for the link of interest
200  std::vector<geometry_msgs::msg::Pose> poses;
201  if (!kinematics_solver_->getPositionFK(fk_link_, values, poses))
202  return false;
203 
204  // copy the resulting data to the desired location in the state
205  ompl::base::SE3StateSpace::StateType* se3_state = full_state->poses[idx];
206  se3_state->setXYZ(poses[0].position.x, poses[0].position.y, poses[0].position.z);
207  ompl::base::SO3StateSpace::StateType& so3_state = se3_state->rotation();
208  so3_state.x = poses[0].orientation.x;
209  so3_state.y = poses[0].orientation.y;
210  so3_state.z = poses[0].orientation.z;
211  so3_state.w = poses[0].orientation.w;
212 
213  return true;
214 }
215 
216 bool ompl_interface::PoseModelStateSpace::PoseComponent::computeStateIK(StateType* full_state, unsigned int idx) const
217 {
218  // read the values from the joint state, in the order expected by the kinematics solver; use these as the seed
219  std::vector<double> seed_values(bijection_.size());
220  for (std::size_t i = 0; i < bijection_.size(); ++i)
221  seed_values[i] = full_state->values[bijection_[i]];
222 
223  /*
224  std::cout << "seed: ";
225  for (std::size_t i = 0 ; i < seed_values.size() ; ++i)
226  std::cout << seed_values[i] << " ";
227  std::cout << '\n';
228  */
229 
230  // construct the pose
231  geometry_msgs::msg::Pose pose;
232  const ompl::base::SE3StateSpace::StateType* se3_state = full_state->poses[idx];
233  pose.position.x = se3_state->getX();
234  pose.position.y = se3_state->getY();
235  pose.position.z = se3_state->getZ();
236  const ompl::base::SO3StateSpace::StateType& so3_state = se3_state->rotation();
237  pose.orientation.x = so3_state.x;
238  pose.orientation.y = so3_state.y;
239  pose.orientation.z = so3_state.z;
240  pose.orientation.w = so3_state.w;
241 
242  // run IK
243  std::vector<double> solution(bijection_.size());
244  moveit_msgs::msg::MoveItErrorCodes err_code;
245  if (!kinematics_solver_->getPositionIK(pose, seed_values, solution, err_code))
246  {
247  if (err_code.val != moveit_msgs::msg::MoveItErrorCodes::TIMED_OUT ||
248  !kinematics_solver_->searchPositionIK(pose, seed_values, kinematics_solver_->getDefaultTimeout() * 2.0,
249  solution, err_code))
250  return false;
251  }
252 
253  for (std::size_t i = 0; i < bijection_.size(); ++i)
254  full_state->values[bijection_[i]] = solution[i];
255 
256  return true;
257 }
258 
259 bool ompl_interface::PoseModelStateSpace::computeStateFK(ompl::base::State* state) const
260 {
261  if (state->as<StateType>()->poseComputed())
262  return true;
263  for (std::size_t i = 0; i < poses_.size(); ++i)
264  if (!poses_[i].computeStateFK(state->as<StateType>(), i))
265  {
266  state->as<StateType>()->markInvalid();
267  return false;
268  }
269  state->as<StateType>()->setPoseComputed(true);
270  return true;
271 }
272 
273 bool ompl_interface::PoseModelStateSpace::computeStateIK(ompl::base::State* state) const
274 {
275  if (state->as<StateType>()->jointsComputed())
276  return true;
277  for (std::size_t i = 0; i < poses_.size(); ++i)
278  if (!poses_[i].computeStateIK(state->as<StateType>(), i))
279  {
280  state->as<StateType>()->markInvalid();
281  return false;
282  }
283  state->as<StateType>()->setJointsComputed(true);
284  return true;
285 }
286 
287 bool ompl_interface::PoseModelStateSpace::computeStateK(ompl::base::State* state) const
288 {
289  if (state->as<StateType>()->jointsComputed() && !state->as<StateType>()->poseComputed())
290  return computeStateFK(state);
291  if (!state->as<StateType>()->jointsComputed() && state->as<StateType>()->poseComputed())
292  return computeStateIK(state);
293  if (state->as<StateType>()->jointsComputed() && state->as<StateType>()->poseComputed())
294  return true;
295  state->as<StateType>()->markInvalid();
296  return false;
297 }
298 
300 {
301  class PoseModelStateSampler : public ompl::base::StateSampler
302  {
303  public:
304  PoseModelStateSampler(const ompl::base::StateSpace* space, ompl::base::StateSamplerPtr sampler)
305  : ompl::base::StateSampler(space), sampler_(std::move(sampler))
306  {
307  }
308 
309  void sampleUniform(ompl::base::State* state) override
310  {
311  sampler_->sampleUniform(state);
312  afterStateSample(state);
313  }
314 
315  void sampleUniformNear(ompl::base::State* state, const ompl::base::State* near, const double distance) override
316  {
317  sampler_->sampleUniformNear(state, near, distance);
318  afterStateSample(state);
319  }
320 
321  void sampleGaussian(ompl::base::State* state, const ompl::base::State* mean, const double stdDev) override
322  {
323  sampler_->sampleGaussian(state, mean, stdDev);
324  afterStateSample(state);
325  }
326 
327  protected:
328  void afterStateSample(ompl::base::State* sample) const
329  {
330  sample->as<StateType>()->setJointsComputed(true);
331  sample->as<StateType>()->setPoseComputed(false);
332  space_->as<PoseModelStateSpace>()->computeStateFK(sample);
333  }
334 
335  ompl::base::StateSamplerPtr sampler_;
336  };
337 
338  return ompl::base::StateSamplerPtr(static_cast<ompl::base::StateSampler*>(
339  new PoseModelStateSampler(this, ModelBasedStateSpace::allocDefaultStateSampler())));
340 }
341 
343  const moveit::core::RobotState& rstate) const
344 {
346  state->as<StateType>()->setJointsComputed(true);
347  state->as<StateType>()->setPoseComputed(false);
348  computeStateFK(state);
349  /*
350  std::cout << "COPY STATE IN:\n";
351  printState(state, std::cout);
352  std::cout << "---------- COPY STATE IN\n"; */
353 }
const std::pair< KinematicsSolver, KinematicsSolverMap > & getGroupKinematics() const
std::map< const JointModelGroup *, KinematicsSolver > KinematicsSolverMap
Map from group instances to allocator functions & bijections.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
virtual void setPlanningVolume(double minX, double maxX, double minY, double maxY, double minZ, double maxZ)
Set the planning volume for the possible SE2 and/or SE3 components of the state space.
ompl::base::StateSamplerPtr allocDefaultStateSampler() const override
void interpolate(const ompl::base::State *from, const ompl::base::State *to, const double t, ompl::base::State *state) const override
void freeState(ompl::base::State *state) const override
void copyState(ompl::base::State *destination, const ompl::base::State *source) const override
virtual void copyToOMPLState(ompl::base::State *state, const moveit::core::RobotState &rstate) const
Copy the data from a set of joint states to an OMPL state.
double distance(const ompl::base::State *state1, const ompl::base::State *state2) const override
ompl::base::SE3StateSpace::StateType ** poses
double distance(const ompl::base::State *state1, const ompl::base::State *state2) const override
ompl::base::State * allocState() const override
PoseModelStateSpace(const ModelBasedStateSpaceSpecification &spec)
void copyState(ompl::base::State *destination, const ompl::base::State *source) const override
void setPlanningVolume(double minX, double maxX, double minY, double maxY, double minZ, double maxZ) override
Set the planning volume for the possible SE2 and/or SE3 components of the state space.
bool computeStateFK(ompl::base::State *state) const
void copyToOMPLState(ompl::base::State *state, const moveit::core::RobotState &rstate) const override
Copy the data from a set of joint states to an OMPL state.
bool computeStateK(ompl::base::State *state) const
void freeState(ompl::base::State *state) const override
static const std::string PARAMETERIZATION_TYPE
ompl::base::StateSamplerPtr allocDefaultStateSampler() const override
void interpolate(const ompl::base::State *from, const ompl::base::State *to, const double t, ompl::base::State *state) const override
bool computeStateIK(ompl::base::State *state) const
The MoveIt interface to OMPL.
double distance(const urdf::Pose &transform)
Definition: pr2_arm_ik.h:55
const moveit::core::JointModelGroup * joint_model_group_