moveit2
The MoveIt Motion Planning Framework for ROS 2.
path_circle_generator.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2018 Pilz GmbH & Co. KG
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 Pilz GmbH & Co. KG 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 
36 
38 {
39 std::unique_ptr<KDL::Path> PathCircleGenerator::circleFromCenter(const KDL::Frame& start_pose,
40  const KDL::Frame& goal_pose,
41  const KDL::Vector& center_point, double eqradius)
42 {
43  double a = (start_pose.p - center_point).Norm();
44  double b = (goal_pose.p - center_point).Norm();
45  double c = (start_pose.p - goal_pose.p).Norm();
46 
47  if (fabs(a - b) > MAX_RADIUS_DIFF)
48  {
50  }
51 
52  // compute the rotation angle
53  double alpha = cosines(a, b, c);
54 
55  KDL::RotationalInterpolation* rot_interpo = new KDL::RotationalInterpolation_SingleAxis();
56  double old_kdl_epsilon = KDL::epsilon;
57  try
58  {
59  KDL::epsilon = MAX_COLINEAR_NORM;
60  auto circle = std::unique_ptr<KDL::Path>(
61  new KDL::Path_Circle(start_pose, center_point, goal_pose.p, goal_pose.M, alpha, rot_interpo, eqradius,
62  true /* take ownership of RotationalInterpolation */));
63  KDL::epsilon = old_kdl_epsilon;
64  return circle;
65  }
66  catch (KDL::Error_MotionPlanning&)
67  {
68  KDL::epsilon = old_kdl_epsilon;
69  throw; // and pass the exception on to the caller
70  }
71 }
72 
73 std::unique_ptr<KDL::Path> PathCircleGenerator::circleFromInterim(const KDL::Frame& start_pose,
74  const KDL::Frame& goal_pose,
75  const KDL::Vector& interim_point, double eqradius)
76 {
77  // compute the center point from interim point
78  // triangle edges
79  const KDL::Vector t = interim_point - start_pose.p;
80  const KDL::Vector u = goal_pose.p - start_pose.p;
81  const KDL::Vector v = goal_pose.p - interim_point;
82  // triangle normal
83  const KDL::Vector w = t * u; // cross product
84 
85  // circle center
86  if (w.Norm() < MAX_COLINEAR_NORM)
87  {
88  throw KDL::Error_MotionPlanning_Circle_No_Plane();
89  }
90  const KDL::Vector center_point =
91  start_pose.p + (u * dot(t, t) * dot(u, v) - t * dot(u, u) * dot(t, v)) * 0.5 / pow(w.Norm(), 2);
92 
93  // compute the rotation angle
94  // triangle edges
95  const KDL::Vector t_center = center_point - start_pose.p;
96  const KDL::Vector v_center = goal_pose.p - center_point;
97  double a = t_center.Norm();
98  double b = v_center.Norm();
99  double c = u.Norm();
100  double alpha = cosines(a, b, c);
101 
102  KDL::Vector kdl_aux_point(interim_point);
103 
104  // if the angle at the interim is an acute angle (<90deg), rotation angle is
105  // an obtuse angle (>90deg)
106  // in this case using the interim as auxiliary point for KDL::Path_Circle can
107  // lead to a path in the wrong direction
108  double interim_angle = cosines(t.Norm(), v.Norm(), u.Norm());
109  if (interim_angle < M_PI / 2)
110  {
111  alpha = 2 * M_PI - alpha;
112 
113  // exclude that the goal is not colinear with start and center, then use the
114  // opposite of the goal as auxiliary point
115  if ((t_center * v_center).Norm() > MAX_COLINEAR_NORM)
116  {
117  kdl_aux_point = 2 * center_point - goal_pose.p;
118  }
119  }
120 
121  KDL::RotationalInterpolation* rot_interpo = new KDL::RotationalInterpolation_SingleAxis();
122  return std::unique_ptr<KDL::Path>(
123  std::make_unique<KDL::Path_Circle>(start_pose, center_point, kdl_aux_point, goal_pose.M, alpha, rot_interpo,
124  eqradius, true /* take ownership of RotationalInterpolation */));
125 }
126 
127 double PathCircleGenerator::cosines(const double a, const double b, const double c)
128 {
129  return acos(std::max(std::min((pow(a, 2) + pow(b, 2) - pow(c, 2)) / (2.0 * a * b), 1.0), -1.0));
130 }
131 
132 } // namespace pilz_industrial_motion_planner
static std::unique_ptr< KDL::Path > circleFromCenter(const KDL::Frame &start_pose, const KDL::Frame &goal_pose, const KDL::Vector &center_point, double eqradius)
set the path circle from start, goal and center point
static std::unique_ptr< KDL::Path > circleFromInterim(const KDL::Frame &start_pose, const KDL::Frame &goal_pose, const KDL::Vector &interim_point, double eqradius)
set circle from start, goal and interim point