diff --git a/CMakeLists.txt b/CMakeLists.txt
index f12c25078f5a0d12f815e031cb82fd225e70ea0b..d8eeffb30c659f8bc8eca14a2553f9db327cc817 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,8 @@ find_package(Eigen3 REQUIRED)
 add_definitions(${EIGEN_DEFINITIONS})
 
 #find_package(iriutils REQUIRED)
+find_package(iriutils REQUIRED)
+find_package(autonomous_driving_tools REQUIRED)
 
 # ******************************************************************** 
 #           Add topic, service and action definition here
@@ -80,9 +82,11 @@ include_directories(include)
 include_directories(${catkin_INCLUDE_DIRS})
 include_directories(${EIGEN3_INCLUDE_DIRS})
 #include_directories(${iriutils_INCLUDE_DIR})
+include_directories(${iriutils_INCLUDE_DIR})
+include_directories(${autonomous_driving_tools_INCLUDE_DIR})
 
 ## Declare a cpp library
-add_library(${PROJECT_NAME} src/ackermann_odom_helper.cpp src/ackermann_planner_util.cpp src/ackermann_planner_ros src/ackermann_planner.cpp src/ackermann_trajectory_generator.cpp src/heading_cost_function.cpp src/ackermann_trajectory_search.cpp)
+add_library(${PROJECT_NAME} src/ackermann_odom_helper.cpp src/ackermann_planner_util.cpp src/ackermann_planner_ros src/ackermann_planner.cpp src/ackermann_trajectory_generator.cpp src/heading_cost_function.cpp src/ackermann_trajectory_search.cpp src/ackermann_spline_generator.cpp)
 
 ## Declare a cpp executable
 # add_executable(${PROJECT_NAME} <list of source files>)
@@ -92,6 +96,8 @@ add_library(${PROJECT_NAME} src/ackermann_odom_helper.cpp src/ackermann_planner_
 # ******************************************************************** 
 target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})
 #target_link_libraries(${PROJECT_NAME} ${iriutils_LIBRARIES})
+target_link_libraries(${PROJECT_NAME} ${iriutils_LIBRARIES})
+target_link_libraries(${PROJECT_NAME} ${autonomous_driving_tools_LIBRARIES})
 
 # ******************************************************************** 
 #               Add message headers dependencies 
diff --git a/cfg/AckermannLocalPlanner.cfg b/cfg/AckermannLocalPlanner.cfg
index 97309a7c621f8b19014c84086f56dc87c04c7bbc..52e2a1c6d36e34a2752b9879bd11d5d427c6200e 100755
--- a/cfg/AckermannLocalPlanner.cfg
+++ b/cfg/AckermannLocalPlanner.cfg
@@ -40,68 +40,77 @@ from dynamic_reconfigure.parameter_generator_catkin import *
 
 gen = ParameterGenerator()
 
-#       Name                       Type       Reconfiguration level            Description                                                                                     Default   Min   Max
-gen.add("max_sim_time",            double_t,  0, "The amount of time to roll trajectories out for in seconds",                                                                 10, 0,    20)
-gen.add("min_sim_time",            double_t,  0, "The amount of time to roll trajectories out for in seconds",                                                                 1.7, 0,   10)
-gen.add("sim_granularity",         double_t,  0, "The granularity with which to check for collisions along each trajectory in meters",                                         0.025,    0)
-gen.add("angular_sim_granularity", double_t,  0, "The granularity with which to check for collisions for rotations in radians",                                                0.1,      0)
-
-gen.add("path_distance_bias",      double_t,  0, "The weight for the path distance part of the cost function",                                                                 32.0,     0.0)
-gen.add("goal_distance_bias",      double_t,  0, "The weight for the goal distance part of the cost function",                                                                 24.0,     0.0)
-gen.add("occdist_scale",           double_t,  0, "The weight for the obstacle distance part of the cost function",                                                             0.01,     0.0)
-
-gen.add("stop_time_buffer",        double_t,  0, "The amount of time that the robot must stop before a collision in order for a trajectory to be considered valid in seconds", 0.2,      0)
-gen.add("oscillation_reset_dist",  double_t,  0, "The distance the robot must travel before oscillation flags are reset, in meters",                                           0.05,     0)
-gen.add("oscillation_reset_angle", double_t,  0, "The angle the robot must turn before oscillation flags are reset, in radians",                                               0.2,      0)
-
-gen.add("forward_point_distance",  double_t,  0, "The distance from the center point of the robot to place an additional scoring point, in meters",                            0.325)
-
-gen.add("scaling_speed",           double_t,  0, "The absolute value of the velocity at which to start scaling the robot's footprint, in m/s",                                 0.25,     0)
-gen.add("max_scaling_factor",      double_t,  0, "The maximum factor to scale the robot's footprint by",                                                                       0.2,      0)
-
-gen.add("trans_vel_samples",       int_t,     0, "The number of samples to use when exploring the x velocity space",                                                           3, 1)
-gen.add("steer_angle_samples",     int_t,     0, "The number of samples to use when exploring the steer angle space",                                                          10, 1)
-gen.add("angular_vel_samples",     int_t,     0, "The number of samples to use when exploring the angular velocity space",                                                     10, 1)
-gen.add("use_steer_angle_cmd",     bool_t,    0, "Whether to use the steer angle or the angular velocity.",                                                                    False)
-gen.add("invert_steer_angle_cmd",  bool_t,    0, "Whether to use the invert the steer angle command or not.",                                                                  False)
-gen.add("use_stopped_steering",    bool_t,    0, "Whether to allow steering while stopped or not.",                                                                            True)
-gen.add("stopped_steering_angle_threshold", double_t,  0, "Angle difference threshold (rad) to perform steering change while stopped.",                                              0.05, 0)
-
-gen.add("use_stuck_check",       bool_t,    0, "Whether to allow robot stuck check or not.",                                                                               True)
-gen.add("stuck_check_vel_threshold", double_t,  0, "Velocity threshold (m/s) to consider robot stuck.",                                              0.05, 0)
-gen.add("stuck_check_max_occurrences", int_t,  0, "Max number of stuck occurrences allowed until moving to next segment or replaning.",                                              10, 0)
-
-gen.add("prune_plan",              bool_t,    0, "Start following closest point of global plan, not first point (if different).",                                              False)
-gen.add("xy_goal_tolerance",       double_t,  0, "Within what maximum distance we consider the robot to be in goal",                                                           0.1)
-gen.add("yaw_goal_tolerance",      double_t,  0, "Within what maximum angle difference we consider the robot to face goal direction",                                          0.1)
-gen.add("trans_stopped_vel",       double_t,  0, "Below what maximum velocity we consider the robot to be stopped in translation",                                             0.1)
-gen.add("rot_stopped_vel",         double_t,  0, "Below what maximum rotation velocity we consider the robot to be stopped in rotation",                                       0.1)
-
-gen.add("restore_defaults",        bool_t,    0, "Restore to the original configuration.",                                                                                     False)
-
-gen.add("max_trans_vel",           double_t,  0, "maximum translational speed",                                                                                                0.3,      0,     20)
-gen.add("min_trans_vel",           double_t,  0, "minimum translational speed",                                                                                                -0.3,     -20,   0)
-gen.add("max_trans_acc",           double_t,  0, "maximum translational acceleration",                                                                                         1.0,      0,     20)
-gen.add("max_steer_angle",         double_t,  0, "maximum steer angle",                                                                                                        0.45,     0,     0.54)
-gen.add("min_steer_angle",         double_t,  0, "minimum steer angle",                                                                                                        -0.45,    -0.54, 0)
-gen.add("max_steer_vel",           double_t,  0, "maximum steer speed",                                                                                                        1.0,      0,     2)
-gen.add("min_steer_vel",           double_t,  0, "minimum steer speed",                                                                                                        -1.0,     -2,    0)
-gen.add("max_steer_acc",           double_t,  0, "maximum steer acceleration",                                                                                                 0.36,     0,     5)
-gen.add("max_angular_vel",         double_t,  0, "maximum angular speed",                                                                                                      0.3,      0,     20)
-gen.add("min_angular_vel",         double_t,  0, "minimum angular speed",                                                                                                      -0.3,     -20,   0)
-gen.add("axis_distance",           double_t,  0, "distance between axes",                                                                                                      1.65,     -2.0,  2)
-gen.add("wheel_distance",          double_t,  0, "distance between wheels",                                                                                                    1.2,      0,     2)
-gen.add("wheel_radius",            double_t,  0, "Wheel diameter",                                                                                                             0.436,    0,     2)
-gen.add("use_trans_vel_deadzone",  bool_t,    0, "Whether to use a deadzone in the translational velocity or not",                                                             False)
-gen.add("trans_vel_deadzone",      double_t,  0, "Translatinal velocity minimum value",                                                                                        0.1,      0.01,  1.0)
-gen.add("split_ignore_length",     double_t,  0, "Paths segments under this length will be ignored",                                                                           1.0,      0.0,   2.0)
-gen.add("cmd_vel_avg",             int_t,     0, "Number of cmd_vel to average",                                                                                               1,        1,     20)
-gen.add("odom_avg",                int_t,     0, "Number of odom to average",                                                                                                  1,        1,     20)
-
-gen.add("planner_patience",        int_t,     0, "number of impossible paths before replanning",                                                                               2,        0,     10)
-
-gen.add("hdiff_scale",             double_t,  0, "The weight for the heading distance part of the cost function",                                                              1.0,      0,     500)
-gen.add("heading_points",          int_t,     0, "The number of points to check the heading",                                                                                  8,        1,     64)
+trajectory = gen.add_group("trajectory")
+costs = gen.add_group("costs")
+planner = gen.add_group("planner")
+ackermann = gen.add_group("ackermann")
+splines = gen.add_group("splines")
 
+#       Name                       Type       Reconfiguration level            Description                                                                                     Default   Min   Max
+planner.add("use_stopped_steering",    bool_t,    0, "Whether to allow steering while stopped or not.",                                                  True)
+planner.add("stopped_steering_angle_threshold", double_t,  0, "Angle difference threshold (rad) to perform steering change while stopped.",              0.05, 0)
+planner.add("use_stuck_check",       bool_t,    0, "Whether to allow robot stuck check or not.",                                                         True)
+planner.add("stuck_check_vel_threshold", double_t,  0, "Velocity threshold (m/s) to consider robot stuck.",                                              0.05, 0)
+planner.add("stuck_check_max_occurrences", int_t,  0, "Max number of stuck occurrences allowed until moving to next segment or replaning.",              10, 0)
+planner.add("prune_plan",              bool_t,    0, "Start following closest point of global plan, not first point (if different).",                    False)
+planner.add("xy_goal_tolerance",       double_t,  0, "Within what maximum distance we consider the robot to be in goal",                                 0.1)
+planner.add("yaw_goal_tolerance",      double_t,  0, "Within what maximum angle difference we consider the robot to face goal direction",                0.1)
+planner.add("trans_stopped_vel",       double_t,  0, "Below what maximum velocity we consider the robot to be stopped in translation",                   0.1)
+planner.add("rot_stopped_vel",         double_t,  0, "Below what maximum rotation velocity we consider the robot to be stopped in rotation",             0.1)
+planner.add("use_trans_vel_deadzone",  bool_t,    0, "Whether to use a deadzone in the translational velocity or not",                                   False)
+planner.add("trans_vel_deadzone",      double_t,  0, "Translatinal velocity minimum value",                                                              0.1,      0.01,  1.0)
+planner.add("cmd_vel_avg",             int_t,     0, "Number of cmd_vel to average",                                                                     1,        1,     20)
+planner.add("odom_avg",                int_t,     0, "Number of odom to average",                                                                        1,        1,     20)
+planner.add("planner_patience",        int_t,     0, "number of impossible paths before replanning",                                                     2,        0,     10)
+planner.add("check_path_r_inc",         double_t,  0, "Radius increment robot's one when checking the path to get last safe point",                       0.1,      0.0,   2.0)
+
+costs.add("path_distance_bias",      double_t,  0, "The weight for the path distance part of the cost function",                                         32.0,     0.0)
+costs.add("goal_distance_bias",      double_t,  0, "The weight for the goal distance part of the cost function",                                         24.0,     0.0)
+costs.add("occdist_scale",           double_t,  0, "The weight for the obstacle distance part of the cost function",                                     0.01,     0.0)
+costs.add("oscillation_reset_dist",  double_t,  0, "The distance the robot must travel before oscillation flags are reset, in meters",                   0.05,     0)
+costs.add("oscillation_reset_angle", double_t,  0, "The angle the robot must turn before oscillation flags are reset, in radians",                       0.2,      0)
+costs.add("scaling_speed",           double_t,  0, "The absolute value of the velocity at which to start scaling the robot's footprint, in m/s",         0.25,     0)
+costs.add("max_scaling_factor",      double_t,  0, "The maximum factor to scale the robot's footprint by",                                               0.2,      0)
+costs.add("hdiff_scale",             double_t,  0, "The weight for the heading distance part of the cost function",                                      1.0,      0,     500)
+costs.add("heading_points",          int_t,     0, "The number of points to check the heading",                                                          8,        1,     64)
+
+trajectory.add("max_sim_time",            double_t,  0, "The amount of time to roll trajectories out for in seconds",                                    10, 0,    20)
+trajectory.add("min_sim_time",            double_t,  0, "The amount of time to roll trajectories out for in seconds",                                    1.7, 0,   10)
+trajectory.add("sim_granularity",         double_t,  0, "The granularity with which to check for collisions along each trajectory in meters",            0.025,    0)
+trajectory.add("max_trans_vel",           double_t,  0, "maximum translational speed",                                                                   0.3,      0,     20)
+trajectory.add("min_trans_vel",           double_t,  0, "minimum translational speed",                                                                   -0.3,     -20,   0)
+trajectory.add("max_trans_acc",           double_t,  0, "maximum translational acceleration",                                                            1.0,      0,     20)
+trajectory.add("max_steer_angle",         double_t,  0, "maximum steer angle",                                                                           0.45,     0,     0.54)
+trajectory.add("min_steer_angle",         double_t,  0, "minimum steer angle",                                                                           -0.45,    -0.54, 0)
+trajectory.add("max_steer_vel",           double_t,  0, "maximum steer speed",                                                                           1.0,      0,     2)
+trajectory.add("min_steer_vel",           double_t,  0, "minimum steer speed",                                                                           -1.0,     -2,    0)
+trajectory.add("max_steer_acc",           double_t,  0, "maximum steer acceleration",                                                                    0.36,     0,     5)
+trajectory.add("max_angular_vel",         double_t,  0, "maximum angular speed",                                                                         0.3,      0,     20)
+trajectory.add("min_angular_vel",         double_t,  0, "minimum angular speed",                                                                         -0.3,     -20,   0)
+trajectory.add("max_curvature",           double_t,  0, "Maximum allowed curvature for trajectory generation",                                           2.0,     0.5,   10.0)
+trajectory.add("trans_vel_samples",       int_t,     0, "The number of samples to use when exploring the x velocity space",                                 3, 1)
+trajectory.add("steer_angle_samples",     int_t,     0, "The number of samples to use when exploring the steer angle space",                                10, 1)
+trajectory.add("angular_vel_samples",     int_t,     0, "The number of samples to use when exploring the angular velocity space",                           10, 1)
+
+ackermann.add("use_steer_angle_cmd",     bool_t,    0, "Whether to use the steer angle or the angular velocity.",                                        False)
+ackermann.add("invert_steer_angle_cmd",  bool_t,    0, "Whether to use the invert the steer angle command or not.",                                      False)
+ackermann.add("axis_distance",           double_t,  0, "distance between axes",                                                                          1.65,     -2.0,  2)
+ackermann.add("wheel_distance",          double_t,  0, "distance between wheels",                                                                        1.2,      0,     2)
+ackermann.add("wheel_radius",            double_t,  0, "Wheel diameter",                                                                                 0.436,    0,     2)
+ackermann.add("split_ignore_length",     double_t,  0, "Paths segments under this length will be ignored",                                               1.0,      0.0,   2.0)
+ackermann.add("comfort_lat_acc",         double_t,  0, "Comfort lateral acceleration",                                                                   3.0,      0.0,   10.0)
+
+splines.add("use_splines",               bool_t,    0, "Use splines to generate the trajectory candidates",                                              False)
+splines.add("n1_samples",                int_t,     0, "Number of samples for the N1 parameter of the spline",                                           10,1,100)
+splines.add("n2_samples",                int_t,     0, "Number of samples for the N2 parameter of the spline",                                           10,1,100)
+splines.add("n3_samples",                int_t,     0, "Number of samples for the N3 parameter of the spline",                                           1,1,100)
+splines.add("n4_samples",                int_t,     0, "Number of samples for the N4 parameter of the spline",                                           1,1,100)
+splines.add("dist_samples",              int_t,     0, "Number of distance samples for the current segment",                                             1,1,10)
+splines.add("min_segment_points",        int_t,     0, "Minimum number of points of each segment",                                                       10,1,100)
+splines.add("lateral_offset_gain",       double_t,  0, "Gain for the lateral offset steering correction",                                                0.1,0.001,10)
+splines.add("temp_horizon",              double_t,  0, "Future time to compute the control command",                                                     0.2,0.01,10)
+splines.add("goal_dist",                 double_t,  0, "Maximum distance to the goal to check for gaol finished",                                       2.0,0.01,10.0)
+
+gen.add("restore_defaults",        bool_t,    0, "Restore to the original configuration.",                                                               False)
 
 exit(gen.generate(PACKAGE, "AckermannLocalPlannerAlgorithm", "AckermannLocalPlanner"))
diff --git a/include/ackermann_odom_helper.h b/include/ackermann_odom_helper.h
index 8f09f7c3ff4b3a172b7879fe0345b073087be594..de57bcb7f93b43dff72216ef06535606dcbcb5d3 100644
--- a/include/ackermann_odom_helper.h
+++ b/include/ackermann_odom_helper.h
@@ -42,6 +42,7 @@
 #include <nav_msgs/Odometry.h>
 #include <ackermann_msgs/AckermannDriveStamped.h>
 #include <ackermann_msgs/AckermannDrive.h>
+#include <costmap_2d/costmap_2d_ros.h>
 #include <ros/ros.h>
 #include <boost/thread.hpp>
 
@@ -67,6 +68,7 @@ class AckermannOdomHelper
     void set_odom_topic(const std::string &odom_topic);
     void set_ackermann_topic(const std::string &ackermann_topic);
     void set_average_samples(int num_average_samples);
+    void set_costmap(costmap_2d::Costmap2DROS* costmap_ros);
 
     /** @brief Return the current odometry topic. */
     std::string get_odom_topic(void) const;
@@ -96,6 +98,7 @@ class AckermannOdomHelper
     ros::Subscriber odom_sub_;
     nav_msgs::Odometry base_odom_;
     boost::mutex odom_mutex_;
+    costmap_2d::Costmap2DROS* costmap_ros_;
 
     ros::Subscriber ackermann_sub_;
     std::vector<ackermann_msgs::AckermannDrive> ackermann_data_;
diff --git a/include/ackermann_planner.h b/include/ackermann_planner.h
index ba93e7247fd3de29f4e28551f19b0cf25a8b0b41..13cf62c303414b0ef1b181686341e23a765a885a 100644
--- a/include/ackermann_planner.h
+++ b/include/ackermann_planner.h
@@ -50,9 +50,9 @@
 #include <costmap_2d/costmap_2d.h>
 
 #include <base_local_planner/trajectory.h>
-#include <base_local_planner/local_planner_limits.h>
 #include <base_local_planner/local_planner_util.h>
 #include <ackermann_trajectory_generator.h>
+#include <ackermann_spline_generator.h>
 #include <ackermann_odom_helper.h>
 
 #include <base_local_planner/oscillation_cost_function.h>
@@ -88,15 +88,6 @@ class AckermannPlanner
      */
     void reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &cfg);
 
-    /**
-     * @brief  Check if a trajectory is legal for a position/velocity pair
-     * @param pos The robot's position
-     * @param vel The robot's velocity
-     * @param vel_samples The desired velocity
-     * @return True if the trajectory is valid, false otherwise
-     */
-    bool check_trajectory(const Eigen::Vector3f pos,const Eigen::Vector3f ackermann,const Eigen::Vector2f samples);
-
     /**
      * @brief Given the current position and velocity of the robot, find the best trajectory to exectue
      * @param global_pose The current position of the robot 
@@ -110,13 +101,7 @@ class AckermannPlanner
      * @brief  Take in a new global plan for the local planner to follow, and adjust local costmaps
      * @param  new_plan The new global plan
      */
-    void update_plan_and_local_costs(geometry_msgs::PoseStamped &global_pose,const std::vector<geometry_msgs::PoseStamped>& new_plan);
-
-    /**
-     * @brief Get the period at which the local planner is expected to run
-     * @return The simulation period
-     */
-    double get_sim_period(void);
+    void update_plan_and_local_costs(geometry_msgs::PoseStamped &global_pose,const std::vector<geometry_msgs::PoseStamped>& new_plan,bool forward);
 
     /**
      * @brief Compute the components and total cost for a map grid cell
@@ -138,17 +123,14 @@ class AckermannPlanner
   private:
 
     AckermannPlannerUtil *planner_util_;
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig current_config_;
 
-    double stop_time_buffer_; ///< @brief How long before hitting something we're going to enforce that the robot stop
-    double pdist_scale_, gdist_scale_, occdist_scale_,hdiff_scale_;
-    Eigen::Vector2f vsamples_;
+    double pdist_scale_, gdist_scale_, occdist_scale_;
 
-    double sim_period_;///< @brief The number of seconds to use to compute max/min vels for dwa
     base_local_planner::Trajectory result_traj_;
 
-    double forward_point_distance_;
-
     std::vector<geometry_msgs::PoseStamped> global_plan_;
+    bool plan_forward;
 
     boost::mutex configuration_mutex_;
     std::string frame_id_;
@@ -156,12 +138,13 @@ class AckermannPlanner
     bool publish_cost_grid_pc_; ///< @brief Whether or not to build and publish a PointCloud
     bool publish_traj_pc_;
 
-    double cheat_factor_;
+    ros::NodeHandle private_nh;
 
     base_local_planner::MapGridVisualizer map_viz_; ///< @brief The map grid visualizer for outputting the potential field generated by the cost function
 
     // see constructor body for explanations
     AckermannTrajectoryGenerator generator_;
+    AckermannSplineGenerator spline_generator_;
     base_local_planner::OscillationCostFunction oscillation_costs_;
     base_local_planner::ObstacleCostFunction obstacle_costs_;
     HeadingCostFunction heading_costs_;
diff --git a/include/ackermann_planner_limits.h b/include/ackermann_planner_limits.h
deleted file mode 100644
index 2907939a4ae5f3fe4728b7722964a64e0f7fe094..0000000000000000000000000000000000000000
--- a/include/ackermann_planner_limits.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/***********************************************************
- * Software License Agreement (BSD License)
- *
- *  Copyright (c) 2008, Willow Garage, Inc.
- *  All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above
- *     copyright notice, this list of conditions and the following
- *     disclaimer in the documentation and/or other materials provided
- *     with the distribution.
- *   * Neither the name of the Willow Garage nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- ***********************************************************/
-
-
-#ifndef _ACKERMANN_PLANNER_LIMITS_H
-#define _ACKERMANN_PLANNER_LIMITS_H
-
-#include <Eigen/Core>
-
-class AckermannPlannerLimits
-{
-  public:
-    // translational limits
-    double max_trans_vel;
-    double min_trans_vel;
-    double max_trans_acc;
-    // steering limits
-    double max_steer_angle;
-    double min_steer_angle;
-    double max_steer_vel;
-    double min_steer_vel;
-    double max_steer_acc;
-    // angular velocity limits
-    double max_angular_vel;
-    double min_angular_vel;
-    // kinematic attributes
-    double axis_distance;
-    double wheel_distance;
-    double wheel_radius; 
-    // general planner limits
-    bool use_trans_vel_deadzone;
-    double trans_vel_deadzone;
-    double split_ignore_length;
-    bool prune_plan;
-    double xy_goal_tolerance;
-    double yaw_goal_tolerance;
-    double trans_stopped_vel;
-    double rot_stopped_vel;
-    bool restore_defaults;
-
-    AckermannPlannerLimits() {}
-
-    AckermannPlannerLimits(
-      // translational limits
-      double max_trans_vel,
-      double min_trans_vel,
-      double max_trans_acc,
-      // steering limits
-      double max_steer_angle,
-      double min_steer_angle,
-      double max_steer_vel,
-      double min_steer_vel,
-      double max_steer_acc,
-      // angular velocity limits
-      double max_angular_vel,
-      double min_angular_vel,
-      // kinematic attributes
-      double axis_distance,
-      double wheel_distance,
-      double wheel_radius, 
-      // general planner limits
-      bool use_trans_vel_deadzone,
-      double trans_vel_deadzone,
-      double split_ignore_length,
-      double xy_goal_tolerance,
-      double yaw_goal_tolerance,
-      bool prune_plan=true,
-      double trans_stopped_vel=0.1,
-      double rot_stopped_vel=0.1):
-      max_trans_vel(max_trans_vel),
-      min_trans_vel(min_trans_vel),
-      max_trans_acc(max_trans_acc),
-      max_steer_angle(max_steer_angle),
-      min_steer_angle(min_steer_angle),
-      max_steer_vel(max_steer_vel),
-      min_steer_vel(min_steer_vel),
-      max_steer_acc(max_steer_acc),
-      max_angular_vel(max_angular_vel),
-      min_angular_vel(min_angular_vel),
-      axis_distance(axis_distance),
-      wheel_distance(wheel_distance),
-      wheel_radius(wheel_radius),
-      use_trans_vel_deadzone(use_trans_vel_deadzone),
-      trans_vel_deadzone(trans_vel_deadzone),
-      split_ignore_length(split_ignore_length),
-      prune_plan(prune_plan),
-      xy_goal_tolerance(xy_goal_tolerance),
-      yaw_goal_tolerance(yaw_goal_tolerance),
-      trans_stopped_vel(trans_stopped_vel),
-      rot_stopped_vel(rot_stopped_vel)
-    {
-    }
-
-    ~AckermannPlannerLimits()
-    {
-    }
-};
-
-#endif // __LOCALPLANNERLIMITS_H__
diff --git a/include/ackermann_planner_ros.h b/include/ackermann_planner_ros.h
index 8eb35b9edf74f3a2e342d55fe689205b3f1094f2..c85ff95cbd4bb1cf72c8f8e0679ff46508ca06c6 100644
--- a/include/ackermann_planner_ros.h
+++ b/include/ackermann_planner_ros.h
@@ -136,10 +136,9 @@ class AckermannPlannerROS : public nav_core::BaseLocalPlanner
 
     dynamic_reconfigure::Server<iri_ackermann_local_planner::AckermannLocalPlannerConfig> *dsrv_;
     iri_ackermann_local_planner::AckermannLocalPlannerConfig default_config_;
-    bool setup_;
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig current_config_;
     geometry_msgs::PoseStamped current_pose_;
     bool initialized_;
-    int patience_;
 
     AckermannOdomHelper odom_helper_;
     std::string odom_topic_;
@@ -147,13 +146,5 @@ class AckermannPlannerROS : public nav_core::BaseLocalPlanner
 
     bool stuck;
     bool first;
-    bool use_steer_angle_cmd;
-    bool invert_steer_angle_cmd;
-    bool use_stopped_steering;
-    double stopped_steering_angle_threshold;
-    bool use_stuck_check;
-    double stuck_check_vel_threshold;
-    int stuck_check_max_occurrences;
-
 };
 #endif
diff --git a/include/ackermann_planner_util.h b/include/ackermann_planner_util.h
index 393d3a3b01095fe3626651cf65134ab5391c1d33..1a32bb697a9db2f220bcec52b2f5869a822c6c8c 100644
--- a/include/ackermann_planner_util.h
+++ b/include/ackermann_planner_util.h
@@ -45,10 +45,9 @@
 #include <costmap_2d/costmap_2d.h>
 #include <tf2_ros/transform_listener.h>
 #include <geometry_msgs/PoseStamped.h>
+#include <base_local_planner/costmap_model.h>
 
-#include <ackermann_planner_limits.h>
-
-
+#include <iri_ackermann_local_planner/AckermannLocalPlannerConfig.h>
 /**
  * @class AckermannPlannerUtil
  * @brief Helper class implementing infrastructure code many local planner implementations may need.
@@ -61,27 +60,29 @@ class AckermannPlannerUtil
     std::string global_frame_;
 
     costmap_2d::Costmap2D* costmap_;
+    base_local_planner::CostmapModel *world_model_;
     tf2_ros::Buffer *tf_;
 
     std::vector<geometry_msgs::PoseStamped> global_plan_;
+    bool plan_forward;
 
-    boost::mutex limits_configuration_mutex_;
-    bool setup_;
-    AckermannPlannerLimits default_limits_;
-    AckermannPlannerLimits limits_;
     bool initialized_;
 
     std::vector < std::vector<geometry_msgs::PoseStamped> > subPathList;
     std::vector < geometry_msgs::PoseStamped > subPath;
+    std::vector < bool > forward_segment;
     unsigned int subPathIndex;
 
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig default_config_;
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig current_config_;
+
   public:
 
     AckermannPlannerUtil();
     /**
      * @brief  Callback to update the local planner's parameters
      */
-    void reconfigure_callback(AckermannPlannerLimits &config, bool restore_defaults);
+    void reconfigure_callback(iri_ackermann_local_planner::AckermannLocalPlannerConfig &config, bool restore_defaults);
 
     void initialize(tf2_ros::Buffer* tf,costmap_2d::Costmap2D* costmap,std::string global_frame);
 
@@ -93,11 +94,11 @@ class AckermannPlannerUtil
    
     bool last_path(void);
 
-    bool get_local_plan(geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan);
+    bool get_local_plan(geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan, bool &forward);
 
     costmap_2d::Costmap2D* get_costmap();
 
-    AckermannPlannerLimits get_current_limits();
+    base_local_planner::CostmapModel *get_world_model();
 
     std::string get_global_frame(void);
 
diff --git a/include/ackermann_spline_generator.h b/include/ackermann_spline_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..05b65687c80d0c2927a9c4a52b253b5ad4abc864
--- /dev/null
+++ b/include/ackermann_spline_generator.h
@@ -0,0 +1,100 @@
+/*********************************************************************
+ *
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2008, Willow Garage, Inc.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: TKruse
+ *********************************************************************/
+
+#ifndef ACKERMANN_SPLINE_GENERATOR_H_
+#define ACKERMANN_SPLINE_GENERATOR_H_
+
+#include <base_local_planner/trajectory_sample_generator.h>
+#include <geometry_msgs/PoseStamped.h>
+#include <Eigen/Core>
+
+#include <iri_ackermann_local_planner/AckermannLocalPlannerConfig.h>
+
+#include "g2_spline.h"
+#include "vel_trapezoid.h"
+
+typedef struct
+{
+  Eigen::Vector4f params;
+  TPoint end_point;
+}TSplineSample;
+
+/**
+ */
+class AckermannSplineGenerator: public base_local_planner::TrajectorySampleGenerator 
+{
+  public:
+
+    AckermannSplineGenerator();
+
+    /**
+     * @brief Reconfigures the trajectory planner
+     */
+    void reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &cfg);
+
+    /**
+     * Whether this generator can create more trajectories
+     */
+    bool hasMoreTrajectories(void);
+
+    /**
+     * Whether this generator can create more trajectories
+     */
+    bool nextTrajectory(base_local_planner::Trajectory &traj);
+
+    void initialise(const Eigen::Vector3f& pos,const Eigen::Vector3f& ackermann,const Eigen::Vector3f& goal,bool forward,std::vector<geometry_msgs::PoseStamped>& current_plan);
+
+    void set_sim_period(double period);
+
+    ~AckermannSplineGenerator();
+  protected:
+    std::vector<TSplineSample> samples_;
+    CG2Spline spline_;
+    unsigned int next_sample_index_;
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig current_config_;
+    Eigen::Vector3f pos_;
+    Eigen::Vector3f goal_pos_;
+    Eigen::Vector3f ackermann_;
+    std::vector<geometry_msgs::PoseStamped> current_plan;
+    bool forward;
+    double sim_period_;
+    double y_offset;
+
+    unsigned int get_path_closest_pose(double &path_x,double &path_y);
+};
+
+#endif /* SIMPLE_TRAJECTORY_GENERATOR_H_ */
diff --git a/include/ackermann_trajectory_generator.h b/include/ackermann_trajectory_generator.h
index 26e6a3f6a883c7f9a8ec7ae1e54922c857abf60e..5e6cfb9d3edb71508202bba9782909f13e05da48 100644
--- a/include/ackermann_trajectory_generator.h
+++ b/include/ackermann_trajectory_generator.h
@@ -39,9 +39,10 @@
 #define ACKERMANN_TRAJECTORY_GENERATOR_H_
 
 #include <base_local_planner/trajectory_sample_generator.h>
-#include <ackermann_planner_limits.h>
 #include <Eigen/Core>
 
+#include <iri_ackermann_local_planner/AckermannLocalPlannerConfig.h>
+
 /**
  * generates trajectories based on equi-distant discretisation of the degrees of freedom.
  * This is supposed to be a simple and robust implementation of the TrajectorySampleGenerator
@@ -71,28 +72,14 @@ class AckermannTrajectoryGenerator: public base_local_planner::TrajectorySampleG
      * @param discretize_by_time if true, the trajectory is split according in chunks of the same duration, else of same length
      */
     void initialise(
-	const Eigen::Vector3f& pos,
-	const Eigen::Vector3f& ackermann,
-	const Eigen::Vector3f& goal,
-	AckermannPlannerLimits* limits,
-	const Eigen::Vector2f& vsamples,
-	bool discretize_by_time = false);
+      const Eigen::Vector3f& pos,
+      const Eigen::Vector3f& ackermann,
+      const Eigen::Vector3f& goal);
 
     /**
-     * This function is to be called only when parameters change
-     *
-     * @param sim_granularity granularity of collision detection
-     * @param angular_sim_granularity angular granularity of collision detection
-     * @param use_dwa whether to use DWA or trajectory rollout
-     * @param sim_period distance between points in one trajectory
+     * @brief Reconfigures the trajectory planner
      */
-    void set_parameters(
-        double max_sim_time,
-        double min_sim_time,
-	double sim_granularity,
-	double angular_sim_granularity,
-        bool use_steer_angle_cmd,
-	double sim_period = 0.0);
+    void reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &cfg);
 
     /**
      * Whether this generator can create more trajectories
@@ -106,10 +93,10 @@ class AckermannTrajectoryGenerator: public base_local_planner::TrajectorySampleG
 
 
     bool generate_trajectory(
-	Eigen::Vector3f pos,
-	Eigen::Vector3f vel,
-	Eigen::Vector2f sample_target_vel,
-	base_local_planner::Trajectory& traj);
+     Eigen::Vector3f pos,
+     Eigen::Vector3f vel,
+     Eigen::Vector2f sample_target_vel,
+     base_local_planner::Trajectory& traj);
 
     ~AckermannTrajectoryGenerator();
   protected:
@@ -117,17 +104,11 @@ class AckermannTrajectoryGenerator: public base_local_planner::TrajectorySampleG
     unsigned int next_sample_index_;
     // to store sample params of each sample between init and generation
     std::vector<Eigen::Vector2f> sample_params_;
-    AckermannPlannerLimits* limits_;
+    iri_ackermann_local_planner::AckermannLocalPlannerConfig current_config_;
     Eigen::Vector3f pos_;
     Eigen::Vector3f ackermann_;
 
-    // whether velocity of trajectory changes over time or not
-    bool discretize_by_time_;
-
-    double max_sim_time_,min_sim_time_,sim_time_;
-    double sim_granularity_, angular_sim_granularity_;
-    double sim_period_; // only for dwa
-    bool use_steer_angle_cmd_;
+    double sim_time_;
 };
 
 #endif /* SIMPLE_TRAJECTORY_GENERATOR_H_ */
diff --git a/include/ackermann_trajectory_search.h b/include/ackermann_trajectory_search.h
index 7c688efc38643740027c67d0026d72c331ca86c4..822397e5fbc208cc933f8f591803967757810184 100644
--- a/include/ackermann_trajectory_search.h
+++ b/include/ackermann_trajectory_search.h
@@ -43,6 +43,9 @@
 #include <base_local_planner/trajectory_cost_function.h>
 #include <base_local_planner/trajectory_sample_generator.h>
 #include <base_local_planner/trajectory_search.h>
+#include <ackermann_spline_generator.h>
+
+#include <iri_ackermann_local_planner/AckermannLocalPlannerConfig.h>
 
 /**
  * @class AckermannTrajectorySearch
@@ -91,7 +94,6 @@ public:
    */
   bool findBestTrajectory(base_local_planner::Trajectory& traj, std::vector<base_local_planner::Trajectory>* all_explored = 0);
 
-
 private:
   std::vector<base_local_planner::TrajectorySampleGenerator*> gen_list_;
   std::vector<base_local_planner::TrajectoryCostFunction*> critics_;
diff --git a/params/ackermann_planner_params.yaml b/params/ackermann_planner_params.yaml
index ab581039c0fc6c37279ea2ec352f548efc61324f..09818d7e211e3423c61ab5c934c54be83a0a86c9 100644
--- a/params/ackermann_planner_params.yaml
+++ b/params/ackermann_planner_params.yaml
@@ -13,6 +13,8 @@ AckermannPlannerROS:
   oscillation_reset_dist: 0.002
   oscillation_reset_angle: 0.001
 
+  check_path_r_inc: 0.25
+
   trans_vel_samples: 31
   steer_angle_samples: 21
   angular_vel_samples: 21
diff --git a/params/ackermann_planner_params_fixed_gplanner.yaml b/params/ackermann_planner_params_fixed_gplanner.yaml
index 5ea2abed65ec37e065e8c7e8a4464b090e455ea2..1c9fad3fc51348ec4c6825a89d34b82661300b74 100644
--- a/params/ackermann_planner_params_fixed_gplanner.yaml
+++ b/params/ackermann_planner_params_fixed_gplanner.yaml
@@ -17,6 +17,8 @@ AckermannPlannerROS:
 #  scaling_speed:
 #  max_scaling_factor:
 
+  check_path_r_inc: 0.25
+
   trans_vel_samples: 21
   steer_angle_samples: 11
 
diff --git a/src/ackermann_odom_helper.cpp b/src/ackermann_odom_helper.cpp
index 5056a825c74f61c9f8fb6a0e6d8eb781e51add5e..9276b8ee6b8c047aa217c602f3ce1518f7288cf8 100644
--- a/src/ackermann_odom_helper.cpp
+++ b/src/ackermann_odom_helper.cpp
@@ -41,15 +41,26 @@ AckermannOdomHelper::AckermannOdomHelper(const std::string &odom_topic,const std
   set_odom_topic(odom_topic);
   set_ackermann_topic(ackermann_topic);
   ackermann_data_.resize(num_avg_samples);
+  this->costmap_ros_=NULL;
 }
 
 void AckermannOdomHelper::odom_callback(const nav_msgs::Odometry::ConstPtr& msg) 
 {
+  geometry_msgs::PoseStamped pose_in;
   ROS_INFO_ONCE("Odom received!");
-
+  
   //we assume that the odometry is published in the frame of the base
   boost::mutex::scoped_lock lock(odom_mutex_);
   base_odom_=*msg;
+  if(this->costmap_ros_!=NULL)
+  {
+    if(!this->costmap_ros_->getRobotPose(pose_in))
+    {
+      ROS_ERROR("AckermannOdomHelper: Could not get robot pose");
+      return;
+    }
+    base_odom_.pose.pose=pose_in.pose;
+  }
 }
 
 void AckermannOdomHelper::ackermann_callback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg) 
@@ -147,6 +158,12 @@ void AckermannOdomHelper::set_average_samples(int num_average_samples)
     this->ackermann_data_.resize(num_average_samples);
 }
 
+void AckermannOdomHelper::set_costmap(costmap_2d::Costmap2DROS* costmap_ros)
+{
+  boost::mutex::scoped_lock lock(odom_mutex_);
+  this->costmap_ros_=costmap_ros;
+}
+
 std::string AckermannOdomHelper::get_odom_topic(void) const
 {
   return this->odom_topic_;
diff --git a/src/ackermann_planner.cpp b/src/ackermann_planner.cpp
index 371634056d22b0706be91c41ba8e31dc9b5c266a..1847eecd2998f4685804904242f57c65ddf89ff8 100644
--- a/src/ackermann_planner.cpp
+++ b/src/ackermann_planner.cpp
@@ -51,94 +51,108 @@
 void AckermannPlanner::reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &config)
 {
   boost::mutex::scoped_lock l(configuration_mutex_);
-
-  generator_.set_parameters(
-      config.max_sim_time,
-      config.min_sim_time,
-      config.sim_granularity,
-      config.angular_sim_granularity,
-      config.use_steer_angle_cmd,
-      sim_period_);
+  double hdiff_scale;
 
   double resolution = planner_util_->get_costmap()->getResolution();
   pdist_scale_ = config.path_distance_bias;
   // pdistscale used for both path and alignment, set  forward_point_distance to zero to discard alignment
-  path_costs_.setScale(resolution * pdist_scale_ * 0.5);
+  path_costs_.setScale(resolution * pdist_scale_);
   //path_costs_.setStopOnFailure(false);
-  hdiff_scale_=config.hdiff_scale;
-  heading_costs_.setScale(hdiff_scale_);
+  hdiff_scale=config.hdiff_scale;
+  heading_costs_.setScale(hdiff_scale);
+  heading_costs_.set_num_points(config.heading_points);
 
   gdist_scale_ = config.goal_distance_bias;
-  goal_costs_.setScale(resolution * gdist_scale_ * 0.5);
+  goal_costs_.setScale(resolution * gdist_scale_);
   goal_costs_.setStopOnFailure(false);
 
   occdist_scale_ = config.occdist_scale;
   obstacle_costs_.setScale(resolution * occdist_scale_);
 
-  stop_time_buffer_ = config.stop_time_buffer;
   oscillation_costs_.setOscillationResetDist(config.oscillation_reset_dist, config.oscillation_reset_angle);
-  forward_point_distance_ = config.forward_point_distance;
-  heading_costs_.set_num_points(config.heading_points);
 
   // obstacle costs can vary due to scaling footprint feature
   obstacle_costs_.setParams(config.max_trans_vel, config.max_scaling_factor, config.scaling_speed);
 
-  int trans_vel_samp, steer_angle_angular_vel_samp;
-  trans_vel_samp = config.trans_vel_samples;
-  if(config.use_steer_angle_cmd)
-    steer_angle_angular_vel_samp = config.steer_angle_samples;
+  std::string controller_frequency_param_name;
+  double sim_period;
+  if(!this->private_nh.searchParam("controller_frequency", controller_frequency_param_name))
+  {
+    ROS_WARN("AckermannPlanner::reconfigure_callback -> Parameter controller_frequency not found. Assuming a rate of 20Hz");
+    sim_period = 0.05;
+  }
   else
-    steer_angle_angular_vel_samp = config.angular_vel_samples;
-
-  if (trans_vel_samp <= 0) 
   {
-    ROS_WARN("You've specified that you don't want any samples in the translational dimension. We'll at least assume that you want to sample one value... so we're going to set vx_samples to 1 instead");
-    trans_vel_samp = 1;
-    config.trans_vel_samples = trans_vel_samp;
+    double controller_frequency = 0;
+    this->private_nh.param(controller_frequency_param_name, controller_frequency, 20.0);
+    if(controller_frequency > 0)
+      sim_period = 1.0 / controller_frequency;
+    else
+    {
+      ROS_WARN("AckermannPlanner::reconfigure_callback -> A controller_frequency less than 0 has been set. Ignoring the parameter, assuming a rate of 20Hz");
+      sim_period = 0.05;
+    }
   }
 
-  if (steer_angle_angular_vel_samp <= 0) 
+  // set up all the cost functions that will be applied in order
+  // (any function returning negative values will abort scoring, so the order can improve performance)
+  std::vector<base_local_planner::TrajectoryCostFunction*> critics;
+  std::vector<base_local_planner::TrajectorySampleGenerator*> generator_list;
+  if(config.use_splines)
   {
-    ROS_WARN("You've specified that you don't want any samples in the steering/angular velocity dimension. We'll at least assume that you want to sample one value... so we're going to set vy_samples to 1 instead");
-    steer_angle_angular_vel_samp = 1;
-    if(config.use_steer_angle_cmd)
-      config.steer_angle_samples = steer_angle_angular_vel_samp;
-    else
-      config.angular_vel_samples = steer_angle_angular_vel_samp;
+    critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
+    critics.push_back(&path_costs_); // prefers trajectories on global path
+    critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+    critics.push_back(&heading_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+
+    // trajectory generators
+    generator_list.push_back(&spline_generator_);
+    spline_generator_.set_sim_period(sim_period);
   }
+  else
+  {
+    critics.push_back(&oscillation_costs_); // discards oscillating motions (assisgns cost -1)
+    critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
+    critics.push_back(&path_costs_); // prefers trajectories on global path
+    critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+    critics.push_back(&heading_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+
+    // trajectory generators
+    generator_list.push_back(&generator_);
+  }
+
+  scored_sampling_planner_ = AckermannTrajectorySearch(generator_list, critics);
 
-  vsamples_[0] = trans_vel_samp;
-  vsamples_[1] = steer_angle_angular_vel_samp;
+  generator_.reconfigure(config);
+  spline_generator_.reconfigure(config);
+
+  current_config_=config;
 }
 
 AckermannPlanner::AckermannPlanner(std::string name,AckermannPlannerUtil *planner_util) :
   planner_util_(planner_util),
   obstacle_costs_(planner_util->get_costmap()),
-  path_costs_(planner_util->get_costmap()),
-  goal_costs_(planner_util->get_costmap(), 0.0, 0.0, true)
+  path_costs_(planner_util->get_costmap(), 0.0, 0.0, false,base_local_planner::Sum),
+  goal_costs_(planner_util->get_costmap(), 0.0, 0.0, true),
+  private_nh("~/" + name)
 {
-  ros::NodeHandle private_nh("~/" + name);
-
-  //Assuming this planner is being run within the navigation stack, we can
-  //just do an upward search for the frequency at which its being run. This
-  //also allows the frequency to be overwritten locally.
   std::string controller_frequency_param_name;
-  if(!private_nh.searchParam("controller_frequency", controller_frequency_param_name)) 
+  double sim_period;
+  if(!this->private_nh.searchParam("controller_frequency", controller_frequency_param_name))
   {
-    sim_period_ = 0.05;
-  } 
-  else 
+    ROS_WARN_STREAM("AckermannPlanner::AckermannPlanner -> Parameter controller_frequency not found at ns " << this->private_nh.getNamespace() << ". Assuming a rate of 20Hz");
+    sim_period = 0.05;
+  }
+  else
   {
     double controller_frequency = 0;
-    private_nh.param(controller_frequency_param_name, controller_frequency, 20.0);
-    if(controller_frequency > 0) 
-    {
-      sim_period_ = 1.0 / controller_frequency;
-    }
-    else 
+    this->private_nh.param(controller_frequency_param_name, controller_frequency, 20.0);
+    if(controller_frequency > 0)
+      sim_period = 1.0 / controller_frequency;
+    else
     {
       ROS_WARN("A controller_frequency less than 0 has been set. Ignoring the parameter, assuming a rate of 20Hz");
-      sim_period_ = 0.05;
+      sim_period = 0.05;
     }
   }
 
@@ -159,19 +173,33 @@ AckermannPlanner::AckermannPlanner(std::string name,AckermannPlannerUtil *planne
   // set up all the cost functions that will be applied in order
   // (any function returning negative values will abort scoring, so the order can improve performance)
   std::vector<base_local_planner::TrajectoryCostFunction*> critics;
-  critics.push_back(&oscillation_costs_); // discards oscillating motions (assisgns cost -1)
-  critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
-  critics.push_back(&path_costs_); // prefers trajectories on global path
-  critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
-  critics.push_back(&heading_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
-
-  // trajectory generators
+  bool use_splines;
+  private_nh.param("use_splines", use_splines, false);
   std::vector<base_local_planner::TrajectorySampleGenerator*> generator_list;
-  generator_list.push_back(&generator_);
+  if(use_splines)
+  {
+    critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
+    critics.push_back(&path_costs_); // prefers trajectories on global path
+    critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+    critics.push_back(&heading_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+
+    // trajectory generators
+    generator_list.push_back(&spline_generator_);
+    spline_generator_.set_sim_period(sim_period);
+  }
+  else
+  {
+    critics.push_back(&oscillation_costs_); // discards oscillating motions (assisgns cost -1)
+    critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
+    critics.push_back(&path_costs_); // prefers trajectories on global path
+    critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+    critics.push_back(&heading_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation
+
+    // trajectory generators
+    generator_list.push_back(&generator_);
+  }
 
   scored_sampling_planner_ = AckermannTrajectorySearch(generator_list, critics);
-
-  private_nh.param("cheat_factor", cheat_factor_, 1.0);
 }
 
 // used for visualization only, total_costs are not really total costs
@@ -199,50 +227,19 @@ bool AckermannPlanner::set_plan(const std::vector<geometry_msgs::PoseStamped>& o
   return planner_util_->set_plan(orig_global_plan);
 }
 
-/**
- * This function is used when other strategies are to be applied,
- * but the cost functions for obstacles are to be reused.
- */
-bool AckermannPlanner::check_trajectory(Eigen::Vector3f pos,Eigen::Vector3f ackermann,Eigen::Vector2f samples)
-{
-  oscillation_costs_.resetOscillationFlags();
-  base_local_planner::Trajectory traj;
-  geometry_msgs::PoseStamped goal_pose = global_plan_.back();
-  Eigen::Vector3f goal(goal_pose.pose.position.x, goal_pose.pose.position.y, tf::getYaw(goal_pose.pose.orientation));
-  AckermannPlannerLimits limits = planner_util_->get_current_limits();
-  generator_.initialise(pos,
-      ackermann,
-      goal,
-      &limits,
-      vsamples_);
-  generator_.generate_trajectory(pos, ackermann, samples, traj);
-  double cost = scored_sampling_planner_.scoreTrajectory(traj, -1);
-  //if the trajectory is a legal one... the check passes
-  if(cost >= 0) 
-    return true;
-  ROS_WARN("Invalid Trajectory %f, %f, cost: %f", samples[0], samples[1], cost);
-
-  //otherwise the check fails
-  return false;
-}
-
-void AckermannPlanner::update_plan_and_local_costs(geometry_msgs::PoseStamped &global_pose,const std::vector<geometry_msgs::PoseStamped>& new_plan) 
+void AckermannPlanner::update_plan_and_local_costs(geometry_msgs::PoseStamped &global_pose,const std::vector<geometry_msgs::PoseStamped>& new_plan,bool forward) 
 {
   global_plan_.resize(new_plan.size());
   for (unsigned int i = 0; i < new_plan.size(); ++i) 
     global_plan_[i] = new_plan[i];
+  plan_forward=forward;
 
   // costs for going away from path
   path_costs_.setTargetPoses(global_plan_);
-
   // costs for not going towards the local goal as much as possible
   goal_costs_.setTargetPoses(global_plan_);
 
   heading_costs_.set_global_plan(global_plan_);
-
-  // alignment costs
-  geometry_msgs::PoseStamped goal_pose = global_plan_.back();
-
 }
 
 /*
@@ -250,6 +247,11 @@ void AckermannPlanner::update_plan_and_local_costs(geometry_msgs::PoseStamped &g
  */
 base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::PoseStamped &global_pose,ackermann_msgs::AckermannDrive &ackermann,geometry_msgs::PoseStamped& drive_velocities,std::vector<geometry_msgs::Point> footprint_spec) 
 {
+  std::vector<geometry_msgs::Point> circular_footprint;
+  geometry_msgs::PoseStamped goal_pose;
+  double min_radius,max_radius;
+  unsigned int path_index=global_plan_.size()-1;
+
   obstacle_costs_.setFootprint(footprint_spec);
 
   //make sure that our configuration doesn't change mid-run
@@ -257,21 +259,52 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P
 
   Eigen::Vector3f pos(global_pose.pose.position.x, global_pose.pose.position.y, tf::getYaw(global_pose.pose.orientation));
   Eigen::Vector3f ack_state(ackermann.speed,ackermann.steering_angle,ackermann.steering_angle_velocity);
-  geometry_msgs::PoseStamped goal_pose = global_plan_.back();
+  costmap_2d::calculateMinAndMaxDistances(footprint_spec,min_radius,max_radius);
+  for(double angle=0;angle<2*3.14159;angle+=0.1)
+  {
+    geometry_msgs::Point new_point;
+    new_point.x=(max_radius+this->current_config_.check_path_r_inc)*cos(angle);
+    new_point.y=(max_radius+this->current_config_.check_path_r_inc)*sin(angle);
+    circular_footprint.push_back(new_point);
+  }
+  do{
+    if(planner_util_->get_world_model()->footprintCost(global_plan_[path_index].pose.position.x,global_plan_[path_index].pose.position.y,tf::getYaw(global_plan_[path_index].pose.orientation),circular_footprint)<0)
+    {
+      if(path_index>0)
+        path_index--;
+      continue;
+    }
+    else
+      break;
+  }while(path_index>0);
+  if(path_index==0)
+  {
+    std::cout << "empty path" << std::endl;
+    drive_velocities.pose.position.x = 0;
+    drive_velocities.pose.position.y = 0;
+    drive_velocities.pose.position.z = 0;
+    drive_velocities.pose.orientation.w = 1;
+    drive_velocities.pose.orientation.x = 0;
+    drive_velocities.pose.orientation.y = 0;
+    drive_velocities.pose.orientation.z = 0;
+    return base_local_planner::Trajectory();
+  }
+  else
+    goal_pose = global_plan_[path_index];
   Eigen::Vector3f goal(goal_pose.pose.position.x, goal_pose.pose.position.y, tf::getYaw(goal_pose.pose.orientation));
-  AckermannPlannerLimits limits = planner_util_->get_current_limits();
+
+  std::vector<geometry_msgs::PoseStamped> plan_fixed(path_index+1);
+  for (unsigned int i=0; i<=path_index; i++)
+    plan_fixed[i] = global_plan_[i];
 
   // prepare cost functions and generators for this run
-  generator_.initialise(pos,
-      ack_state,
-      goal,
-      &limits,
-      vsamples_);
+  generator_.initialise(pos,ack_state,goal);
+  spline_generator_.initialise(pos,ack_state,goal,plan_forward,plan_fixed);
 
   result_traj_.cost_ = -7;
   // find best trajectory by sampling and scoring the samples
   std::vector<base_local_planner::Trajectory> all_explored;
-  scored_sampling_planner_.findBestTrajectory(result_traj_, &all_explored);
+  scored_sampling_planner_.findBestTrajectory(result_traj_, (publish_traj_pc_? &all_explored: NULL));
 
   if(publish_traj_pc_)
   {
@@ -289,8 +322,8 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P
     unsigned int num_points = 0;
     for(std::vector<base_local_planner::Trajectory>::iterator t=all_explored.begin(); t != all_explored.end(); ++t)
     {
-      if (t->cost_<0)
-        continue;
+//      if (t->cost_<0)
+//        continue;
       num_points += t->getPointsSize();
     }
 
@@ -298,8 +331,8 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P
     sensor_msgs::PointCloud2Iterator<float> iter_x(traj_cloud, "x");
     for(std::vector<base_local_planner::Trajectory>::iterator t=all_explored.begin(); t != all_explored.end(); ++t)
     {
-      if(t->cost_<0)
-        continue;
+//      if(t->cost_<0)
+//        continue;
       // Fill out the plan
       for(unsigned int i = 0; i < t->getPointsSize(); ++i) 
       {
@@ -324,11 +357,12 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P
   }
 
   // debrief stateful scoring functions
-  oscillation_costs_.updateOscillationFlags(pos, &result_traj_, planner_util_->get_current_limits().min_trans_vel);
+  oscillation_costs_.updateOscillationFlags(pos, &result_traj_, current_config_.min_trans_vel);
 
   //if we don't have a legal trajectory, we'll just command zero
   if (result_traj_.cost_ < 0) 
   {
+    std::cout << "no legal trajectory" << std::endl;
     drive_velocities.pose.position.x = 0;
     drive_velocities.pose.position.y = 0;
     drive_velocities.pose.position.z = 0;
@@ -339,12 +373,20 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P
   } 
   else 
   {
+    std::cout << result_traj_.xv_ << "," << result_traj_.thetav_ << std::endl;
     drive_velocities.pose.position.x = result_traj_.xv_;
     drive_velocities.pose.position.y = result_traj_.yv_;
-    drive_velocities.pose.position.z = 0;
+    drive_velocities.pose.position.z = 0.0;
     tf2::Quaternion q;
     q.setRPY(0, 0, result_traj_.thetav_);
     tf2::convert(q, drive_velocities.pose.orientation);
+
+//    drive_velocities.pose.position.x = 0.0;
+//    drive_velocities.pose.position.y = 0.0;
+//    drive_velocities.pose.position.z = 0.0;
+//    tf2::Quaternion q;
+//    q.setRPY(0, 0, 0);
+//    tf2::convert(q, drive_velocities.pose.orientation);
   }
 
   return result_traj_;
diff --git a/src/ackermann_planner_ros.cpp b/src/ackermann_planner_ros.cpp
index c770851c21a041f78058b9c8f749d4cf4e1dcf70..76c23a8b2d472409c162e7ad9efbbefa5c5cb009 100644
--- a/src/ackermann_planner_ros.cpp
+++ b/src/ackermann_planner_ros.cpp
@@ -52,65 +52,32 @@
 PLUGINLIB_EXPORT_CLASS(AckermannPlannerROS, nav_core::BaseLocalPlanner)
 
 AckermannPlannerROS::AckermannPlannerROS() : initialized_(false),
-  odom_helper_("odom","ackermann_feedback",10), setup_(false) 
+  odom_helper_("odom","ackermann_feedback",10) 
 {
-  patience_=1;
   this->stuck=false;
   this->first=true;
 }
 
 void AckermannPlannerROS::reconfigure_callback(iri_ackermann_local_planner::AckermannLocalPlannerConfig &config, uint32_t level) 
 {
-  if (setup_ && config.restore_defaults) 
+  static bool setup=false;
+
+  if (setup && config.restore_defaults) 
   {
     config = default_config_;
     config.restore_defaults = false;
   }
-  if ( ! setup_) 
+  if (!setup) 
   {
     default_config_ = config;
-    setup_ = true;
+    setup = true;
   }
 
-  // update generic local planner params
-  AckermannPlannerLimits limits;
-  limits.max_trans_vel = config.max_trans_vel;
-  limits.min_trans_vel = config.min_trans_vel;
-  limits.max_trans_acc = config.max_trans_acc;
-  limits.max_steer_angle = config.max_steer_angle;
-  limits.min_steer_angle = config.min_steer_angle;
-  limits.max_steer_vel = config.max_steer_vel;
-  limits.min_steer_vel = config.min_steer_vel;
-  limits.max_steer_acc = config.max_steer_acc;
-  limits.max_angular_vel = config.max_angular_vel;
-  limits.min_angular_vel = config.min_angular_vel;
-  // kinematic attributes
-  limits.axis_distance = config.axis_distance;
-  limits.wheel_distance = config.wheel_distance;
-  limits.wheel_radius = config.wheel_radius;
-  // general planner limits
-  limits.use_trans_vel_deadzone = config.use_trans_vel_deadzone;
-  limits.trans_vel_deadzone = config.trans_vel_deadzone;
-  limits.split_ignore_length = config.split_ignore_length;
-  limits.xy_goal_tolerance = config.xy_goal_tolerance;
-  limits.yaw_goal_tolerance = config.yaw_goal_tolerance;
-  limits.prune_plan = config.prune_plan;
-  limits.trans_stopped_vel = config.trans_stopped_vel;
-  limits.rot_stopped_vel = config.rot_stopped_vel;
-  planner_util_.reconfigure_callback(limits, config.restore_defaults);
+  planner_util_.reconfigure_callback(config, config.restore_defaults);
   this->last_cmds.resize(config.cmd_vel_avg);
-  this->use_steer_angle_cmd=config.use_steer_angle_cmd;
-  this->invert_steer_angle_cmd=config.invert_steer_angle_cmd;
-  this->use_stopped_steering=config.use_stopped_steering;
-
-  this->stopped_steering_angle_threshold=config.stopped_steering_angle_threshold;
-  this->use_stuck_check = config.use_stuck_check;
-  this->stuck_check_vel_threshold=config.stuck_check_vel_threshold;
-  this->stuck_check_max_occurrences=config.stuck_check_max_occurrences;
-
   odom_helper_.set_average_samples(config.odom_avg);
 
-  patience_=config.planner_patience;
+  current_config_=config;
 
   // update ackermann specific configuration
   dp_->reconfigure(config);
@@ -136,13 +103,16 @@ void AckermannPlannerROS::initialize(std::string name,tf2_ros::Buffer* tf,costma
     dp_ = boost::shared_ptr<AckermannPlanner>(new AckermannPlanner(name, &planner_util_));
 
     if( private_nh.getParam( "odom_topic", odom_topic_ ))
-    {
       odom_helper_.set_odom_topic( odom_topic_ );
-    }
+    else
+      ROS_WARN_STREAM("AckermannPlannerROS::initialize -> Parameter odom_topic not found at ns " << private_nh.getNamespace() << "");
+
     if( private_nh.getParam( "ackermann_topic", ackermann_topic_ ))
-    {
       odom_helper_.set_ackermann_topic( ackermann_topic_ );
-    }
+    else
+      ROS_WARN_STREAM("AckermannPlannerROS::initialize -> Parameter ackermann_topic not found at ns " << private_nh.getNamespace() << "");
+    
+    odom_helper_.set_costmap(costmap_ros_);
 
     initialized_ = true;
 
@@ -153,9 +123,7 @@ void AckermannPlannerROS::initialize(std::string name,tf2_ros::Buffer* tf,costma
     this->first=true;
   }
   else
-  {
     ROS_WARN("AckermannPlannerROS: this planner has already been initialized, doing nothing.");
-  }
 }
 
 bool AckermannPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan) {
@@ -195,23 +163,21 @@ bool AckermannPlannerROS::ackermann_compute_velocity_commands(geometry_msgs::Pos
   }
 
   ackermann_msgs::AckermannDrive ackermann;
-  AckermannPlannerLimits limits; 
-
   odom_helper_.get_ackermann_state(ackermann);
-  limits=planner_util_.get_current_limits();
+
   // saturate speeds and angles
-  if(ackermann.speed>limits.max_trans_vel)
-    ackermann.speed=limits.max_trans_vel;
-  else if(ackermann.speed<limits.min_trans_vel)
-    ackermann.speed=limits.min_trans_vel;
-  if(ackermann.steering_angle>limits.max_steer_angle)
-    ackermann.steering_angle=limits.max_steer_angle;
-  else if(ackermann.steering_angle<limits.min_steer_angle)
-    ackermann.steering_angle=limits.min_steer_angle;
-  if(ackermann.steering_angle_velocity>limits.max_steer_vel)
-    ackermann.steering_angle_velocity=limits.max_steer_vel;
-  else if(ackermann.steering_angle_velocity<limits.min_steer_vel)
-    ackermann.steering_angle_velocity=limits.min_steer_vel;
+  if(ackermann.speed>current_config_.max_trans_vel)
+    ackermann.speed=current_config_.max_trans_vel;
+  else if(ackermann.speed<current_config_.min_trans_vel)
+    ackermann.speed=current_config_.min_trans_vel;
+  if(ackermann.steering_angle>current_config_.max_steer_angle)
+    ackermann.steering_angle=current_config_.max_steer_angle;
+  else if(ackermann.steering_angle<current_config_.min_steer_angle)
+    ackermann.steering_angle=current_config_.min_steer_angle;
+  if(ackermann.steering_angle_velocity>current_config_.max_steer_vel)
+    ackermann.steering_angle_velocity=current_config_.max_steer_vel;
+  else if(ackermann.steering_angle_velocity<current_config_.min_steer_vel)
+    ackermann.steering_angle_velocity=current_config_.min_steer_vel;
 
   //compute what trajectory to drive along
   geometry_msgs::PoseStamped drive_cmds;
@@ -224,7 +190,7 @@ bool AckermannPlannerROS::ackermann_compute_velocity_commands(geometry_msgs::Pos
   //pass along drive commands
   cmd_vel.linear.x = drive_cmds.pose.position.x;
   cmd_vel.linear.y = drive_cmds.pose.position.y;
-  if(this->invert_steer_angle_cmd)
+  if(current_config_.invert_steer_angle_cmd)
     cmd_vel.angular.z = -tf::getYaw(drive_cmds.pose.orientation);
   else
     cmd_vel.angular.z = tf::getYaw(drive_cmds.pose.orientation);
@@ -238,7 +204,7 @@ bool AckermannPlannerROS::ackermann_compute_velocity_commands(geometry_msgs::Pos
     local_plan.clear();
     publish_local_plan(local_plan);
     count++;
-    if(count>patience_)
+    if(count>current_config_.planner_patience)
     {
       count=0;
       return false;
@@ -278,7 +244,7 @@ bool AckermannPlannerROS::ackermann_compute_velocity_commands(geometry_msgs::Pos
 bool AckermannPlannerROS::isGoalReached(void)
 {
   nav_msgs::Odometry odom;
-  AckermannPlannerLimits limits;
+  bool forward;
 
   if (! is_initialized()) {
     ROS_ERROR("AckermannPlannerROS: this planner has not been initialized, please call initialize() before using this planner");
@@ -289,13 +255,18 @@ bool AckermannPlannerROS::isGoalReached(void)
     return false;
   }
   std::vector<geometry_msgs::PoseStamped> transformed_plan;
-  if ( ! planner_util_.get_local_plan(current_pose_, transformed_plan))
+  if ( ! planner_util_.get_local_plan(current_pose_, transformed_plan,forward))
   {
     ROS_ERROR("AckermannPlannerROS: could not get local plan");
     return false;
   }
+  if(transformed_plan.empty()) 
+  {
+    ROS_WARN_NAMED("AckermannPlannerROS", "Received an empty transformed plan.");
+    return false;
+  }
+ 
   odom_helper_.get_odom(odom);
-  limits=planner_util_.get_current_limits();
   if(planner_util_.last_path())
   {
     if(base_local_planner::isGoalReached(*tf_,
@@ -304,8 +275,8 @@ bool AckermannPlannerROS::isGoalReached(void)
                                          costmap_ros_->getGlobalFrameID(),
                                          current_pose_,
                                          odom,
-                                         limits.rot_stopped_vel,limits.trans_stopped_vel,
-                                         limits.xy_goal_tolerance,limits.yaw_goal_tolerance))
+                                         current_config_.rot_stopped_vel,current_config_.trans_stopped_vel,
+                                         current_config_.xy_goal_tolerance,current_config_.yaw_goal_tolerance))
     {
       ROS_INFO("AckermannPlannerROS: Goal reached");
       return true;
@@ -313,7 +284,25 @@ bool AckermannPlannerROS::isGoalReached(void)
     else if(this->stuck)
       return true;
     else
-      return false;
+    {
+      double yaw=tf::getYaw(current_pose_.pose.orientation);
+      if(yaw<0.0)
+        yaw+=3.14159*2.0;
+      double goal_dist=sqrt(pow(transformed_plan.back().pose.position.x-current_pose_.pose.position.x,2.0)+pow(transformed_plan.back().pose.position.y-current_pose_.pose.position.y,2.0));
+      double x_dist=((transformed_plan.back().pose.position.x-current_pose_.pose.position.x)*cos(yaw)+(transformed_plan.back().pose.position.y-current_pose_.pose.position.y)*sin(yaw));
+      if(forward && x_dist<0.0 && goal_dist<current_config_.goal_dist)
+      {
+        ROS_INFO_STREAM("AckermannPlannerROS: Goal reached (x_dist: " << x_dist << " goal_dist: " << goal_dist);
+        return true;
+      }
+      else if(!forward && x_dist>0.0 && goal_dist<current_config_.goal_dist)
+      {
+        ROS_INFO_STREAM("AckermannPlannerROS: Goal reached (x_dist: " << x_dist << " goal_dist: " << goal_dist);
+        return true;
+      }
+      else
+        return false;
+    }
   } 
   else
     return false;
@@ -350,11 +339,11 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
 {
   geometry_msgs::Twist tmp_cmd_vel;
   nav_msgs::Odometry odom;
-  AckermannPlannerLimits limits;
   geometry_msgs::PoseStamped goal_pose;
   static int stuck_count=0;
   static int replan_count=0;
   static bool new_segment=false;
+  bool forward,goal_passed,goal_reached;
 
   // dispatches to either ackermann sampling control or stop and rotate control, depending on whether we have been close enough to goal
   if ( ! costmap_ros_->getRobotPose(current_pose_)) 
@@ -370,7 +359,7 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
     return false;
   }
   std::vector<geometry_msgs::PoseStamped> transformed_plan;
-  if ( ! planner_util_.get_local_plan(current_pose_, transformed_plan)) 
+  if ( ! planner_util_.get_local_plan(current_pose_, transformed_plan,forward)) 
   {
     ROS_ERROR("AckermannPlannerROS: could not get local plan");
     cmd_vel.linear.x = 0.0;
@@ -399,18 +388,30 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
   ROS_DEBUG_NAMED("ackermann_local_planner", "Received a transformed plan with %zu points.", transformed_plan.size());
 
   // update plan in ackermann_planner even if we just stop and rotate, to allow checkTrajectory
-  dp_->update_plan_and_local_costs(current_pose_, transformed_plan);
-
+  dp_->update_plan_and_local_costs(current_pose_, transformed_plan,forward);
+
+  double yaw=tf::getYaw(current_pose_.pose.orientation);
+  if(yaw<0.0)
+    yaw+=3.14159*2.0;
+  if(forward && ((transformed_plan.back().pose.position.x-current_pose_.pose.position.x)*cos(yaw)+(transformed_plan.back().pose.position.y-current_pose_.pose.position.y)*sin(yaw))<0.0)
+    goal_passed=true;
+  else if(!forward && ((transformed_plan.back().pose.position.x-current_pose_.pose.position.x)*cos(yaw)+(transformed_plan.back().pose.position.y-current_pose_.pose.position.y)*sin(yaw))>0.0)
+    goal_passed=true;
+  else
+    goal_passed=false;
   odom_helper_.get_odom(odom);
-  limits=planner_util_.get_current_limits();
-  if(this->stuck || base_local_planner::isGoalReached(*tf_,
-                                                        transformed_plan,
-                                                        *costmap_ros_->getCostmap(),
-                                                        costmap_ros_->getGlobalFrameID(),
-                                                        current_pose_,
-                                                        odom,
-                                                        limits.rot_stopped_vel,limits.trans_stopped_vel,
-                                                        limits.xy_goal_tolerance,limits.yaw_goal_tolerance))
+  if(base_local_planner::isGoalReached(*tf_,
+                                       transformed_plan,
+                                       *costmap_ros_->getCostmap(),
+                                       costmap_ros_->getGlobalFrameID(),
+                                       current_pose_,
+                                       odom,
+                                       current_config_.rot_stopped_vel,current_config_.trans_stopped_vel,
+                                       current_config_.xy_goal_tolerance,current_config_.yaw_goal_tolerance))
+    goal_reached=true;
+  else
+    goal_reached=false;
+  if(this->stuck || goal_reached || goal_passed)
   {
     if(planner_util_.set_next_path())
     {
@@ -453,17 +454,17 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
       ackermann_msgs::AckermannDrive ackermann;
       odom_helper_.get_ackermann_state(ackermann);
       // steer the car without moving if the steering angle is big
-      if(this->use_steer_angle_cmd && this->use_stopped_steering)
+      if(current_config_.use_steer_angle_cmd && current_config_.use_stopped_steering)
       {
         double ang_z = cmd_vel.angular.z;
-        if(this->invert_steer_angle_cmd)
+        if(current_config_.invert_steer_angle_cmd)
           ang_z = -ang_z;
 
         double diff = fabs(ackermann.steering_angle-ang_z);
-        if(diff > this->stopped_steering_angle_threshold)
+        if(diff > current_config_.stopped_steering_angle_threshold)
         {
-          //ROS_INFO("AckermannPlannerROS: steering without moving")
-          //ROS_INFO("AckermannPlannerROS: stopped steering. Angle current - target = %f - %f = %f, vs threshold %f )",ackermann.steering_angle, ang_z, diff, this->stopped_steering_angle_threshold);
+          ROS_INFO("AckermannPlannerROS: steering without moving");
+          ROS_INFO("AckermannPlannerROS: stopped steering. Angle current - target = %f - %f = %f, vs threshold %f )",ackermann.steering_angle, ang_z, diff, current_config_.stopped_steering_angle_threshold);
           cmd_vel.linear.x=0.0;
         }
         else
@@ -482,20 +483,33 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
           new_segment=false;
       }
     }
-    else if(this->use_stuck_check && fabs(cmd_vel.linear.x)<this->stuck_check_vel_threshold)
+    else if(current_config_.use_stuck_check && fabs(cmd_vel.linear.x)<current_config_.stuck_check_vel_threshold)
     {
-       //ROS_INFO_STREAM("linear.x " << cmd_vel.linear.x << " deadzone: " << limits.trans_vel_deadzone );
+       //ROS_INFO_STREAM("linear.x " << cmd_vel.linear.x << " deadzone: " << current_config_.trans_vel_deadzone );
        // get the position of the goal
-       base_local_planner::getGoalPose(*tf_,
-                                       transformed_plan,
-                                       costmap_ros_->getGlobalFrameID(),
-                                       goal_pose);
+       if(!base_local_planner::getGoalPose(*tf_,
+                                           transformed_plan,
+                                           costmap_ros_->getGlobalFrameID(),
+                                           goal_pose))
+       {
+         ROS_WARN_NAMED("ackermann_local_planner", "Ackermann planner failed to produce path.");
+         std::vector<geometry_msgs::PoseStamped> empty_plan;
+         publish_global_plan(empty_plan);
+         cmd_vel.linear.x = 0.0;
+         cmd_vel.linear.y = 0.0;
+         cmd_vel.angular.z = 0.0;
+         this->stuck=false;
+         new_segment=false;
+         replan_count=0;
+         stuck_count=0;
+         return false;
+       }
        // get the distance to the goal
        double dist=base_local_planner::getGoalPositionDistance(current_pose_,goal_pose.pose.position.x,goal_pose.pose.position.y);
-       if(dist>limits.xy_goal_tolerance && dist<2*limits.xy_goal_tolerance)
+       if(dist>current_config_.xy_goal_tolerance && dist<2*current_config_.xy_goal_tolerance)
        {
          stuck_count++;
-         if(stuck_count>this->stuck_check_max_occurrences)
+         if(stuck_count>current_config_.stuck_check_max_occurrences)
          {
            this->stuck=true;
            ROS_INFO("AckermannPlannerROS: Robot may be stuck near segment end point. Jumping to the next path segment");
@@ -504,7 +518,7 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
        else
        {
          replan_count++;
-         if(replan_count>this->stuck_check_max_occurrences)
+         if(replan_count>current_config_.stuck_check_max_occurrences)
          {
            ROS_INFO("AckermannPlannerROS: Robot seems stuck. Replanning");
            cmd_vel.linear.x = 0.0;
@@ -526,16 +540,7 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
     }
 
     if (isOk) 
-    {
       publish_global_plan(transformed_plan);
-      if(limits.use_trans_vel_deadzone && fabs(cmd_vel.linear.x)<limits.trans_vel_deadzone)
-      { 
-        if(cmd_vel.linear.x>0.0)
-          cmd_vel.linear.x=limits.trans_vel_deadzone;
-        else if(cmd_vel.linear.x<0.0)
-          cmd_vel.linear.x=-limits.trans_vel_deadzone;
-      }
-    }
     else 
     {
       ROS_WARN_NAMED("ackermann_local_planner", "Ackermann planner failed to produce path.");
diff --git a/src/ackermann_planner_util.cpp b/src/ackermann_planner_util.cpp
index 11254acddd7b05a3076e7eef7445407690fc01cc..34dc68931e1f3c6c039793a49483fdfc237c8c39 100644
--- a/src/ackermann_planner_util.cpp
+++ b/src/ackermann_planner_util.cpp
@@ -36,6 +36,7 @@
  *********************************************************************/
 
 #include <ackermann_planner_util.h>
+#include <tf/transform_datatypes.h>
 
 #include <base_local_planner/goal_functions.h>
 
@@ -50,6 +51,7 @@ void AckermannPlannerUtil::initialize(tf2_ros::Buffer* tf, costmap_2d::Costmap2D
   {
     tf_ = tf;
     costmap_ = costmap;
+    this->world_model_= new base_local_planner::CostmapModel(*costmap_);
     global_frame_ = global_frame;
     initialized_ = true;
   }
@@ -59,18 +61,19 @@ void AckermannPlannerUtil::initialize(tf2_ros::Buffer* tf, costmap_2d::Costmap2D
   }
 }
 
-void AckermannPlannerUtil::reconfigure_callback(AckermannPlannerLimits &config, bool restore_defaults)
+void AckermannPlannerUtil::reconfigure_callback(iri_ackermann_local_planner::AckermannLocalPlannerConfig &config, bool restore_defaults)
 {
-  if(setup_ && restore_defaults) 
-    config = default_limits_;
+  static bool setup=false;
 
-  if(!setup_) 
+  if(setup && restore_defaults) 
+    config = default_config_;
+
+  if(!setup) 
   {
-    default_limits_ = config;
-    setup_ = true;
+    default_config_ = config;
+    setup = true;
   }
-  boost::mutex::scoped_lock l(limits_configuration_mutex_);
-  limits_ = AckermannPlannerLimits(config);
+  current_config_=config;
 }
 
 costmap_2d::Costmap2D* AckermannPlannerUtil::get_costmap() 
@@ -78,10 +81,9 @@ costmap_2d::Costmap2D* AckermannPlannerUtil::get_costmap()
   return costmap_;
 }
 
-AckermannPlannerLimits AckermannPlannerUtil::get_current_limits() 
+base_local_planner::CostmapModel *AckermannPlannerUtil::get_world_model()
 {
-  boost::mutex::scoped_lock l(limits_configuration_mutex_);
-  return limits_;
+  return world_model_;
 }
 
 std::string AckermannPlannerUtil::get_global_frame(void)
@@ -101,57 +103,97 @@ bool AckermannPlannerUtil::set_plan(const std::vector<geometry_msgs::PoseStamped
     ROS_ERROR("AckermannPlannerUtil: planner utils have not been initialized, please call initialize() first");
     return false;
   }
-  ////divide plan by manuveurs
   subPathList.clear();
   subPath.clear();
+  forward_segment.clear();
   subPathIndex      = 0;
-  double pathLength = 0;
+  double pathLength = 0, yaw;
   for(unsigned int i = 0; i < orig_global_plan.size(); ++i)
+    std::cout << orig_global_plan[i].pose.position.x << "," << orig_global_plan[i].pose.position.y << "," << tf::getYaw(orig_global_plan[i].pose.orientation) << std::endl;
+  if(orig_global_plan.size()<5)
   {
-    if(i>2 && i<(orig_global_plan.size()-1))
+    for(unsigned int i = 0; i < orig_global_plan.size(); ++i)
+      subPath.push_back(orig_global_plan[i]);
+  }
+  else
+  {
+    ////divide plan by manuveurs
+    for(unsigned int i = 0; i < orig_global_plan.size(); ++i)
     {
-      double x_1 = orig_global_plan[i+1].pose.position.x;
-      double x0 = orig_global_plan[i  ].pose.position.x;
-      double x1 = orig_global_plan[i-1].pose.position.x;
-      double x2 = orig_global_plan[i-2].pose.position.x;
-      double x3 = orig_global_plan[i-3].pose.position.x;
-      double y0 = orig_global_plan[i  ].pose.position.y;
-      double y_1 = orig_global_plan[i+1].pose.position.y;
-      double y1 = orig_global_plan[i-1].pose.position.y;
-      double y2 = orig_global_plan[i-2].pose.position.y;
-      double y3 = orig_global_plan[i-3].pose.position.y;
-      double angle=((x0-x1)*(x1-x2)+(y0-y1)*(y1-y2))/(std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2))*std::sqrt(std::pow(x1-x2,2)+std::pow(y1-y2,2)));
-      if(angle<-1.0)
-        angle=-1.0;
-      else if(angle>1.0)
-        angle=1.0;
-      angle=std::acos(angle);
-      pathLength+= std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2));
-      if(fabs(angle)>1.57) //if changes of direction detected
+      if(i>2 && i<(orig_global_plan.size()-1))
       {
-        angle=((x_1-x0)*(x2-x3)+(y_1-y0)*(y2-y3))/(std::sqrt(std::pow(x_1-x0,2)+std::pow(y_1-y0,2))*std::sqrt(std::pow(x2-x3,2)+std::pow(y2-y3,2)));
+        double x_1 = orig_global_plan[i+1].pose.position.x;
+        double x0 = orig_global_plan[i  ].pose.position.x;
+        double x1 = orig_global_plan[i-1].pose.position.x;
+        double x2 = orig_global_plan[i-2].pose.position.x;
+        double x3 = orig_global_plan[i-3].pose.position.x;
+        double y0 = orig_global_plan[i  ].pose.position.y;
+        double y_1 = orig_global_plan[i+1].pose.position.y;
+        double y1 = orig_global_plan[i-1].pose.position.y;
+        double y2 = orig_global_plan[i-2].pose.position.y;
+        double y3 = orig_global_plan[i-3].pose.position.y;
+        double angle=((x0-x1)*(x1-x2)+(y0-y1)*(y1-y2))/(std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2))*std::sqrt(std::pow(x1-x2,2)+std::pow(y1-y2,2)));
+        double curvature;
+        curvature=((x_1-x0)*(y0-2*y1+y2)-(x0-2*x1+x2)*(y_1-y0))/sqrt(pow(pow(x_1-x0,2.0)+pow(y_1-y0,2.0),3.0));
+//        std::cout << curvature << std::endl;
         if(angle<-1.0)
           angle=-1.0;
         else if(angle>1.0)
           angle=1.0;
         angle=std::acos(angle);
-        if(fabs(angle)>1.57)
+        pathLength+= std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2));
+        if(fabs(angle)>1.57) //if changes of direction detected
         {
-          if(pathLength>limits_.split_ignore_length)
-          {
-            //ROS_INFO("AckermannPlannerUtil::setPlan: subPath split at i=%d, angle=%f, length=%f", i, angle, pathLength);
-            subPathList.push_back(subPath);
-          }
-          else //ignored subpath, too short
+          angle=((x_1-x0)*(x2-x3)+(y_1-y0)*(y2-y3))/(std::sqrt(std::pow(x_1-x0,2)+std::pow(y_1-y0,2))*std::sqrt(std::pow(x2-x3,2)+std::pow(y2-y3,2)));
+          if(angle<-1.0)
+            angle=-1.0;
+          else if(angle>1.0)
+            angle=1.0;
+          angle=std::acos(angle);
+          if(fabs(angle)>1.57)
           {
-            //ROS_INFO("AckermannPlannerUtil::setPlan: subPath split at i=%d, angle=%f, Ignored by length=%f", i, angle, pathLength);
+            if(pathLength>current_config_.split_ignore_length)
+            {
+              //ROS_INFO("AckermannPlannerUtil::setPlan: subPath split at i=%d, angle=%f, length=%f", i, angle, pathLength);
+              yaw=tf::getYaw(subPath[0].pose.orientation);
+              if(yaw<0.0)
+                yaw+=3.14159*2.0;
+              if(((subPath[subPath.size()-1].pose.position.x-subPath[0].pose.position.x)*cos(yaw)+(subPath[subPath.size()-1].pose.position.y-subPath[0].pose.position.y)*sin(yaw))<0.0)
+              {
+                std::cout << "backward segment" << std::endl;
+                this->forward_segment.push_back(false);
+              }
+              else
+              {
+                std::cout << "forward segment" << std::endl;
+                this->forward_segment.push_back(true);
+              }
+              subPathList.push_back(subPath);
+            }
+            else //ignored subpath, too short
+            {
+              //ROS_INFO("AckermannPlannerUtil::setPlan: subPath split at i=%d, angle=%f, Ignored by length=%f", i, angle, pathLength);
+            }
+            subPath.clear();
+            pathLength=0.0;
           }
-          subPath.clear();
-          pathLength=0.0;
         }
       }
+      subPath.push_back(orig_global_plan[i]);
     }
-    subPath.push_back(orig_global_plan[i]);
+  }
+  yaw=tf::getYaw(subPath[0].pose.orientation);
+  if(yaw<0.0)
+    yaw+=3.14159*2.0;
+  if(((subPath[subPath.size()-1].pose.position.x-subPath[0].pose.position.x)*cos(yaw)+(subPath[subPath.size()-1].pose.position.y-subPath[0].pose.position.y)*sin(yaw))<0.0)
+  {
+    std::cout << "backward segment" << std::endl;
+    this->forward_segment.push_back(false);
+  }
+  else
+  {
+    std::cout << "forward segment" << std::endl;
+    this->forward_segment.push_back(true);
   }
   subPathList.push_back(subPath);
   //ROS_INFO("AckermannPlannerUtil::setPlan: subPath last length=%f", pathLength);
@@ -161,6 +203,7 @@ bool AckermannPlannerUtil::set_plan(const std::vector<geometry_msgs::PoseStamped
   global_plan_.clear();
 
   global_plan_ = subPathList[subPathIndex];
+  this->plan_forward=this->forward_segment[subPathIndex];
 
   return true;
 }
@@ -173,6 +216,7 @@ bool AckermannPlannerUtil::set_next_path(void)
     subPathIndex++;
     global_plan_.clear();
     global_plan_ = subPathList[subPathIndex];
+    this->plan_forward=this->forward_segment[subPathIndex];
     return true;
   }
   else
@@ -188,10 +232,13 @@ bool AckermannPlannerUtil::last_path(void)
     return false;
 }
 
-bool AckermannPlannerUtil::get_local_plan(geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan) 
+bool AckermannPlannerUtil::get_local_plan(geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan,bool &forward) 
 {
-  global_pose.header.stamp-=ros::Duration(1.0);
-
+  if (!tf_->canTransform(global_frame_, ros::Time::now(), global_plan_[0].header.frame_id, global_plan_[0].header.stamp, global_plan_[0].header.frame_id, ros::Duration(0.5)))
+  {
+    ROS_ERROR_STREAM("AckermannPlannerUtil::get_local_plan -> no tf from " << global_frame_ << " to " << global_plan_[0].header.frame_id << " from " << global_plan_[0].header.stamp << " to " << ros::Time::now());
+    return false;
+  }
   //get the global plan in our frame
   if(!base_local_planner::transformGlobalPlan(*tf_,global_plan_,global_pose,*costmap_,global_frame_,transformed_plan)) {
     ROS_WARN("AckermannPlannerUtil: could not transform the global plan to the frame of the controller");
@@ -199,13 +246,19 @@ bool AckermannPlannerUtil::get_local_plan(geometry_msgs::PoseStamped& global_pos
   }
 
   //now we'll prune the plan based on the position of the robot
-  if(limits_.prune_plan) 
+  if(current_config_.prune_plan) 
     base_local_planner::prunePlan(global_pose, transformed_plan, global_plan_);
 
+  forward=plan_forward;
+
   return true;
 }
 
 AckermannPlannerUtil::~AckermannPlannerUtil()
 {
-
+  if(this->world_model_!=NULL)
+  {
+    delete this->world_model_;
+    this->world_model_=NULL;
+  }
 }
diff --git a/src/ackermann_spline_generator.cpp b/src/ackermann_spline_generator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8a88edb528b9a251567a8317bbf5d933160dde50
--- /dev/null
+++ b/src/ackermann_spline_generator.cpp
@@ -0,0 +1,286 @@
+/*********************************************************************
+ *
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2008, Willow Garage, Inc.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: TKruse
+ *********************************************************************/
+
+#include <ackermann_spline_generator.h>
+
+#include <cmath>
+#include <iostream>
+#include <algorithm> 
+#include <limits>
+
+#include <ros/console.h>
+#include <tf/transform_datatypes.h>
+
+#include "exceptions.h"
+
+AckermannSplineGenerator::AckermannSplineGenerator()
+{
+}
+
+unsigned int AckermannSplineGenerator::get_path_closest_pose(double &path_x,double &path_y)
+{
+  double dist,min_dist=std::numeric_limits<double>::max();
+  unsigned int min_index=0;
+
+  /* find the path point closest to the robot */
+  for(unsigned int i=0;i<this->current_plan.size();i++)
+  {
+    dist=sqrt(pow(pos_(0)-this->current_plan[i].pose.position.x,2.0)+pow(pos_(1)-this->current_plan[i].pose.position.y,2.0));
+    if(dist<min_dist)
+    {
+      min_dist=dist;
+      min_index=i;
+    }
+  }
+  path_x=this->current_plan[min_index].pose.position.x;
+  path_y=this->current_plan[min_index].pose.position.y;
+  
+  return min_index;
+}
+
+void AckermannSplineGenerator::initialise(
+  const Eigen::Vector3f& pos,
+  const Eigen::Vector3f& ackermann,//[0] -> trans_vel, [1]-> steer_angle, [2]-> steer_vel
+  const Eigen::Vector3f& goal,
+  bool forward,
+  std::vector<geometry_msgs::PoseStamped>& current_plan)
+{
+  double diff_x,diff_y,current_x,current_y,step; 
+  double min_n1,max_n1,min_n2,max_n2,min_n3,max_n3,min_n4,max_n4;
+  double n1_step, n2_step, n3_step, n4_step;
+  unsigned int int_step,current_index,num_samples;
+  TSplineSample new_sample;
+  
+  try{
+    this->forward=forward;
+    this->current_plan=current_plan;
+    pos_=pos;
+    ackermann_=ackermann;
+    goal_pos_=goal;
+    next_sample_index_=0;
+    min_n1=0.0;
+    min_n2=0.0;
+    min_n3=0.0;
+    max_n3=0.0;
+    min_n4=0.0;
+    max_n4=0.0;
+    samples_.clear();
+    current_index=this->get_path_closest_pose(current_x,current_y);
+    step=(current_plan.size()-current_index)/current_config_.dist_samples;
+    if(step<current_config_.min_segment_points)
+    {
+      num_samples=(current_plan.size()-current_index)/current_config_.min_segment_points;
+      if(num_samples==0)
+      {
+        num_samples=1;
+        step=(current_plan.size()-current_index);
+      }
+      else
+        step=(current_plan.size()-current_index)/num_samples;
+    }
+    else
+      num_samples=current_config_.dist_samples;
+    for(unsigned int i=0;i<num_samples;i++)
+    {
+      int_step=current_index+(unsigned int)(step*(i+1));
+      Eigen::Vector3f tmp_goal=Eigen::Vector3f(current_plan[int_step-1].pose.position.x,current_plan[int_step-1].pose.position.y,tf::getYaw(current_plan[int_step-1].pose.orientation));
+      diff_x=sqrt(pow(tmp_goal(0)-pos(0),2));
+      diff_y=sqrt(pow(tmp_goal(1)-pos(1),2));
+      max_n1=2.0*diff_x;
+      if (max_n1 < min_n1)
+        max_n1 = min_n1;
+      max_n2 = 2.0*diff_y;
+      if (max_n2 < min_n2)
+        max_n2 = min_n2;
+
+      if (current_config_.n1_samples == 1 || max_n1 == min_n1)
+        n1_step = std::numeric_limits<double>::max();
+      else
+        n1_step = (max_n1-min_n1)/(current_config_.n1_samples-1);
+      if (current_config_.n2_samples == 1 || max_n2 == min_n2)
+        n2_step = std::numeric_limits<double>::max();
+      else
+        n2_step = (max_n2-min_n2)/(current_config_.n2_samples-1);
+      if (current_config_.n3_samples == 1 || max_n3 == min_n3)
+        n3_step = std::numeric_limits<double>::max();
+      else
+        n3_step = (max_n3-min_n3)/(current_config_.n3_samples-1);
+      if (current_config_.n4_samples == 1 || max_n4 == min_n4)
+        n4_step = std::numeric_limits<double>::max();
+      else
+        n4_step = (max_n4-min_n4)/(current_config_.n4_samples-1);
+
+      for(double current_n1=min_n1;current_n1<=max_n1;current_n1+=n1_step)
+        for(double current_n2=min_n2;current_n2<=max_n2;current_n2+=n2_step)
+          for(double current_n3=min_n3;current_n3<=max_n3;current_n3+=n3_step)
+            for(double current_n4=min_n4;current_n4<=max_n4;current_n4+=n4_step)
+            {
+              new_sample.params=Eigen::Vector4f(current_n1,current_n2,current_n3,current_n4);
+              new_sample.end_point.x=tmp_goal(0);
+              new_sample.end_point.y=tmp_goal(1);
+   	          new_sample.end_point.heading=tmp_goal(2);
+              samples_.push_back(new_sample);
+	    } 
+    }
+  }catch(std::exception &e){
+    std::cout << e.what() << std::endl;
+  }
+
+  //Calculate lateral offset
+  y_offset=(-(current_x-pos_(0))*sin(pos_(2))+(current_y-pos_(1))*cos(pos_(2)));
+
+}
+
+void AckermannSplineGenerator::reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &cfg)
+{
+  current_config_=cfg;
+}
+
+/**
+ * Whether this generator can create more trajectories
+ */
+bool AckermannSplineGenerator::hasMoreTrajectories() 
+{
+  return next_sample_index_ < samples_.size();
+}
+
+/**
+ * Create and return the next sample trajectory
+ */
+bool AckermannSplineGenerator::nextTrajectory(base_local_planner::Trajectory &comp_traj) 
+{
+  TPoint start,end;
+  double resolution,k_max;
+  std::vector<double> x,y,curvature,heading;
+
+  try{
+    start.x=pos_(0);
+    start.y=pos_(1);
+    if(this->forward)
+      start.heading=pos_(2);
+    else
+      start.heading=pos_(2)+3.14159;
+    if(fabs(ackermann_(1))<0.001)
+      start.curvature=0.0;
+    else
+      start.curvature=tan(ackermann_(1))/current_config_.axis_distance;
+    spline_.set_start_point(start);
+    //std::cout << "start position: " << pos_(0) << "," << pos_(1) << "," << pos_(2) << "," << start.curvature << std::endl;
+    end.x=samples_[next_sample_index_].end_point.x;
+    end.y=samples_[next_sample_index_].end_point.y;
+    if(this->forward)
+      end.heading=samples_[next_sample_index_].end_point.heading;
+    else
+      end.heading=samples_[next_sample_index_].end_point.heading+3.14159;
+    end.curvature=0.0;
+    spline_.set_end_point(end);
+    //std::cout << "end position: " << end.x << "," << end.y << "," << end.heading << "," << end.curvature << std::endl;
+    resolution=current_config_.sim_granularity;
+    spline_.generate(resolution,samples_[next_sample_index_].params(0),samples_[next_sample_index_].params(1),samples_[next_sample_index_].params(2),samples_[next_sample_index_].params(3));
+    spline_.evaluate_all(x,y,curvature,heading);
+  //  std::cout << "generate: " << samples_[next_sample_index_].params(0) << "," << samples_[next_sample_index_].params(1) << "," << samples_[next_sample_index_].params(2) << "," << samples_[next_sample_index_].params(3) << std::endl;
+    // discard trajectories with two much curvature
+    k_max=0.0;
+    for(unsigned int i=0;i<curvature.size();i++)
+      if(fabs(curvature[i])>k_max)
+        k_max=fabs(curvature[i]);
+    next_sample_index_++;
+    if(k_max>current_config_.max_curvature)
+      return false;
+    /* fill the ouput trajectory object */
+    double k_max_speed,min_max_speed,new_start_vel,new_max_vel;
+    double acceleration,length,steer_angle;
+    CVelTrapezoid vel_profile;
+    TPoint point;
+
+    if(k_max==0)
+      k_max_speed=std::numeric_limits<double>::max();
+    else
+      k_max_speed=sqrt(current_config_.comfort_lat_acc/fabs(k_max));
+    min_max_speed=std::min(current_config_.max_trans_vel,k_max_speed);
+    if(vel_profile.generate(fabs(ackermann_(0)),0.0,min_max_speed,current_config_.max_trans_acc,spline_.get_length(),new_start_vel,new_max_vel))
+    {
+      try{
+        vel_profile.evaluate_at_time(current_config_.temp_horizon,comp_traj.xv_,acceleration,length);
+      }catch(CException &e){
+        length=spline_.get_length();
+        comp_traj.xv_=vel_profile.get_max_vel();
+      }
+      if(!this->forward)
+        comp_traj.xv_*=-1.0;
+      comp_traj.yv_=0.0;
+      spline_.evaluate(length, point);
+      comp_traj.thetav_=-(point.heading-start.heading);
+      if(comp_traj.thetav_>3.14159)
+        comp_traj.thetav_-=2*3.14159;
+      else if(comp_traj.thetav_<-3.14159)
+        comp_traj.thetav_+=2*3.14159;
+      if(forward)
+        comp_traj.thetav_-=atan2(current_config_.lateral_offset_gain*y_offset,comp_traj.xv_);
+      else
+        comp_traj.thetav_+=atan2(current_config_.lateral_offset_gain*y_offset,-comp_traj.xv_);
+      if(forward)
+        comp_traj.thetav_*=-1.0;
+      if(comp_traj.thetav_>current_config_.max_steer_angle)
+        comp_traj.thetav_=current_config_.max_steer_angle;
+      else if(comp_traj.thetav_<current_config_.min_steer_angle)
+        comp_traj.thetav_=current_config_.min_steer_angle;
+      comp_traj.resetPoints();
+      for(unsigned int i=0;i<x.size();i++)
+        comp_traj.addPoint(x[i],y[i],heading[i]);
+      return true;
+    }
+    else
+      return false;
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;	  
+    return false;
+  }catch(std::exception &e){
+    std::cout << e.what() << std::endl;	  
+    return false;
+  }
+}
+
+void AckermannSplineGenerator::set_sim_period(double period)
+{
+  sim_period_=period;
+}
+
+AckermannSplineGenerator::~AckermannSplineGenerator()
+{
+
+}
diff --git a/src/ackermann_trajectory_generator.cpp b/src/ackermann_trajectory_generator.cpp
index 789c1bec6b67391fa0c1da31ac61dc6e83f0d332..85a77ca0ceddc185a4997864b8e0bdae3d1edb8c 100644
--- a/src/ackermann_trajectory_generator.cpp
+++ b/src/ackermann_trajectory_generator.cpp
@@ -47,16 +47,12 @@
 
 AckermannTrajectoryGenerator::AckermannTrajectoryGenerator()
 {
-  limits_=NULL;
 }
 
 void AckermannTrajectoryGenerator::initialise(
     const Eigen::Vector3f& pos,
     const Eigen::Vector3f& ackermann,//[0] -> trans_vel, [1]-> steer_angle, [2]-> steer_vel
-    const Eigen::Vector3f& goal,
-    AckermannPlannerLimits* limits,
-    const Eigen::Vector2f& vsamples,//trans_vel samples & steer_angle samples
-    bool discretize_by_time) 
+    const Eigen::Vector3f& goal)
 {
   double steer_angle,steer_vel,trans_vel;
   double max_steer_vel,min_steer_vel;
@@ -67,196 +63,206 @@ void AckermannTrajectoryGenerator::initialise(
    * We actually generate all velocity sample vectors here, from which to generate trajectories later on
    */
   pos_ = pos;
-  limits_ = limits;
   ackermann_ = ackermann;
   next_sample_index_ = 0;
   sample_params_.clear();
   // saturate the current ackermann state if necessary
-/*  if(ackermann[0]>limits->max_trans_vel)
-    trans_vel=limits->max_trans_vel;
-  else if (ackermann[0]<limits->min_trans_vel)
-    trans_vel=limits->min_trans_vel;
+/*  if(ackermann[0]>current_config_.max_trans_vel)
+    trans_vel=current_config_.max_trans_vel;
+  else if (ackermann[0]<current_config_.min_trans_vel)
+    trans_vel=current_config_.min_trans_vel;
   else*/
     trans_vel=ackermann[0];
-/*  if(ackermann[1]>limits->max_steer_angle)
-    steer_angle=limits->max_steer_angle;
-  else if(ackermann[1]<limits->min_steer_angle)
-    steer_angle=limits->min_steer_angle;
+/*  if(ackermann[1]>current_config_.max_steer_angle)
+    steer_angle=current_config_.max_steer_angle;
+  else if(ackermann[1]<current_config_.min_steer_angle)
+    steer_angle=current_config_.min_steer_angle;
   else */
     steer_angle=ackermann[1];
-/*  if(ackermann[2]>limits->max_steer_vel)
-    steer_vel=limits->max_steer_vel;
-  else if(ackermann[2]<limits->min_steer_vel)
-    steer_vel=limits->min_steer_vel;
+/*  if(ackermann[2]>current_config_.max_steer_vel)
+    steer_vel=current_config_.max_steer_vel;
+  else if(ackermann[2]<current_config_.min_steer_vel)
+    steer_vel=current_config_.min_steer_vel;
   else*/
     steer_vel=ackermann[2];
   // compute the simulation time
   double dist=sqrt((goal[0]-pos[0])*(goal[0]-pos[0])+(goal[1]-pos[1])*(goal[1]-pos[1]));
-  sim_time_=dist/limits->max_trans_vel+limits->max_trans_vel/limits->max_trans_acc;
-  if(sim_time_>max_sim_time_)
-    sim_time_=max_sim_time_;
-  else if(sim_time_<min_sim_time_)
-    sim_time_=min_sim_time_;
+  sim_time_=dist/current_config_.max_trans_vel+current_config_.max_trans_vel/current_config_.max_trans_acc;
+  if(sim_time_>current_config_.max_sim_time)
+    sim_time_=current_config_.max_sim_time;
+  else if(sim_time_<current_config_.min_sim_time)
+    sim_time_=current_config_.min_sim_time;
   // compute the trajectory times and windows
   if(steer_vel>=0)
   {
-    max_steer_vel=(steer_vel+limits->max_steer_acc*sim_time_)/2.0;
-    if(max_steer_vel>=limits->max_steer_vel)
+    max_steer_vel=(steer_vel+current_config_.max_steer_acc*sim_time_)/2.0;
+    if(max_steer_vel>=current_config_.max_steer_vel)
     {
-      max_steer_vel=limits->max_steer_vel;  
-      T4=sim_time_-(2.0*max_steer_vel-steer_vel)/limits->max_steer_acc;
-      max_steer_angle=max_steer_vel*max_steer_vel/limits->max_steer_acc-steer_vel*steer_vel/(2.0*limits->max_steer_acc)+max_steer_vel*T4+steer_angle;
-      if(max_steer_angle>limits->max_steer_angle) 
+      max_steer_vel=current_config_.max_steer_vel;  
+      T4=sim_time_-(2.0*max_steer_vel-steer_vel)/current_config_.max_steer_acc;
+      max_steer_angle=max_steer_vel*max_steer_vel/current_config_.max_steer_acc-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+max_steer_vel*T4+steer_angle;
+      if(max_steer_angle>current_config_.max_steer_angle) 
       {
-        max_steer_angle=limits->max_steer_angle;
-        T4=(limits->max_steer_angle-steer_angle-max_steer_vel*max_steer_vel/limits->max_steer_acc+steer_vel*steer_vel/(2.0*limits->max_steer_acc))/max_steer_vel;
+        max_steer_angle=current_config_.max_steer_angle;
+        T4=(current_config_.max_steer_angle-steer_angle-max_steer_vel*max_steer_vel/current_config_.max_steer_acc+steer_vel*steer_vel/(2.0*current_config_.max_steer_acc))/max_steer_vel;
         if(T4<0)
         {
           T4=0;
-          max_steer_vel=sqrt(steer_vel*steer_vel/2.0+limits->max_steer_acc*(limits->max_steer_angle-steer_angle));
+          max_steer_vel=sqrt(steer_vel*steer_vel/2.0+current_config_.max_steer_acc*(current_config_.max_steer_angle-steer_angle));
         }
       }
     }
     else
     { 
-      max_steer_angle=max_steer_vel*max_steer_vel/limits->max_steer_acc-steer_vel*steer_vel/(2.0*limits->max_steer_acc)+steer_angle;
+      max_steer_angle=max_steer_vel*max_steer_vel/current_config_.max_steer_acc-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+steer_angle;
       T4=0;
-      if(max_steer_angle>limits->max_steer_angle)
+      if(max_steer_angle>current_config_.max_steer_angle)
       {
-        max_steer_angle=limits->max_steer_angle;
-        max_steer_vel=sqrt(steer_vel*steer_vel/2.0+limits->max_steer_acc*(limits->max_steer_angle-steer_angle));
+        max_steer_angle=current_config_.max_steer_angle;
+        max_steer_vel=sqrt(steer_vel*steer_vel/2.0+current_config_.max_steer_acc*(current_config_.max_steer_angle-steer_angle));
       }
     }
-    min_steer_vel=(steer_vel-limits->max_steer_acc*sim_time_)/2.0;
-    if(min_steer_vel<=limits->min_steer_vel)
+    min_steer_vel=(steer_vel-current_config_.max_steer_acc*sim_time_)/2.0;
+    if(min_steer_vel<=current_config_.min_steer_vel)
     {
-      min_steer_vel=limits->min_steer_vel;
-      T4=sim_time_+(2.0*min_steer_vel-steer_vel)/limits->max_steer_acc;
-      min_steer_angle=steer_vel*steer_vel/(2.0*limits->max_steer_acc)-min_steer_vel*min_steer_vel/limits->max_steer_acc+min_steer_vel*T4+steer_angle;
-      if(min_steer_angle<limits->min_steer_angle)
+      min_steer_vel=current_config_.min_steer_vel;
+      T4=sim_time_+(2.0*min_steer_vel-steer_vel)/current_config_.max_steer_acc;
+      min_steer_angle=steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)-min_steer_vel*min_steer_vel/current_config_.max_steer_acc+min_steer_vel*T4+steer_angle;
+      if(min_steer_angle<current_config_.min_steer_angle)
       {
-        min_steer_angle=limits->min_steer_angle;
-        T4=(limits->min_steer_angle-steer_angle+min_steer_vel*min_steer_vel/limits->max_steer_acc-steer_vel*steer_vel/(2.0*limits->max_steer_acc))/min_steer_vel;
+        min_steer_angle=current_config_.min_steer_angle;
+        T4=(current_config_.min_steer_angle-steer_angle+min_steer_vel*min_steer_vel/current_config_.max_steer_acc-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc))/min_steer_vel;
         if(T4<0)
         {
           T4=0;
-          min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-limits->max_steer_acc*(limits->min_steer_angle-steer_angle));
+          min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-current_config_.max_steer_acc*(current_config_.min_steer_angle-steer_angle));
         }
       }
     }
     else
     {
-      min_steer_angle=steer_vel*steer_vel/(2.0*limits->max_steer_acc)-min_steer_vel*min_steer_vel/limits->max_steer_acc+steer_angle;
+      min_steer_angle=steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)-min_steer_vel*min_steer_vel/current_config_.max_steer_acc+steer_angle;
       T4=0;
-      if(min_steer_angle<limits->min_steer_angle)
+      if(min_steer_angle<current_config_.min_steer_angle)
       {
-        min_steer_angle=limits->min_steer_angle;
-        min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-limits->max_steer_acc*(limits->min_steer_angle-steer_angle)); 
+        min_steer_angle=current_config_.min_steer_angle;
+        min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-current_config_.max_steer_acc*(current_config_.min_steer_angle-steer_angle)); 
       }
     }
   }
   else
   {
-    max_steer_vel=(steer_vel+limits->max_steer_acc*sim_time_)/2.0;
-    if(max_steer_vel>=limits->max_steer_vel)
+    max_steer_vel=(steer_vel+current_config_.max_steer_acc*sim_time_)/2.0;
+    if(max_steer_vel>=current_config_.max_steer_vel)
     {
-      max_steer_vel=limits->max_steer_vel;
-      T4=sim_time_-(2.0*max_steer_vel-steer_vel)/limits->max_steer_acc;
-      max_steer_angle=-steer_vel*steer_vel/(2.0*limits->max_steer_acc)+max_steer_vel*max_steer_vel/limits->max_steer_acc+max_steer_vel*T4+steer_angle;
-      if(max_steer_angle>limits->max_steer_angle)
+      max_steer_vel=current_config_.max_steer_vel;
+      T4=sim_time_-(2.0*max_steer_vel-steer_vel)/current_config_.max_steer_acc;
+      max_steer_angle=-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+max_steer_vel*max_steer_vel/current_config_.max_steer_acc+max_steer_vel*T4+steer_angle;
+      if(max_steer_angle>current_config_.max_steer_angle)
       {
-        max_steer_angle=limits->max_steer_angle;
-        T4=(limits->max_steer_angle-steer_angle-max_steer_vel*max_steer_vel/limits->max_steer_acc+steer_vel*steer_vel/(2.0*limits->max_steer_acc))/max_steer_vel;
+        max_steer_angle=current_config_.max_steer_angle;
+        T4=(current_config_.max_steer_angle-steer_angle-max_steer_vel*max_steer_vel/current_config_.max_steer_acc+steer_vel*steer_vel/(2.0*current_config_.max_steer_acc))/max_steer_vel;
         if(T4<0)
         {
           T4=0;
-          max_steer_vel=sqrt(steer_vel*steer_vel/2.0+limits->max_steer_acc*(limits->max_steer_angle-steer_angle));
+          max_steer_vel=sqrt(steer_vel*steer_vel/2.0+current_config_.max_steer_acc*(current_config_.max_steer_angle-steer_angle));
         }
       }
     }
     else
     {
-      max_steer_angle=-steer_vel*steer_vel/(2.0*limits->max_steer_acc)+max_steer_vel*max_steer_vel/limits->max_steer_acc+steer_angle;
+      max_steer_angle=-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+max_steer_vel*max_steer_vel/current_config_.max_steer_acc+steer_angle;
       T4=0;
-      if(max_steer_angle>limits->max_steer_angle)
+      if(max_steer_angle>current_config_.max_steer_angle)
       {
-        max_steer_angle=limits->max_steer_angle;
-        max_steer_vel=sqrt(steer_vel*steer_vel/2.0+limits->max_steer_acc*(limits->max_steer_angle-steer_angle));
+        max_steer_angle=current_config_.max_steer_angle;
+        max_steer_vel=sqrt(steer_vel*steer_vel/2.0+current_config_.max_steer_acc*(current_config_.max_steer_angle-steer_angle));
       }
     }
-    min_steer_vel=(steer_vel-limits->max_steer_acc*sim_time_)/2.0;
-    if(min_steer_vel<=limits->min_steer_vel)
+    min_steer_vel=(steer_vel-current_config_.max_steer_acc*sim_time_)/2.0;
+    if(min_steer_vel<=current_config_.min_steer_vel)
     {
-      min_steer_vel=limits->min_steer_vel;
-      T4=sim_time_+(2.0*min_steer_vel-steer_vel)/limits->max_steer_acc;
-      min_steer_angle=-min_steer_vel*min_steer_vel/limits->max_steer_acc+steer_vel*steer_vel/(2.0*limits->max_steer_acc)+min_steer_vel*T4+steer_angle;
-      if(min_steer_angle<limits->min_steer_angle)
+      min_steer_vel=current_config_.min_steer_vel;
+      T4=sim_time_+(2.0*min_steer_vel-steer_vel)/current_config_.max_steer_acc;
+      min_steer_angle=-min_steer_vel*min_steer_vel/current_config_.max_steer_acc+steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+min_steer_vel*T4+steer_angle;
+      if(min_steer_angle<current_config_.min_steer_angle)
       {
-        min_steer_angle=limits->min_steer_angle;
-        T4=(limits->min_steer_angle-steer_angle+min_steer_vel*min_steer_vel/limits->max_steer_acc-steer_vel*steer_vel/(2.0*limits->max_steer_acc))/min_steer_vel;
+        min_steer_angle=current_config_.min_steer_angle;
+        T4=(current_config_.min_steer_angle-steer_angle+min_steer_vel*min_steer_vel/current_config_.max_steer_acc-steer_vel*steer_vel/(2.0*current_config_.max_steer_acc))/min_steer_vel;
         if(T4<0)
         {
           T4=0;
-          min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-limits->max_steer_acc*(limits->min_steer_angle-steer_angle));
+          min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-current_config_.max_steer_acc*(current_config_.min_steer_angle-steer_angle));
         }
       }
     }
     else
     {
-      min_steer_angle=-min_steer_vel*min_steer_vel/limits->max_steer_acc+steer_vel*steer_vel/(2.0*limits->max_steer_acc)+steer_angle;
+      min_steer_angle=-min_steer_vel*min_steer_vel/current_config_.max_steer_acc+steer_vel*steer_vel/(2.0*current_config_.max_steer_acc)+steer_angle;
       T4=0;
-      if(min_steer_angle<limits->min_steer_angle)
+      if(min_steer_angle<current_config_.min_steer_angle)
       {
-        min_steer_angle=limits->min_steer_angle;
-        min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-limits->max_steer_acc*(limits->min_steer_angle-steer_angle)); 
+        min_steer_angle=current_config_.min_steer_angle;
+        min_steer_vel=-sqrt(steer_vel*steer_vel/2.0-current_config_.max_steer_acc*(current_config_.min_steer_angle-steer_angle)); 
       }
     }
   }
   double Tacc,Tdeacc;
   // maximum translation speed
-  Tacc=(limits->max_trans_vel-trans_vel)/limits->max_trans_acc;
-  Tdeacc=limits->max_trans_vel/limits->max_trans_acc;
+  Tacc=(current_config_.max_trans_vel-trans_vel)/current_config_.max_trans_acc;
+  Tdeacc=current_config_.max_trans_vel/current_config_.max_trans_acc;
   if((sim_time_-Tacc-Tdeacc)>0.0)
-    max_trans_vel=limits->max_trans_vel;
+    max_trans_vel=current_config_.max_trans_vel;
   else
-    max_trans_vel=(sim_time_*limits->max_trans_acc+trans_vel)/2.0;
+    max_trans_vel=(sim_time_*current_config_.max_trans_acc+trans_vel)/2.0;
   // minimum translation speed
-  Tacc=-(limits->min_trans_vel-trans_vel)/limits->max_trans_acc;
-  Tdeacc=-(limits->min_trans_vel)/limits->max_trans_acc;
+  Tacc=-(current_config_.min_trans_vel-trans_vel)/current_config_.max_trans_acc;
+  Tdeacc=-(current_config_.min_trans_vel)/current_config_.max_trans_acc;
   if((sim_time_-Tacc-Tdeacc)>0.0)
-    min_trans_vel=limits->min_trans_vel;
+    min_trans_vel=current_config_.min_trans_vel;
   else
-    min_trans_vel=-(sim_time_*limits->max_trans_acc-trans_vel)/2.0;
+    min_trans_vel=-(sim_time_*current_config_.max_trans_acc-trans_vel)/2.0;
   /* compute the margins */
   Eigen::Vector2f sample = Eigen::Vector2f::Zero();
-  base_local_planner::VelocityIterator trans_vel_it(min_trans_vel, max_trans_vel, vsamples[0]);
-  base_local_planner::VelocityIterator steer_angle_it(min_steer_angle, max_steer_angle, vsamples[1]);
+  int trans_vel_samp, steer_angle_angular_vel_samp;
+  trans_vel_samp = current_config_.trans_vel_samples;
+  if(current_config_.use_steer_angle_cmd)
+    steer_angle_angular_vel_samp = current_config_.steer_angle_samples;
+  else
+    steer_angle_angular_vel_samp = current_config_.angular_vel_samples;
+
+  if (trans_vel_samp <= 0)
+  {
+    ROS_WARN("You've specified that you don't want any samples in the translational dimension. We'll at least assume that you want to sample one value... so we're going to set vx_samples to 1 instead");
+    trans_vel_samp = 1;
+  }
+
+  if (steer_angle_angular_vel_samp <= 0)
+  {
+    ROS_WARN("You've specified that you don't want any samples in the steering/angular velocity dimension. We'll at least assume that you want to sample one value... so we're going to set vy_samples to 1 instead");
+    steer_angle_angular_vel_samp = 1;
+  }
+
+  base_local_planner::VelocityIterator trans_vel_it(min_trans_vel, max_trans_vel, trans_vel_samp);
+  base_local_planner::VelocityIterator steer_angle_it(min_steer_angle, max_steer_angle, steer_angle_angular_vel_samp);
   for(; !trans_vel_it.isFinished(); trans_vel_it++) 
   {
-    sample[0] = trans_vel_it.getVelocity();
-    for(; !steer_angle_it.isFinished(); steer_angle_it++) 
+    if(!current_config_.use_trans_vel_deadzone || (current_config_.use_trans_vel_deadzone && trans_vel_it.getVelocity()>current_config_.trans_vel_deadzone))
     {
-      sample[1] = steer_angle_it.getVelocity();
-      sample_params_.push_back(sample);
+      sample[0] = trans_vel_it.getVelocity();
+      for(; !steer_angle_it.isFinished(); steer_angle_it++) 
+      {
+        sample[1] = steer_angle_it.getVelocity();
+        sample_params_.push_back(sample);
+      }
+      steer_angle_it.reset();
     }
-    steer_angle_it.reset();
   }
 }
 
-void AckermannTrajectoryGenerator::set_parameters(
-    double max_sim_time,
-    double min_sim_time,
-    double sim_granularity,
-    double angular_sim_granularity,
-    bool use_steer_angle_cmd,
-    double sim_period) 
+void AckermannTrajectoryGenerator::reconfigure(iri_ackermann_local_planner::AckermannLocalPlannerConfig &cfg)
 {
-  max_sim_time_ = max_sim_time;
-  min_sim_time_ = min_sim_time;
-  sim_granularity_ = sim_granularity;
-  angular_sim_granularity_ = angular_sim_granularity;
-  sim_period_ = sim_period;
-  use_steer_angle_cmd_ = use_steer_angle_cmd;
+  current_config_=cfg;
 }
 
 /**
@@ -308,7 +314,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
   traj.cost_   = -1.0; // placed here in case we return early
   //trajectory might be reused so we'll make sure to reset it
   traj.resetPoints();
-  int num_steps = int(sim_time_ / sim_granularity_ + 0.5);
+  int num_steps = int(sim_time_ / current_config_.sim_granularity + 0.5);
   //we at least want to take one step... even if we won't move, we want to score our current position
   if(num_steps == 0)
     num_steps = 1;
@@ -317,22 +323,22 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
   double T1=0.0,T4=0.0,T2=0.0,T3=0.0;
 
   /* check wether the trajectory can be generated or not */
-/*  if(steer_vel_i<0 && (-steer_vel_i*steer_vel_i/(2*limits_->max_steer_acc)+steer_angle_i)>limits_->max_steer_angle)
+/*  if(steer_vel_i<0 && (-steer_vel_i*steer_vel_i/(2*current_config_.max_steer_acc)+steer_angle_i)>current_config_.max_steer_angle)
   {
     ROS_WARN("Impossible steering trajectory: speed: %f, angle: %f",steer_vel_i,steer_angle_i);
     return false;
   }
-  if(steer_vel_i>0 && (steer_vel_i*steer_vel_i/(2*limits_->max_steer_acc)+steer_angle_i)>limits_->max_steer_angle)
+  if(steer_vel_i>0 && (steer_vel_i*steer_vel_i/(2*current_config_.max_steer_acc)+steer_angle_i)>current_config_.max_steer_angle)
   {
     ROS_WARN("Impossible steering trajectory: speed: %f, angle: %f",steer_vel_i,steer_angle_i);
     return false;
   }
-  if(steer_vel_i<0 && (-steer_vel_i*steer_vel_i/(2*limits_->max_steer_acc)+steer_angle_i)<limits_->min_steer_angle)
+  if(steer_vel_i<0 && (-steer_vel_i*steer_vel_i/(2*current_config_.max_steer_acc)+steer_angle_i)<current_config_.min_steer_angle)
   {
     ROS_WARN("Impossible steering trajectory: speed: %f, angle: %f",steer_vel_i,steer_angle_i);
     return false;
   }
-  if(steer_vel_i>0 && (steer_vel_i*steer_vel_i/(2*limits_->max_steer_acc)+steer_angle_i)<limits_->min_steer_angle)
+  if(steer_vel_i>0 && (steer_vel_i*steer_vel_i/(2*current_config_.max_steer_acc)+steer_angle_i)<current_config_.min_steer_angle)
   {
     ROS_WARN("Impossible steering trajectory: speed: %f, angle: %f",steer_vel_i,steer_angle_i);
     return false;
@@ -342,145 +348,145 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
   {
     if(sample_target_vel[1]>steer_angle_i)
     { 
-      speed=(steer_vel_i+limits_->max_steer_acc*sim_time_)/2.0;
-      if(speed>=limits_->max_steer_vel)
+      speed=(steer_vel_i+current_config_.max_steer_acc*sim_time_)/2.0;
+      if(speed>=current_config_.max_steer_vel)
       {
-        speed=limits_->max_steer_vel;  
-        T4=sim_time_-(2.0*speed-steer_vel_i)/limits_->max_steer_acc;
-        angle=speed*speed/limits_->max_steer_acc-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+speed*sim_time_*T4+steer_angle_i;
+        speed=current_config_.max_steer_vel;  
+        T4=sim_time_-(2.0*speed-steer_vel_i)/current_config_.max_steer_acc;
+        angle=speed*speed/current_config_.max_steer_acc-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+speed*sim_time_*T4+steer_angle_i;
         if(angle>sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          T4=(sample_target_vel[1]-steer_angle_i-speed*speed/limits_->max_steer_acc+steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc))/speed;
+          T4=(sample_target_vel[1]-steer_angle_i-speed*speed/current_config_.max_steer_acc+steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc))/speed;
           if(T4<0)
           {
             T4=0;
-            speed=sqrt(steer_vel_i*steer_vel_i/2.0+limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+            speed=sqrt(steer_vel_i*steer_vel_i/2.0+current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
           }
         }
       }
       else
       { 
-        angle=speed*speed/limits_->max_steer_acc-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+steer_angle_i;
+        angle=speed*speed/current_config_.max_steer_acc-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+steer_angle_i;
         T4=0;
         if(angle>sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          speed=sqrt(steer_vel_i*steer_vel_i/2.0+limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+          speed=sqrt(steer_vel_i*steer_vel_i/2.0+current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
         }
       }
-      T1=fabs(speed-steer_vel_i)/limits_->max_steer_acc;
+      T1=fabs(speed-steer_vel_i)/current_config_.max_steer_acc;
     }
     else
     {
-      speed=(steer_vel_i-limits_->max_steer_acc*sim_time_)/2.0;
-      if(speed<=limits_->min_steer_vel)
+      speed=(steer_vel_i-current_config_.max_steer_acc*sim_time_)/2.0;
+      if(speed<=current_config_.min_steer_vel)
       {
-        speed=limits_->min_steer_vel;
-        T4=sim_time_+(2.0*speed-steer_vel_i)/limits_->max_steer_acc;
-        angle=steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)-speed*speed/limits_->max_steer_acc+speed*T4+steer_angle_i;
+        speed=current_config_.min_steer_vel;
+        T4=sim_time_+(2.0*speed-steer_vel_i)/current_config_.max_steer_acc;
+        angle=steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)-speed*speed/current_config_.max_steer_acc+speed*T4+steer_angle_i;
         if(angle<sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          T4=(sample_target_vel[1]-steer_angle_i+speed*speed/limits_->max_steer_acc-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc))/speed;
+          T4=(sample_target_vel[1]-steer_angle_i+speed*speed/current_config_.max_steer_acc-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc))/speed;
           if(T4<0)
           {
             T4=0;
-            speed=-sqrt(steer_vel_i*steer_vel_i/2.0-limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+            speed=-sqrt(steer_vel_i*steer_vel_i/2.0-current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
           }
         }
       }
       else
       {
-        angle=steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)-speed*speed/limits_->max_steer_acc+steer_angle_i;
+        angle=steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)-speed*speed/current_config_.max_steer_acc+steer_angle_i;
         T4=0;
         if(angle<sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          speed=-sqrt(steer_vel_i*steer_vel_i/2.0-limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i)); 
+          speed=-sqrt(steer_vel_i*steer_vel_i/2.0-current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i)); 
         }
       }
-      T1=fabs(speed-steer_vel_i)/limits_->max_steer_acc;
+      T1=fabs(speed-steer_vel_i)/current_config_.max_steer_acc;
     }
   }
   else
   {
     if(sample_target_vel[1]>steer_angle_i)
     {
-      speed=(steer_vel_i+limits_->max_steer_acc*sim_time_)/2.0;
-      if(speed>=limits_->max_steer_vel)
+      speed=(steer_vel_i+current_config_.max_steer_acc*sim_time_)/2.0;
+      if(speed>=current_config_.max_steer_vel)
       {
-        speed=limits_->max_steer_vel;
-        T4=sim_time_-(2.0*speed-steer_vel_i)/limits_->max_steer_acc;
-        angle=-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+speed*speed/limits_->max_steer_acc+speed*T4+steer_angle_i;
+        speed=current_config_.max_steer_vel;
+        T4=sim_time_-(2.0*speed-steer_vel_i)/current_config_.max_steer_acc;
+        angle=-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+speed*speed/current_config_.max_steer_acc+speed*T4+steer_angle_i;
         if(angle>sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          T4=(sample_target_vel[1]-steer_angle_i-speed*speed/limits_->max_steer_acc+steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc))/speed;
+          T4=(sample_target_vel[1]-steer_angle_i-speed*speed/current_config_.max_steer_acc+steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc))/speed;
           if(T4<0)
           {
             T4=0;
-            speed=sqrt(steer_vel_i*steer_vel_i/2.0+limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+            speed=sqrt(steer_vel_i*steer_vel_i/2.0+current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
           }
         }
       }
       else
       {
-        angle=-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+speed*speed/limits_->max_steer_acc+steer_angle_i;
+        angle=-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+speed*speed/current_config_.max_steer_acc+steer_angle_i;
         T4=0;
         if(angle>sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          speed=sqrt(steer_vel_i*steer_vel_i/2.0+limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+          speed=sqrt(steer_vel_i*steer_vel_i/2.0+current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
         }
       }
-      T1=fabs(speed-steer_vel_i)/limits_->max_steer_acc;
+      T1=fabs(speed-steer_vel_i)/current_config_.max_steer_acc;
     }
     else
     {
-      speed=(steer_vel_i-limits_->max_steer_acc*sim_time_)/2.0;
-      if(speed<=limits_->min_steer_vel)
+      speed=(steer_vel_i-current_config_.max_steer_acc*sim_time_)/2.0;
+      if(speed<=current_config_.min_steer_vel)
       {
-        speed=limits_->min_steer_vel;
-        T4=sim_time_+(2.0*speed-steer_vel_i)/limits_->max_steer_acc;
-        angle=-speed*speed/limits_->max_steer_acc+steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+speed*T4+steer_angle_i;
+        speed=current_config_.min_steer_vel;
+        T4=sim_time_+(2.0*speed-steer_vel_i)/current_config_.max_steer_acc;
+        angle=-speed*speed/current_config_.max_steer_acc+steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+speed*T4+steer_angle_i;
         if(angle<sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          T4=(sample_target_vel[1]-steer_angle_i+speed*speed/limits_->max_steer_acc-steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc))/speed;
+          T4=(sample_target_vel[1]-steer_angle_i+speed*speed/current_config_.max_steer_acc-steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc))/speed;
           if(T4<0)
           {
             T4=0;
-            speed=-sqrt(steer_vel_i*steer_vel_i/2.0-limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i));
+            speed=-sqrt(steer_vel_i*steer_vel_i/2.0-current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i));
           }
         }
       }
       else
       {
-        angle=-speed*speed/limits_->max_steer_acc+steer_vel_i*steer_vel_i/(2.0*limits_->max_steer_acc)+steer_angle_i;
+        angle=-speed*speed/current_config_.max_steer_acc+steer_vel_i*steer_vel_i/(2.0*current_config_.max_steer_acc)+steer_angle_i;
         T4=0;
         if(angle<sample_target_vel[1])
         {
           angle=sample_target_vel[1];
-          speed=-sqrt(steer_vel_i*steer_vel_i/2.0-limits_->max_steer_acc*(sample_target_vel[1]-steer_angle_i)); 
+          speed=-sqrt(steer_vel_i*steer_vel_i/2.0-current_config_.max_steer_acc*(sample_target_vel[1]-steer_angle_i)); 
         }
       }
-      T1=fabs(speed-steer_vel_i)/limits_->max_steer_acc;
+      T1=fabs(speed-steer_vel_i)/current_config_.max_steer_acc;
     }
   }
 
   double v=0.0;
   if(sample_target_vel[0]>trans_vel_i)
   {
-    v=(trans_vel_i+limits_->max_trans_acc*sim_time_)/2.0;
+    v=(trans_vel_i+current_config_.max_trans_acc*sim_time_)/2.0;
     if(v>sample_target_vel[0])
     {
       v=sample_target_vel[0];
-      T3=sim_time_-(2.0*v-trans_vel_i)/limits_->max_trans_acc;
+      T3=sim_time_-(2.0*v-trans_vel_i)/current_config_.max_trans_acc;
     }
     else
       T3=0;
-    T2=(v-trans_vel_i)/limits_->max_trans_acc;
+    T2=(v-trans_vel_i)/current_config_.max_trans_acc;
     if(T2<0)
     {
       ROS_WARN("Impossible drive trajectory: v_trans: %f",trans_vel_i);
@@ -489,15 +495,15 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
   }
   else
   {
-    v=(trans_vel_i-limits_->max_trans_acc*sim_time_)/2.0;
+    v=(trans_vel_i-current_config_.max_trans_acc*sim_time_)/2.0;
     if(v<sample_target_vel[0])
     {
       v=sample_target_vel[0];
-      T3=sim_time_+(2.0*v-trans_vel_i)/limits_->max_trans_acc;
+      T3=sim_time_+(2.0*v-trans_vel_i)/current_config_.max_trans_acc;
     }
     else
       T3=0;
-    T2=-(v-trans_vel_i)/limits_->max_trans_acc;
+    T2=-(v-trans_vel_i)/current_config_.max_trans_acc;
     if(T2<0)
     {
       ROS_WARN("Impossible drive trajectory: v_trans: %f",trans_vel_i);
@@ -523,7 +529,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     {
       if(time<T1)
       {
-        steer_vel_i=steer_vel_i+limits_->max_steer_acc*dt;
+        steer_vel_i=steer_vel_i+current_config_.max_steer_acc*dt;
         if(steer_vel_i>speed)
           steer_vel_i=speed;
       }
@@ -531,7 +537,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
         steer_vel_i=speed;
       else
       { 
-        steer_vel_i=steer_vel_i-limits_->max_steer_acc*dt;
+        steer_vel_i=steer_vel_i-current_config_.max_steer_acc*dt;
         if(steer_vel_i<0)
           steer_vel_i=0;
       }
@@ -540,7 +546,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     {
       if(time<T1)
       {
-        steer_vel_i=steer_vel_i-limits_->max_steer_acc*dt;
+        steer_vel_i=steer_vel_i-current_config_.max_steer_acc*dt;
         if(steer_vel_i<speed)
           steer_vel_i=speed;
       }
@@ -548,7 +554,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
         steer_vel_i=speed;
       else
       {
-        steer_vel_i=steer_vel_i+limits_->max_steer_acc*dt;
+        steer_vel_i=steer_vel_i+current_config_.max_steer_acc*dt;
         if(steer_vel_i>0)
           steer_vel_i=0;
       }
@@ -558,7 +564,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     {
       if(time<T2)
       {
-        trans_vel_i=trans_vel_i+limits_->max_trans_acc*dt;
+        trans_vel_i=trans_vel_i+current_config_.max_trans_acc*dt;
         if(trans_vel_i>v)
           trans_vel_i=v;
       }
@@ -566,7 +572,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
         trans_vel_i=v;
       else
       {
-        trans_vel_i=trans_vel_i-limits_->max_trans_acc*dt;
+        trans_vel_i=trans_vel_i-current_config_.max_trans_acc*dt;
         if(trans_vel_i<0)
           trans_vel_i=0;
       }
@@ -575,7 +581,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     {
       if(time<T2)
       {
-        trans_vel_i=trans_vel_i-limits_->max_trans_acc*dt;
+        trans_vel_i=trans_vel_i-current_config_.max_trans_acc*dt;
         if(trans_vel_i<v)
           trans_vel_i=v;
       }
@@ -583,7 +589,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
         trans_vel_i=v;
       else
       {  
-        trans_vel_i=trans_vel_i+limits_->max_trans_acc*dt;
+        trans_vel_i=trans_vel_i+current_config_.max_trans_acc*dt;
         if(trans_vel_i>0)
           trans_vel_i=0;
       }
@@ -591,7 +597,7 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     double r,d;
     if(fabs(steer_angle_i)>0.001)
     {
-      r=fabs(limits_->axis_distance/tan(steer_angle_i));
+      r=fabs(current_config_.axis_distance/tan(steer_angle_i));
       d=trans_vel_i*dt;
       if(steer_angle_i>0)
         theta_i+=d/r;
@@ -609,20 +615,24 @@ bool AckermannTrajectoryGenerator::generate_trajectory(
     time+=dt;
   } // end for simulation steps
 
-  if(this->use_steer_angle_cmd_)
+  if(this->current_config_.use_steer_angle_cmd)   
   {
     traj.thetav_ = sample_target_vel[1];
-    if(traj.thetav_>limits_->max_angular_vel)
-      traj.thetav_=limits_->max_angular_vel;
-    else if(traj.thetav_<limits_->min_angular_vel)
-      traj.thetav_=limits_->min_angular_vel;
+    if(traj.thetav_>current_config_.max_steer_angle)
+      traj.thetav_=current_config_.max_steer_angle;
+    else if(traj.thetav_<current_config_.min_steer_angle)
+      traj.thetav_=current_config_.min_steer_angle;
   }
   else
   {
     if(fabs(sample_target_vel[1])>0.0)
     {
-      double radius=limits_->axis_distance/tan(sample_target_vel[1]);
+      double radius=current_config_.axis_distance/tan(sample_target_vel[1]);
       traj.thetav_ = sample_target_vel[0]/radius;
+      if(traj.thetav_>current_config_.max_angular_vel)
+        traj.thetav_=current_config_.max_angular_vel;
+      else if(traj.thetav_<current_config_.min_angular_vel)
+        traj.thetav_=current_config_.min_angular_vel;     
     }
     else
       traj.thetav_ = 0.0;
diff --git a/src/ackermann_trajectory_search.cpp b/src/ackermann_trajectory_search.cpp
index ceb10bfcc010babf594736516ebe0d08d0a6bed0..7ba497220a48054eab38d3c50e072c3485a6e02e 100644
--- a/src/ackermann_trajectory_search.cpp
+++ b/src/ackermann_trajectory_search.cpp
@@ -36,9 +36,11 @@
  *********************************************************************/
 
 #include <ackermann_trajectory_search.h>
-
 #include <ros/console.h>
 
+#include "g2_spline.h"
+#include "vel_trapezoid.h"
+
 AckermannTrajectorySearch::AckermannTrajectorySearch(std::vector<base_local_planner::TrajectorySampleGenerator*> gen_list, std::vector<base_local_planner::TrajectoryCostFunction*>& critics, int max_samples) 
 {
   max_samples_ = max_samples;
@@ -50,6 +52,7 @@ double AckermannTrajectorySearch::scoreTrajectory(base_local_planner::Trajectory
 {
   double traj_cost = 0;
   int gen_id = 0;
+
   for(std::vector<base_local_planner::TrajectoryCostFunction*>::iterator score_function = critics_.begin(); score_function != critics_.end(); ++score_function) 
   {
     base_local_planner::TrajectoryCostFunction* score_function_p = *score_function;
@@ -69,7 +72,7 @@ double AckermannTrajectorySearch::scoreTrajectory(base_local_planner::Trajectory
     {
       // since we keep adding positives, once we are worse than the best, we will stay worse
       if (traj_cost > best_traj_cost) 
-  break;
+        break;
     }
     gen_id ++;
     ROS_DEBUG("Velocity %.3lf, %.3lf, %.3lf evaluated by cost function %d with cost: %f (best cost: %f)", traj.xv_, traj.yv_, traj.thetav_, gen_id, cost,best_traj_cost);
@@ -85,6 +88,7 @@ bool AckermannTrajectorySearch::findBestTrajectory(base_local_planner::Trajector
   double loop_traj_cost, best_traj_cost = -1;
   bool gen_success;
   int count, count_valid,num=0;
+
   for (std::vector<base_local_planner::TrajectoryCostFunction*>::iterator loop_critic = critics_.begin(); loop_critic != critics_.end(); ++loop_critic) 
   {
     base_local_planner::TrajectoryCostFunction* loop_critic_p = *loop_critic;
@@ -125,10 +129,7 @@ bool AckermannTrajectorySearch::findBestTrajectory(base_local_planner::Trajector
       }
       count++;
       if (max_samples_ > 0 && count >= max_samples_) 
-      {
-        std::cout << "Max sample limit" << std::endl;
         break;
-      }
     }
     if (best_traj_cost >= 0) 
     {
diff --git a/src/heading_cost_function.cpp b/src/heading_cost_function.cpp
index d7b1846cb51f9670db0e85d2ecdc7092dbb25b01..0770792a56a230848a9ce0f151f074fdb147c0f8 100644
--- a/src/heading_cost_function.cpp
+++ b/src/heading_cost_function.cpp
@@ -95,7 +95,7 @@ double HeadingCostFunction::scoreTrajectory(base_local_planner::Trajectory &traj
       diff=fabs(diff-3.14159);
     heading_diff+=diff;
   }
-  heading_diff/=this->num_points;
+  heading_diff/=samples;
 
   return heading_diff;
 }