linear_interpolator.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 from scipy.interpolate import splrep, splev
16 import numpy as np
17 from copy import deepcopy
18 from uuv_waypoints import Waypoint, WaypointSet
19 from visualization_msgs.msg import MarkerArray
20 from tf_quaternion.transformations import quaternion_multiply, \
21  quaternion_about_axis, quaternion_conjugate, \
22  quaternion_from_matrix, euler_from_matrix
23 
24 from ..trajectory_point import TrajectoryPoint
25 from .line_segment import LineSegment
26 from .bezier_curve import BezierCurve
27 from .path_generator import PathGenerator
28 
29 
30 class LinearInterpolator(PathGenerator):
31  """Simple interpolator that generates a parametric
32  line connecting the input waypoints.
33 
34  > *Example*
35 
36  ```python
37  from uuv_waypoints import Waypoint, WaypointSet
38  from uuv_trajectory_generator import LinearInterpolator
39 
40  # Some sample 3D points
41  q_x = [0, 1, 2, 4, 5, 6]
42  q_y = [0, 2, 3, 3, 2, 0]
43  q_z = [0, 1, 0, 0, 2, 2]
44 
45  q = np.vstack((q_x, q_y, q_z)).T
46 
47  # Create waypoint set
48  waypoints = WaypointSet()
49  for i in range(q.shape[0]):
50  waypoints.add_waypoint(Waypoint(q[i, 0], q[i, 1], q[i, 2], max_forward_speed=0.5))
51 
52  interpolator = LinearInterpolator()
53  interpolator.init_waypoints(waypoints)
54  interpolator.init_interpolator()
55 
56  # Use get_samples to retrieve points interpolated
57  # using a fixed step, step being represented in the line's
58  # parametric space
59  pnts = interpolator.get_samples(max_time=None, step=0.01)
60 
61  # Or use the following to retrieve a position vector on the
62  # set of lines
63  pos = interpolator.generate_pos(s=0.2)
64  ```
65  """
66  LABEL = 'linear'
67 
68  def __init__(self):
69  super(LinearInterpolator, self).__init__(self)
70 
71  # Set of interpolation functions for each degree of freedom
72  # The heading function interpolates the given heading offset and its
73  # value is added to the heading computed from the trajectory
74  self._interp_fcns = dict(pos=None,
75  heading=None)
76  self._heading_spline = None
77 
78  def init_interpolator(self):
79  """Initialize the interpolator. To have the path segments generated,
80  `init_waypoints()` must be called beforehand by providing a set of
81  waypoints as `uuv_waypoints.WaypointSet` type.
82 
83  > *Returns*
84 
85  `True` if the path segments were successfully generated.
86  """
87  if self._waypoints is None:
88  return False
89 
90  if self._waypoints.num_waypoints < 2:
91  return False
92 
93  self._markers_msg = MarkerArray()
94  self._marker_id = 0
95 
96  self._interp_fcns['pos'] = list()
97  # TODO: Segment tracking map
98  self._segment_to_wp_map = [0]
99 
100  for i in range(1, self._waypoints.num_waypoints):
101  self._interp_fcns['pos'].append(
102  LineSegment(self._waypoints.get_waypoint(i - 1).pos,
103  self._waypoints.get_waypoint(i).pos))
104 
105  # Reparametrizing the curves
106  lengths = [seg.get_length() for seg in self._interp_fcns['pos']]
107  lengths = [0] + lengths
108  self._s = np.cumsum(lengths) / np.sum(lengths)
109  mean_vel = np.mean(
110  [self._waypoints.get_waypoint(k).max_forward_speed for k in range(self._waypoints.num_waypoints)])
111  if self._duration is None:
112  self._duration = np.sum(lengths) / mean_vel
113  if self._start_time is None:
114  self._start_time = 0.0
115 
116  # Set a simple spline to interpolate heading offset, if existent
117  heading = [self._waypoints.get_waypoint(k).heading_offset for k in range(self._waypoints.num_waypoints)]
118  self._heading_spline = splrep(self._s, heading, k=3, per=False)
119  self._interp_fcns['heading'] = lambda x: splev(x, self._heading_spline)
120 
121  return True
122 
123  def set_parameters(self, params):
124  """Not implemented for this interpolator."""
125  return True
126 
127  def get_samples(self, max_time, step=0.001):
128  """Sample the full path for position and quaternion vectors.
129  `step` is represented in the path's parametric space.
130 
131  > *Input arguments*
132 
133  * `step` (*type:* `float`, *default:* `0.001`): Parameter description
134 
135  > *Returns*
136 
137  List of `uuv_trajectory_generator.TrajectoryPoint`.
138  """
139  if self._waypoints is None:
140  return None
141  if self._interp_fcns['pos'] is None:
142  return None
143  s = np.arange(0, 1 + step, step)
144 
145  pnts = list()
146  for i in s:
147  pnt = TrajectoryPoint()
148  pnt.pos = self.generate_pos(i).tolist()
149  pnt.t = 0.0
150  pnts.append(pnt)
151  return pnts
152 
153  def generate_pos(self, s):
154  """Generate a position vector for the path sampled point
155  interpolated on the position related to `s`, `s` being
156  represented in the curve's parametric space.
157 
158  > *Input arguments*
159 
160  * `s` (*type:* `float`): Curve's parametric input expressed in the
161  interval of [0, 1]
162 
163  > *Returns*
164 
165  3D position vector as a `numpy.array`.
166  """
167  if self._interp_fcns['pos'] is None:
168  return None
169  idx = self.get_segment_idx(s)
170  if idx == 0:
171  u_k = 0
172  pos = self._interp_fcns['pos'][idx].interpolate(u_k)
173  else:
174  u_k = (s - self._s[idx - 1]) / (self._s[idx] - self._s[idx - 1])
175  pos = self._interp_fcns['pos'][idx - 1].interpolate(u_k)
176  return pos
177 
178  def generate_pnt(self, s, t, *args):
179  """Compute a point that belongs to the path on the
180  interpolated space related to `s`, `s` being represented
181  in the curve's parametric space.
182 
183  > *Input arguments*
184 
185  * `s` (*type:* `float`): Curve's parametric input expressed in the
186  interval of [0, 1]
187  * `t` (*type:* `float`): Trajectory point's timestamp
188 
189  > *Returns*
190 
191  `uuv_trajectory_generator.TrajectoryPoint` including position
192  and quaternion vectors.
193  """
194  pnt = TrajectoryPoint()
195  # Trajectory time stamp
196  pnt.t = t
197  # Set position vector
198  pnt.pos = self.generate_pos(s).tolist()
199  # Set rotation quaternion
200  pnt.rotq = self.generate_quat(s)
201  return pnt
202 
203  def generate_quat(self, s):
204  """Compute the quaternion of the path reference for a interpolated
205  point related to `s`, `s` being represented in the curve's parametric
206  space.
207  The quaternion is computed assuming the heading follows the direction
208  of the path towards the target. Roll and pitch can also be computed
209  in case the `full_dof` is set to `True`.
210 
211  > *Input arguments*
212 
213  * `s` (*type:* `float`): Curve's parametric input expressed in the
214  interval of [0, 1]
215 
216  > *Returns*
217 
218  Rotation quaternion as a `numpy.array` as `(x, y, z, w)`
219  """
220  s = max(0, s)
221  s = min(s, 1)
222 
223  if s == 0:
224  self._last_rot = deepcopy(self._init_rot)
225  return self._init_rot
226 
227  last_s = max(0, s - self._s_step)
228 
229  this_pos = self.generate_pos(s)
230  last_pos = self.generate_pos(last_s)
231 
232  dx = this_pos[0] - last_pos[0]
233  dy = this_pos[1] - last_pos[1]
234  dz = this_pos[2] - last_pos[2]
235 
236  rotq = self._compute_rot_quat(dx, dy, dz)
237  self._last_rot = rotq
238  # Calculating the step for the heading offset
239  q_step = quaternion_about_axis(
240  self._interp_fcns['heading'](s),
241  np.array([0, 0, 1]))
242  # Adding the heading offset to the rotation quaternion
243  rotq = quaternion_multiply(rotq, q_step)
244 
245  self._last_rot = rotq
246  return rotq


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