19 from copy
import deepcopy
21 import geometry_msgs.msg
as geometry_msgs
22 import uuv_control_msgs.msg
as uuv_control_msgs
24 import tf.transformations
as trans
26 from nav_msgs.msg
import Odometry
27 from uuv_thrusters.models
import Thruster
28 from uuv_gazebo_ros_plugins_msgs.msg
import FloatStamped
29 from uuv_control_msgs.msg
import TrajectoryPoint
30 from uuv_control_interfaces
import DPControllerLocalPlanner
37 self.
namespace = rospy.get_namespace().replace(
'/',
'')
38 rospy.loginfo(
'Initialize control for vehicle <%s>' % self.
namespace)
40 self.
local_planner = DPControllerLocalPlanner(full_dof=
True, thrusters_only=
False,
41 stamped_pose_only=
False)
43 self.
base_link = rospy.get_param(
'~base_link',
'base_link')
48 rospy.loginfo(
'Min. thrust [N]=%.2f', self.
min_thrust)
53 rospy.loginfo(
'Max. thrust [N]=%.2f', self.
max_thrust)
56 self.
thruster_topic = rospy.get_param(
'~thruster_topic',
'thrusters/0/input')
67 self.
p_roll = rospy.get_param(
'~p_roll', 0.0)
71 self.
p_pitch = rospy.get_param(
'~p_pitch', 0.0)
75 self.
d_pitch = rospy.get_param(
'~d_pitch', 0.0)
79 self.
p_yaw = rospy.get_param(
'~p_yaw', 0.0)
83 self.
d_yaw = rospy.get_param(
'~d_yaw', 0.0)
84 assert self.
d_yaw >= 0
95 self.
n_fins = rospy.get_param(
'~n_fins', 0)
99 self.
map_roll = rospy.get_param(
'~map_roll', [0, 0, 0, 0])
100 assert isinstance(self.
map_roll, list)
104 self.
map_pitch = rospy.get_param(
'~map_pitch', [0, 0, 0, 0])
109 self.
map_yaw = rospy.get_param(
'~map_yaw', [0, 0, 0, 0])
110 assert isinstance(self.
map_yaw, list)
117 thruster_params = [
'conversion_fcn_params',
'conversion_fcn',
118 'topic_prefix',
'topic_suffix',
'frame_base',
'max_thrust']
119 for p
in thruster_params:
121 raise rospy.ROSException(
122 'Parameter <%s> for thruster conversion function is ' 137 rospy.loginfo(
'Lookup: Thruster transform found %s -> %s' % (base, frame))
138 trans = self.tf_buffer.lookup_transform(base, frame, rospy.Time(), rospy.Duration(5))
139 pos = np.array([trans.transform.translation.x,
140 trans.transform.translation.y,
141 trans.transform.translation.z])
142 quat = np.array([trans.transform.rotation.x,
143 trans.transform.rotation.y,
144 trans.transform.rotation.z,
145 trans.transform.rotation.w])
146 rospy.loginfo(
'Thruster transform found %s -> %s' % (base, frame))
147 rospy.loginfo(
'pos=' + str(pos))
148 rospy.loginfo(
'rot=' + str(quat))
170 for i
in range(self.
n_fins):
173 rospy.Publisher(topic, FloatStamped, queue_size=10))
179 'reference', TrajectoryPoint, queue_size=1)
183 'error', TrajectoryPoint, queue_size=1)
187 return math.atan2(math.sin(t),math.cos(t))
191 return np.array([v.x, v.y, v.z])
195 return np.array([q.x, q.y, q.z, q.w])
198 """Handle odometry callback: The actual control loop.""" 201 pos = [msg.pose.pose.position.x,
202 msg.pose.pose.position.y,
203 msg.pose.pose.position.z]
205 quat = [msg.pose.pose.orientation.x,
206 msg.pose.pose.orientation.y,
207 msg.pose.pose.orientation.z,
208 msg.pose.pose.orientation.w]
210 self.local_planner.update_vehicle_pose(pos, quat)
213 t = rospy.Time.now().to_sec()
214 des = self.local_planner.interpolate(t)
217 ref_msg = TrajectoryPoint()
218 ref_msg.header.stamp = rospy.Time.now()
219 ref_msg.header.frame_id = self.local_planner.inertial_frame_id
220 ref_msg.pose.position = geometry_msgs.Vector3(*des.p)
221 ref_msg.pose.orientation = geometry_msgs.Quaternion(*des.q)
222 ref_msg.velocity.linear = geometry_msgs.Vector3(*des.vel[0:3])
223 ref_msg.velocity.angular = geometry_msgs.Vector3(*des.vel[3::])
225 self.reference_pub.publish(ref_msg)
229 ref_vel = des.vel[0:3]
232 rpy = trans.euler_from_quaternion(q, axes=
'sxyz')
236 abs_pos_error = np.linalg.norm(e_p)
237 abs_vel_error = np.linalg.norm(ref_vel - forward_vel)
240 error_msg = TrajectoryPoint()
241 error_msg.header.stamp = rospy.Time.now()
242 error_msg.header.frame_id = self.local_planner.inertial_frame_id
243 error_msg.pose.position = geometry_msgs.Vector3(*e_p)
244 error_msg.pose.orientation = geometry_msgs.Quaternion(
245 *trans.quaternion_multiply(trans.quaternion_inverse(q), des.q))
246 error_msg.velocity.linear = geometry_msgs.Vector3(*(des.vel[0:3] - self.
vector_to_np(msg.twist.twist.linear)))
247 error_msg.velocity.angular = geometry_msgs.Vector3(*(des.vel[3::] - self.
vector_to_np(msg.twist.twist.angular)))
250 pitch_des = -math.atan2(e_p[2], np.linalg.norm(e_p[0:2]))
254 yaw_des = math.atan2(e_p[1], e_p[0])
261 roll_control = self.
p_roll * rpy[0]
264 pitch_control = self.
p_pitch * self.
unwrap_angle(pitch_des - rpy[1]) + self.
d_pitch * (des.vel[4] - msg.twist.twist.angular.y)
267 yaw_control = self.
p_yaw * yaw_err + self.
d_yaw * (des.vel[5] - msg.twist.twist.angular.z)
273 rpy = np.array([roll_control, pitch_control, yaw_control])
278 if self.local_planner.inertial_frame_id ==
'world_ned':
285 max_angle = max(np.abs(fins))
289 thrust_force = self.thruster.tam_column * thrust
290 self.thruster.publish_command(thrust_force[0])
293 for i
in range(self.
n_fins):
294 cmd.header.stamp = rospy.Time.now()
295 cmd.header.frame_id =
'%s/fin%d' % (self.
namespace, i)
300 self.error_pub.publish(error_msg)
303 if __name__ ==
'__main__':
304 print(
'Starting AUV trajectory tracker')
305 rospy.init_node(
'auv_geometric_tracking_controller')
310 except rospy.ROSInterruptException:
311 print(
'caught exception')
def odometry_callback(self, msg)