lost_comms_recovery.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 import sys
3 import time
4 import rospy
5 import subprocess
6 import actionlib
7 
8 from sensor_msgs.msg import Joy
9 from geometry_msgs.msg import Twist, PoseWithCovarianceStamped
10 from actionlib_msgs.msg import GoalStatus, GoalStatusArray
11 from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
12 
13 
14 def ping_host(host):
15  ping_fail_count = rospy.get_param('~ping_fail_count', 2)
16  ping_command = "ping -c %s -n -W 1 %s" % (ping_fail_count, host)
17  # TODO: don't shell out, use a more secure python library
18  p = subprocess.Popen(ping_command,
19  stdout=subprocess.PIPE,
20  stderr=subprocess.PIPE,
21  shell=True)
22  (output, error) = p.communicate()
23  returncode = p.returncode
24  return output, error, returncode
25 
27  def __init__(self):
28  # By default recover to a pose at the origin of the frame
29  self.recovery_pose = PoseWithCovarianceStamped()
30  self.recovery_pose.pose.pose.position.x = 0.0
31  self.recovery_pose.pose.pose.position.y = 0.0
32  self.recovery_pose.pose.pose.position.z = 0.0
33  self.recovery_pose.pose.pose.orientation.x = 0.0
34  self.recovery_pose.pose.pose.orientation.y = 0.0
35  self.recovery_pose.pose.pose.orientation.z = 0.0
36  self.recovery_pose.pose.pose.orientation.w = 1
37 
38  rospy.Subscriber('recovery_pose', PoseWithCovarianceStamped,
40  self.twist_publisher = rospy.Publisher('cmd_vel', Twist, queue_size=10)
41  self.joy_publisher = rospy.Publisher('joy', Joy, queue_size=10)
42 
43  def recovery_pose_callback(self, data):
44  rospy.loginfo("Not connected to move_base.")
45  self.recovery_pose = data
46 
47  def working_comms(self):
48  working_comms = False
49  for ip in self.ips.split(','):
50  (output, error, returncode) = ping_host(ip)
51  if returncode == 0:
52  working_comms = True
53  return working_comms
54 
55  def zero_joystick(self):
56  rospy.loginfo('Zeroing joystick.')
57  joy = Joy()
58  joy.axes = [0] * 25 # Set axes to an array of zeros. Needed because
59  # the default value here is an empty list which won't zero anything
60  joy.buttons = [0] * 25 # Set buttons to an array of zeros
61  self.joy_publisher.publish(joy)
62 
63  def stop_motors(self):
64  rospy.loginfo('Stopping motors.')
65  twist = Twist() # zero motion
66  self.twist_publisher.publish(twist)
67 
69  self.move_base = actionlib.SimpleActionClient('move_base', MoveBaseAction)
70  if self.move_base.wait_for_server(timeout=rospy.Duration(3)):
71  rospy.loginfo("Connected to move_base.")
73  else:
74  rospy.loginfo("Not connected to move_base.")
75  self.connected_to_move_base = False
76  return self.connected_to_move_base
77 
78  def navigation_goal_to(self, pose):
79  # Create move_base goal
80  goal = MoveBaseGoal()
81  goal.target_pose.pose = pose.pose.pose
82  goal.target_pose.header.frame_id = rospy.get_param('~goal_frame_id', 'map')
83  rospy.loginfo('Executing move_base goal to position (x,y) %s, %s.' %
84  (goal.target_pose.pose.position.x, goal.target_pose.pose.position.y))
85 
86  # Send goal
87  self.move_base.send_goal(goal)
88  rospy.loginfo('Inital goal status: %s' % GoalStatus.to_string(self.move_base.get_state()))
89  status = self.move_base.get_goal_status_text()
90  if status:
91  rospy.loginfo(status)
92 
93  # Wait for goal result
94  self.move_base.wait_for_result()
95  rospy.loginfo('Final goal status: %s' % GoalStatus.to_string(self.move_base.get_state()))
96  status = self.move_base.get_goal_status_text()
97  if status:
98  rospy.loginfo(status)
99 
100  def goal_in_progress(self):
101  data = rospy.wait_for_message('/move_base/status', GoalStatusArray)
102  if data.status_list == []: # you see this if move_base just started
103  return False
104  # See possible statuses http://docs.ros.org/api/actionlib_msgs/html/msg/GoalStatus.html
105  PENDING = 0
106  ACTIVE = 1
107  status_codes = [status.status for status in data.status_list]
108  if PENDING in status_codes:
109  return True
110  if ACTIVE in status_codes:
111  return True
112  return False
113 
114  def do_recovery(self):
115  if rospy.is_shutdown(): return
116  rospy.logerr('No connection to base station.')
117  if self.connect_to_move_base():
118  if self.goal_in_progress():
119  rospy.loginfo("Navigation in progress, not recovering until finished...")
120  return
122  else:
123  self.zero_joystick()
124  self.stop_motors()
125 
126  def main_loop(self):
127  while not rospy.is_shutdown():
128  if not self.working_comms():
129  self.do_recovery()
130  else:
131  rospy.loginfo('Connected to base station.')
132  time.sleep(3)
133 
134 
135 def main():
136  rospy.init_node("lost_comms_recovery")
137  Controller = RecorveryController()
138  Controller.ips = rospy.get_param('~ips_to_monitor')
139  rospy.loginfo('Monitoring base station on IP(s): %s.' % Controller.ips)
140  Controller.main_loop() # start monitoring


lost_comms_recovery
Author(s): Daniel Snider
autogenerated on Mon Jun 10 2019 13:51:56