Final Assignment  1.0
Research Track part 1 - Assignment 2 - RobEng A.A. 2020/2021
go_to_point_service_m.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 
11 
12 # import ros stuff
13 import rospy
14 from sensor_msgs.msg import LaserScan
15 from geometry_msgs.msg import Twist, Point
16 from nav_msgs.msg import Odometry
17 from tf import transformations
18 from std_srvs.srv import *
19 
20 import math
21 
22 active_ = False
23 
24 # robot state variables
25 position_ = Point()
26 yaw_ = 0
27 # machine state
28 state_ = 0
29 # goal
30 desired_position_ = Point()
31 desired_position_.x = rospy.get_param('des_pos_x')
32 desired_position_.y = rospy.get_param('des_pos_y')
33 desired_position_.z = 0
34 # parameters
35 yaw_precision_ = math.pi / 9 # +/- 20 degree allowed
36 yaw_precision_2_ = math.pi / 90 # +/- 2 degree allowed
37 dist_precision_ = 0.3
38 
39 kp_a = 3.0 # In ROS Noetic, it may be necessary to change the sign of this proportional controller
40 kp_d = 0.2
41 ub_a = 0.6
42 lb_a = -0.5
43 ub_d = 0.6
44 
45 # publishers
46 pub = None
47 
48 # service callbacks
49 
50 
52  global active_
53  active_ = req.data
54  res = SetBoolResponse()
55  res.success = True
56  res.message = 'Done!'
57  return res
58 
59 # callbacks
60 
61 
62 def clbk_odom(msg):
63  global position_
64  global yaw_
65 
66  # position
67  position_ = msg.pose.pose.position
68 
69  # yaw
70  quaternion = (
71  msg.pose.pose.orientation.x,
72  msg.pose.pose.orientation.y,
73  msg.pose.pose.orientation.z,
74  msg.pose.pose.orientation.w)
75  euler = transformations.euler_from_quaternion(quaternion)
76  yaw_ = euler[2]
77 
78 
79 def change_state(state):
80  global state_
81  state_ = state
82  print ('State changed to [%s]' % state_)
83 
84 
85 def normalize_angle(angle):
86  if(math.fabs(angle) > math.pi):
87  angle = angle - (2 * math.pi * angle) / (math.fabs(angle))
88  return angle
89 
90 
91 def fix_yaw(des_pos):
92  global yaw_, pub, yaw_precision_2_, state_
93  desired_yaw = math.atan2(des_pos.y - position_.y, des_pos.x - position_.x)
94  err_yaw = normalize_angle(desired_yaw - yaw_)
95 
96  rospy.loginfo(err_yaw)
97 
98  twist_msg = Twist()
99  if math.fabs(err_yaw) > yaw_precision_2_:
100  twist_msg.angular.z = kp_a*err_yaw
101  if twist_msg.angular.z > ub_a:
102  twist_msg.angular.z = ub_a
103  elif twist_msg.angular.z < lb_a:
104  twist_msg.angular.z = lb_a
105 
106  pub.publish(twist_msg)
107 
108  # state change conditions
109  if math.fabs(err_yaw) <= yaw_precision_2_:
110  print ('Yaw error: [%s]' % err_yaw)
111  change_state(1)
112 
113 
114 def go_straight_ahead(des_pos):
115  global yaw_, pub, yaw_precision_, state_
116  desired_yaw = math.atan2(des_pos.y - position_.y, des_pos.x - position_.x)
117  err_yaw = desired_yaw - yaw_
118  err_pos = math.sqrt(pow(des_pos.y - position_.y, 2) +
119  pow(des_pos.x - position_.x, 2))
120 
121  if err_pos > dist_precision_:
122  twist_msg = Twist()
123  twist_msg.linear.x = kp_d*(err_pos)
124  if twist_msg.linear.x > ub_d:
125  twist_msg.linear.x = ub_d
126 
127  twist_msg.angular.z = kp_a*err_yaw
128  pub.publish(twist_msg)
129  else:
130  print ('Position error: [%s]' % err_pos)
131  change_state(2)
132 
133  # state change conditions
134  if math.fabs(err_yaw) > yaw_precision_:
135  print ('Yaw error: [%s]' % err_yaw)
136  change_state(0)
137 
138 
139 def done(des_pos):
140  twist_msg = Twist()
141  twist_msg.linear.x = 0
142  twist_msg.angular.z = 0
143  pub.publish(twist_msg)
144  err_pos = math.sqrt(pow(des_pos.y - position_.y, 2) +
145  pow(des_pos.x - position_.x, 2))
146  if(err_pos > 0.35):
147  change_state(0)
148 
149 
150 def main():
151  global pub, active_, desired_position_
152 
153  rospy.init_node('go_to_point')
154 
155  pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
156 
157  sub_odom = rospy.Subscriber('/odom', Odometry, clbk_odom)
158 
159  srv = rospy.Service('go_to_point_switch', SetBool, go_to_point_switch)
160 
161  rate = rospy.Rate(20)
162  while not rospy.is_shutdown():
163  desired_position_.x = rospy.get_param('des_pos_x')
164  desired_position_.y = rospy.get_param('des_pos_y')
165  if not active_:
166  continue
167  else:
168  if state_ == 0:
169  fix_yaw(desired_position_)
170  elif state_ == 1:
171  go_straight_ahead(desired_position_)
172  elif state_ == 2:
173  done(desired_position_)
174  else:
175  rospy.logerr('Unknown state!')
176 
177  rate.sleep()
178 
179 
180 if __name__ == '__main__':
181  main()