Final Assignment  1.0
Research Track part 1 - Assignment 2 - RobEng A.A. 2020/2021
user_console.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 
16 
17 import rospy
18 from std_srvs.srv import SetBool
19 from final_assignment.srv import switch_service, switch_serviceRequest, switch_serviceResponse
20 from final_assignment.srv import user_target, user_targetRequest, user_targetResponse
21 from final_assignment.srv import position_defined, position_definedRequest, position_definedResponse
22 from final_assignment.srv import bug0_status, bug0_statusRequest, bug0_statusResponse
23 from geometry_msgs.msg import Point
24 
25 
26 
27 # --------------------------------- DATA
28 
29 
30 node_name = "user_console"
31 
32 
33 name_wall_follower_switch = "/wall_follower_switch"
34 
35 
36 name_reach_random_pos_switch = "/reach_random_pos_switch"
37 
38 
39 name_user_target = "/user_target"
40 
41 
42 name_position_defined = "/position_defined"
43 
44 
45 name_bug0_switch = "/bug0_switch"
46 
47 
48 name_bug0_status = "/bug0_status"
49 
50 
51 commands = [ "", \
52  "reach_random_pos", \
53  "reach_user_pos", \
54  "wall_follow", \
55  "last_pos", \
56  "change_motion_planning_algorithm", \
57  "help", \
58  "exit" ]
59 
60 
61 commands_info = [ "", \
62  "periodically ask a position to the server, then try and reach it.", \
63  "ask to the user a position, then try and reach it. ", \
64  "use the component wall_follower.", \
65  "Stop any ongoing movement", \
66  "select your motion planning algorithm between 'move_base' and 'bug0'", \
67  "print this help", \
68  "Close this program." ]
69 
70 
71 last_command_idx = -1
72 
73 
74 robot_busy = False
75 
76 
77 reach_random_pos_active = False
78 
79 
80 wall_follow_active = False
81 
82 
83 use_bug0 = False
84 
85 
86 
87 # --------------------------------- FUNCTIONS
88 
89 
101  global node_name, use_bug0
102  global reach_random_pos_active, robot_busy
103  global name_reach_random_pos_switch, srv_reach_random_pos_switch
104  global name_bug0_switch, srv_bug0_switch
105 
106  if reach_random_pos_active:
107  # the service is already active
108  rospy.logwarn( " [%s] ATTENTION: each_random_pos already active. ", node_name )
109  else:
110  if robot_busy:
111  # you cannot call this command when the robot is busy
112  # before calling this, please turn off the previous operation
113  rospy.logwarn( " [%s] ATTENTION: the robot is busy! ", node_name )
114  print( "\tPlease turn off the previous command (use last_pos) before calling this one. " )
115  else:
116  # activate the service
117  if not use_bug0:
118  srv_reach_random_pos_switch( True, False )
119  else:
120  srv_bug0_switch( True, False )
121 
122  # set the robot as busy
123  robot_busy = True
124  reach_random_pos_active = True
125 
126  rospy.loginfo( " [%s] reach_random_pos STARTED using '%s'", node_name, ( "bug0" if use_bug0 else "move_base" ) )
127 
128 
129 
130 
138  global use_bug0
139  global robot_busy, reach_random_pos_active
140  global name_bug0_switch, srv_bug0_switch
141  global name_reach_random_pos_switch, srv_reach_random_pos_switch
142 
143  # send the stop signal to the node
144  rospy.loginfo( " [%s] sending the stop signal... ", node_name )
145  res = None
146  if not use_bug0:
147  res = srv_reach_random_pos_switch( False, False )
148  else:
149  res = srv_bug0_switch( False, False )
150 
151  # then wait for the robot to reach the final position
152  if res.success or use_bug0:
153  # immediate end of the activity
154  pass
155  else:
156  # wait until the robot has reached the position
157  rospy.loginfo( " [%s] waiting for the robot to end the path... ", node_name )
158  while res.in_progress:
159  rospy.sleep( rospy.Duration( 0, 500 ) )
160  res = srv_reach_random_pos_switch( False, False )
161 
162  robot_busy = False
163  reach_random_pos_active = False
164 
165  rospy.loginfo( " [%s] reach_random_pos STOPPED. ", node_name )
166 
167 
168 
169 
182  global node_name
183  global name_position_defined, srv_position_defined
184  global name_user_target, srv_user_target
185  global robot_busy
186  global name_bug0_switch, srv_bug0_switch
187  global name_bug0_status, srv_bug0_status
188 
189  if robot_busy:
190  rospy.logwarn( " [%s] ATTENTION: the robot is busy now! ", node_name )
191  print( "\tPlease turn off the previous command (use last_pos) before calling this one. " )
192  return
193 
194  # ask the user for a target
195  rospy.loginfo( " [user console] Give me a target:" )
196  print( "available: [(-4,-3);(-4,2);(-4,7);(5,-7);(5,-3);(5,1)]" )
197  target = Point()
198  target.x = float(input( "\tx : " ))
199  target.y = float(input( "\ty : " ))
200 
201  # check the position
202  res = srv_position_defined( target )
203  if res.defined :
204  rospy.loginfo( " [user console] selected: ( %f, %f )", target.x, target.y )
205  else:
206  rospy.logerr( " [user console] ERROR: not a valid position. " )
207  return
208 
209  # reach the position
210  rospy.loginfo( " [%s] reaching the position... ", node_name )
211  if not use_bug0:
212  srv_user_target( target )
213  else:
214  reach_user_pos_bug0( target )
215 
216  rospy.loginfo( " [%s] Arrived. ", node_name )
217 
218 
219 
220 
233 def reach_user_pos_bug0( target ):
234  global node_name
235  global name_user_target, srv_user_target
236  global name_bug0_switch, srv_bug0_switch
237  global name_bug0_status, srv_bug0_status
238 
239  # first of all, put the target into the parameter server
240  rospy.set_param("des_pos_x", target.x)
241  rospy.set_param("des_pos_y", target.y)
242 
243  # activate bug0 in once_only mode
244  res = srv_bug0_switch( True, True )
245 
246  # wait until the robot has reached the goal
247  goal_reached = ( srv_bug0_status( ) ).reached
248  while not goal_reached:
249  rospy.sleep( rospy.Duration( 0, 500 ) )
250  goal_reached = ( srv_bug0_status( ) ).reached
251 
252 
253 
254 
267 def wall_follow( val=True ):
268  global node_name
269  global name_wall_follower_switch, srv_wall_follower_switch
270  global robot_busy, wall_follow_active
271 
272  if val and robot_busy:
273  if wall_follow_active:
274  rospy.loginfo( " [%s] wall_follow already active. ", node_name )
275  else:
276  rospy.logwarn( " [%s] ATTENTION: the robot is busy now! ", node_name )
277  print( "\tPlease turn off the previous command (use last_pos) before calling this one. " )
278 
279  return
280 
282 
283  wall_follow_active = val
284  robot_busy = val
285 
286  rospy.loginfo( " [%s] wall follow is %s ", node_name, ( "ON" if val else "OFF" ) )
287 
288 
289 
290 
300 def last_pos():
301  global node_name
302  global robot_busy
303  global reach_random_pos_active, wall_follow_active
304 
305  if robot_busy:
306  if reach_random_pos_active:
308 
309  elif wall_follow_active:
310  wall_follow( False )
311 
312  else:
313  # nothing to stop
314  rospy.logwarn( " [%s] WARNING: no activity to stop. ", node_name )
315 
316 
317 
318 
329  global node_name, use_bug0, robot_busy
330 
331  # you can't change the motion planning algorithm while you're using it!
332  if robot_busy:
333  rospy.logwarn( " [%s] ATTENTION: the robot is busy now! ", node_name )
334  print( "\tPlease turn off the previous command (use last_pos) before calling this one. " )
335 
336  return
337 
338  rospy.loginfo( "[%s] actually you're using this motion planning algorithm: '%s' ", node_name, ('bug0' if use_bug0 else 'move_base') )
339  print( "[%s] would you like to change with this? '%s' [Y/n]" % ( node_name, ('bug0' if not use_bug0 else 'move_base') ) )
340  answer = input( "[Y/n]" )
341 
342  if answer == "Y" or answer == "y":
343  # change planning algorithm
344  use_bug0 = not use_bug0
345  else:
346  # don't change algorithm
347  pass
348 
349  rospy.loginfo( "[%s] using algorithm: '%s' ", node_name, ('bug0' if use_bug0 else 'move_base') )
350 
351 
352 
353 
364  global node_name
365  global commands, commands_info
366 
367  print( "\nAvailable commands:" )
368 
369  for i in range( 1, len( commands ) ):
370  print( "\t [no." + str(i) + "] " + commands[i] + ":" )
371  print( "\t\t" + commands_info[i] )
372 
373 
374 
375 # --------------------------------- SERVICES
376 
377 
378 srv_wall_follower_switch = None
379 
380 
381 srv_reach_random_pos_switch = None
382 
383 
384 srv_user_target = None
385 
386 
387 srv_position_defined = None
388 
389 
390 srv_bug0_switch = None
391 
392 
393 srv_bug0_status = None
394 
395 
396 
397 # --------------------------------- WORKING CYCLE
398 
399 
410 def main():
411  global node_name
412  global commands, last_command_idx
413 
414  print( "\n\tready!\n" )
415 
416  while not rospy.is_shutdown():
417  # wait for one command from the user
418  cmd = input( "-> " )
419 
420  # first, clean the command
421  cmd = cmd.strip( )
422 
423  # then parse it
424  cmd_idx = -1
425  if cmd.isnumeric( ):
426  # take the corresponding integer
427  i = int( cmd )
428 
429  # if the integer is a command, set the command
430  if i > 0 and i < len( commands ):
431  cmd_idx = i
432  else:
433  # case-insensitive
434  cmd = cmd.lower( )
435 
436  # interpretation
437  if cmd in commands:
438  cmd_idx = commands.index( cmd )
439 
440  # store the previous command
441  if cmd_idx > 0:
442  last_command_idx = cmd_idx
443 
444  # finally, call the proper function
445  if cmd_idx < 0:
446  rospy.loginfo( " [user console] ERROR: not a valid command!" )
447  print( "need infos? write ''help" )
448  continue
449  elif cmd_idx == 1:
451  elif cmd_idx == 2:
452  reach_user_pos( )
453  elif cmd_idx == 3:
454  wall_follow( )
455  elif cmd_idx == 4:
456  last_pos( )
457  elif cmd_idx == 5:
459  elif cmd_idx == 6:
460  print_help( )
461  elif cmd_idx == 7:
462  # close the program
463  rospy.loginfo( " [user console] exit command received" )
464  break
465 
466 
467 
468 # --------------------------------- NODE
469 
470 
474  global node_name
475  rospy.loginfo( " [%s] is OFFLINE", node_name )
476 
477 
478 
479 if __name__ == "__main__":
480  rospy.init_node( node_name )
481  rospy.on_shutdown( cbk_on_shutdown )
482 
483  # require the server 'wall_follower_switch'
484  rospy.loginfo( " [%s] getting service %s ...", node_name, name_wall_follower_switch )
485  rospy.wait_for_service( name_wall_follower_switch )
486  srv_wall_follower_switch = rospy.ServiceProxy( name_wall_follower_switch, SetBool )
487  rospy.loginfo( " [%s] service %s ... OK", node_name, name_wall_follower_switch )
488 
489  # service 'reach_random_pos_switch'
490  rospy.loginfo( " [%s] getting service %s ...", node_name, name_reach_random_pos_switch )
491  rospy.wait_for_service( name_reach_random_pos_switch )
492  srv_reach_random_pos_switch = rospy.ServiceProxy( name_reach_random_pos_switch, switch_service )
493  rospy.loginfo( " [%s] service %s ... OK", node_name, name_reach_random_pos_switch )
494 
495  # require the server 'user_target'
496  rospy.loginfo( " [%s] getting service %s ...", node_name, name_user_target )
497  rospy.wait_for_service( name_user_target )
498  srv_user_target = rospy.ServiceProxy( name_user_target, user_target )
499  rospy.loginfo( " [%s] service %s ... OK", node_name, name_user_target )
500 
501  # service 'position_defined'
502  rospy.loginfo( " [%s] getting service %s ...", node_name, name_position_defined )
503  rospy.wait_for_service( name_position_defined )
504  srv_position_defined = rospy.ServiceProxy( name_position_defined, position_defined )
505  rospy.loginfo( " [%s] service %s ... OK", node_name, name_position_defined )
506 
507  # service 'bug0_switch'
508  rospy.loginfo( " [%s] getting service %s ...", node_name, name_bug0_switch )
509  rospy.wait_for_service( name_bug0_switch )
510  srv_bug0_switch = rospy.ServiceProxy( name_bug0_switch, switch_service )
511  rospy.loginfo( " [%s] service %s ... OK", node_name, name_bug0_switch )
512 
513  # service 'bug0_status'
514  rospy.loginfo( " [%s] getting service %s ...", node_name, name_bug0_status )
515  rospy.wait_for_service( name_bug0_status )
516  srv_bug0_status = rospy.ServiceProxy( name_bug0_status, bug0_status )
517  rospy.loginfo( " [%s] service %s ... OK", node_name, name_bug0_status )
518 
519  try:
520  rospy.loginfo( " [%s] is ONLINE", node_name )
521  main()
522  except rospy.ROSException:
523  rospy.logwarn( " [%s] Raised an Exception ... ", node_name )
srv_bug0_status
call-point of the service 'bug0_status'
def print_help()
Implementation of the command help [no.6].
def reach_user_pos_bug0(target)
Send manually a goal to bug0.
srv_bug0_switch
call-point of the service 'bug0_switch'
def last_pos()
Implementation of the command last_pos [no.4].
def cbk_on_shutdown()
Called when the shutdown signal is raised.
def stop_reach_random_pos()
Stop the background process reach_random_pos
srv_wall_follower_switch
call point of the server 'wall_follower_switch'
srv_user_target
entry point of the service 'user_target'
def main()
Ask the next command to the user.
def wall_follow(val=True)
Implementation of the command wall_follow [no.3].
srv_position_defined
call-point of the service 'position_defined'
def change_motion_planning_algorithm()
Implementation of the command change_motion_planning_algorithm [no.5].
def reach_random_pos()
Implementation of the command reach_random_pos [no.1].
def reach_user_pos()
Implementation of the command reach_user_pos [no.2].
srv_reach_random_pos_switch
call-point of the service 'reach_random_pos_switch'