Final Assignment  1.0
Research Track part 1 - Assignment 2 - RobEng A.A. 2020/2021
bug0.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 
39 
40 import rospy
41 import time
42 from geometry_msgs.msg import Point
43 from sensor_msgs.msg import LaserScan
44 from nav_msgs.msg import Odometry
45 from tf import transformations
46 from std_srvs.srv import *
47 from geometry_msgs.msg import Twist
48 from final_assignment.srv import switch_service, switch_serviceRequest, switch_serviceResponse
49 from final_assignment.srv import bug0_status, bug0_statusRequest, bug0_statusResponse
50 from final_assignment.srv import get_point, get_pointRequest, get_pointResponse
51 
52 import math
53 
54 # --------------------------------- DATA
55 
56 
57 node_name = "bug0"
58 
59 
60 name_bug0_switch = "/bug0_switch"
61 
62 
63 name_bug0_status = "/bug0_status"
64 
65 
66 name_get_point = "/get_point"
67 
68 
69 srv_get_point = None
70 
71 
72 service_active = False
73 
74 
75 only_once = False
76 
77 
78 pub = None
79 
80 
81 yaw_ = 0
82 
83 
84 position_ = Point()
85 
86 
87 desired_position_ = Point()
88 
89 
90 regions_ = None
91 
92 
93 state_desc_ = ['Go to point', 'wall following', 'target reached']
94 
95 
102 state_ = 0
103 
104 
105 err_pos = -1
106 
107 
108 max_tolerance_target = 0.5
109 
110 
111 # --------------------------------- FUNCTIONS
112 
113 
121  global name_get_point, srv_get_point
122  global desired_position_
123 
124  # get the target from the server
125  desired_position_ = ( srv_get_point( ) ).position
126 
127  # then write it on the parameter server
128  rospy.set_param("des_pos_x", desired_position_.x)
129  rospy.set_param("des_pos_y", desired_position_.y)
130 
131 
132 
133 
146 def change_state( state ):
147  global state_, state_desc_, only_once, service_active
148  global srv_client_wall_follower_, srv_client_go_to_point_
149  state_ = state
150  log = "state changed: %s" % state_desc_[state]
151  rospy.loginfo(log)
152  if state_ == 0:
153  resp = srv_client_go_to_point_(True)
154  resp = srv_client_wall_follower_(False)
155  if state_ == 1:
156  resp = srv_client_go_to_point_(False)
157  resp = srv_client_wall_follower_(True)
158  if state_ == 2:
159  resp = srv_client_go_to_point_(False)
160  resp = srv_client_wall_follower_(False)
161  twist_msg = Twist()
162  twist_msg.linear.x = 0
163  twist_msg.angular.z = 0
164  pub.publish(twist_msg)
165 
166  if not only_once:
168  else:
169  service_active = False
170  only_once = False
171 
172 
173 
174 
180 def normalize_angle(angle):
181  if(math.fabs(angle) > math.pi):
182  angle = angle - (2 * math.pi * angle) / (math.fabs(angle))
183  return angle
184 
185 
186 
187 # --------------------------------- SERVICES
188 
189 
190 srv_client_go_to_point_ = None
191 
192 
193 srv_client_wall_follower_ = None
194 
195 
196 
197 
220 def srv_bug0_switch( data ):
221  global service_active, only_once
222 
223  if data.val:
224  if service_active:
225  return switch_serviceResponse( success=False, in_progress=False )
226 
227  state_ = 2
228  only_once = data.only_once
229 
230  # set the new target
231  if not only_once:
233 
234  service_active = True
235  else:
236  if not service_active:
237  return switch_serviceResponse( success=True, in_progress=False )
238 
239  # the node is turned off
240  service_active = False
241  only_once = False
242 
243  # stop the robot
244  resp = srv_client_go_to_point_(False)
245  resp = srv_client_wall_follower_(False)
246  twist_msg = Twist()
247  twist_msg.linear.x = 0
248  twist_msg.angular.z = 0
249  pub.publish(twist_msg)
250 
251  # initial state
252  state_ = 2
253 
254  return switch_serviceResponse( success=True, in_progress=False )
255 
256 
257 
258 
267 def srv_bug0_status( empty ):
268  global desired_position_, position_, yaw_, state_, err_pos, service_active, max_tolerance_target, err_pos
269 
270  to_return = bug0_statusResponse( )
271  to_return.target_position = desired_position_
272  to_return.actual_position = position_
273  to_return.actual_yaw = yaw_
274  to_return.status = state_
275  to_return.active = service_active
276  to_return.distance = err_pos
277  to_return.reached = ( err_pos < max_tolerance_target )
278 
279  return to_return
280 
281 
282 
283 # --------------------------------- TOPICS
284 
285 
293 def clbk_odom( msg ):
294  global position_, yaw_
295 
296  # position
297  position_ = msg.pose.pose.position
298 
299  # yaw
300  quaternion = (\
301  msg.pose.pose.orientation.x,\
302  msg.pose.pose.orientation.y,\
303  msg.pose.pose.orientation.z,\
304  msg.pose.pose.orientation.w)
305  euler = transformations.euler_from_quaternion(quaternion)
306  yaw_ = euler[2]
307 
308 
309 
310 
319 def clbk_laser(msg):
320  global regions_
321  regions_ = {\
322  'right': min(min(msg.ranges[0:143]), 10),\
323  'fright': min(min(msg.ranges[144:287]), 10),\
324  'front': min(min(msg.ranges[288:431]), 10),\
325  'fleft': min(min(msg.ranges[432:575]), 10),\
326  'left': min(min(msg.ranges[576:719]), 10),\
327  }
328 
329 
330 
331 # --------------------------------- WORKING CYCLE
332 
333 
344 def main():
345  time.sleep(2)
346  global regions_, position_, desired_position_, state_, yaw_, yaw_error_allowed_
347  global srv_client_go_to_point_, srv_client_wall_follower_, srv_client_user_interface_, pub
348  global service_active, err_pos, only_once, state_, max_tolerance_target
349 
350  # initialize: get a new target
351  state_ = 2
352 
353  rate = rospy.Rate(20)
354  while not rospy.is_shutdown():
355  if regions_ == None:
356  continue
357 
358  if not service_active:
359  continue
360 
361  if state_ == 0:
362  err_pos = math.sqrt(pow(desired_position_.y - position_.y, 2) + pow(desired_position_.x - position_.x, 2))
363  if(err_pos < max_tolerance_target):
364  change_state(2)
365 
366  elif regions_['front'] < 0.5:
367  change_state(1)
368 
369 
370  elif state_ == 1:
371  desired_yaw = math.atan2(desired_position_.y - position_.y, desired_position_.x - position_.x)
372  err_yaw = normalize_angle(desired_yaw - yaw_)
373  err_pos = math.sqrt(pow(desired_position_.y - position_.y, 2) + pow(desired_position_.x - position_.x, 2))
374 
375  if(err_pos < max_tolerance_target):
376  change_state(2)
377 
378  if regions_['front'] > 1 and math.fabs(err_yaw) < 0.05:
379  change_state(0)
380 
381 
382  elif state_ == 2:
383 
384  desired_position_.x = rospy.get_param('des_pos_x')
385  desired_position_.y = rospy.get_param('des_pos_y')
386 
387  err_pos = math.sqrt(pow(desired_position_.y - position_.y, 2) + pow(desired_position_.x - position_.x, 2))
388 
389  if(err_pos > max_tolerance_target + 0.05):
390  change_state(0)
391 
392  rate.sleep()
393 
394 
395 
396 # --------------------------------- NODE
397 
398 
400  global node_name
401 
402  rospy.loginfo( " [%s] is OFFLINE", node_name )
403 
404 
405 
406 
407 if __name__ == "__main__":
408 
409  rospy.init_node( node_name )
410 
411  # service 'bug0_switch'
412  rospy.loginfo( " [%s] advertising service %s ...", node_name, name_bug0_switch )
413  rospy.Service( name_bug0_switch, switch_service, srv_bug0_switch )
414  rospy.loginfo( " [%s] service %s ... OK", node_name, name_bug0_switch )
415 
416  # service 'bug0_status'
417  rospy.loginfo( " [%s] advertising service %s ...", node_name, name_bug0_status )
418  rospy.Service( name_bug0_status, bug0_status, srv_bug0_status )
419  rospy.loginfo( " [%s] service %s ... OK", node_name, name_bug0_status )
420 
421  # service 'get_point'
422  rospy.loginfo( " [%s] getting service %s ...", node_name, name_get_point )
423  rospy.wait_for_service( name_get_point )
424  srv_get_point = rospy.ServiceProxy( name_get_point, get_point )
425  rospy.loginfo( " [%s] service %s ... OK", node_name, name_get_point )
426 
427  sub_laser = rospy.Subscriber('/scan', LaserScan, clbk_laser)
428  sub_odom = rospy.Subscriber('/odom', Odometry, clbk_odom)
429  pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
430 
431  srv_client_go_to_point_ = rospy.ServiceProxy( '/go_to_point_switch', SetBool)
432  srv_client_wall_follower_ = rospy.ServiceProxy( '/wall_follower_switch', SetBool)
433 
434  main()
def main()
The main section of the Bug0 algorithm.
Definition: bug0.py:344
srv_get_point
call-point of the service 'get_point'
Definition: bug0.py:69
def cbk_on_shutdown()
Called on the shutdown of the node.
Definition: bug0.py:399
def srv_bug0_switch(data)
Turn on or off the node.
Definition: bug0.py:220
srv_client_wall_follower_
call-point of the service 'wall_follow_switch'
Definition: bug0.py:193
def clbk_laser(msg)
Get the laser measurements.
Definition: bug0.py:319
srv_client_go_to_point_
call-point of the service 'go_to_point_switch'
Definition: bug0.py:190
def change_state(state)
Change the state of the node.
Definition: bug0.py:146
def normalize_angle(angle)
Normalize an angle in [-pi, pi].
Definition: bug0.py:180
def srv_bug0_status(empty)
Get the status of the service.
Definition: bug0.py:267
def clbk_odom(msg)
Get the actual posture.
Definition: bug0.py:293
def new_random_target()
Get a new randomly-chosen target.
Definition: bug0.py:120