disturbance_manager.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Copyright (c) 2016 The UUV Simulator Authors.
3 # All rights reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 import rospy
18 import sys
19 import numpy as np
20 import logging
22 from gazebo_msgs.srv import ApplyBodyWrench
23 from uuv_gazebo_ros_plugins_msgs.srv import SetThrusterState, SetThrusterEfficiency
24 from geometry_msgs.msg import Point, WrenchStamped, Vector3
25 
26 
28 
29  def __init__(self):
30  self._logger = logging.getLogger('dp_local_planner')
31  out_hdlr = logging.StreamHandler(sys.stdout)
32  out_hdlr.setFormatter(logging.Formatter('%(asctime)s | %(levelname)s | %(module)s | %(message)s'))
33  out_hdlr.setLevel(logging.INFO)
34  self._logger.addHandler(out_hdlr)
35  self._logger.setLevel(logging.INFO)
36 
37  # Load disturbances and check for missing information
38  specs = dict(current=['starting_time', 'velocity', 'horizontal_angle',
39  'vertical_angle'],
40  wrench=['starting_time', 'duration', 'force', 'torque'],
41  thruster_state=['starting_time', 'thruster_id', 'is_on',
42  'duration'],
43  propeller_efficiency=['starting_time', 'thruster_id', 'duration',
44  'efficiency'],
45  thrust_efficiency=['starting_time', 'thruster_id', 'duration',
46  'efficiency'])
47 
48  thruster_ids = list()
49 
50  if rospy.has_param('~disturbances'):
51  self._disturbances = rospy.get_param('~disturbances')
52  self._logger.info(self._disturbances)
53  if type(self._disturbances) != list:
54  raise rospy.ROSException('Current specifications must be '
55  'given as a list of dict')
56  for i in range(len(self._disturbances)):
57  item = self._disturbances[i]
58  if type(item) != dict:
59  raise rospy.ROSException('Disturbance description must be'
60  ' given as a dict')
61  if 'type' not in item:
62  raise rospy.ROSException('Type of disturbance not '
63  'specified')
64  if item['type'] not in specs:
65  raise rospy.ROSException(
66  'Invalid type of disturbance, value=%s' % item['type'])
67 
68  for spec in specs[item['type']]:
69  if spec not in item:
70  raise rospy.ROSException(
71  'Invalid current model specification, '
72  'missing tag=%s' % spec)
73 
74  if item['type'] == 'thruster_state':
75  thruster_ids.append(item['thruster_id'])
76 
77  # Create flag to indicate that perturbation has been applied
78  self._disturbances[i]['is_applied'] = False
79  self._disturbances[i]['ended'] = False
80  else:
81  raise rospy.ROSException('No disturbance specifications given')
82 
83  # List all disturbances to be applied
84  for i in range(len(self._disturbances)):
85  self._logger.info('Disturbance #%d: %s' % (i, self._disturbances[i]))
86 
87  self._body_force = np.zeros(3)
88  self._body_torque = np.zeros(3)
89  self._body_wrench_msg = WrenchStamped()
90 
91  # For body wrench disturbances, publish a topic
92  self._wrench_topic = rospy.Publisher(
93  'wrench_perturbation', WrenchStamped, queue_size=1)
94 
95  vehicle_name = rospy.get_namespace().replace('/', '')
96 
97  # Test if services are reachable
98  try:
99  services = ['/hydrodynamics/set_current_velocity',
100  '/gazebo/apply_body_wrench']
101  for item in self._disturbances:
102  if item['type'] == 'thruster_state':
103  services.append('/%s/thrusters/%d/set_thruster_state' % (vehicle_name, item['thruster_id']))
104  elif item['type'] == 'propeller_efficiency':
105  services.append('/%s/thrusters/%d/set_dynamic_state_efficiency' % (vehicle_name, item['thruster_id']))
106  elif item['type'] == 'thrust_efficiency':
107  services.append('/%s/thrusters/%d/set_thrust_force_efficiency' % (vehicle_name, item['thruster_id']))
108  for s in services:
109  rospy.wait_for_service(s, timeout=10)
110  except Exception as e:
111  self._logger.error('Some services are not available! message=' + str(e))
112  self._logger.error('Closing node...')
113  sys.exit(-1)
114 
115  # Obtain service proxy
116  self._service_cb = dict()
117  try:
118  self._service_cb['current_velocity'] = rospy.ServiceProxy(
119  '/hydrodynamics/set_current_velocity', SetCurrentVelocity)
120  self._service_cb['wrench'] = rospy.ServiceProxy(
121  '/gazebo/apply_body_wrench', ApplyBodyWrench)
122  self._service_cb['thrusters'] = dict()
123  for item in self._disturbances:
124  if item['type'] == 'thruster_state':
125  if 'state' not in self._service_cb['thrusters']:
126  self._service_cb['thrusters']['state'] = dict()
127  self._service_cb['thrusters']['state'][item['thruster_id']] = rospy.ServiceProxy(
128  '/%s/thrusters/%d/set_thruster_state' % (vehicle_name, item['thruster_id']),
129  SetThrusterState)
130  elif item['type'] == 'propeller_efficiency':
131  if 'propeller_efficiency' not in self._service_cb['thrusters']:
132  self._service_cb['thrusters']['propeller_efficiency'] = dict()
133  self._service_cb['thrusters']['propeller_efficiency'][item['thruster_id']] = rospy.ServiceProxy(
134  '/%s/thrusters/%d/set_dynamic_state_efficiency' % (vehicle_name, item['thruster_id']),
135  SetThrusterEfficiency)
136  elif item['type'] == 'thrust_efficiency':
137  if 'thrust_efficiency' not in self._service_cb['thrusters']:
138  self._service_cb['thrusters']['thrust_efficiency'] = dict()
139  self._service_cb['thrusters']['thrust_efficiency'][item['thruster_id']] = rospy.ServiceProxy(
140  '/%s/thrusters/%d/set_thrust_force_efficiency' % (vehicle_name, item['thruster_id']),
141  SetThrusterEfficiency)
142  except rospy.ServiceException as e:
143  self._logger.info('Service call failed, error=%s' % str(e))
144  sys.exit(-1)
145 
146  self._wrench_timer = rospy.timer.Timer(rospy.Duration(0.1),
148 
149  rate = rospy.Rate(100)
150  while not rospy.is_shutdown():
151  t = rospy.get_time()
152  for i in range(len(self._disturbances)):
153  d = self._disturbances[i]
154  if t > d['starting_time'] and not d['is_applied']:
155  ###########################################################
156  if d['type'] == 'current':
157  self.set_current(d['velocity'], d['horizontal_angle'],
158  d['vertical_angle'])
159  ###########################################################
160  elif d['type'] == 'wrench':
161  self.set_body_wrench(d['force'],
162  d['torque'],
163  -1,
164  d['starting_time'])
165  ###########################################################
166  elif d['type'] == 'thruster_state':
167  self.set_thruster_state(d['thruster_id'], bool(d['is_on']))
168  ###########################################################
169  elif d['type'] == 'propeller_efficiency':
170  self.set_propeller_efficiency(d['thruster_id'], d['efficiency'])
171  ###########################################################
172  elif d['type'] == 'thrust_efficiency':
173  self.set_thrust_efficiency(d['thruster_id'], d['efficiency'])
174  # Set applied flag to true
175  self._disturbances[i]['is_applied'] = True
176 
177  if 'duration' in d:
178  if d['duration'] == -1:
179  self._disturbances[i]['ended'] = True
180  else:
181  self._disturbances[i]['ended'] = True
182  elif d['is_applied'] and 'duration' in d and not d['ended']:
183  if d['duration'] > 0:
184  if rospy.get_time() > d['starting_time'] + d['duration']:
185  ###########################################################
186  if d['type'] == 'current':
187  # Set current to zero
188  self.set_current(0, d['horizontal_angle'],
189  d['vertical_angle'])
190  ###########################################################
191  elif d['type'] == 'wrench':
192  # Cancel out force and torque
193  self.set_body_wrench([-1 * d['force'][n] for n in range(3)],
194  [-1 * d['torque'][n] for n in range(3)],
195  -1,
196  rospy.get_time())
197  ###########################################################
198  elif d['type'] == 'thruster_state':
199  self.set_thruster_state(d['thruster_id'], not bool(d['is_on']))
200  ###########################################################
201  elif d['type'] == 'propeller_efficiency':
202  self.set_propeller_efficiency(d['thruster_id'], 1.0)
203  ###########################################################
204  elif d['type'] == 'thrust_efficiency':
205  self.set_thrust_efficiency(d['thruster_id'], 1.0)
206 
207  self._disturbances[i]['ended'] = True
208  rate.sleep()
209 
210  def _publish_wrench_disturbance(self, event):
211  msg = WrenchStamped()
212  msg.header.stamp = rospy.Time().now()
213  msg.header.frame_id = 'world'
214  msg.wrench.force = Vector3(*self._body_force)
215  msg.wrench.torque = Vector3(*self._body_torque)
216  # Publish the applied body wrench
217  self._wrench_topic.publish(msg)
218  return True
219 
220  def set_current(self, velocity, horizontal_angle, vertical_angle):
221  self._logger.info('Appying current velocity model...')
222  if self._service_cb['current_velocity'](velocity, horizontal_angle, vertical_angle):
223  self._logger.info('Current velocity changed successfully at %f s! vel= %f m/s' % (rospy.get_time(), velocity))
224  else:
225  self._logger.error('Failed to change current velocity')
226 
227  def set_body_wrench(self, force, torque, duration, starting_time):
228  ns = rospy.get_namespace().replace('/', '')
229  body_name = '%s/base_link' % ns
230 
231  self._body_force = np.array([self._body_force[i] + force[i] for i in range(3)])
232  self._body_torque = np.array([self._body_torque[i] + torque[i] for i in range(3)])
233 
234  self._body_wrench_msg = WrenchStamped()
235  self._body_wrench_msg.header.stamp = rospy.Time().now()
236  self._body_wrench_msg.header.frame_id = 'world'
237  self._body_wrench_msg.wrench.force = Vector3(*self._body_force)
238  self._body_wrench_msg.wrench.torque = Vector3(*self._body_torque)
239  success = self._service_cb['wrench'](
240  body_name,
241  'world',
242  Point(0, 0, 0),
243  self._body_wrench_msg.wrench,
244  rospy.Time(secs=starting_time),
245  rospy.Duration(duration))
246 
247  if success:
248  self._logger.info('Body wrench perturbation applied!, body_name=%s, t=%.2f s' % (body_name, rospy.get_time()))
249  else:
250  self._logger.error('Failed to apply body wrench!, body_name=%s, t=%.2f s' % (body_name, rospy.get_time()))
251 
252  def set_thruster_state(self, thruster_id, is_on):
253  if self._service_cb['thrusters']['state'][thruster_id](is_on):
254  self._logger.info('Setting state of thruster #%d, state=%s, t=%.2f s' % (thruster_id, 'ON' if is_on else 'OFF', rospy.get_time()))
255  else:
256  self._logger.error('Setting state of thruster #%d failed! t=%.2f s' % (thruster_id, rospy.get_time()))
257 
258  def set_propeller_efficiency(self, thruster_id, eff):
259  if self._service_cb['thrusters']['propeller_efficiency'][thruster_id](eff):
260  self._logger.info('Setting propeller efficiency of thruster #%d, eff=%s, t=%.2f s' % (thruster_id, eff, rospy.get_time()))
261  else:
262  self._logger.error('Setting propeller efficiency of thruster #%d failed! t=%.2f s' % (thruster_id, rospy.get_time()))
263 
264  def set_thrust_efficiency(self, thruster_id, eff):
265  if self._service_cb['thrusters']['thrust_efficiency'][thruster_id](eff):
266  self._logger.info('Setting thrust efficiency of thruster #%d, eff=%s, t=%.2f s' % (thruster_id, eff, rospy.get_time()))
267  else:
268  self._logger.error('Setting thrust efficiency of thruster #%d failed! t=%.2f s' % (thruster_id, rospy.get_time()))
269 
270 if __name__ == '__main__':
271  print('Starting disturbance manager')
272  rospy.init_node('disturbance_manager')
273 
274  try:
276  rospy.spin()
277  except rospy.ROSInterruptException:
278  print('caught exception')
279  print('exiting')
def set_thruster_state(self, thruster_id, is_on)
def set_thrust_efficiency(self, thruster_id, eff)
def set_body_wrench(self, force, torque, duration, starting_time)
def set_current(self, velocity, horizontal_angle, vertical_angle)
def set_propeller_efficiency(self, thruster_id, eff)


uuv_control_utils
Author(s): Musa Morena Marcusso Manhaes , Sebastian Scherer , Luiz Ricardo Douat
autogenerated on Mon Jul 1 2019 19:39:33