2 from xmlrpc.client
import Boolean
10 from geometry_msgs.msg
import Twist, Point
11 from visualization_msgs.msg
import Marker, MarkerArray
12 from geometry_msgs.msg
import PoseStamped
13 from std_msgs.msg
import Empty, ColorRGBA, Bool
15 from tf.transformations
import euler_from_quaternion
16 from tf2_geometry_msgs
import do_transform_pose
18 from dynamic_reconfigure.server
import Server
as DynamicReconfigureServer
20 from line_planner.cfg
import LinePlannerConfig
21 from nav_msgs.msg
import Path
23 ROBOT_FRAME =
"base_link"
24 PLANNING_FRAME =
"map"
57 rospy.loginfo(
"New route received.")
59 if len(msg.poses) == 0:
60 rospy.loginfo(
"Empty route, stopping.")
64 self.
route = msg.poses
73 if len(self.
route) > 0:
79 rospy.loginfo(
"-> Route finished.")
83 rospy.loginfo(
"Simple goal reached.")
95 except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException)
as e:
96 rospy.logwarn(
"TF2 exception: %s", e)
104 if PLANNING_FRAME == goal.header.frame_id:
105 rospy.loginfo(
"------------------")
106 rospy.loginfo(
"Received goal in planning ("+PLANNING_FRAME+
") frame.")
107 rospy.loginfo(
"Position: X: %f, Y: %f, Z: %f", goal.pose.position.x, goal.pose.position.y, goal.pose.position.z)
108 rospy.loginfo(
"Orientation: X: %f, Y: %f, Z: %f, W: %f", goal.pose.orientation.x, goal.pose.orientation.y, goal.pose.orientation.z, goal.pose.orientation.w)
112 transform = self.
tf2_buffer.lookup_transform(PLANNING_FRAME, goal.header.frame_id, rospy.Time(0))
113 goal_transformed = do_transform_pose(goal, transform)
115 rospy.loginfo(
"------------------")
116 rospy.loginfo(
"Received goal in "+goal.header.frame_id+
" frame, transformed to "+PLANNING_FRAME+
".")
117 rospy.loginfo(
"Position: X: %f, Y: %f, Z: %f", goal_transformed.pose.position.x, goal_transformed.pose.position.y, goal_transformed.pose.position.z)
118 rospy.loginfo(
"Orientation: X: %f, Y: %f, Z: %f, W: %f", goal_transformed.pose.orientation.x, goal_transformed.pose.orientation.y, goal_transformed.pose.orientation.z, goal_transformed.pose.orientation.w)
120 except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException)
as e:
121 rospy.logwarn(
"TF2 exception: %s", e)
126 rospy.init_node(
"line_following_controller")
127 global ROBOT_FRAME, PLANNING_FRAME
129 ROBOT_FRAME = rospy.get_param(
'~robot_frame',
'base_link')
130 PLANNING_FRAME = rospy.get_param(
'~planning_frame',
'map')
153 self.
cmd_vel_pub = rospy.Publisher(
"cmd_vel", Twist, queue_size=1)
155 self.
status_pub = rospy.Publisher(
"line_planner/active", Bool, queue_size=1, latch=
True)
156 self.
plan_pub = rospy.Publisher(
"line_planner/plan", Path, queue_size=1, latch=
True)
157 self.
marker_pub = rospy.Publisher(
"line_planner/markers", MarkerArray, queue_size=1)
160 rospy.get_param(
'P', 3.0),
161 rospy.get_param(
'I', 0.001),
162 rospy.get_param(
'D', 65.0)
173 rospy.loginfo(
"Line planner started.")
174 rospy.loginfo(
"Robot frame: "+ROBOT_FRAME)
175 rospy.loginfo(
"Planning frame: "+PLANNING_FRAME)
178 self.
pid.kp = config.P
179 self.
pid.ki = config.I
180 self.
pid.kd = config.D
199 _, _, current_yaw = euler_from_quaternion([
200 current_pose.orientation.x,
201 current_pose.orientation.y,
202 current_pose.orientation.z,
203 current_pose.orientation.w,
206 target_unit_vector =
get_dir(current_pose.position, target_position)
207 current_unit_vector = [math.cos(current_yaw), math.sin(current_yaw)]
210 dot_product = target_unit_vector[0] * current_unit_vector[0] + target_unit_vector[1] * current_unit_vector[1]
213 cross_product = current_unit_vector[0] * target_unit_vector[1] - current_unit_vector[1] * target_unit_vector[0]
215 return -math.copysign(math.acos(dot_product), cross_product)
218 deltax = goal.position.x - pose.position.x
219 deltay = goal.position.y - pose.position.y
220 return math.sqrt(deltax** 2 + deltay ** 2)
226 abserr = math.fabs(angle_error)
229 vel *=
clamp(-1.598 * abserr + 3.196, -1.0, 0.0)
233 vel *=
clamp((-1.0 / 0.52) * abserr + 2, 0.0, 1.0)
239 start_goal, end_goal = self.
goal_server.get_goals()
241 if start_goal ==
None or end_goal ==
None:
277 self.
send_twist(linear_velocity, angular_velocity)
282 except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
283 rospy.logwarn(
"TF Exception")
288 msg.header.frame_id = PLANNING_FRAME
293 start_goal, end_goal = self.
goal_server.get_goals()
295 if start_goal ==
None or end_goal ==
None:
299 start_stamped = PoseStamped()
300 start_stamped.header.frame_id = PLANNING_FRAME
301 start_stamped.pose = start_goal
302 msg.poses.append(start_stamped)
304 end_stamped = PoseStamped()
305 end_stamped.header.frame_id = PLANNING_FRAME
306 end_stamped.pose = end_goal
308 msg.poses = [start_stamped, end_stamped]
315 if math.isnan(vel_x):
318 if math.isnan(vel_z):
322 twist.linear.x = vel_x
323 twist.angular.z = vel_z
335 markerArray = MarkerArray()
336 markerArray.markers.append(marker)
341 def sphere_marker(position, marker_id, r, g, b, size):
343 marker.header.frame_id = PLANNING_FRAME
344 marker.type = Marker.SPHERE
345 marker.pose.position = position
346 marker.pose.orientation.w = 1.0
347 marker.scale.x = size
348 marker.scale.y = size
349 marker.scale.z = size
354 marker.id = marker_id
357 def line_marker(p_from, p_to, marker_id, r, g, b):
359 marker.header.frame_id = PLANNING_FRAME
360 marker.type = Marker.LINE_STRIP
361 marker.pose.orientation.w = 1.0
364 Point(p_from.x, p_from.y, p_from.z),
365 Point(p_to.x, p_to.y, p_to.z),
368 c = ColorRGBA(r,g,b, 1.0)
370 marker.colors = [c, c]
372 marker.scale.x = 0.05
373 marker.id = marker_id
378 markerArray = MarkerArray()
379 markerArray.markers.append(line_marker(start_goal.position, end_goal.position, 0, 0.575, 0.870, 0.0261))
380 markerArray.markers.append(sphere_marker(start_goal.position, 1, 1.0, 0.0, 0.0, 0.2))
381 markerArray.markers.append(sphere_marker(end_goal.position, 2, 0.0, 0.0, 1.0, self.
MIN_GOAL_DIST*2))
382 markerArray.markers.append(sphere_marker(target_position, 3, 0.0, 1.0, 0.0, 0.2))
390 rate = rospy.Rate(rospy.get_param(
'rate', 30))
391 rospy.on_shutdown(ctrl.cleanup)
393 while not rospy.is_shutdown():