path_generator.py
Go to the documentation of this file.
1 # Copyright (c) 2016-2019 The UUV Simulator Authors.
2 # All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import rospy
16 import numpy as np
17 from copy import deepcopy
18 
19 from visualization_msgs.msg import MarkerArray
20 from uuv_waypoints import Waypoint, WaypointSet
21 from tf_quaternion.transformations import quaternion_multiply, quaternion_about_axis, \
22  quaternion_from_euler, rotation_matrix, quaternion_from_matrix
23 
24 from ..trajectory_point import TrajectoryPoint
25 from .._log import get_logger
26 
27 
28 class PathGenerator(object):
29  """Base class to be inherited by custom path generator
30  to generate paths from interpolated waypoints.
31 
32  > *Attributes*
33 
34  * `LABEL` (*type:* `str`): Name of the path generator
35 
36  > *Input arguments*
37 
38  * `full_dof` (*type:* `bool`, *default:* `False`): If `True`, generate
39  6 DoF paths, if `False`, roll and pitch are set to zero.
40  """
41  LABEL = ''
42 
43  def __init__(self, full_dof=False):
45  # Waypoint set
46  self._waypoints = None
47 
48  # True if the path is generated for all degrees of freedom, otherwise
49  # the path will be generated for (x, y, z, yaw) only
50  self._is_full_dof = full_dof
51 
52  # The parametric variable to use as input for the interpolator
53  self._s = list()
54  self._segment_to_wp_map = list()
55  self._cur_s = 0
56  self._s_step = 0.0001
57 
58  self._start_time = None
59  self._duration = None
60 
62 
64 
65  self._init_rot = quaternion_about_axis(0.0, [0, 0, 1])
66  self._last_rot = quaternion_about_axis(0.0, [0, 0, 1])
67 
68  self._markers_msg = MarkerArray()
69  self._marker_id = 0
70 
71  @staticmethod
72  def get_generator(name, *args, **kwargs):
73  """Factory method for all derived path generators.
74 
75  > *Input arguments*
76 
77  * `name` (*type:* `str`): Name identifier of the path generator
78  * `args` (*type:* `list`): List of arguments for the path generator constructor
79  * `kwards` (*type:* `dict`): Keyword arguments for the path generator constructor
80 
81  > *Returns*
82 
83  An instance of the desired path generator. If the `name` input
84  does not describe any of the derived path generator classes, an
85  `ValueError` will be raised.
86  """
87  for gen in PathGenerator.__subclasses__():
88  if name == gen.LABEL:
89  return gen(*args, **kwargs)
90 
91  msg = 'Invalid path generator method'
92  self._logger.error(msg)
93  raise ValueError(msg)
94 
95  @staticmethod
97  """Get the name identifiers of all path generator classes.
98 
99  > *Returns*
100 
101  List of `str`
102  """
103  generators = list()
104  for gen in PathGenerator.__subclasses__():
105  generators.append(gen())
106  return generators
107 
108  @property
109  def waypoints(self):
110  """`uuv_waypoints.WaypointSet`: Set of waypoints"""
111  return self._waypoints
112 
113  @property
114  def max_time(self):
115  """`float`: Absolute final timestamp assigned to the path in seconds"""
116  return self._duration + self._start_time
117 
118  @property
119  def duration(self):
120  """`float`: Duration in seconds for the whole path"""
121  return self._duration
122 
123  @duration.setter
124  def duration(self, t):
125  assert t > 0, 'Duration must be a positive value'
126  self._duration = t
127 
128  @property
129  def start_time(self):
130  """`float`: Start timestamp assigned to the first waypoint"""
131  return self._start_time
132 
133  @start_time.setter
134  def start_time(self, time):
135  assert time >= 0, 'Invalid negative time'
136  self._start_time = time
137 
138  @property
139  def closest_waypoint(self):
140  """`uuv_waypoints.Waypoint`: Return the closest waypoint
141  to the current position on the path.
142  """
143  return self._waypoints.get_waypoint(self.closest_waypoint_idx)
144 
145  @property
147  """Return the index of the closest waypoint to the current
148  position on the path.
149  """
150 
151  if self._cur_s == 0:
152  return 0
153  if self._cur_s == 1:
154  return len(self._s) - 1
155  v = np.array(self._s - self._cur_s)
156  idx = np.argmin(v)
157  return idx
158 
159  @property
160  def s_step(self):
161  """`float`: Value of the step size for the path's parametric
162  variable
163  """
164  return self._s_step
165 
166  @s_step.setter
167  def s_step(self, step):
168  assert 0 < step < 1
169  self._s_step = step
170 
171  @property
173  """`data_type`: Property description"""
174  return self._termination_by_time
175 
176  def reset(self):
177  self._s = list()
178  self._segment_to_wp_map = list()
179  self._cur_s = 0
180  self._s_step = 0.0001
181 
182  self._start_time = None
183  self._duration = None
184 
185  def get_segment_idx(self, s):
186  if len(self._s) == 0:
187  return 0
188  # Ensure the parameter s is 0 <= s <= 1
189  s = max(0, s)
190  s = min(s, 1)
191 
192  if s == 1:
193  idx = self._s.size - 1
194  else:
195  idx = (self._s - s >= 0).nonzero()[0][0]
196  return idx
197 
199  idx = self.get_segment_idx(s)
200  try:
201  wps = self._segment_to_wp_map[idx::]
202  return np.unique(wps)
203  except:
204  self._logger.error('Invalid segment index')
205  return None
206 
207  def is_full_dof(self):
208  return self._is_full_dof
209 
210  def set_full_dof(self, flag):
211  self._is_full_dof = flag
212 
213  def get_label(self):
214  return self.LABEL
215 
216  def init_interpolator(self):
217  raise NotImplementedError()
218 
219  def get_samples(self, max_time, step=0.005):
220  raise NotImplementedError()
221 
223  return self._markers_msg
224 
225  def add_waypoint(self, waypoint, add_to_beginning=False):
226  """Add waypoint to the existing waypoint set. If no waypoint set has
227  been initialized, create new waypoint set structure and add the given
228  waypoint."""
229  if self._waypoints is None:
230  self._waypoints = WaypointSet()
231  self._waypoints.add_waypoint(waypoint, add_to_beginning)
232  return self.init_interpolator()
233 
234  def init_waypoints(self, waypoints=None, init_rot=np.array([0, 0, 0, 1])):
235  if waypoints is not None:
236  self._waypoints = deepcopy(waypoints)
237 
238  if self._waypoints is None:
239  self._logger.error('Waypoint list has not been initialized')
240  return False
241 
242  self._init_rot = init_rot
243  self._logger.info('Setting initial rotation as={}'.format(init_rot))
244  return True
245 
246  def interpolate(self, tag, s):
247  return self._interp_fcns[tag](s)
248 
249  def is_finished(self, t):
250  if self._termination_by_time:
251  return t > self.max_time
252  else:
253  return True
254 
255  def has_started(self, t):
256  if self._termination_by_time:
257  return t - self.start_time > 0
258  else:
259  return True
260 
261  def generate_pnt(self, s):
262  raise NotImplementedError()
263 
264  def generate_pos(self, s):
265  raise NotImplementedError()
266 
267  def generate_quat(self, s):
268  raise NotImplementedError()
269 
270  def set_parameters(self, params):
271  raise NotImplementedError()
272 
273  def _compute_rot_quat(self, dx, dy, dz):
274  if np.isclose(dx, 0) and np.isclose(dy, 0):
275  rotq = self._last_rot
276  else:
277  heading = np.arctan2(dy, dx)
278  rotq = quaternion_about_axis(heading, [0, 0, 1])
279 
280  if self._is_full_dof:
281  rote = quaternion_about_axis(
282  -1 * np.arctan2(dz, np.sqrt(dx**2 + dy**2)),
283  [0, 1, 0])
284  rotq = quaternion_multiply(rotq, rote)
285 
286  # Certify that the next quaternion remains in the same half hemisphere
287  d_prod = np.dot(self._last_rot, rotq)
288  if d_prod < 0:
289  rotq *= -1
290 
291  return rotq
def init_waypoints(self, waypoints=None, init_rot=np.array([0, 0, 0, 1]))
def add_waypoint(self, waypoint, add_to_beginning=False)


uuv_trajectory_control
Author(s):
autogenerated on Thu Jun 18 2020 03:28:42