dp_controller_local_planner.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 logging
17 import sys
18 import time
19 import numpy as np
20 from copy import deepcopy
21 from os.path import isfile
22 from threading import Lock, Event
23 
24 from std_msgs.msg import Bool, Float64
25 from geometry_msgs.msg import Twist
26 from uuv_control_msgs.srv import *
27 from uuv_control_msgs.msg import Trajectory, TrajectoryPoint, WaypointSet
28 from visualization_msgs.msg import MarkerArray
29 from geometry_msgs.msg import Point
30 
31 import uuv_trajectory_generator
32 import uuv_waypoints
33 from tf_quaternion.transformations import quaternion_about_axis, quaternion_multiply, \
34  quaternion_inverse, quaternion_matrix, euler_from_quaternion, quaternion_from_euler
35 
36 from ._log import get_logger
37 
38 
40  """Local planner for the dynamic positioning controllers
41  to interpolate trajectories and generate trajectories from
42  interpolated waypoint paths.
43 
44  > *Input parameters*
45 
46  * `full_dof` (*type:* `bool`, *default:* `False`): If `True`,
47  the reference trajectory reference will be computed for 6 DoF,
48  otherwise, 4 DoF `(x, y, z, yaw)`.
49  * `stamped_pose_only` (*type:* `bool`, *default:* `False`): If
50  `True`, only stamped poses will be generated as a reference, with
51  velocity and acceleration reference being set to zero.
52  * `thrusters_only` (*type:* `bool`, *default:* `True`): If `False`,
53  the idle mode will be used to keep the vehicle moving.
54 
55  > *ROS parameters*
56 
57  * `max_forward_speed` (*type:* `float`, *default:* `1.0`): Maximum
58  allowed forward speed.
59  * `idle_radius` (*type:* `float`, *default:* `10.0`): Radius of the circle
60  path generated when an AUV is in idle mode.
61  * `inertial_frame_id` (*type:* `str`): Name of the inertial frame used,
62  options are `world` or `world_ned`.
63  * `timeout_idle_mode` (*type:* `float`): Timeout at the start or after
64  a trajectory is finished where the AUV is set to start idle mode path.
65  * `look_ahead_delay` (*type:* `float`): Look ahead delay in seconds. This
66  parameters will offset the interpolation of the trajectory in the given
67  amount of seconds to compute the look-ahead target for AUVs.
68 
69  !!! warning
70 
71  The parameters for the path interpolators must also be provided when
72  starting a node that includes the local planner, since the interpolators
73  are initialized by the local planner.
74 
75  > *ROS publishers*
76 
77  * `trajectory` (*type:* `uuv_control_msgs.Trajectory`): Generated trajectory or
78  stamped pose path.
79  * `waypoints` (*type:* `uuv_control_msgs.WaypointSet`): Set of waypoints provided
80  as input for the interpolator
81  * `station_keeping_on` (*type:* `std_msgs.Bool`): Status of the station keeping mode
82  * `automatic_on` (*type:* `std_msgs.Bool`): Status of automatic model. If `False`
83  the vehicle can receive control inputs from a teleop node.
84  * `trajectory_tracking_on` (*type:* `std_msgs.Bool`): Sets the output flag to `True`
85  when trajectory tracking is ongoing
86  * `interpolator_visual_markers` (*type:* `visualization_msgs.MarkerArray`): Helper
87  visual markers from the interpolator class.
88  * `time_to_target` (*type:* `std_msgs.Float64`): Estimated time to target in seconds.
89 
90  > *ROS services*
91 
92  * `hold_vehicle` (*type:* `uuv_control_msgs.Hold`)
93  * `start_waypoint_list` (*type:* `uuv_control_msgs.InitWaypointSet`)
94  * `start_circular_trajectory` (*type:* `uuv_control_msgs.InitCircularTrajectory`)
95  * `start_helical_trajectory` (*type:* `uuv_control_msgs.InitHelicalTrajectory`)
96  * `init_waypoints_from_file` (*type:* `uuv_control_msgs.InitWaypointsFromFile`)
97  * `go_to` (*type:* `uuv_control_msgs.GoTo`)
98  * `go_to_incremental` (*type:* `uuv_control_msgs.GoToIncremental`)
99  """
100 
101  def __init__(self, full_dof=False, stamped_pose_only=False, thrusters_only=True):
103 
104  self._lock = Lock()
105 
106  self._traj_interpolator = uuv_trajectory_generator.TrajectoryGenerator(
107  full_dof=full_dof, stamped_pose_only=stamped_pose_only)
108 
109  # Max. allowed forward speed
110  self._max_forward_speed = rospy.get_param('~max_forward_speed', 1.0)
111 
113  self._idle_z = None
114 
115  self._logger.info('Max. forward speed [m/s]=%.2f' % self._max_forward_speed)
116 
117  self._idle_radius = rospy.get_param('~idle_radius', 10.0)
118  assert self._idle_radius > 0
119 
120  self._logger.info('Idle circle radius [m] = %.2f' % self._idle_radius)
121 
122  # Is underactuated?
123  self._is_underactuated = rospy.get_param('~is_underactuated', False)
124 
125  self.inertial_frame_id = 'world'
127  self.q_ned_to_enu = None
128  if rospy.has_param('~inertial_frame_id'):
129  self.inertial_frame_id = rospy.get_param('~inertial_frame_id')
130  assert len(self.inertial_frame_id) > 0
131  assert self.inertial_frame_id in ['world', 'world_ned']
132 
133  self._logger.info('Inertial frame ID=' + self.inertial_frame_id)
134 
135  rospy.set_param('inertial_frame_id', self.inertial_frame_id)
136 
137  try:
138  import tf2_ros
139 
140  tf_buffer = tf2_ros.Buffer()
141  listener = tf2_ros.TransformListener(tf_buffer)
142 
143  tf_trans_ned_to_enu = tf_buffer.lookup_transform(
144  'world', 'world_ned', rospy.Time(),
145  rospy.Duration(10))
146 
147  self.q_ned_to_enu = np.array(
148  [tf_trans_ned_to_enu.transform.rotation.x,
149  tf_trans_ned_to_enu.transform.rotation.y,
150  tf_trans_ned_to_enu.transform.rotation.z,
151  tf_trans_ned_to_enu.transform.rotation.w])
152  except Exception as ex:
153  self._logger.warning(
154  'Error while requesting ENU to NED transform'
155  ', message={}'.format(ex))
156  self.q_ned_to_enu = quaternion_from_euler(2 * np.pi, 0, np.pi)
157 
158  self.transform_ned_to_enu = quaternion_matrix(
159  self.q_ned_to_enu)[0:3, 0:3]
160 
161  if self.transform_ned_to_enu is not None:
162  self._logger.info('Transform world_ned (NED) to world (ENU)=\n' +
163  str(self.transform_ned_to_enu))
164 
165  self._logger.info('Inertial frame ID=' + self.inertial_frame_id)
166  self._logger.info('Max. forward speed = ' +
167  str(self._max_forward_speed))
168 
169  for method in self._traj_interpolator.get_interpolator_tags():
170  if rospy.has_param('~' + method):
171  self._logger.info('Parameters for interpolation method <%s> found' % method)
172  params = rospy.get_param('~' + method)
173  self._logger.info('\t' + str(params))
174 
175  self._traj_interpolator.set_interpolator_parameters(method, params)
176  else:
177  self._logger.info('No parameters for interpolation method <%s> found' % method)
178 
179  # dt used to compute the pose reference from the joystick input
180  self._dt = 0.0
181  # Time stamp for the last velocity reference received
183  # Flag to indicate if the teleoperation node is active
184  self._is_teleop_active = False
185  # Teleop node twist message
186  self._teleop_vel_ref = None
187 
188  self.init_odom_event = Event()
189  self.init_odom_event.clear()
190 
191  self._timeout_idle_mode = rospy.get_param('~timeout_idle_mode', 5)
192  self._start_count_idle = rospy.get_time()
193 
194  self._thrusters_only = thrusters_only
195 
196  if not self._thrusters_only:
197  self._look_ahead_delay = rospy.get_param('~look_ahead_delay', 3.0)
198  else:
199  self._look_ahead_delay = 0.0
200 
202 
203  # Publishing topic for the trajectory given to the controller
204  self._trajectory_pub = rospy.Publisher('trajectory',
205  Trajectory,
206  queue_size=1)
207  # Publishing waypoints
208  self._waypoints_pub = rospy.Publisher('waypoints',
209  WaypointSet,
210  queue_size=1)
211 
212  self._station_keeping_pub = rospy.Publisher('station_keeping_on',
213  Bool,
214  queue_size=1)
215 
216  self._automatic_control_pub = rospy.Publisher('automatic_on',
217  Bool,
218  queue_size=1)
219 
220  self._traj_tracking_pub = rospy.Publisher('trajectory_tracking_on',
221  Bool,
222  queue_size=1)
223 
224  self._interp_visual_markers = rospy.Publisher('interpolator_visual_markers',
225  MarkerArray,
226  queue_size=1)
227 
228  self._teleop_sub = rospy.Subscriber('cmd_vel', Twist, self._update_teleop)
229 
230  self._waypoints_msg = None
231  self._trajectory_msg = None
232 
233  # Subscribing topic for the trajectory given to the controller
234  self._input_trajectory_sub = rospy.Subscriber(
235  'input_trajectory', Trajectory, self._update_trajectory_from_msg)
236 
237  self._max_time_pub = rospy.Publisher('time_to_target', Float64, queue_size=1)
238 
239  self._traj_info_update_timer = rospy.Timer(rospy.Duration(0.2),
241  # Flag to activate station keeping
243  # Flag to set vehicle control to automatic
244  self._is_automatic = True
245  # Flag true if a trajectory is being tracked
246  self._traj_running = False
247  # Current vehicle pose
248  self._vehicle_pose = None
249  # Current reference point
250  self._this_ref_pnt = None
251  # Flag that indicates that a waypoint set has been initialized
252  self._smooth_approach_on = False
253  # Time stamp for received trajectory
255  # Dictionary of services
256  self._services = dict()
257  self._services['hold_vehicle'] = rospy.Service(
258  'hold_vehicle', Hold, self.hold_vehicle)
259  self._services['start_waypoint_list'] = rospy.Service(
260  'start_waypoint_list', InitWaypointSet, self.start_waypoint_list)
261  self._services['start_circular_trajectory'] = rospy.Service(
262  'start_circular_trajectory', InitCircularTrajectory,
263  self.start_circle)
264  self._services['start_helical_trajectory'] = rospy.Service(
265  'start_helical_trajectory', InitHelicalTrajectory,
266  self.start_helix)
267  self._services['init_waypoints_from_file'] = rospy.Service(
268  'init_waypoints_from_file', InitWaypointsFromFile,
270  self._services['go_to'] = rospy.Service('go_to', GoTo, self.go_to)
271  self._services['go_to_incremental'] = rospy.Service(
272  'go_to_incremental', GoToIncremental, self.go_to_incremental)
273 
274  def __del__(self):
275  """Remove logging message handlers"""
276  while self._logger.handlers:
277  self._logger.handlers.pop()
278 
279  def _transform_position(self, vec, target, source):
280  """Transform the position vector between `world` and `world_ned`.
281 
282  > *Input arguments*
283 
284  * `vec` (*type:* `numpy.array`): Position vector
285  * `target` (*type:* `str`): Target frame
286  * `source` (*type:* `str`): Source frame
287 
288  > *Returns*
289 
290  `numpy.array`: Transformed vector
291  """
292  if target == source:
293  return vec
294  if target == 'world':
295  return np.dot(self.transform_ned_to_enu, vec)
296  if target == 'world_ned':
297  return np.dot(self.transform_ned_to_enu.T, vec)
298 
299  def _transform_waypoint(self, waypoint):
300  """Transform position vector of a waypoint between
301  `world` and `world_ned` frames.
302 
303  > *Input arguments*
304 
305  * `waypoint` (*type:* `uuv_waypoints.Waypoint`): Input waypoint
306 
307  > *Returns*
308 
309  `uuv_waypoints.Waypoint`: Transformed waypoint
310  """
311  output = deepcopy(waypoint)
312  output.pos = self._transform_position(output.pos,
313  self.inertial_frame_id,
314  output.inertial_frame_id)
315  output.inertial_frame_id = self.inertial_frame_id
316  output.max_forward_speed = min(waypoint.max_forward_speed, self._max_forward_speed)
317  return output
318 
319  def _transform_waypoint_set(self, waypoint_set):
320  """Apply transformation between `world` and 'world_ned` frames
321  to waypoints in a waypoint set.
322 
323  > *Input arguments*
324 
325  * `waypoint_set` (*type:* `uuv_waypoins.WaypointSet`): Set of waypoints
326 
327  > *Returns*
328 
329  `uuv_waypoins.WaypointSet`: Set of transformed waypoints
330  """
331  output = uuv_waypoints.WaypointSet(
332  inertial_frame_id=self.inertial_frame_id)
333  for i in range(waypoint_set.num_waypoints):
334  wp = self._transform_waypoint(waypoint_set.get_waypoint(i))
335  output.add_waypoint(wp)
336  return output
337 
338  def _apply_workspace_constraints(self, waypoint_set):
339  """Filter out waypoints that are positioned above
340  sea surface, namely `z > 0` if the inertial frame is
341  `world`, or `z < 0` if the inertial frame is `world_ned`.
342 
343  > *Input arguments*
344 
345  * `waypoint_set` (*type:* `uuv_waypoins.WaypointSet`): Set of waypoints
346 
347  > *Returns*
348 
349  `uuv_waypoins.WaypointSet`: Filtered set of waypoints
350  """
351  wp_set = uuv_waypoints.WaypointSet(
352  inertial_frame_id=self.inertial_frame_id)
353  for i in range(waypoint_set.num_waypoints):
354  wp = waypoint_set.get_waypoint(i)
355  if wp.z > 0 and self.inertial_frame_id == 'world':
356  continue
357  if wp.z < 0 and self.inertial_frame_id == 'world_ned':
358  continue
359  wp_set.add_waypoint(wp)
360  return wp_set
361 
362  def _publish_trajectory_info(self, event):
363  """Publish messages for the waypoints, trajectory and
364  debug flags.
365  """
366  if self._waypoints_msg is not None:
367  self._waypoints_pub.publish(self._waypoints_msg)
368  if self._trajectory_msg is not None:
369  self._trajectory_pub.publish(self._trajectory_msg)
370  markers = self._traj_interpolator.get_visual_markers()
371  if markers is not None:
372  self._interp_visual_markers.publish(markers)
373  else:
374  self._interp_visual_markers.publish(MarkerArray())
375  self._station_keeping_pub.publish(Bool(self._station_keeping_on))
376  self._automatic_control_pub.publish(Bool(self._is_automatic))
377  self._traj_tracking_pub.publish(Bool(self._traj_running))
378  return True
379 
381  """Update the trajectory message."""
382  self._waypoints_msg = WaypointSet()
383  if self._traj_interpolator.is_using_waypoints():
384  wps = self._traj_interpolator.get_waypoints()
385  if wps is not None:
386  wps.inertial_frame_id = self.inertial_frame_id
387  self._waypoints_msg = wps.to_message()
388  self._waypoints_msg.header.frame_id = self.inertial_frame_id
389  msg = self._traj_interpolator.get_trajectory_as_message()
390  if msg is not None:
391  msg.header.frame_id = self.inertial_frame_id
392  self._trajectory_msg = msg
393  self._logger.info('Updating the trajectory information')
394  else:
395  self._trajectory_msg = None
396  self._logger.error('Error generating trajectory message')
397 
398  def _update_teleop(self, msg):
399  """Callback to the twist teleop subscriber."""
400  # Test whether the vehicle is in automatic mode (following a given
401  # trajectory)
402  if self._is_automatic:
403  self._teleop_vel_ref = None
404  return
405 
406  # If this is the first twist message since the last time automatic mode
407  # was turned off, then just update the teleop timestamp and wait for
408  # the next message to allow computing pose and velocity reference.
409  if self._last_teleop_update is None:
410  self._teleop_vel_ref = None
411  self._last_teleop_update = rospy.get_time()
412  return
413 
414  # Store twist reference message
415  self._teleop_vel_ref = msg
416 
417  # Set the teleop mode is active only if any of the linear velocity components and
418  # yaw rate are non-zero
419  vel = np.array([self._teleop_vel_ref.linear.x, self._teleop_vel_ref.linear.y, self._teleop_vel_ref.linear.z, self._teleop_vel_ref.angular.z])
420  self._is_teleop_active = np.abs(vel).sum() > 0
421 
422  # Store time stamp
423  self._last_teleop_update = rospy.get_time()
424 
426  """Compute pose and velocity reference using the
427  joystick linear and angular velocity input.
428  """
429  # Check if there is already a timestamp for the last received reference
430  # message from the teleop node
431  if self._last_teleop_update is None:
432  self._is_teleop_active = False
433 
434  # Compute time step
435  self._dt = rospy.get_time() - self._last_teleop_update
436 
437  # Compute the pose and velocity reference if the computed time step is
438  # positive and the twist teleop message is valid
439  if self._dt > 0 and self._teleop_vel_ref is not None and self._dt < 0.1:
440  speed = np.sqrt(self._teleop_vel_ref.linear.x**2 + self._teleop_vel_ref.linear.y**2)
441  vel = np.array([self._teleop_vel_ref.linear.x, self._teleop_vel_ref.linear.y, self._teleop_vel_ref.linear.z])
442  # Cap the forward speed if needed
443  if speed > self._max_forward_speed:
444  vel[0] *= self._max_forward_speed / speed
445  vel[1] *= self._max_forward_speed / speed
446 
447  vel = np.dot(self._vehicle_pose.rot_matrix, vel)
448 
449  # Compute pose step
450  step = uuv_trajectory_generator.TrajectoryPoint()
451  step.pos = np.dot(self._vehicle_pose.rot_matrix, vel * self._dt)
452  step.rotq = quaternion_about_axis(self._teleop_vel_ref.angular.z * self._dt, [0, 0, 1])
453 
454  # Compute new reference
455  ref_pnt = uuv_trajectory_generator.TrajectoryPoint()
456  ref_pnt.pos = self._vehicle_pose.pos + step.pos
457 
458  ref_pnt.rotq = quaternion_multiply(self.get_vehicle_rot(), step.rotq)
459 
460  # Cap the pose reference in Z to stay underwater
461  if ref_pnt.z > 0:
462  ref_pnt.z = 0.0
463  ref_pnt.vel = [vel[0], vel[1], 0, 0, 0, self._teleop_vel_ref.angular.z]
464  else:
465  ref_pnt.vel = [vel[0], vel[1], vel[2], 0, 0, self._teleop_vel_ref.angular.z]
466 
467  ref_pnt.acc = np.zeros(6)
468  else:
469  self._is_teleop_active = False
470  ref_pnt = deepcopy(self._vehicle_pose)
471  return ref_pnt
472 
474  """Add the current vehicle position as waypoint
475  to allow a smooth approach to the given trajectory.
476  """
477  if self._vehicle_pose is None:
478  self._logger.error('Simulation not properly initialized yet, ignoring approach...')
479  return
480  if not self._traj_interpolator.is_using_waypoints():
481  self._logger.error('Not using the waypoint interpolation method')
482  return
483 
484  heading = euler_from_quaternion(self.get_vehicle_rot())[2]
485 
486  if self._thrusters_only:
487  init_wp = uuv_waypoints.Waypoint(
488  x=self._vehicle_pose.pos[0],
489  y=self._vehicle_pose.pos[1],
490  z=self._vehicle_pose.pos[2],
491  max_forward_speed=self._traj_interpolator.get_waypoints().get_waypoint(0).max_forward_speed,
492  heading_offset=self._traj_interpolator.get_waypoints().get_waypoint(0).heading_offset)
493  else:
494  max_speed = self._traj_interpolator.get_waypoints().get_waypoint(0).max_forward_speed
495  init_wp = uuv_waypoints.Waypoint(
496  x=self._vehicle_pose.pos[0],# + max_speed / self._look_ahead_delay * np.cos(heading),
497  y=self._vehicle_pose.pos[1],# + max_speed / self._look_ahead_delay * np.sin(heading),
498  z=self._vehicle_pose.pos[2],
499  max_forward_speed=max_speed,
500  heading_offset=self._traj_interpolator.get_waypoints().get_waypoint(0).heading_offset)
501  first_wp = self._traj_interpolator.get_waypoints().get_waypoint(0)
502 
503  dx = first_wp.x - init_wp.x
504  dy = first_wp.y - init_wp.y
505  dz = first_wp.z - init_wp.z
506 
507  # One new waypoint at each meter
508  self._logger.info('Adding waypoints to approach the first position in the given waypoint set')
509  steps = int(np.floor(first_wp.dist(init_wp.pos)) / 10)
510  if steps > 0 and self._traj_interpolator.get_interp_method() != 'dubins':
511  for i in range(1, steps):
512  wp = uuv_waypoints.Waypoint(
513  x=first_wp.x - i * dx / steps,
514  y=first_wp.y - i * dy / steps,
515  z=first_wp.z - i * dz / steps,
516  max_forward_speed=self._traj_interpolator.get_waypoints().get_waypoint(0).max_forward_speed)
517  self._traj_interpolator.add_waypoint(wp, add_to_beginning=True)
518  self._traj_interpolator.add_waypoint(init_wp, add_to_beginning=True)
520 
522  """Return `True`, if vehicle is holding its position."""
523  return self._station_keeping_on
524 
525  def is_automatic_on(self):
526  """Return `True` if vehicle if following a trajectory in
527  automatic mode.
528  """
529  return self._is_automatic
530 
531  def set_station_keeping(self, is_on=True):
532  """Set station keeping mode flag.
533 
534  > *Input arguments*
535 
536  * `is_on` (*type:* `bool`, *default:* `True`): Station keeping flag
537  """
538  self._station_keeping_on = is_on
539  self._logger.info('STATION KEEPING MODE = ' + ('ON' if is_on else 'OFF'))
540 
541  def set_automatic_mode(self, is_on=True):
542  """Set automatic mode flag."""
543  self._is_automatic = is_on
544  self._logger.info('AUTOMATIC MODE = ' + ('ON' if is_on else 'OFF'))
545 
546  def set_trajectory_running(self, is_on=True):
547  """Set trajectory tracking flag."""
548  self._traj_running = is_on
549  self._logger.info('TRAJECTORY TRACKING = ' + ('ON' if is_on else 'OFF'))
550 
551  def has_started(self):
552  """Return if the trajectory interpolator has started generating
553  reference points.
554  """
555 
556  return self._traj_interpolator.has_started()
557 
558  def has_finished(self):
559  """Return `True` if the trajectory has finished."""
560  return self._traj_interpolator.has_finished()
561 
562  def update_vehicle_pose(self, pos, quat):
563  """Update the vehicle's pose information.
564 
565  > *Input arguments*
566 
567  * `pos` (*type:* `numpy.array`): Position vector
568  * `quat` (*type:* `numpy.array`): Quaternion as `(qx, qy, qz, qw)`
569  """
570  if self._vehicle_pose is None:
571  self._vehicle_pose = uuv_trajectory_generator.TrajectoryPoint()
572  self._vehicle_pose.pos = pos
573  self._vehicle_pose.rotq = quat
574  self._vehicle_pose.t = rospy.get_time()
575  self.init_odom_event.set()
576 
577  def get_vehicle_rot(self):
578  """Return the vehicle's rotation quaternion."""
579  self.init_odom_event.wait()
580  return self._vehicle_pose.rotq
581 
583  self._stamp_trajectory_received = rospy.get_time()
584  self._traj_interpolator.init_from_trajectory_message(msg)
585  self._logger.info('New trajectory received at ' + str(self._stamp_trajectory_received) + 's')
587 
589  """Start station keeping mode by setting the pose
590  set-point of the vehicle as the last pose before the
591  vehicle finished automatic mode.
592  """
593  if self._vehicle_pose is not None:
594  self._this_ref_pnt = deepcopy(self._vehicle_pose)
595  self._this_ref_pnt.vel = np.zeros(6)
596  self._this_ref_pnt.acc = np.zeros(6)
597  self.set_station_keeping(True)
598  self.set_automatic_mode(False)
599  self._smooth_approach_on = False
600 
601  def hold_vehicle(self, request):
602  """Service callback function to hold the vehicle's
603  current position.
604  """
605  if self._vehicle_pose is None:
606  self._logger.error('Current pose of the vehicle is invalid')
607  return HoldResponse(False)
608  self.start_station_keeping()
609  return HoldResponse(True)
610 
611  def start_waypoint_list(self, request):
612  """Service callback function to follow a set of waypoints
613 
614  > *Input arguments*
615 
616  * `request` (*type:* `uuv_control_msgs.InitWaypointSet`)
617  """
618  if len(request.waypoints) == 0:
619  self._logger.error('Waypoint list is empty')
620  return InitWaypointSetResponse(False)
621  t = rospy.Time(request.start_time.data.secs, request.start_time.data.nsecs)
622  if t.to_sec() < rospy.get_time() and not request.start_now:
623  self._logger.error('The trajectory starts in the past, correct the starting time!')
624  return InitWaypointSetResponse(False)
625  else:
626  self._logger.info('Start waypoint trajectory now!')
627  self._lock.acquire()
628  # Create a waypoint set
629  wp_set = uuv_waypoints.WaypointSet(
630  inertial_frame_id=self.inertial_frame_id)
631  # Create a waypoint set message, to fill wp_set
632  waypointset_msg = WaypointSet()
633  waypointset_msg.header.stamp = rospy.get_time()
634  waypointset_msg.header.frame_id = self.inertial_frame_id
635  if request.start_now:
636  waypointset_msg.start_time = rospy.get_time()
637  else:
638  waypointset_msg.start_time = t.to_sec()
639  waypointset_msg.waypoints = request.waypoints
640  wp_set.from_message(waypointset_msg)
641  wp_set = self._transform_waypoint_set(wp_set)
642  wp_set = self._apply_workspace_constraints(wp_set)
643 
644  if self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot()):
645  self._station_keeping_center = None
646  self._traj_interpolator.set_start_time((t.to_sec() if not request.start_now else rospy.get_time()))
648  self.set_station_keeping(False)
649  self.set_automatic_mode(True)
650  self.set_trajectory_running(True)
651  self._idle_circle_center = None
652  self._smooth_approach_on = True
653  self._logger.info('============================')
654  self._logger.info(' WAYPOINT SET ')
655  self._logger.info('============================')
656  self._logger.info('Interpolator = ' + request.interpolator.data)
657  self._logger.info('# waypoints = %d' % self._traj_interpolator.get_waypoints().num_waypoints)
658  self._logger.info('Starting time = %.2f' % (t.to_sec() if not request.start_now else rospy.get_time()))
659  self._logger.info('Inertial frame ID = ' + self.inertial_frame_id)
660  self._logger.info('============================')
661  self._lock.release()
662  return InitWaypointSetResponse(True)
663  else:
664  self._logger.error('Error occurred while parsing waypoints')
665  self._lock.release()
666  return InitWaypointSetResponse(False)
667 
668  def start_circle(self, request):
669  """Service callback function to initialize a parametrized
670  circular trajectory.
671 
672  > *Input arguments*
673 
674  * `request` (*type:* `uuv_control_msgs.InitCircularTrajectory`)
675  """
676  if request.max_forward_speed <= 0 or request.radius <= 0 or \
677  request.n_points <= 0:
678  self._logger.error('Invalid parameters to generate a circular trajectory')
679  return InitCircularTrajectoryResponse(False)
680  t = rospy.Time(request.start_time.data.secs, request.start_time.data.nsecs)
681  if t.to_sec() < rospy.get_time() and not request.start_now:
682  self._logger.error('The trajectory starts in the past, correct the starting time!')
683  return InitCircularTrajectoryResponse(False)
684  try:
685  wp_set = uuv_waypoints.WaypointSet(
686  inertial_frame_id=self.inertial_frame_id)
687  success = wp_set.generate_circle(radius=request.radius,
688  center=request.center,
689  num_points=request.n_points,
690  max_forward_speed=request.max_forward_speed,
691  theta_offset=request.angle_offset,
692  heading_offset=request.heading_offset)
693  if not success:
694  self._logger.error('Error generating circular trajectory from waypoint set')
695  return InitCircularTrajectoryResponse(False)
696  wp_set = self._apply_workspace_constraints(wp_set)
697  if wp_set.is_empty:
698  self._logger.error('Waypoints violate workspace constraints, are you using world or world_ned as reference?')
699  return InitCircularTrajectoryResponse(False)
700 
701  self._lock.acquire()
702  # Activates station keeping
703  self.set_station_keeping(True)
704  self._traj_interpolator.set_interp_method('cubic')
705  self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot())
706  self._station_keeping_center = None
707  self._traj_interpolator.set_start_time((t.to_sec() if not request.start_now else rospy.get_time()))
708  if request.duration > 0:
709  if self._traj_interpolator.set_duration(request.duration):
710  self._logger.info('Setting a maximum duration, duration=%.2f s' % request.duration)
711  else:
712  self._logger.error('Setting maximum duration failed')
714  # Disables station keeping to start trajectory
715  self.set_station_keeping(False)
716  self.set_automatic_mode(True)
717  self.set_trajectory_running(True)
718  self._idle_circle_center = None
719  self._smooth_approach_on = True
720 
721  self._logger.info('============================')
722  self._logger.info('CIRCULAR TRAJECTORY GENERATED FROM WAYPOINT INTERPOLATION')
723  self._logger.info('============================')
724  self._logger.info('Radius [m] = %.2f' % request.radius)
725  self._logger.info('Center [m] = (%.2f, %.2f, %.2f)' % (request.center.x, request.center.y, request.center.z))
726  self._logger.info('# of points = %d' % request.n_points)
727  self._logger.info('Max. forward speed = %.2f' % request.max_forward_speed)
728  self._logger.info('Circle angle offset = %.2f' % request.angle_offset)
729  self._logger.info('Heading offset = %.2f' % request.heading_offset)
730  self._logger.info('# waypoints = %d' % self._traj_interpolator.get_waypoints().num_waypoints)
731  self._logger.info('Starting from = ' + str(self._traj_interpolator.get_waypoints().get_waypoint(0).pos))
732  self._logger.info('Starting time [s] = %.2f' % (t.to_sec() if not request.start_now else rospy.get_time()))
733  self._logger.info('============================')
734  self._lock.release()
735  return InitCircularTrajectoryResponse(True)
736  except Exception as e:
737  self._logger.error('Error while setting circular trajectory, msg={}'.format(e))
738  self.set_station_keeping(True)
739  self.set_automatic_mode(False)
740  self.set_trajectory_running(False)
741  self._lock.release()
742  return InitCircularTrajectoryResponse(False)
743 
744  def start_helix(self, request):
745  """Service callback function to initialize a parametrized helical
746  trajectory.
747 
748  > *Input arguments*
749 
750  * `request` (*type:* `uuv_control_msgs.InitHelicalTrajectory`)
751  """
752  if request.radius <= 0 or request.n_points <= 0 or \
753  request.n_turns <= 0:
754  self._logger.error('Invalid parameters to generate a helical trajectory')
755  return InitHelicalTrajectoryResponse(False)
756  t = rospy.Time(request.start_time.data.secs, request.start_time.data.nsecs)
757  if t.to_sec() < rospy.get_time() and not request.start_now:
758  self._logger.error('The trajectory starts in the past, correct the starting time!')
759  return InitHelicalTrajectoryResponse(False)
760  else:
761  self._logger.info('Start helical trajectory now!')
762 
763  try:
764  wp_set = uuv_waypoints.WaypointSet(inertial_frame_id=self.inertial_frame_id)
765  success = wp_set.generate_helix(radius=request.radius,
766  center=request.center,
767  num_points=request.n_points,
768  max_forward_speed=request.max_forward_speed,
769  delta_z=request.delta_z,
770  num_turns=request.n_turns,
771  theta_offset=request.angle_offset,
772  heading_offset=request.heading_offset)
773 
774  if not success:
775  self._logger.error('Error generating circular trajectory from waypoint set')
776  return InitHelicalTrajectoryResponse(False)
777  wp_set = self._apply_workspace_constraints(wp_set)
778  if wp_set.is_empty:
779  self._logger.error('Waypoints violate workspace constraints, are you using world or world_ned as reference?')
780  return InitHelicalTrajectoryResponse(False)
781 
782  self._lock.acquire()
783  self.set_station_keeping(True)
784  self._traj_interpolator.set_interp_method('cubic')
785  if not self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot()):
786  self._logger.error('Error setting the waypoints')
787  return InitHelicalTrajectoryResponse(False)
788 
789  self._station_keeping_center = None
790  self._traj_interpolator.set_start_time((t.to_sec() if not request.start_now else rospy.get_time()))
791 
792  if request.duration > 0:
793  if self._traj_interpolator.set_duration(request.duration):
794  self._logger.info('Setting a maximum duration, duration=%.2f s' % request.duration)
795  else:
796  self._logger.error('Setting maximum duration failed')
798  self.set_station_keeping(False)
799  self.set_automatic_mode(True)
800  self.set_trajectory_running(True)
801  self._idle_circle_center = None
802  self._smooth_approach_on = True
803 
804  self._logger.info('============================')
805  self._logger.info('HELICAL TRAJECTORY GENERATED FROM WAYPOINT INTERPOLATION')
806  self._logger.info('============================')
807  self._logger.info('Radius [m] = %.2f' % request.radius)
808  self._logger.info('Center [m] = (%.2f, %.2f, %.2f)' % (request.center.x, request.center.y, request.center.z))
809  self._logger.info('# of points = %d' % request.n_points)
810  self._logger.info('Max. forward speed = %.2f' % request.max_forward_speed)
811  self._logger.info('Delta Z = %.2f' % request.delta_z)
812  self._logger.info('# of turns = %d' % request.n_turns)
813  self._logger.info('Helix angle offset = %.2f' % request.angle_offset)
814  self._logger.info('Heading offset = %.2f' % request.heading_offset)
815  self._logger.info('# waypoints = %d' % self._traj_interpolator.get_waypoints().num_waypoints)
816  self._logger.info('Starting from = ' + str(self._traj_interpolator.get_waypoints().get_waypoint(0).pos))
817  self._logger.info('Starting time [s] = %.2f' % (t.to_sec() if not request.start_now else rospy.get_time()))
818  self._logger.info('============================')
819  self._lock.release()
820  return InitHelicalTrajectoryResponse(True)
821  except Exception as e:
822  self._logger.error('Error while setting helical trajectory, msg={}'.format(e))
823  self.set_station_keeping(True)
824  self.set_automatic_mode(False)
825  self.set_trajectory_running(False)
826  self._lock.release()
827  return InitHelicalTrajectoryResponse(False)
828 
829  def init_waypoints_from_file(self, request):
830  """Service callback function to initialize the path interpolator
831  with a set of waypoints loaded from a YAML file.
832 
833  > *Input arguments*
834 
835  * `request` (*type:* `uuv_control_msgs.InitWaypointsFromFile`)
836  """
837  if (len(request.filename.data) == 0 or
838  not isfile(request.filename.data)):
839  self._logger.error('Invalid waypoint file')
840  return InitWaypointsFromFileResponse(False)
841  t = rospy.Time(request.start_time.data.secs, request.start_time.data.nsecs)
842  if t.to_sec() < rospy.get_time() and not request.start_now:
843  self._logger.error('The trajectory starts in the past, correct the starting time!')
844  return InitWaypointsFromFileResponse(False)
845  else:
846  self._logger.info('Start waypoint trajectory now!')
847  self._lock.acquire()
848  self.set_station_keeping(True)
849  self._traj_interpolator.set_interp_method(request.interpolator.data)
850 
851  wp_set = uuv_waypoints.WaypointSet()
852  if not wp_set.read_from_file(request.filename.data):
853  self._logger.info('Error occurred while parsing waypoint file')
854  return InitWaypointsFromFileResponse(False)
855  wp_set = self._transform_waypoint_set(wp_set)
856  wp_set = self._apply_workspace_constraints(wp_set)
857 
858  if self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot()):
859  self._station_keeping_center = None
860  self._traj_interpolator.set_start_time((t.to_sec() if not request.start_now else rospy.get_time()))
862  self.set_station_keeping(False)
863  self.set_automatic_mode(True)
864  self.set_trajectory_running(True)
865  self._idle_circle_center = None
866  self._smooth_approach_on = True
867 
868  self._logger.info('============================')
869  self._logger.info('IMPORT WAYPOINTS FROM FILE')
870  self._logger.info('============================')
871  self._logger.info('Filename = ' + request.filename.data)
872  self._logger.info('Interpolator = ' + request.interpolator.data)
873  self._logger.info('# waypoints = %d' % self._traj_interpolator.get_waypoints().num_waypoints)
874  self._logger.info('Starting time = %.2f' % (t.to_sec() if not request.start_now else rospy.get_time()))
875  self._logger.info('Inertial frame ID = ' + self.inertial_frame_id)
876  self._logger.info('============================')
877  self._lock.release()
878  return InitWaypointsFromFileResponse(True)
879  else:
880  self._logger.error('Error occurred while parsing waypoint file')
881  self._lock.release()
882  return InitWaypointsFromFileResponse(False)
883 
884  def go_to(self, request):
885  """Service callback function to initialize to set one target
886  waypoint .
887 
888  > *Input arguments*
889 
890  * `request` (*type:* `uuv_control_msgs.GoTo`)
891  """
892  if self._vehicle_pose is None:
893  self._logger.error('Current pose has not been initialized yet')
894  return GoToResponse(False)
895  if request.waypoint.max_forward_speed <= 0.0:
896  self._logger.error('Max. forward speed must be greater than zero')
897  return GoToResponse(False)
898  self.set_station_keeping(True)
899  self._lock.acquire()
900  wp_set = uuv_waypoints.WaypointSet(
901  inertial_frame_id=self.inertial_frame_id)
902 
903  init_wp = uuv_waypoints.Waypoint(
904  x=self._vehicle_pose.pos[0],
905  y=self._vehicle_pose.pos[1],
906  z=self._vehicle_pose.pos[2],
907  max_forward_speed=request.waypoint.max_forward_speed,
908  heading_offset=euler_from_quaternion(self.get_vehicle_rot())[2],
909  use_fixed_heading=request.waypoint.use_fixed_heading,
910  inertial_frame_id=self.inertial_frame_id)
911  wp_set.add_waypoint(init_wp)
912  wp_set.add_waypoint_from_msg(request.waypoint)
913  wp_set = self._transform_waypoint_set(wp_set)
914  self._traj_interpolator.set_interp_method(request.interpolator)
915  if not self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot()):
916  self._logger.error('Error while setting waypoints')
917  self._lock.release()
918  return GoToResponse(False)
919 
920  self._station_keeping_center = None
921  t = rospy.get_time()
922  self._traj_interpolator.set_start_time(t)
924  self.set_station_keeping(False)
925  self.set_automatic_mode(True)
926  self.set_trajectory_running(True)
927  self._idle_circle_center = None
928  self._smooth_approach_on = False
929 
930  self._logger.info('============================')
931  self._logger.info('GO TO')
932  self._logger.info('============================')
933  self._logger.info('Heading offset [rad] = %.2f' % request.waypoint.heading_offset)
934  self._logger.info('# waypoints = %d' % self._traj_interpolator.get_waypoints().num_waypoints)
935  self._logger.info('Starting from = ' + str(self._traj_interpolator.get_waypoints().get_waypoint(0).pos))
936  self._logger.info('Start time [s] = %.2f ' % t)
937  self._logger.info('Inertial frame ID = ' + self.inertial_frame_id)
938  self._logger.info('============================')
939  self._lock.release()
940  return GoToResponse(True)
941 
942  def go_to_incremental(self, request):
943  """Service callback to set the command to the vehicle to move to a
944  relative position in the world.
945 
946  > *Input arguments*
947 
948  * `request` (*type:* `uuv_control_msgs.GoToIncremental`)
949  """
950  if self._vehicle_pose is None:
951  self._logger.error('Current pose has not been initialized yet')
952  return GoToIncrementalResponse(False)
953  if request.max_forward_speed <= 0:
954  self._logger.error('Max. forward speed must be positive')
955  return GoToIncrementalResponse(False)
956 
957  self._lock.acquire()
958  self.set_station_keeping(True)
959  wp_set = uuv_waypoints.WaypointSet(
960  inertial_frame_id=self.inertial_frame_id)
961  init_wp = uuv_waypoints.Waypoint(
962  x=self._vehicle_pose.pos[0],
963  y=self._vehicle_pose.pos[1],
964  z=self._vehicle_pose.pos[2],
965  max_forward_speed=request.max_forward_speed,
966  heading_offset=euler_from_quaternion(self.get_vehicle_rot())[2],
967  inertial_frame_id=self.inertial_frame_id)
968  wp_set.add_waypoint(init_wp)
969 
970  wp = uuv_waypoints.Waypoint(
971  x=self._vehicle_pose.pos[0] + request.step.x,
972  y=self._vehicle_pose.pos[1] + request.step.y,
973  z=self._vehicle_pose.pos[2] + request.step.z,
974  max_forward_speed=request.max_forward_speed,
975  inertial_frame_id=self.inertial_frame_id)
976  wp_set.add_waypoint(wp)
977 
978  self._traj_interpolator.set_interp_method(request.interpolator)
979  if not self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot()):
980  self._logger.error('Error while setting waypoints')
981  self._lock.release()
982  return GoToIncrementalResponse(False)
983 
984  self._station_keeping_center = None
985  self._traj_interpolator.set_start_time(rospy.Time.now().to_sec())
987  self.set_station_keeping(False)
988  self.set_automatic_mode(True)
989  self.set_trajectory_running(True)
990  self._idle_circle_center = None
991  self._smooth_approach_on = False
992 
993  self._logger.info('============================')
994  self._logger.info('GO TO INCREMENTAL')
995  self._logger.info('============================')
996  self._logger.info(str(wp_set))
997  self._logger.info('# waypoints = %d' % wp_set.num_waypoints)
998  self._logger.info('Inertial frame ID = ' + self.inertial_frame_id)
999  self._logger.info('============================')
1000  self._lock.release()
1001  return GoToIncrementalResponse(True)
1002 
1003  def generate_reference(self, t):
1004  """Return a trajectory point computed by the interpolator for the
1005  timestamp `t`, in case the vehicle is on `automatic` mode. In case
1006  it is in station keeping, the pose is kept constant.
1007 
1008  > *Input arguments*
1009 
1010  * `t` (*type:* `float`): Timestamp
1011 
1012  > *Returns*
1013 
1014  `uuv_trajectory_generator.TrajectoryPoint`: Trajectory point
1015  """
1016  pnt = self._traj_interpolator.generate_reference(t, self._vehicle_pose.pos, self.get_vehicle_rot())
1017  if pnt is None:
1018  return self._vehicle_pose
1019  else:
1020  return pnt
1021 
1022  def get_idle_circle_path(self, n_points, radius=30):
1023  """Generate a waypoint set starting from the current
1024  position of the vehicle in the shape of a circle to
1025  initialize an AUVs idle mode.
1026 
1027  > *Input arguments*
1028 
1029  * `n_points` (*type:* `int`): Number of waypoints
1030  * `radius` (*type:* `float`): Circle radius in meters
1031 
1032  > *Returns*
1033 
1034  `uuv_waypoints.WaypointSet`: Set of waypoints for idle mode
1035  """
1036  pose = deepcopy(self._vehicle_pose)
1037  if self._idle_circle_center is None:
1038  frame = np.array([
1039  [np.cos(pose.rot[2]), -np.sin(pose.rot[2]), 0],
1040  [np.sin(pose.rot[2]), np.cos(pose.rot[2]), 0],
1041  [0, 0, 1]])
1042  self._idle_circle_center = (pose.pos + 0.8 * self._max_forward_speed * frame[:, 0].flatten()) + radius * frame[:, 1].flatten()
1043  self._idle_z = pose.pos[2]
1044 
1045  phi = lambda u: 2 * np.pi * u + pose.rot[2] - np.pi / 2
1046  u = lambda angle: (angle - pose.rot[2] + np.pi / 2) / (2 * np.pi)
1047 
1048  vec = pose.pos - self._idle_circle_center
1049  vec /= np.linalg.norm(vec)
1050  u_init = u(np.arctan2(vec[1], vec[0]))
1051 
1052  wp_set = uuv_waypoints.WaypointSet(
1053  inertial_frame_id=self.inertial_frame_id)
1054 
1055  for i in np.linspace(u_init, u_init + 1, n_points):
1056  wp = uuv_waypoints.Waypoint(
1057  x=self._idle_circle_center[0] + radius * np.cos(phi(i)),
1058  y=self._idle_circle_center[1] + radius * np.sin(phi(i)),
1059  z=self._idle_z,
1060  max_forward_speed=0.8 * self._max_forward_speed,
1061  inertial_frame_id=self.inertial_frame_id)
1062  wp_set.add_waypoint(wp)
1063  return wp_set
1064 
1065  def interpolate(self, t):
1066  """Function interface to the controller. Calls the interpolator to
1067  calculate the current trajectory sample or returns a fixed position
1068  based on the past odometry measurements for station keeping.
1069 
1070  > *Input arguments*
1071 
1072  * `t` (*type:* `float`): Timestamp
1073 
1074  > *Returns*
1075 
1076  `uuv_trajectory_generator.TrajectoryPoint`: Trajectory point
1077  """
1078 
1079  self._lock.acquire()
1080  if not self._station_keeping_on and self._traj_running:
1081  if self._smooth_approach_on:
1082  # Generate extra waypoint before the initial waypoint
1083  self._calc_smooth_approach()
1084  self._smooth_approach_on = False
1086  time.sleep(0.5)
1087  self._logger.info('Adding waypoints to approach the given waypoint trajectory')
1088 
1089  # Get interpolated reference from the reference trajectory
1090  self._this_ref_pnt = self._traj_interpolator.interpolate(t, self._vehicle_pose.pos, self.get_vehicle_rot())
1091 
1092  if self._look_ahead_delay > 0:
1093  self._this_ref_pnt = self.generate_reference(t + self._look_ahead_delay)
1094 
1095  self._max_time_pub.publish(Float64(self._traj_interpolator.get_max_time() - rospy.get_time()))
1096 
1097  if not self._traj_running:
1098  self._traj_running = True
1099  self._logger.info(rospy.get_namespace() + ' - Trajectory running')
1100 
1101  if self._traj_running and (self._traj_interpolator.has_finished() or self._station_keeping_on):
1102  # Trajectory ended, start station keeping mode
1103  self._logger.info(rospy.get_namespace() + ' - Trajectory completed!')
1104  if self._this_ref_pnt is None:
1105  # TODO Fix None value coming from the odometry
1106  if self._is_teleop_active:
1108  else:
1109  self._this_ref_pnt = deepcopy(self._vehicle_pose)
1110  self._this_ref_pnt.vel = np.zeros(6)
1111  self._this_ref_pnt.acc = np.zeros(6)
1112  self._start_count_idle = rospy.get_time()
1113  self.set_station_keeping(True)
1114  self.set_automatic_mode(False)
1115  self.set_trajectory_running(False)
1116  elif self._this_ref_pnt is None:
1117  self._traj_interpolator.set_interp_method('lipb')
1118  # Use the latest position and heading of the vehicle from the odometry to enter station keeping mode
1119  if self._is_teleop_active:
1121  else:
1122  self._this_ref_pnt = deepcopy(self._vehicle_pose)
1123  # Set roll and pitch reference to zero
1124  yaw = self._this_ref_pnt.rot[2]
1125  self._this_ref_pnt.rot = [0, 0, yaw]
1126  self.set_automatic_mode(False)
1127  elif self._station_keeping_on:
1128  if self._is_teleop_active:
1130  self._max_time_pub.publish(Float64(0))
1131  #######################################################################
1132  if not self._thrusters_only and not self._is_teleop_active and rospy.get_time() - self._start_count_idle > self._timeout_idle_mode:
1133  self._logger.info('AUV STATION KEEPING')
1134  if self._station_keeping_center is None:
1136 
1137  wp_set = self.get_idle_circle_path(20, self._idle_radius)
1138  wp_set = self._apply_workspace_constraints(wp_set)
1139  if wp_set.is_empty:
1140  raise rospy.ROSException('Waypoints violate workspace constraints, are you using world or world_ned as reference?')
1141 
1142  # Activates station keeping
1143  self.set_station_keeping(True)
1144  self._traj_interpolator.set_interp_method('cubic')
1145  self._traj_interpolator.set_waypoints(wp_set, self.get_vehicle_rot())
1146  self._traj_interpolator.set_start_time(rospy.get_time())
1148  # Disables station keeping to start trajectory
1149  self.set_station_keeping(False)
1150  self.set_automatic_mode(True)
1151  self.set_trajectory_running(True)
1152  self._smooth_approach_on = False
1153  #######################################################################
1154  self._lock.release()
1155  return self._this_ref_pnt
def __init__(self, full_dof=False, stamped_pose_only=False, thrusters_only=True)


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