PositionControl.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 math
18 import numpy
19 import rospy
20 import tf.transformations as trans
21 from PID import PIDRegulator
22 
23 from dynamic_reconfigure.server import Server
24 from uuv_control_cascaded_pid.cfg import PositionControlConfig
25 import geometry_msgs.msg as geometry_msgs
26 from nav_msgs.msg import Odometry
27 from rospy.numpy_msg import numpy_msg
28 
30  def __init__(self):
31  print('PositionControllerNode: initializing node')
32 
33  self.config = {}
34 
35  self.pos_des = numpy.zeros(3)
36  self.quat_des = numpy.array([0, 0, 0, 1])
37 
38  self.initialized = False
39 
40  # Initialize pids with default parameters
41  self.pid_rot = PIDRegulator(1, 0, 0, 1)
42  self.pid_pos = PIDRegulator(1, 0, 0, 1)
43 
44  # ROS infrastructure
45  self.sub_cmd_pose = rospy.Subscriber('cmd_pose', numpy_msg(geometry_msgs.PoseStamped), self.cmd_pose_callback)
46  self.sub_odometry = rospy.Subscriber('odom', numpy_msg(Odometry), self.odometry_callback)
47  self.pub_cmd_vel = rospy.Publisher('cmd_vel', geometry_msgs.Twist, queue_size=10)
48  self.srv_reconfigure = Server(PositionControlConfig, self.config_callback)
49 
50  def cmd_pose_callback(self, msg):
51  """Handle updated set pose callback."""
52  # Just store the desired pose. The actual control runs on odometry callbacks
53  p = msg.pose.position
54  q = msg.pose.orientation
55  self.pos_des = numpy.array([p.x, p.y, p.z])
56  self.quat_des = numpy.array([q.x, q.y, q.z, q.w])
57 
58  def odometry_callback(self, msg):
59  """Handle updated measured velocity callback."""
60  if not bool(self.config):
61  return
62 
63  p = msg.pose.pose.position
64  q = msg.pose.pose.orientation
65  p = numpy.array([p.x, p.y, p.z])
66  q = numpy.array([q.x, q.y, q.z, q.w])
67 
68  if not self.initialized:
69  # If this is the first callback: Store and hold latest pose.
70  self.pos_des = p
71  self.quat_des = q
72  self.initialized = True
73 
74  # Compute control output:
75  t = msg.header.stamp.to_sec()
76 
77  # Position error
78  e_pos_world = self.pos_des - p
79  e_pos_body = trans.quaternion_matrix(q).transpose()[0:3,0:3].dot(e_pos_world)
80 
81  # Error quaternion wrt body frame
82  e_rot_quat = trans.quaternion_multiply(trans.quaternion_conjugate(q), self.quat_des)
83 
84  if numpy.linalg.norm(e_pos_world[0:2]) > 5.0:
85  # special case if we are far away from goal:
86  # ignore desired heading, look towards goal position
87  heading = math.atan2(e_pos_world[1],e_pos_world[0])
88  quat_des = numpy.array([0, 0, math.sin(0.5*heading), math.cos(0.5*heading)])
89  e_rot_quat = trans.quaternion_multiply(trans.quaternion_conjugate(q), quat_des)
90 
91  # Error angles
92  e_rot = numpy.array(trans.euler_from_quaternion(e_rot_quat))
93 
94  v_linear = self.pid_pos.regulate(e_pos_body, t)
95  v_angular = self.pid_rot.regulate(e_rot, t)
96 
97  # Convert and publish vel. command:
98  cmd_vel = geometry_msgs.Twist()
99  cmd_vel.linear = geometry_msgs.Vector3(*v_linear)
100  cmd_vel.angular = geometry_msgs.Vector3(*v_angular)
101  self.pub_cmd_vel.publish(cmd_vel)
102 
103  def config_callback(self, config, level):
104  """Handle updated configuration values."""
105  # Config has changed, reset PID controllers
106  self.pid_pos = PIDRegulator(config['pos_p'], config['pos_i'], config['pos_d'], config['pos_sat'])
107  self.pid_rot = PIDRegulator(config['rot_p'], config['rot_i'], config['rot_d'], config['rot_sat'])
108 
109  self.config = config
110 
111  return config
112 
113 
114 if __name__ == '__main__':
115  print('starting PositionControl.py')
116  rospy.init_node('position_control')
117 
118  try:
120  rospy.spin()
121  except rospy.ROSInterruptException:
122  print('caught exception')
123  print('exiting')
def config_callback(self, config, level)


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