emulation_nav.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import actionlib
4 import argparse
5 import numpy
6 import rospy
7 import tf
8 import tf2_ros
9 from actionlib_msgs.msg import GoalStatus
10 from geometry_msgs.msg import Transform, TransformStamped, PoseStamped
11 from geometry_msgs.msg import PoseWithCovarianceStamped, Quaternion
12 from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal, MoveBaseResult
13 
14 class EmulationNav(object):
15  def __init__(self, odom_frame):
16  # this node emulates a very basic navigation including move_base action and localization
17  #
18  # interfaces
19  # - subscribers:
20  # - /initialpose [geometry_msgs/PoseWithCovarianceStamped]
21  # - publishers:
22  # - tf (map --> odom_frame)
23  # - actions:
24  # - move_base [move_base_msgs/MoveBaseAction] (optional)
25 
26 
27  # TODO
28  # - speed factor
29  # - handle cancel on move_base action
30 
31  self._odom_frame = odom_frame
32 
36 
37  rospy.Subscriber("/initialpose", PoseWithCovarianceStamped, self.initalpose_callback, queue_size=1)
38  initialpose = rospy.get_param("~initialpose", None)
39  if type(initialpose) == list:
40  rospy.loginfo("using initialpose from parameter server: %s", str(initialpose))
41  elif type(initialpose) == str:
42  rospy.loginfo("using initialpose from script server: %s", str(initialpose))
43  initialpose = rospy.get_param("/script_server/base/" + initialpose)
44  else:
45  rospy.loginfo("initialpose not set, using [0, 0, 0] as initialpose")
46  initialpose = [0, 0, 0]
47 
48  self._odom_transform = Transform()
49  self._odom_transform.translation.x = initialpose[0]
50  self._odom_transform.translation.y = initialpose[1]
51  quat = tf.transformations.quaternion_from_euler(0, 0, initialpose[2])
52  self._odom_transform.rotation = Quaternion(*quat)
53 
54  rospy.Timer(rospy.Duration(0.04), self.timer_cb)
55 
56  rospy.loginfo("Emulation for navigation running")
57 
58  # Optional move_base action
59  self._move_base_mode = rospy.get_param("~move_base_mode", None)
60  if self._move_base_mode == None:
61  rospy.loginfo("Emulation running without move_base")
62  elif self._move_base_mode == "beam" or self._move_base_mode == "linear_nav":
63  self._move_base_action_name = "/move_base"
64  rospy.Subscriber(self._move_base_action_name + "_simple/goal", PoseStamped, self.move_base_simple_callback, queue_size=1)
65  self._as_move_base = actionlib.SimpleActionServer(self._move_base_action_name, MoveBaseAction, execute_cb=self.move_base_cb, auto_start = False)
66  self._as_move_base.start()
67  rospy.loginfo("Emulation running for action %s of type MoveBaseAction with mode '%s'"%(self._move_base_action_name, self._move_base_mode))
68  else:
69  rospy.logwarn("Emulation running without move_base due to invalid value for parameter move_base_mode: '%s'", self._move_base_mode)
70 
71  def initalpose_callback(self, msg):
72  rospy.loginfo("Got initialpose, updating %s transformation.", self._odom_frame)
73  try:
74  # get pose of base_footprint within odom frame
75  base_in_odom = self._buffer.lookup_transform("base_footprint", self._odom_frame, rospy.Time(0))
76  # convert initialpose to matrix (necessary for matrix multiplication)
77  trans_ini = tf.transformations.translation_matrix([msg.pose.pose.position.x, msg.pose.pose.position.y, msg.pose.pose.position.z])
78  rot_ini = tf.transformations.quaternion_matrix([msg.pose.pose.orientation.x, msg.pose.pose.orientation.y, msg.pose.pose.orientation.z, msg.pose.pose.orientation.w])
79  matrix_ini = numpy.dot(trans_ini, rot_ini)
80  # convert footprint->odom transform to matrix (necessary for matrix multiplication)
81  trans_base_odom = tf.transformations.translation_matrix([base_in_odom.transform.translation.x, base_in_odom.transform.translation.y, base_in_odom.transform.translation.z])
82  rot_base_odom = tf.transformations.quaternion_matrix([base_in_odom.transform.rotation.x, base_in_odom.transform.rotation.y, base_in_odom.transform.rotation.z, base_in_odom.transform.rotation.w])
83  matrix_base_odom = numpy.dot(trans_base_odom, rot_base_odom)
84 
85  # matrix multiplication of footprint->odom transform in respect of initialpose
86  matrix_new_odom = numpy.dot(matrix_ini, matrix_base_odom)
87 
88  # translate back into Transform
89  trans_new_odom = tf.transformations.translation_from_matrix(matrix_new_odom)
90  rot_new_odom = tf.transformations.quaternion_from_matrix(matrix_new_odom)
91  self._odom_transform.translation.x = trans_new_odom[0]
92  self._odom_transform.translation.y = trans_new_odom[1]
93  self._odom_transform.translation.z = trans_new_odom[2]
94  self._odom_transform.rotation.x = rot_new_odom[0]
95  self._odom_transform.rotation.y = rot_new_odom[1]
96  self._odom_transform.rotation.z = rot_new_odom[2]
97  self._odom_transform.rotation.w = rot_new_odom[3]
98 
99  except Exception as e:
100  rospy.logerr("Could not calculate new odom transformation:\n%s", e)
101  return
102 
103  def timer_cb(self, event):
104  # publish tf
105  # pub odom_frame --> map
106  t_loc = TransformStamped()
107  t_loc.header.stamp = rospy.Time.now()
108  t_loc.header.frame_id = "map"
109  t_loc.child_frame_id = self._odom_frame
110  t_loc.transform = self._odom_transform
111 
112  transforms = [t_loc]
113 
114  self._transform_broadcaster.sendTransform(transforms)
115 
116  def move_base_cb(self, goal):
117  pwcs = PoseWithCovarianceStamped()
118  pwcs.header = goal.target_pose.header
119  pwcs.pose.pose = goal.target_pose.pose
120  if self._move_base_mode == "beam":
121  rospy.loginfo("move_base: beaming robot to new goal")
122  self.initalpose_callback(pwcs)
123  elif self._move_base_mode == "linear_nav":
124  move_base_linear_action_name = "/move_base_linear"
125  ac_move_base_linear = actionlib.SimpleActionClient(move_base_linear_action_name, MoveBaseAction)
126  rospy.loginfo("Waiting for ActionServer: %s", move_base_linear_action_name)
127  if not ac_move_base_linear.wait_for_server(rospy.Duration(1)):
128  rospy.logerr("Emulator move_base failed because move_base_linear action server is not available")
129  self._as_move_base.set_aborted()
130  return
131  rospy.loginfo("send goal to %s", move_base_linear_action_name)
132  ac_move_base_linear.send_goal(goal)
133  ac_move_base_linear.wait_for_result()
134  ac_move_base_linear_status = ac_move_base_linear.get_state()
135  ac_move_base_linear_result = ac_move_base_linear.get_result()
136  if ac_move_base_linear_status != GoalStatus.SUCCEEDED:
137  rospy.logerr("Emulator move_base failed because move_base_linear failed")
138  self._as_move_base.set_aborted()
139  return
140  else:
141  rospy.logerr("Invalid move_base_action_mode")
142  self._as_move_base.set_aborted()
143  return
144  rospy.loginfo("Emulator move_base succeeded")
145  self._as_move_base.set_succeeded(MoveBaseResult())
146 
148  goal = MoveBaseGoal()
149  goal.target_pose = msg
150  ac_move_base = actionlib.SimpleActionClient(self._move_base_action_name, MoveBaseAction)
151  rospy.loginfo("Waiting for ActionServer: %s", self._move_base_action_name)
152  if not ac_move_base.wait_for_server(rospy.Duration(1)):
153  rospy.logerr("Emulator move_base simple failed because move_base action server is not available")
154  return
155  rospy.loginfo("send goal to %s", self._move_base_action_name)
156  ac_move_base.send_goal(goal)
157  # ac_move_base.wait_for_result() # no need to wait for the result as this is the topic interface to move_base without feedback
158 
159 if __name__ == '__main__':
160  rospy.init_node('emulation_nav')
161  parser = argparse.ArgumentParser(conflict_handler='resolve',
162  description="Tool for emulating nav by providing localization and move base interface")
163  parser.add_argument('-o', '--odom_frame', help='odom frame name (default: \'odom_combined\')', default='odom_combined')
164  args, unknown = parser.parse_known_args()
165  rospy.loginfo("emulation_nav started!")
166  EmulationNav(args.odom_frame)
167  rospy.spin()
emulation_nav.EmulationNav.initalpose_callback
def initalpose_callback(self, msg)
Definition: emulation_nav.py:71
emulation_nav.EmulationNav._odom_transform
_odom_transform
Definition: emulation_nav.py:48
emulation_nav.EmulationNav
Definition: emulation_nav.py:14
emulation_nav.EmulationNav.move_base_cb
def move_base_cb(self, goal)
Definition: emulation_nav.py:116
emulation_nav.EmulationNav._move_base_mode
_move_base_mode
Definition: emulation_nav.py:59
emulation_nav.EmulationNav._move_base_action_name
_move_base_action_name
Definition: emulation_nav.py:63
emulation_nav.EmulationNav.__init__
def __init__(self, odom_frame)
Definition: emulation_nav.py:15
emulation_nav.EmulationNav._listener
_listener
Definition: emulation_nav.py:34
emulation_nav.EmulationNav._buffer
_buffer
Definition: emulation_nav.py:33
tf2_ros::TransformListener
actionlib::SimpleActionClient
tf2_ros::Buffer
emulation_nav.EmulationNav.move_base_simple_callback
def move_base_simple_callback(self, msg)
Definition: emulation_nav.py:147
emulation_nav.EmulationNav._odom_frame
_odom_frame
Definition: emulation_nav.py:31
actionlib::SimpleActionServer
tf2_ros::TransformBroadcaster
emulation_nav.EmulationNav.timer_cb
def timer_cb(self, event)
Definition: emulation_nav.py:103
emulation_nav.EmulationNav._as_move_base
_as_move_base
Definition: emulation_nav.py:65
emulation_nav.EmulationNav._transform_broadcaster
_transform_broadcaster
Definition: emulation_nav.py:35


cob_hardware_emulation
Author(s): Florian Weisshardt
autogenerated on Mon May 1 2023 02:44:27