Esempio n. 1
0
    def timer_cb(self, event):
        '''
        if object is relevant given position of ego car at (pos_x, pos_y)
        returns True, else returns False
        '''
        def relevant_filter(pos_x, pos_y, object):
            # return True
            pos_car = [object.pose.position.x, object.pose.position.y]
            if not self.enable_lane_filter:
                '''
                does not filter relevant vehicles based on their lane
                '''
                if pos_x > 0 and pos_y < 0:
                    if (pos_car[0] > 15 and pos_car[1] > 0):
                        # if (pos_car[0] > 0 and pos_car[1] < -20) or (pos_car[0] > 20 and pos_car[1] > 0):
                        return True
                    return False
                elif pos_x > 0 and pos_y >= 0:
                    if (pos_car[0] < 0 and pos_car[1] > 15):
                        return True
                    return False
                elif pos_x <= 0 and pos_y >= 0:
                    if (pos_car[0] < -20 and pos_car[1] < 0):
                        return True
                    return False
                else:
                    if pos_car[0] > 0 and pos_car[1] < -20:
                        return True
                    return False
            else:
                '''
                filter vehicles based on their lane number
                currently, using road geometry, should be changed to based on closest waypoint information
                '''
                if pos_x > 0 and pos_y < 0:
                    if (pos_car[0] > 15 and pos_car[1] > 0 and pos_car[1] < 7):
                        # if (pos_car[0] > 0 and pos_car[1] < -20) or (pos_car[0] > 20 and pos_car[1] > 0):
                        return True
                    return False
                elif pos_x > 0 and pos_y >= 0:
                    if (pos_car[0] < 0 and pos_car[0] > -6 and pos_car[1] > 15)\
                            or (pos_car[0] < -5 and pos_car[0] > -10 and pos_car[1] > 20 and pos_car[1] < 25):
                        return True
                    return False
                elif pos_x <= 0 and pos_y >= 0:
                    # if (pos_car[0] < -20 and pos_car[1]< 0):
                    #     return True
                    return False
                else:
                    if (pos_car[0] > 0 and pos_car[0] < 5 and pos_car[1] < -20) \
                            or (pos_car[0] > 5 and pos_car[0] < 10 and pos_car[1] < -20 and pos_car[1] > -25):
                        return True
                    return False

        if self.ego_ready and self.nearby_ready:
            # ----------------------
            # publish derived object message for all relevant cars
            # ----------------------
            header = Header()
            header.stamp = rospy.Time.now()
            header.frame_id = 'map'
            relevant_msg = ObjectArray()
            relevant_msg.header = header
            relevant_msg.objects = [obj for obj in self.nearby_obj.objects \
                            if relevant_filter(self.ego_location.x, self.ego_location.y, obj)]
            self.relevant_pub.publish(relevant_msg)

            # ----------------------
            # predict future path for relevant cars
            # ----------------------
            future_path = PathArray()
            future_path.header.stamp = rospy.Time.now()
            future_path.header.frame_id = 'map'
            future_path.paths = []
            for obj in relevant_msg.objects:
                obj_pose = obj.pose
                try:
                    path_list_resp = self.get_path_handle(obj_pose)
                    for path in path_list_resp.paths.paths:
                        future_path.paths.append(path)
                except rospy.ServiceException, e:
                    print "Service call failed: %s" % e
            self.path_pub.publish(future_path)
            self.viz_path_list(future_path.paths)

            # ----------------------
            # predict future trajectory for relevant cars, incorporating speed information
            # ----------------------
            predicted_traj = PathArray()
            predicted_traj.header.stamp = rospy.Time.now()
            predicted_traj.header.frame_id = 'map'
            # includes all the predicted trajectories for
            # all the relevant objects
            for obj in relevant_msg.objects:
                speed = np.linalg.norm(
                    [obj.twist.linear.x, obj.twist.linear.y])
                waypoint_dist = speed * self.time_step  # predicted distance between waypoints
                obj_pose = obj.pose
                try:
                    path_list_resp = self.get_path_handle(obj_pose)
                    for path in path_list_resp.paths.paths:
                        # path is a ROS path message now
                        traj = self.interpolate_path(path, waypoint_dist)
                        predicted_traj.paths.append(traj)
                except rospy.ServiceException, e:
                    print "Service call failed: %s" % e
    def timer_cb(self, event):
        '''
        This is a callback for the class timer, which will be called every tick.
        The callback will filter out objects not relevant to the ego vehicle and
        publish to the ROS topics defined in the class.
        
        Parameters
        ----------
        event : rospy.TimerEvent
            The timer's tick event.
        '''
        def relevant_filter(pos_x, pos_y, yaw, object):
            '''
            Determines if the object is in the circle and relevant to the
            current ego position.
            
            Parameters
            ----------
            pos_x : float64
                The x location of the ego vehicle.
            pos_y : float64
                The y location of the ego vehicle.
            yaw : float64
                The yaw, heading, of the ego vehicle.
            object : derived_object_msgs.Object
                The converted Carla object.
            
            Returns
            -------
            bool, int, float
                A tuple containing the information about the provided object.
                Specifically, whether the object is relevant, its location
                (in front, 1, or behind, 0) and distance [meters], all with
                respect to the ego vehicle.
            '''
            # Position of the object of interest
            car_pos = [object.pose.position.x, object.pose.position.y]

            # If position is too far from circle center, ignore
            if np.linalg.norm(car_pos) <= 5:
                return False, 0, 0

            # Orientation of object
            quat = (object.pose.orientation.x, object.pose.orientation.y,
                    object.pose.orientation.z, object.pose.orientation.w)
            car_yaw = tf.transformations.euler_from_quaternion(quat)[2]
            ori_car = [np.cos(car_yaw), np.sin(car_yaw)]
            ori_circle = [-car_pos[0], -car_pos[1]]
            ori_circle = ori_circle / np.linalg.norm(ori_circle)
            rel_ang = np.dot(ori_circle, ori_car)
            # print(" this is the position of car", car_pos)
            # print(" this is yaw angle ", car_yaw)
            # print(" this is ori car ", ori_car)
            # print(" this is ori circle ", ori_circle)
            # print("this is rel ang ", rel_ang)

            # If object is facing away from circle (exiting), ignore
            if rel_ang <= -0.3:
                return False, 0, 0

            # Unit vector representation of ego heading
            ori_ego = [np.cos(yaw), np.sin(yaw)]
            # Relative position of object w.r.t ego vehicle
            ori_rel = [car_pos[0] - pos_x, car_pos[1] - pos_y]
            # Distance from object along the heading of ego car
            distance_tangent = np.dot(ori_rel, ori_ego)
            # Distance from object along normal of the ego car heading
            distance_normal = np.dot(ori_rel, [ori_ego[1], -ori_ego[0]])

            # Object's relative postion is relevant
            if (distance_tangent > -15 and distance_tangent < 25
                    and abs(distance_normal) < 25):
                if distance_tangent > 0:  # Object is in front
                    return True, 1, np.linalg.norm(ori_rel)
                else:  # Object is behind
                    return True, 0, np.linalg.norm(ori_rel)

            # Object is in the circle, but not relevant to ego location
            return False, 0, 0

        def relevant_filter_entrance(pos_x, pos_y, object):
            '''
            Determines if the object is trying to enter the circle and relevant
            to the current ego position. The filter will take into account
            whether the object is ahead of the ego and whether to base its
            relevancy on the object's current lane.
            
            Parameters
            ----------
            pos_x : float64
                The x location of the ego vehicle.
            pos_y : float64
                The y location of the ego vehicle.
            object : derived_object_msgs.Object
                The converted Carla object.
            
            Returns
            -------
            bool
                Whether the object is relevant to the ego vehicle.
            '''
            pos_car = [object.pose.position.x, object.pose.position.y]

            if not self.enable_lane_filter:
                if pos_x > 0 and pos_y < 0:
                    if (pos_car[0] > 15 and pos_car[1] > 0):
                        return True
                    return False
                elif pos_x > 0 and pos_y >= 0:
                    if (pos_car[0] < 0 and pos_car[1] > 15):
                        return True
                    return False
                elif pos_x <= 0 and pos_y >= 0:
                    if (pos_car[0] < -20 and pos_car[1] < 0):
                        return True
                    return False
                else:
                    if pos_car[0] > 0 and pos_car[1] < -20:
                        return True
                    return False
            else:  #TODO: Update to use waypoint information
                if pos_x > 0 and pos_y < 0:
                    if (pos_car[0] > 15 and pos_car[1] > 0 and pos_car[1] < 7):
                        return True
                    return False
                elif pos_x > 0 and pos_y >= 0:
                    if ((pos_car[0] < 0 and pos_car[0] > -6
                         and pos_car[1] > 15)
                            or (pos_car[0] < -5 and pos_car[0] > -10
                                and pos_car[1] > 20 and pos_car[1] < 25)):
                        return True
                    return False
                elif pos_x <= 0 and pos_y >= 0:
                    return False
                else:
                    if ((pos_car[0] > 0 and pos_car[0] < 5
                         and pos_car[1] < -20)
                            or (pos_car[0] > 5 and pos_car[0] < 10
                                and pos_car[1] < -20 and pos_car[1] > -25)):
                        return True

                    return False

        if self.ego_ready and self.nearby_ready:
            self.ego_odom_pub.publish(self.ego_odom)

            ahead_distance = 100
            behind_distance = 100
            front_closest_obj = None
            behind_closest_obj = None

            header = Header()
            header.stamp = rospy.Time.now()
            header.frame_id = 'map'

            relevant_msg = ObjectArray()
            relevant_msg.header = header
            relevant_msg.objects = []

            ori_quat = (self.ego_odom.pose.pose.orientation.x,
                        self.ego_odom.pose.pose.orientation.y,
                        self.ego_odom.pose.pose.orientation.z,
                        self.ego_odom.pose.pose.orientation.w)
            ori_euler = tf.transformations.euler_from_quaternion(ori_quat)
            yaw = ori_euler[2]

            # For each object nearby, check if relevant and store.
            for obj in self.nearby_obj.objects:
                bool_rel, rel_pos, dist = relevant_filter(
                    self.ego_odom.pose.pose.position.x,
                    self.ego_odom.pose.pose.position.y, yaw, obj)

                if bool_rel:
                    relevant_msg.objects.append(obj)

                    if rel_pos == 1:
                        if dist < ahead_distance:
                            ahead_distance = dist
                            front_closest_obj = obj
                    else:
                        if dist < behind_distance:
                            behind_distance = dist
                            behind_closest_obj = obj

            # Visualization of all relevant objects
            color_relevant = ColorRGBA()
            color_relevant.r = 0
            color_relevant.g = 0
            color_relevant.b = 1
            color_relevant.a = 0.5
            self.viz_cars(relevant_msg.objects, header, color_relevant,
                          self.marker_pub)

            # Determine the current opponent. Default to closest relevant front
            # object, then closest relevant behind object, otherwise create
            # ghost opponent far from the circle.
            if front_closest_obj:
                ado_object = front_closest_obj
            elif behind_closest_obj:
                ado_object = behind_closest_obj
            else:
                ado_object = Object()
                ado_object.header.stamp = rospy.Time.now()
                ado_object.header.frame_id = "map"
                ado_object.pose.position.x = -5.5
                ado_object.pose.position.y = 170
                ado_object.pose.position.z = 0
                ado_object.pose.orientation.x = 0
                ado_object.pose.orientation.y = 0
                ado_object.pose.orientation.z = 0
                ado_object.pose.orientation.w = 1
                ado_object.twist.linear.x = 0
                ado_object.twist.linear.y = 0
                ado_object.twist.linear.z = 0

            ado_odom = Odometry()
            ado_odom.header.stamp = rospy.Time.now()
            ado_odom.header.frame_id = "map"
            ado_odom.child_frame_id = "ado"
            ado_odom.pose.pose = ado_object.pose
            ado_odom.twist.twist = ado_object.twist

            self.opp_odom_pub.publish(ado_odom)

            # Visualization of current opponent
            color_opp = ColorRGBA()
            color_opp.r = 1
            color_opp.g = 0
            color_opp.b = 0
            color_opp.a = 1
            self.viz_cars([ado_object], header, color_opp, self.ado_marker_pub)