コード例 #1
0
 def plan_to(self, pose):
     """Plan a path to the given pose using A*."""
     x_min = self.snap_to_grid((-self.plan_horizon, -self.plan_horizon))
     x_max = self.snap_to_grid((self.plan_horizon, self.plan_horizon))
     x_i = nearest_free((self.x, self.y), self.occupancy_strict,
                        self.plan_resolution)
     x_g = nearest_free((pose[0], pose[1]), self.occupancy_strict,
                        self.plan_resolution)
     publish_marker("goal", (x_g[0], x_g[1]), 100, (0, 0, 1))
     problem = AStar(x_min, x_max, x_i, x_g, self.occupancy_strict,
                     self.occupancy, self.plan_resolution)
     success = problem.solve()
     if not success:
         return None
     return problem
コード例 #2
0
    def replan(self):
        """
        loads goal into pose controller
        runs planner based on current pose
        if plan long enough to track:
            smooths resulting traj, loads it into traj_controller
            sets self.current_plan_start_time
            sets mode to ALIGN
        else:
            sets mode to PARK
        """
        # Make sure we have a map
        if not self.occupancy:
            rospy.loginfo(
                "Navigator: replanning canceled, waiting for occupancy map.")
            self.switch_mode(Mode.IDLE)
            return

        # Attempt to plan a path
        state_min = self.snap_to_grid((-self.plan_horizon, -self.plan_horizon))
        state_max = self.snap_to_grid((self.plan_horizon, self.plan_horizon))
        x_init = self.snap_to_grid((self.x, self.y))
        self.plan_start = x_init
        x_goal = self.snap_to_grid((self.x_g, self.y_g))
        problem = AStar(state_min, state_max, x_init, x_goal, self.occupancy,
                        self.plan_resolution)

        rospy.loginfo("Navigator: computing navigation plan")
        success = problem.solve()
        if not success:
            rospy.loginfo("Planning failed")
            return
        rospy.loginfo("Planning Succeeded")

        planned_path = problem.path

        # Check whether path is too short
        if len(planned_path) < 4:
            rospy.loginfo("Path too short to track")
            self.switch_mode(Mode.PARK)
            return

        # Smooth and generate a trajectory
        traj_new, t_new = compute_smoothed_traj(planned_path, self.v_des,
                                                self.spline_alpha,
                                                self.traj_dt)

        # If currently tracking a trajectory, check whether new trajectory will take more time to follow
        if self.mode == Mode.TRACK:
            t_remaining_curr = self.current_plan_duration - self.get_current_plan_time(
            )

            # Estimate duration of new trajectory
            th_init_new = traj_new[0, 2]
            th_err = wrapToPi(th_init_new - self.theta)
            t_init_align = abs(th_err / self.om_max)
            t_remaining_new = t_init_align + t_new[-1]

            if t_remaining_new > t_remaining_curr:
                rospy.loginfo(
                    "New plan rejected (longer duration than current plan)")
                self.publish_smoothed_path(traj_new,
                                           self.nav_smoothed_path_rej_pub)
                return

        # Otherwise follow the new plan
        self.publish_planned_path(planned_path, self.nav_planned_path_pub)
        self.publish_smoothed_path(traj_new, self.nav_smoothed_path_pub)

        self.pose_controller.load_goal(self.x_g, self.y_g, self.theta_g)
        self.traj_controller.load_traj(t_new, traj_new)

        self.current_plan_start_time = rospy.get_rostime()
        self.current_plan_duration = t_new[-1]

        self.th_init = traj_new[0, 2]
        self.heading_controller.load_goal(self.th_init)

        if not self.aligned():
            rospy.loginfo("Not aligned with start direction")
            self.switch_mode(Mode.ALIGN)
            return

        rospy.loginfo("Ready to track")
        self.switch_mode(Mode.TRACK)
コード例 #3
0
    def replan(self, force=False):
        """
        loads goal into pose controller
        runs planner based on current pose
        if plan long enough to track:
            smooths resulting traj, loads it into traj_controller
            sets self.current_plan_start_time
            sets mode to ALIGN
        else:
            sets mode to PARK
        """
        # Make sure we have a map
        if not self.occupancy:
            rospy.loginfo(
                "Navigator: replanning canceled, waiting for occupancy map.")
            return

        # Check if the goal is free
        if not self.x_g or not self.y_g or not self.theta_g:
            rospy.loginfo("No goal.")
            return

        X_g = (self.x_g, self.y_g)

        # Before planning a path, load goal pose
        self.pose_controller.load_goal(X_g[0], X_g[1], self.theta_g)

        # Attempt to plan a path
        state_min = self.snap_to_grid((-self.plan_horizon, -self.plan_horizon))
        state_max = self.snap_to_grid((self.plan_horizon, self.plan_horizon))
        x_init = nearest_free((self.x, self.y), self.occupancy_strict,
                              self.plan_resolution)
        self.plan_start = x_init
        problem = AStar(state_min, state_max, x_init, X_g,
                        self.occupancy_strict, self.occupancy,
                        self.plan_resolution)
        success = problem.solve()
        if not success:
            if self.prev_goal != X_g:
                self.error_count = 0
            self.prev_goal = X_g
            self.error_count += 1
            return
        planned_path = problem.path

        # Check whether path is too short
        if len(planned_path) < 4:
            self.switch_mode(Mode.PARK)
            return

        # Smooth and generate a trajectory
        traj_new, t_new = compute_smoothed_traj(planned_path, self.v_des,
                                                self.spline_alpha,
                                                self.traj_dt)

        # If currently tracking a trajectory, check whether new trajectory will take more time to follow
        if self.mode == Mode.TRACK:
            t_remaining_curr = self.current_plan_duration - self.get_current_plan_time(
            )

            # Estimate duration of new trajectory
            th_init_new = traj_new[0, 2]
            th_err = wrapToPi(th_init_new - self.theta)
            t_init_align = abs(th_err / self.om_max)
            t_remaining_new = t_init_align + t_new[-1]

            if t_remaining_new > t_remaining_curr and not (self.new_goal
                                                           or force):
                self._publish_smoothed_path(traj_new,
                                            self.nav_smoothed_path_rej_pub)
                return

        # Otherwise follow the new plan
        self.publish_planned_path(planned_path, self.nav_planned_path_pub)
        self._publish_smoothed_path(traj_new, self.nav_smoothed_path_pub)

        self.traj_controller.load_traj(t_new, traj_new)

        self.current_plan_start_time = rospy.get_rostime()
        self.current_plan_duration = t_new[-1]
        self.new_goal = False

        self.th_init = traj_new[0, 2]
        self.heading_controller.load_goal(self.th_init)

        if not self.aligned():
            self.switch_mode(Mode.ALIGN)
            return

        self.switch_mode(Mode.TRACK)
コード例 #4
0
    def run_navigator(self):
        """ computes a path from current state to goal state using A* and sends it to the path controller """

        # makes sure we have a location
        try:
            (translation, rotation) = self.trans_listener.lookupTransform(
                '/map', '/base_footprint', rospy.Time(0))
            self.x = translation[0]
            self.y = translation[1]
            euler = tf.transformations.euler_from_quaternion(rotation)
            self.theta = euler[2]
        except (tf.LookupException, tf.ConnectivityException,
                tf.ExtrapolationException):
            print("tf exception in run navigator")
            self.current_plan = []
            return

        # makes sure we have a map
        if not self.occupancy:
            self.current_plan = []
            print("no map")
            return

        # if close to the goal, use the pose_controller instead
        if self.close_to_end_location():
            rospy.loginfo("Navigator: Close to nav goal using pose controller")
            pose_g_msg = Pose2D()
            pose_g_msg.x = self.x_g
            pose_g_msg.y = self.y_g
            pose_g_msg.theta = self.theta_g
            self.nav_pose_pub.publish(pose_g_msg)
            self.current_plan = []
            self.V_prev = 0
            return

        # if there is no plan, we are far from the start of the plan,
        # or the occupancy grid has been updated, update the current plan
        if len(self.current_plan) == 0 or not (
                self.close_to_start_location()) or self.occupancy_updated:

            # use A* to compute new plan
            state_min = self.snap_to_grid(
                (-self.plan_horizon, -self.plan_horizon))
            state_max = self.snap_to_grid(
                (self.plan_horizon, self.plan_horizon))
            x_init = self.snap_to_grid((self.x, self.y))
            x_goal = self.snap_to_grid((self.x_g, self.y_g))
            problem = AStar(state_min, state_max, x_init, x_goal,
                            self.occupancy, self.plan_resolution)

            rospy.loginfo("Navigator: Computing navigation plan")
            if problem.solve():
                if len(problem.path) > 3:
                    # cubic spline interpolation requires 4 points
                    self.current_plan = problem.path
                    self.current_plan_start_time = rospy.get_rostime()
                    self.current_plan_start_loc = [self.x, self.y]
                    self.occupancy_updated = False

                    # publish plan for visualization
                    path_msg = Path()
                    path_msg.header.frame_id = 'map'
                    for state in self.current_plan:
                        pose_st = PoseStamped()
                        pose_st.pose.position.x = state[0]
                        pose_st.pose.position.y = state[1]
                        pose_st.pose.orientation.w = 1
                        pose_st.header.frame_id = 'map'
                        path_msg.poses.append(pose_st)
                    self.nav_path_pub.publish(path_msg)

                    path_t = [0]
                    path_x = [self.current_plan[0][0]]
                    path_y = [self.current_plan[0][1]]
                    for i in range(len(self.current_plan) - 1):
                        dx = self.current_plan[i +
                                               1][0] - self.current_plan[i][0]
                        dy = self.current_plan[i +
                                               1][1] - self.current_plan[i][1]
                        path_t.append(path_t[i] +
                                      np.sqrt(dx**2 + dy**2) / V_DES)
                        path_x.append(self.current_plan[i + 1][0])
                        path_y.append(self.current_plan[i + 1][1])

                    # interpolate the path with cubic spline
                    self.path_x_spline = scipy.interpolate.splrep(path_t,
                                                                  path_x,
                                                                  k=3,
                                                                  s=SMOOTH)
                    self.path_y_spline = scipy.interpolate.splrep(path_t,
                                                                  path_y,
                                                                  k=3,
                                                                  s=SMOOTH)
                    self.path_tf = path_t[-1]

                    # to inspect the interpolation and smoothing
                    # t_test = np.linspace(path_t[0],path_t[-1],1000)
                    # plt.plot(path_t,path_x,'ro')
                    # plt.plot(t_test,scipy.interpolate.splev(t_test,self.path_x_spline,der=0))
                    # plt.plot(path_t,path_y,'bo')
                    # plt.plot(t_test,scipy.interpolate.splev(t_test,self.path_y_spline,der=0))
                    # plt.show()
                else:
                    rospy.logwarn("Navigator: Path too short, not updating")
            else:
                rospy.logwarn("Navigator: Could not find path")
                self.current_plan = []

        # if we have a path, execute it (we need at least 3 points for this controller)
        if len(self.current_plan) > 3:

            # if currently not moving, first line up with the plan
            if self.V_prev == 0:
                theta_init = np.arctan2(
                    self.current_plan[1][1] - self.current_plan[0][1],
                    self.current_plan[1][0] - self.current_plan[0][0])
                theta_err = theta_init - self.theta
                if abs(theta_err) > THETA_START_THRESH:
                    cmd_msg = Twist()
                    cmd_msg.linear.x = 0
                    cmd_msg.angular.z = np.sign(theta_err) * np.min(
                        [THETA_START_P * np.abs(theta_err), W_MAX])
                    self.nav_vel_pub.publish(cmd_msg)
                    return

            # compute the "current" time along the path execution
            t = (rospy.get_rostime() - self.current_plan_start_time).to_sec()
            t = max(0.0, t)
            t = min(t, self.path_tf)

            x_d = scipy.interpolate.splev(t, self.path_x_spline, der=0)
            y_d = scipy.interpolate.splev(t, self.path_y_spline, der=0)
            xd_d = scipy.interpolate.splev(t, self.path_x_spline, der=1)
            yd_d = scipy.interpolate.splev(t, self.path_y_spline, der=1)
            xdd_d = scipy.interpolate.splev(t, self.path_x_spline, der=2)
            ydd_d = scipy.interpolate.splev(t, self.path_y_spline, der=2)

            # publish current desired x and y for visualization only
            pathsp_msg = PoseStamped()
            pathsp_msg.header.frame_id = 'map'
            pathsp_msg.pose.position.x = x_d
            pathsp_msg.pose.position.y = y_d
            theta_d = np.arctan2(yd_d, xd_d)
            quat_d = tf.transformations.quaternion_from_euler(0, 0, theta_d)
            pathsp_msg.pose.orientation.x = quat_d[0]
            pathsp_msg.pose.orientation.y = quat_d[1]
            pathsp_msg.pose.orientation.z = quat_d[2]
            pathsp_msg.pose.orientation.w = quat_d[3]
            self.nav_pathsp_pub.publish(pathsp_msg)

            if self.V_prev <= 0.0001:
                self.V_prev = linalg.norm([xd_d, yd_d])

            dt = (rospy.get_rostime() - self.V_prev_t).to_sec()

            xd = self.V_prev * np.cos(self.theta)
            yd = self.V_prev * np.sin(self.theta)

            u = np.array([
                xdd_d + KPX * (x_d - self.x) + KDX * (xd_d - xd),
                ydd_d + KPY * (y_d - self.y) + KDY * (yd_d - yd)
            ])
            J = np.array(
                [[np.cos(self.theta), -self.V_prev * np.sin(self.theta)],
                 [np.sin(self.theta), self.V_prev * np.cos(self.theta)]])
            a, om = linalg.solve(J, u)
            V = self.V_prev + a * dt

            # apply saturation limits
            cmd_x_dot = np.sign(V) * min(V_MAX, np.abs(V))
            cmd_theta_dot = np.sign(om) * min(W_MAX, np.abs(om))
        elif len(self.current_plan) > 0:
            # using the pose controller for paths too short
            # just send the next point
            pose_g_msg = Pose2D()
            pose_g_msg.x = self.current_plan[0][0]
            pose_g_msg.y = self.current_plan[0][1]
            if len(self.current_plan) > 1:
                pose_g_msg.theta = np.arctan2(
                    self.current_plan[1][1] - self.current_plan[0][1],
                    self.current_plan[1][0] - self.current_plan[0][0])
            else:
                pose_g_msg.theta = self.theta_g
            rospy.loginfo(
                "Navigator: Using Pose Controller For Paths Too Short")
            self.nav_pose_pub.publish(pose_g_msg)
            return
        else:
            # just stop
            print("Going backward to find new path")
            cmd_x_dot = BACKWARD_RECOVERY_SPEED
            cmd_theta_dot = 0

        # saving the last velocity for the controller
        self.V_prev = cmd_x_dot
        self.V_prev_t = rospy.get_rostime()

        cmd_msg = Twist()
        cmd_msg.linear.x = cmd_x_dot
        cmd_msg.angular.z = cmd_theta_dot
        self.nav_vel_pub.publish(cmd_msg)
コード例 #5
0
    def execute(self, userdata):
        rospy.loginfo('Executing state PLANNING')
        ci_outcome = check_inputs(userdata)
        if ci_outcome:
            return ci_outcome

        if not userdata.nav_in.occupancy:
            rospy.loginfo(
                "Navigator: replanning canceled, waiting for occupancy map.")
            return 'failure'

        # Attempt to plan a path
        state_min = userdata.nav_out.snap_to_grid(
            (-userdata.nav_in.plan_horizon, -userdata.nav_in.plan_horizon))
        state_max = userdata.nav_out.snap_to_grid(
            (userdata.nav_in.plan_horizon, userdata.nav_in.plan_horizon))
        x_init = userdata.nav_out.snap_to_grid(
            (userdata.nav_in.x, userdata.nav_in.y))
        userdata.nav_out.plan_start = x_init
        x_goal = userdata.nav_out.snap_to_grid(
            (userdata.nav_in.x_g, userdata.nav_in.y_g))
        problem = AStar(state_min, state_max, x_init, x_goal,
                        userdata.nav_out.occupancy,
                        userdata.nav_out.plan_resolution)

        rospy.loginfo("Navigator: computing navigation plan")
        success = problem.solve()
        if not success:
            rospy.loginfo("Planning failed")
            return 'failure'
        rospy.loginfo("Planning Succeeded")

        planned_path = problem.path

        # Check whether path is too short
        if len(planned_path) < 4:
            rospy.loginfo("Path too short to track")
            return 'failure'

        # Smooth and generate a trajectory
        traj_new, t_new = compute_smoothed_traj(planned_path,
                                                userdata.nav_in.v_des,
                                                userdata.nav_in.spline_alpha,
                                                userdata.nav_in.traj_dt)

        # Otherwise follow the new plan
        userdata.nav_out.publish_planned_path(
            planned_path, userdata.nav_out.nav_planned_path_pub)
        userdata.nav_out.publish_smoothed_path(
            traj_new, userdata.nav_out.nav_smoothed_path_pub)

        userdata.nav_out.pose_controller.load_goal(userdata.nav_in.x_g,
                                                   userdata.nav_in.y_g,
                                                   userdata.nav_in.theta_g)
        userdata.nav_out.traj_controller.load_traj(t_new, traj_new)

        userdata.nav_out.current_plan_start_time = rospy.get_rostime()
        userdata.nav_out.current_plan_duration = t_new[-1]

        userdata.nav_out.th_init = traj_new[0, 2]
        userdata.nav_out.heading_controller.load_goal(traj_new[0, 2])

        return 'success'
コード例 #6
0
    def replan(self):
        """
        loads goal into pose controller
        runs planner based on current pose
        if plan long enough to track:
            smooths resulting traj, loads it into traj_controller
            sets self.current_plan_start_time
            sets mode to ALIGN
        else:
            sets mode to PARK
        """
        # Make sure we have a map
        if not self.occupancy:
            rospy.loginfo(
                "Navigator: replanning canceled, waiting for occupancy map.")
            self.switch_mode(Mode.IDLE)
            return

        # Attempt to plan a path
        state_min = self.snap_to_grid((-self.plan_horizon, -self.plan_horizon))
        state_max = self.snap_to_grid((self.plan_horizon, self.plan_horizon))
        x_init = self.snap_to_grid((self.x, self.y))
        self.plan_start = x_init
        x_goal = self.snap_to_grid((self.x_g, self.y_g))
        problem = AStar(state_min, state_max, x_init, x_goal, self.occupancy,
                        self.plan_resolution)

        rospy.loginfo("Navigator: computing navigation plan")

        success = problem.solve()
        if not success:
            rospy.loginfo("Planning failed")

            #tell squirtle we could not find a path
            msg = String()
            msg.data = "no_path"
            self.publish_squirtle.publish(msg)

            if self.mode == Mode.BACKING_UP:
                self.deflate_map()
                self.switch_mode(Mode.IDLE)
            return
        rospy.loginfo("Planning Succeeded")

        planned_path = problem.path

        # Check whether path is too short
        if self.at_goal():
            #check the stop flag and don't post 'at_goal' if set (or else Squirtle will get confused at stop signs)
            if not self.stop_flag:
                rospy.loginfo("Path already at goal pose")
                #tell squirtle we are at the goal
                msg = String()
                msg.data = "at_goal"
                self.publish_squirtle.publish(msg)
            self.switch_mode(Mode.IDLE)
            return
        elif len(planned_path) < 4:
            rospy.loginfo("Path too short to track")
            self.switch_mode(Mode.PARK)
            return

        # Smooth and generate a trajectory
        traj_new, t_new = compute_smoothed_traj(planned_path, self.v_des,
                                                self.spline_alpha,
                                                self.traj_dt)

        # If currently tracking a trajectory, check whether new trajectory will take more time to follow
        if self.mode == Mode.TRACK:
            t_remaining_curr = self.current_plan_duration - self.get_current_plan_time(
            )

            # Estimate duration of new trajectory
            th_init_new = traj_new[0, 2]
            th_err = wrapToPi(th_init_new - self.theta)
            t_init_align = abs(th_err / self.om_max)
            t_remaining_new = t_init_align + t_new[-1]

            if t_remaining_new > t_remaining_curr:
                rospy.loginfo(
                    "New plan rejected (longer duration than current plan)")
                self.publish_smoothed_path(traj_new,
                                           self.nav_smoothed_path_rej_pub)
                return

        # Otherwise follow the new plan
        self.publish_planned_path(planned_path, self.nav_planned_path_pub)
        self.publish_smoothed_path(traj_new, self.nav_smoothed_path_pub)

        self.pose_controller.load_goal(self.x_g, self.y_g, self.theta_g)
        self.traj_controller.load_traj(t_new, traj_new)

        self.current_plan_start_time = rospy.get_rostime()
        self.current_plan_duration = t_new[-1]

        self.th_init = traj_new[0, 2]
        self.heading_controller.load_goal(self.th_init)

        if not self.aligned():
            rospy.loginfo("Not aligned with start direction")
            if self.mode == Mode.BACKING_UP:
                self.switch_mode(Mode.INFLATE_ALIGN)
            else:
                self.switch_mode(Mode.ALIGN)
            return

        if self.mode == Mode.BACKING_UP:  #what happens if we want to nav to new goal here...?
            self.start_timer(INFLATE_TIME)
            self.switch_mode(Mode.INFLATE)
        else:
            rospy.loginfo("Ready to track")
            self.switch_mode(Mode.TRACK)
コード例 #7
0
    def replan(self):
        """
        loads goal into pose controller
        runs planner based on current pose
        if plan long enough to track:
            smooths resulting traj, loads it into traj_controller
            sets self.current_plan_start_time
            sets mode to ALIGN
        else:
            sets mode to PARK
        """
        # Make sure we have a map
        if not self.occupancy:
            rospy.loginfo(
                "Navigator: replanning canceled, waiting for occupancy map.")
            self.switch_mode(Mode.IDLE)
            return

        # Attempt to plan a path
        state_min = self.snap_to_grid((-self.plan_horizon, -self.plan_horizon))
        state_max = self.snap_to_grid((self.plan_horizon, self.plan_horizon))
        x_init = self.snap_to_grid((self.x, self.y))
        self.plan_start = x_init
        x_goal = self.snap_to_grid((self.x_g, self.y_g))
        astar_problem = AStar(state_min, state_max, x_init, x_goal,
                              self.occupancy, self.plan_resolution)

        rrt_problem = GeometricRRTConnect(state_min, state_max, x_init, x_goal,
                                          self.occupancy, self.plan_resolution)

        rospy.loginfo("Navigator: computing navigation plan")
        rospy.loginfo("Current mode: " + str(self.mode))

        astar_success = astar_problem.solve()
        astar_path = astar_problem.path

        rrt_success = rrt_problem.solve()
        rrt_path = rrt_problem.path

        success = (astar_success or rrt_success)
        if not success:
            rospy.loginfo("Planning failed")
            return
        else:
            rospy.loginfo("Planning Succeeded")

        if astar_success:
            traj_new_astar, t_new_astar, path_length_astar = compute_smoothed_traj(
                astar_path, self.v_des, self.spline_alpha, self.traj_dt)
        else:
            path_length_astar = np.Inf

        if rrt_success:
            traj_new_rrt, t_new_rrt, path_length_rrt = compute_smoothed_traj(
                rrt_path, self.v_des, self.spline_alpha, self.traj_dt)
        else:
            path_length_rrt = np.Inf

        if path_length_astar <= path_length_rrt:
            traj_new = traj_new_astar
            t_new = t_new_astar
            planned_path = astar_path
            rospy.loginfo("AStar Gave Shortest Path")
        else:
            traj_new = traj_new_rrt
            t_new = t_new_rrt
            planned_path = rrt_path
            rospy.loginfo("RRT Gave Shortest Path")

        # load goal into pose controller
        self.pose_controller.load_goal(self.x_g, self.y_g, self.theta_g)

        # Check whether path is too short
        '''
        if len(planned_path) < 4:
            rospy.loginfo("Path too short to track")
            self.switch_mode(Mode.PARK)
            return
        '''
        # Smooth and generate a trajectory

        # If currently tracking a trajectory, check whether new trajectory will take more time to follow
        if self.mode == Mode.TRACK:
            t_remaining_curr = self.current_plan_duration - self.get_current_plan_time(
            )

            # Estimate duration of new trajectory
            th_init_new = traj_new[0, 2]
            th_err = wrapToPi(th_init_new - self.theta)
            t_init_align = abs(th_err / self.om_max)
            t_remaining_new = t_init_align + t_new[-1]

            if t_remaining_new > t_remaining_curr:
                rospy.loginfo(
                    "New plan rejected (longer duration than current plan)")
                self.publish_smoothed_path(traj_new,
                                           self.nav_smoothed_path_rej_pub)
                return

        # Otherwise follow the new plan
        self.publish_planned_path(planned_path, self.nav_planned_path_pub)
        self.publish_smoothed_path(traj_new, self.nav_smoothed_path_pub)

        self.traj_controller.load_traj(t_new, traj_new)

        self.current_plan_start_time = rospy.get_rostime()
        self.current_plan_duration = t_new[-1]

        self.th_init = traj_new[0, 2]
        self.heading_controller.load_goal(self.th_init)

        if (not self.aligned() and self.mode != Mode.CROSS and self.mode != Mode.STOP) \
            or (self.mode == Mode.IDLE):
            rospy.loginfo("Not aligned with start direction")
            self.switch_mode(Mode.ALIGN)
            return