actuator_manager.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 .fin_model import FinModel
16 import rospy
17 import numpy as np
18 import tf2_ros
19 from tf_quaternion.transformations import quaternion_matrix
20 from uuv_thrusters.models import Thruster
21 from uuv_auv_control_allocator.msg import AUVCommand
22 from uuv_gazebo_ros_plugins_msgs.msg import FloatStamped
23 from geometry_msgs.msg import Wrench, WrenchStamped
24 import os
25 import yaml
26 
27 
28 class ActuatorManager(object):
29  MAX_FINS = 4
30 
31 
32  def __init__(self):
33  # Acquiring the namespace of the vehicle
34  self.namespace = rospy.get_namespace().replace('/', '')
35  rospy.loginfo('Initialize control allocator for vehicle <%s>' % self.namespace)
36 
37  self.tf_buffer = tf2_ros.Buffer()
38  self.listener = tf2_ros.TransformListener(self.tf_buffer)
39  tf_trans_ned_to_enu = None
40 
41  try:
42  if self.namespace != '':
43  target = '{}/base_link'.format(self.namespace)
44  source = '{}/base_link_ned'.format(self.namespace)
45  else:
46  target = 'base_link'
47  source = 'base_link_ned'
48  rospy.loginfo('Lookup transfrom from %s to %s' % (source, target))
49  tf_trans_ned_to_enu = self.tf_buffer.lookup_transform(
50  target, source, rospy.Time(), rospy.Duration(1))
51  except Exception as e:
52  rospy.logwarn('No transform found between base_link and base_link_ned'
53  ' for vehicle {}, message={}'.format(self.namespace, e))
55 
56  if tf_trans_ned_to_enu is not None:
57  self.base_link_ned_to_enu = quaternion_matrix(
58  (tf_trans_ned_to_enu.transform.rotation.x,
59  tf_trans_ned_to_enu.transform.rotation.y,
60  tf_trans_ned_to_enu.transform.rotation.z,
61  tf_trans_ned_to_enu.transform.rotation.w))[0:3, 0:3]
62 
63  rospy.logwarn('base_link transform NED to ENU=\n{}'.format(
65 
66  self.base_link = rospy.get_param('~base_link', 'base_link')
67 
68  # Check if the thruster configuration is available
69  if not rospy.has_param('~thruster_config'):
70  raise rospy.ROSException('Thruster configuration not available')
71 
72  # Retrieve the thruster configuration parameters
73  self.thruster_config = rospy.get_param('~thruster_config')
74 
75  # Check if all necessary thruster model parameter are available
76  thruster_params = ['conversion_fcn_params', 'conversion_fcn',
77  'topic_prefix', 'topic_suffix', 'frame_base', 'max_thrust']
78  for p in thruster_params:
79  if p not in self.thruster_config:
80  raise rospy.ROSException(
81  'Parameter <%s> for thruster conversion function is missing' % p)
82 
83  # Setting up the thruster topic name
84  self.thruster_topic = '/%s/%s/%d/%s' % (self.namespace,
85  self.thruster_config['topic_prefix'], 0,
86  self.thruster_config['topic_suffix'])
87  self.thruster = None
88 
89  # Check if the fin configuration is available
90  if not rospy.has_param('~fin_config'):
91  raise rospy.ROSException('Fin configuration is not available')
92 
93  # Retrieve the fin configuration is available
94  self.fin_config = rospy.get_param('~fin_config')
95 
96  # Check if all necessary fin parameters are available
97  fin_params = ['fluid_density', 'lift_coefficient', 'fin_area',
98  'topic_prefix', 'topic_suffix', 'frame_base']
99 
100  for p in fin_params:
101  if p not in self.fin_config:
102  raise rospy.ROSException(
103  'Parameter <%s> for fin configuration is missing' % p)
104 
105  self.fin_lower_limit = -np.pi / 2
106  if 'lower_limit' in self.fin_config:
107  self.fin_lower_limit = self.fin_config['lower_limit']
108 
109  self.fin_upper_limit = np.pi / 2
110  if 'upper_limit' in self.fin_config:
111  self.fin_upper_limit = self.fin_config['upper_limit']
112 
113  if self.fin_config['lower_limit'] >= self.fin_config['upper_limit']:
114  raise rospy.ROSException('Fin angle limits are invalid')
115 
116  self.fins = dict()
117 
118  self.n_fins = 0
119 
120  if not self.find_actuators():
121  raise rospy.ROSException('No thruster and/or fins found')
122 
123  def find_actuators(self):
124  """Calculate the control allocation matrix, if one is not given."""
125 
126  self.ready = False
127  rospy.loginfo('ControlAllocator: updating thruster poses')
128 
129  base = '%s/%s' % (self.namespace, self.base_link)
130 
131  frame = '%s/%s%d' % (self.namespace, self.thruster_config['frame_base'], 0)
132 
133  rospy.loginfo('Lookup: Thruster transform found %s -> %s' % (base, frame))
134  trans = self.tf_buffer.lookup_transform(base, frame, rospy.Time(), rospy.Duration(1))
135  pos = np.array([trans.transform.translation.x,
136  trans.transform.translation.y,
137  trans.transform.translation.z])
138  quat = np.array([trans.transform.rotation.x,
139  trans.transform.rotation.y,
140  trans.transform.rotation.z,
141  trans.transform.rotation.w])
142  rospy.loginfo('Thruster transform found %s -> %s' % (base, frame))
143  rospy.loginfo('pos=' + str(pos))
144  rospy.loginfo('rot=' + str(quat))
145 
146  # Read transformation from thruster
147  self.thruster = Thruster.create_thruster(
148  self.thruster_config['conversion_fcn'], 0,
149  self.thruster_topic, pos, quat,
150  **self.thruster_config['conversion_fcn_params'])
151 
152  for i in range(self.MAX_FINS):
153  try:
154  frame = '%s/%s%d' % (self.namespace, self.fin_config['frame_base'], i)
155 
156  rospy.loginfo('Lookup: Fin transform found %s -> %s' % (base, frame))
157  trans = self.tf_buffer.lookup_transform(base, frame, rospy.Time(), rospy.Duration(1))
158  pos = np.array([trans.transform.translation.x,
159  trans.transform.translation.y,
160  trans.transform.translation.z])
161  quat = np.array([trans.transform.rotation.x,
162  trans.transform.rotation.y,
163  trans.transform.rotation.z,
164  trans.transform.rotation.w])
165  rospy.loginfo('Fin transform found %s -> %s' % (base, frame))
166  rospy.loginfo('pos=' + str(pos))
167  rospy.loginfo('quat=' + str(quat))
168 
169  fin_topic = '/%s/%s/%d/%s' % (self.namespace,
170  self.fin_config['topic_prefix'], i, self.fin_config['topic_suffix'])
171 
172  self.fins[i] = FinModel(
173  i,
174  pos,
175  quat,
176  fin_topic)
177 
178  except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException):
179  rospy.loginfo('Could not get transform from %s to %s ' % (base, frame))
180  break
181 
182  self.n_fins = len(self.fins.keys())
183  rospy.loginfo('# fins found: %d' % len(self.fins.keys()))
184 
185  for i in range(self.n_fins):
186  rospy.loginfo(i)
187  rospy.loginfo(self.fins[i].pos)
188  rospy.loginfo(self.fins[i].rot)
189 
190  self.ready = True
191  return True
192 
193  def compute_control_force(self, thrust, delta, u):
194  actuator_model = self.thruster.tam_column.reshape((6, 1)) * thrust
195  for i in self.fins:
196  f_lift = (0.5 * self.fin_config['fluid_density'] *
197  self.fin_config['lift_coefficient'] * self.fin_config['fin_area'] *
198  delta[i] * u**2)
199 
200  tau = np.zeros(6)
201  tau[0:3] = f_lift * self.fins[i].lift_vector
202  tau[3::] = np.cross(self.fins[i].pos, f_lift)
203 
204  actuator_model += tau
205  return actuator_model
206 
207  def publish_commands(self, command):
208  self.thruster.publish_command(command[0])
209 
210  for i in range(self.n_fins):
211  self.fins[i].publish_command(command[i + 1])


uuv_auv_control_allocator
Author(s): Musa Morena Marcusso Manhaes
autogenerated on Thu Jun 18 2020 03:28:21