diff --git a/industrial_core/package.xml b/industrial_core/package.xml
index c0eddfc8..3973c571 100644
--- a/industrial_core/package.xml
+++ b/industrial_core/package.xml
@@ -15,6 +15,7 @@
industrial_robot_simulatorindustrial_deprecatedindustrial_utils
+ industrial_trajectory_filters
diff --git a/industrial_robot_simulator/industrial_robot_simulator b/industrial_robot_simulator/industrial_robot_simulator
index a43e5f30..e0b83d82 100755
--- a/industrial_robot_simulator/industrial_robot_simulator
+++ b/industrial_robot_simulator/industrial_robot_simulator
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import roslib; roslib.load_manifest('industrial_robot_simulator')
import rospy
diff --git a/industrial_trajectory_filters/CMakeLists.txt b/industrial_trajectory_filters/CMakeLists.txt
new file mode 100644
index 00000000..7911f47d
--- /dev/null
+++ b/industrial_trajectory_filters/CMakeLists.txt
@@ -0,0 +1,35 @@
+# http://ros.org/doc/groovy/api/catkin/html/user_guide/supposed.html
+cmake_minimum_required(VERSION 2.8.3)
+project(industrial_trajectory_filters)
+
+find_package(catkin REQUIRED COMPONENTS moveit_ros_planning trajectory_msgs)
+
+catkin_package(
+ CATKIN_DEPENDS moveit_ros_planning trajectory_msgs
+ INCLUDE_DIRS include
+ LIBRARIES ${MOVEIT_LIB_NAME}
+)
+
+include_directories(include
+ ${catkin_INCLUDE_DIRS}
+)
+
+###########
+## Build ##
+###########
+
+add_library(${PROJECT_NAME} src/n_point_filter.cpp src/uniform_sample_filter.cpp)
+target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})
+
+
+#############
+## Install ##
+#############
+install(TARGETS ${PROJECT_NAME}
+ LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION})
+
+install(DIRECTORY include/${PROJECT_NAME}/
+ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION})
+
+install(FILES planning_request_adapters_plugin_description.xml
+ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
diff --git a/industrial_trajectory_filters/include/industrial_trajectory_filters/filter_base.h b/industrial_trajectory_filters/include/industrial_trajectory_filters/filter_base.h
new file mode 100644
index 00000000..5591d337
--- /dev/null
+++ b/industrial_trajectory_filters/include/industrial_trajectory_filters/filter_base.h
@@ -0,0 +1,272 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2011, Southwest Research Institute
+ * 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 Southwest Research Institute, 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 FILTER_BASE_H_
+#define FILTER_BASE_H_
+
+#include
+#include "ros/assert.h"
+#include "ros/console.h"
+#include "ros/ros.h"
+#include
+#include
+
+namespace industrial_trajectory_filters
+{
+
+/**
+ * @brief Message Adapter structure serves as a stand-in for the arm navigation message type with
+ * which the filter was specialized.
+ *
+ */
+struct MessageAdapter
+{
+
+ /**
+ * @brief Arm navigation message type for trajectory filter
+ *
+ */
+ struct Request
+ {
+ trajectory_msgs::JointTrajectory trajectory;
+ } request;
+};
+
+/**
+ * @brief This version of the FilterBase can be used to encapsulate the functionality from an arm navigation
+ * trajectory filter into a PlanningRequestAdapter that is used by MoveIt.
+ *
+ * Since this version of the FilterBase class only provides some degree of backwards compatibility
+ * with the original FilterBase interface, then some parts of the arm navigation filter must be modified in order
+ * to accommodate the differences introduced by this new interface class.
+ *
+ * The purely virtual methods "update" and "configure" have been preserved since it is assumed that any
+ * trajectory filter specialization implemented at least these two methods. The getter methods for the
+ * filter's type and name have been kept as well, however the corresponding members aren't populated from within
+ * the scope of the FilterBase class. Thus, the users implementation must fill these members with
+ * the appropriate string data.
+ *
+ * All the "getParam" methods for parameter lookup have been removed and so the filter implementation
+ * must be modified to read parameters using the regular roscpp parameter API (either through the node
+ * handle or the bare version)
+ *
+ * Steps for conversion to a Moveit PlanningRequestAdapter:
+ *
+ * a - Remove all arm_navigation header files since these can not be included in a catkin based package.
+ *
+ * b - Remove all header files that belong to a rosbuild only package.
+ *
+ * c - Include the #include " header file in your filter's
+ * implementation header file.
+ *
+ * d- In your filter implementation, replace the base class "filters::FilterBase" with
+ * "industrial_trajectory_filters::FilterBase"
+ *
+ * e- Remove all calls to the getParam() methods from the old FilterBase class and use the roscpp
+ * parameter interface for any parameter lookup tasks instead.
+ *
+ * f- In your filter's header file, declare a typedef that specializes your filter template implementation
+ * to a version that uses the "MessageAdapter" structure. For instance, if we are converting the NPointFilter
+ * filter class then we would add the following after the class declaration:
+ *
+ * typedef NPointFilter NPointFilterAdapter;
+ *
+ * In case the "MessageAdapter" structure does not fit the expected template class then the filter's implementation
+ * must provide its own adapter structure that resembles the necessary parts of expected arm_navigation message type.
+ * The specialization of such filter would then pass the custom adapter structure in the template argument as follows:
+ *
+ * typedef NPointFilter NPointFilterAdapter;
+ *
+ * g- In your filter's source file, remove the plugin declaration "PLUGINLIB_DECLARE_CLASS" and add the
+ * class loader macro. In the case of the "NPointFilter" this would be as follows:
+ *
+ * CLASS_LOADER_REGISTER_CLASS(industrial_trajectory_filters::NPointFilterAdapter,
+ * planning_request_adapter::PlanningRequestAdapter);
+ *
+ * h - All parameters used by your filter must me made available as a regular ros parameter. For instance, in the
+ * "ompl_planning_pipeline.launch" file in a moveit package for your robot you would add the following element:
+ *
+ *
+ * i - (Optional) the "adaptAndPlan" methods default implementation already maps the trajectory data between the
+ * MessageAdapter structure and the planning interface objects in the argument list. The filter's implementation
+ * should override this method whenever a custom adapter structure is used.
+ */
+template
+ class FilterBase : public planning_request_adapter::PlanningRequestAdapter
+ {
+ public:
+
+ /**
+ * @brief Default constructor
+ */
+ FilterBase() :
+ planning_request_adapter::PlanningRequestAdapter(), nh_("~"), configured_(false), filter_type_("FilterBase"), filter_name_(
+ "Unimplemented")
+ {
+
+ }
+
+ /**
+ * Default destructor
+ */
+ virtual ~FilterBase()
+ {
+ }
+ ;
+
+ /**
+ * @brief Update the filter and return the data separately. This function
+ * must be implemented in the derived class.
+ *
+ * @param data_in A reference to the data to be input to the filter
+ * @param data_out A reference to the data output location
+ * @return true on success, otherwise false.
+ */
+ virtual bool update(const T& data_in, T& data_out)=0;
+
+ /**
+ * @brief Original FilterBase method, return filter type
+ * @return filter type (as string)
+ */
+ std::string getType()
+ {
+ return filter_type_;
+ }
+ ;
+
+ /**
+ * @brief Original FitlerBase Method
+ * @return filter name (as string).
+ */
+ inline const std::string& getName()
+ {
+ return filter_name_;
+ }
+ ; // original FilterBase method
+
+ protected:
+
+ /**
+ * @brief FilterBase method for the sub class to configure the filter
+ * This function must be implemented in the derived class.
+ * @return true if successful, otherwise false.
+ */
+ virtual bool configure()=0;
+
+ /**
+ * @brief filter name
+ */
+ std::string filter_name_;
+
+ /**
+ * The type of the filter (Used by FilterChain for Factory construction)
+ */
+ std::string filter_type_;
+
+ /**
+ * @brief Holds filter configuration state.
+ */
+ bool configured_;
+
+ /**
+ * @brief Internal node handle (used for parameter lookup)
+ */
+ ros::NodeHandle nh_;
+
+ protected:
+
+ /**
+ * @brief Moveit Planning Request Adapter method. This basic implementation of the
+ * adaptAndPlan method calls the planner and then maps the trajectory data from the
+ * MotionPlanResponse object into the MessageAdapter mapping structure. The
+ * MessageAdapter object is then passed to the "update" method that resembles that
+ * from the old FilterBase interface class. The filtered trajectory is finally
+ * saved in the MotionPlanResponse object.
+ */
+ virtual bool adaptAndPlan(const PlannerFn &planner, const planning_scene::PlanningSceneConstPtr &planning_scene,
+ const planning_interface::MotionPlanRequest &req,
+ planning_interface::MotionPlanResponse &res,
+ std::vector &added_path_index) const
+ {
+
+ // non const pointer to this
+ FilterBase *p = const_cast*>(this);
+
+ // calling the configure method
+ if (!configured_ && p->configure())
+ {
+ p->configured_ = true;
+ }
+
+ // moveit messages for saving trajectory data
+ moveit_msgs::RobotTrajectory robot_trajectory_in, robot_trajectory_out;
+ MessageAdapter trajectory_in, trajectory_out; // mapping structures
+
+ // calling planner first
+ bool result = planner(planning_scene, req, res);
+
+ // applying filter to planned trajectory
+ if (result && res.trajectory_)
+ {
+ // mapping arguments into message adapter struct
+ res.trajectory_->getRobotTrajectoryMsg(robot_trajectory_in);
+ trajectory_in.request.trajectory = robot_trajectory_in.joint_trajectory;
+
+ // applying arm navigation filter to planned trajectory
+ p->update(trajectory_in, trajectory_out);
+
+ // saving filtered trajectory into moveit message.
+ robot_trajectory_out.joint_trajectory = trajectory_out.request.trajectory;
+ res.trajectory_->setRobotTrajectoryMsg(planning_scene->getCurrentState(), robot_trajectory_out);
+
+ }
+
+ return result;
+ }
+
+ /**
+ * @brief Return description string
+ * @return description (as a string)
+ */
+ virtual std::string getDescription() const
+ {
+ // non const pointer to this
+ FilterBase *p = const_cast*>(this);
+
+ std::stringstream ss;
+ ss << "Trajectory filter '" << p->getName() << "' of type '" << p->getType() << "'";
+ return ss.str();
+ }
+ };
+
+}
+
+#endif /* FILTER_BASE_H_ */
diff --git a/industrial_trajectory_filters/include/industrial_trajectory_filters/n_point_filter.h b/industrial_trajectory_filters/include/industrial_trajectory_filters/n_point_filter.h
new file mode 100644
index 00000000..612d6597
--- /dev/null
+++ b/industrial_trajectory_filters/include/industrial_trajectory_filters/n_point_filter.h
@@ -0,0 +1,89 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2011, Southwest Research Institute
+ * 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 Southwest Research Institute, 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 N_POINT_FILTER_H_
+#define N_POINT_FILTER_H_
+
+#include
+
+namespace industrial_trajectory_filters
+{
+
+/**
+ * @brief This is a simple filter which reduces a trajectory to N points or less
+ */
+template
+
+ class NPointFilter : public industrial_trajectory_filters::FilterBase
+ {
+ public:
+ /**
+ * @brief Default constructor
+ */
+ NPointFilter();
+ /**
+ * @brief Default destructor
+ */
+ ~NPointFilter();
+ ;
+
+ virtual bool configure();
+
+ // \brief Reduces a trajectory to N points or less. The resulting trajectory
+ // contains only point within the original trajectory (no interpolation is done
+ // between points).
+
+ /**
+ * \brief Reduces a trajectory to N points or less. The resulting trajectory
+ * contains only point within the original trajectory (no interpolation is done
+ * between points).
+ * @param trajectory_in input trajectory
+ * @param trajectory_out filtered trajectory (N points or less
+ * @return true if successful
+ */
+ bool update(const T& trajectory_in, T& trajectory_out);
+
+ private:
+ /**
+ * @brief number of points to reduce trajectory to
+ */
+ int n_points_;
+
+ };
+
+/**
+ * @brief Specializing trajectory filter implementation
+ */
+typedef NPointFilter NPointFilterAdapter;
+
+}
+
+#endif
diff --git a/industrial_trajectory_filters/include/industrial_trajectory_filters/uniform_sample_filter.h b/industrial_trajectory_filters/include/industrial_trajectory_filters/uniform_sample_filter.h
new file mode 100644
index 00000000..9469c066
--- /dev/null
+++ b/industrial_trajectory_filters/include/industrial_trajectory_filters/uniform_sample_filter.h
@@ -0,0 +1,106 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2013, Southwest Research Institute
+ * 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 Southwest Research Institute, 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 UNIFORM_SAMPLE_FILTER_H_
+#define UNIFORM_SAMPLE_FILTER_H_
+
+#include
+
+/*
+ * These headers were part of the trajectory filter interface from the
+ * arm navigation system. These can no longer be included in a catkin based
+ * package.
+ #include
+ #include
+ */
+
+namespace industrial_trajectory_filters
+{
+
+/**
+ * \brief This is a simple filter which performs a uniforming sampling of
+ * a trajectory using linear interpolation.
+ *
+ */
+template
+
+ class UniformSampleFilter : public industrial_trajectory_filters::FilterBase
+ {
+ public:
+ /**
+ * @brief Default constructor
+ */
+ UniformSampleFilter();
+ /**
+ * @brief Default destructor
+ */
+ ~UniformSampleFilter();
+
+ virtual bool configure();
+
+ /**
+ * Uniformly samples(in terms of time) the input trajectory based upon the
+ * sample duration. Sampling is performed via interpolation ensuring smooth
+ * velocity and acceleration. NOTE: For this reason trajectories must be
+ * fully defined before using this filter.
+ * @param trajectory_in non uniform trajectory
+ * @param trajectory_out uniform(in terms of time) trajectory
+ * @return
+ */
+ bool update(const T& trajectory_in, T& trajectory_out);
+
+ /**
+ * @brief Perform interpolation between p1 and p2. Time from start must be
+ * in between p1 and p2 times.
+ * @param p1 prior trajectory point
+ * @param p2 subsequent trajectory point
+ * @param time_from_start time from start of trajectory (i.e. p0).
+ * @param interp_pt resulting interpolated point
+ * @return true if successful, otherwise false.
+ */
+ bool interpolatePt(trajectory_msgs::JointTrajectoryPoint & p1, trajectory_msgs::JointTrajectoryPoint & p2,
+ double time_from_start, trajectory_msgs::JointTrajectoryPoint & interp_pt);
+
+ private:
+ /**
+ * @brief uniform sample duration (sec)
+ */
+ double sample_duration_;
+ };
+
+/**
+ * @brief Specializing trajectory filter implementation
+ */
+typedef UniformSampleFilter UniformSampleFilterAdapter;
+
+}
+
+#endif
diff --git a/industrial_trajectory_filters/mainpage.dox b/industrial_trajectory_filters/mainpage.dox
new file mode 100644
index 00000000..893983c5
--- /dev/null
+++ b/industrial_trajectory_filters/mainpage.dox
@@ -0,0 +1,14 @@
+/**
+\mainpage
+\htmlinclude manifest.html
+
+\b industrial_trajectory_filters provides robot trajectory filters. It also includes plugin adapters for the moveit motion planning library.
+
+
+\section codeapi Code API
+
+The main APIs of are largely captured in the following interface classes:
+- industrial_trajectory_filters::NPointFilter : A simple filter that removes trajectory points until the trajectory is N or less points
+- industrial_trajectory_filters::UniformSampleFilter : Resamples a trajectory uniformly (in time).
+- industrial_trajectory_filters::FilterBase : A moveit adapter class for old arm navigation packages.
+*/
diff --git a/industrial_trajectory_filters/package.xml b/industrial_trajectory_filters/package.xml
new file mode 100644
index 00000000..7f572d3b
--- /dev/null
+++ b/industrial_trajectory_filters/package.xml
@@ -0,0 +1,38 @@
+
+ industrial_trajectory_filters
+ 1.0.0
+
+
+ ROS Industrial libraries/plugins for filtering trajectories.
+
+
+ This package is part of the ROS Industrial program and contains libraries
+ and moveit plugins for filtering robot trajectories.
+
+
+ Shaun Edwards
+ Jorge Nicho
+ Shaun Edwards
+ BSD
+ http://ros.org/wiki/industrial_trajectory_filters
+ https://github.com/ros-industrial/industrial_core/issues
+ https://github.com/ros-industrial/industrial_core
+
+ catkin
+
+ trajectory_msgs
+ pluginlib
+ moveit_core
+ moveit_ros_planning
+ orocos_kdl
+
+ trajectory_msgs
+ pluginlib
+ moveit_core
+ moveit_ros_planning
+ orocos_kdl
+
+
+
+
+
diff --git a/industrial_trajectory_filters/planning_request_adapters_plugin_description.xml b/industrial_trajectory_filters/planning_request_adapters_plugin_description.xml
new file mode 100644
index 00000000..5a26761c
--- /dev/null
+++ b/industrial_trajectory_filters/planning_request_adapters_plugin_description.xml
@@ -0,0 +1,24 @@
+
+
+
+
+ This is a simple filter which reduces a trajectory to N points or less.
+ ROS parameters:
+ - n_points (default = 2)
+
+
+
+
+
+ This is a simple filter which performs a uniforming sampling of
+ a trajectory using linear interpolation.
+ ROS parameters:
+ - sample_duration (default = 0.050)
+
+
+
+
diff --git a/industrial_trajectory_filters/src/n_point_filter.cpp b/industrial_trajectory_filters/src/n_point_filter.cpp
new file mode 100644
index 00000000..41d86dbe
--- /dev/null
+++ b/industrial_trajectory_filters/src/n_point_filter.cpp
@@ -0,0 +1,136 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2011, Southwest Research Institute
+ * 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 Southwest Research Institute, 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.
+ */
+
+//#include
+#include
+#include
+
+using namespace industrial_trajectory_filters;
+
+const int DEFAULT_N = 2;
+
+template
+ NPointFilter::NPointFilter() :
+ FilterBase()
+ {
+ ROS_INFO_STREAM("Constructing N point filter");
+ n_points_ = DEFAULT_N;
+ this->filter_name_ = "NPointFilter";
+ this->filter_type_ = "NPointFilter";
+ }
+
+template
+ NPointFilter::~NPointFilter()
+ {
+ }
+
+template
+ bool NPointFilter::configure()
+ {
+ //if (!filters::FilterBase::getParam("n_points", n_points_))
+ if (!this->nh_.getParam("n_points", n_points_))
+ {
+ ROS_WARN_STREAM("NPointFilter, params has no attribute n_points.");
+ }
+ if (n_points_ < 2)
+ {
+ ROS_WARN_STREAM( "n_points attribute less than min(2), setting to minimum");
+ n_points_ = 2;
+ }
+ ROS_INFO_STREAM("Using a n_points value of " << n_points_);
+
+ return true;
+ }
+
+template
+ bool NPointFilter::update(const T& trajectory_in, T& trajectory_out)
+ {
+ bool success = false;
+ int size_in = trajectory_in.request.trajectory.points.size();
+
+ // Copy non point related data
+ trajectory_out.request.trajectory = trajectory_in.request.trajectory;
+ // Clear out the trajectory points
+ trajectory_out.request.trajectory.points.clear();
+
+ if (size_in > n_points_)
+ {
+ //Add first point to output trajectory
+ trajectory_out.request.trajectory.points.push_back(trajectory_in.request.trajectory.points.front());
+
+ int intermediate_points = n_points_ - 2; //subtract the first and last elements
+ double int_point_increment = double(size_in) / double(intermediate_points + 1.0);
+ ROS_INFO_STREAM(
+ "Number of intermediate points: " << intermediate_points << ", increment: " << int_point_increment);
+
+ // The intermediate point index is determined by the following equation:
+ // int_point_index = i * int_point_increment
+ // Ex: n_points_ = 4, size_in = 11, intermediate_points = 2 ->
+ // int_point_increment = 3.66667,
+ // i = 1: int_point_index = 3
+ // i = 2: int_point_index = 7
+ for (int i = 1; i <= intermediate_points; i++)
+ {
+ int int_point_index = int(double(i) * int_point_increment);
+ ROS_INFO_STREAM("Intermediate point index: " << int_point_index);
+ trajectory_out.request.trajectory.points.push_back(trajectory_in.request.trajectory.points[int_point_index]);
+ }
+
+ //Add last point to output trajectory
+ trajectory_out.request.trajectory.points.push_back(trajectory_in.request.trajectory.points.back());
+
+ ROS_INFO_STREAM(
+ "Filtered trajectory from: " << trajectory_in.request.trajectory.points.size() << " to: " << trajectory_out.request.trajectory.points.size());
+
+ success = true;
+ }
+ else
+ {
+ ROS_WARN_STREAM( "Trajectory size less than n: " << n_points_ << ", pass through");
+ trajectory_out.request.trajectory = trajectory_in.request.trajectory;
+ success = true;
+ }
+
+ return success;
+ }
+
+// registering planner adapter
+CLASS_LOADER_REGISTER_CLASS(industrial_trajectory_filters::NPointFilterAdapter,
+ planning_request_adapter::PlanningRequestAdapter);
+
+/*
+ * Old plugin declaration for arm navigation trajectory filters
+ PLUGINLIB_DECLARE_CLASS(industrial_trajectory_filters,
+ IndustrialNPointFilterJointTrajectoryWithConstraints,
+ industrial_trajectory_filters::NPointFilter,
+ filters::FilterBase);
+
+ */
diff --git a/industrial_trajectory_filters/src/uniform_sample_filter.cpp b/industrial_trajectory_filters/src/uniform_sample_filter.cpp
new file mode 100644
index 00000000..157c32cc
--- /dev/null
+++ b/industrial_trajectory_filters/src/uniform_sample_filter.cpp
@@ -0,0 +1,227 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2013, Southwest Research Institute
+ * 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 Southwest Research Institute, 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.
+ */
+
+#include
+#include
+#include
+
+using namespace industrial_trajectory_filters;
+
+const double DEFAULT_SAMPLE_DURATION = 0.050; //seconds
+
+template
+ UniformSampleFilter::UniformSampleFilter() :
+ industrial_trajectory_filters::FilterBase()
+ {
+ ROS_INFO_STREAM("Constructing N point filter");
+ sample_duration_ = DEFAULT_SAMPLE_DURATION;
+ this->filter_name_ = "UniformSampleFilter";
+ this->filter_type_ = "UniformSampleFilter";
+ }
+
+template
+ UniformSampleFilter::~UniformSampleFilter()
+ {
+ }
+
+template
+ bool UniformSampleFilter::configure()
+ {
+ if (!this->nh_.getParam("sample_duration", sample_duration_))
+ {
+ ROS_WARN_STREAM( "UniformSampleFilter, params has no attribute sample_duration.");
+ }
+ ROS_INFO_STREAM("Using a sample_duration value of " << sample_duration_);
+
+ return true;
+ }
+
+template
+ bool UniformSampleFilter::update(const T& trajectory_in, T& trajectory_out)
+ {
+ bool success = false;
+ size_t size_in = trajectory_in.request.trajectory.points.size();
+ double duration_in = trajectory_in.request.trajectory.points.back().time_from_start.toSec();
+ double interpolated_time = 0.0;
+ size_t index_in = 0;
+
+ trajectory_msgs::JointTrajectoryPoint p1, p2, interp_pt;
+
+ trajectory_out = trajectory_in;
+
+ // Clear out the trajectory points
+ trajectory_out.request.trajectory.points.clear();
+
+ while (interpolated_time < duration_in)
+ {
+ ROS_INFO_STREAM("Interpolated time: " << interpolated_time);
+ // Increment index until the interpolated time is past the start time.
+ while (interpolated_time > trajectory_in.request.trajectory.points[index_in + 1].time_from_start.toSec())
+ {
+ ROS_INFO_STREAM(
+ "Interpolated time: " << interpolated_time << ", next point time: " << (trajectory_in.request.trajectory.points[index_in + 1].time_from_start.toSec()));
+ ROS_INFO_STREAM("Incrementing index");
+ index_in++;
+ if (index_in >= size_in)
+ {
+ ROS_ERROR_STREAM(
+ "Programming error, index: " << index_in << ", greater(or equal) to size: " << size_in << " input duration: " << duration_in << " interpolated time:)" << interpolated_time);
+ return false;
+ }
+ }
+ p1 = trajectory_in.request.trajectory.points[index_in];
+ p2 = trajectory_in.request.trajectory.points[index_in + 1];
+ if (!interpolatePt(p1, p2, interpolated_time, interp_pt))
+ {
+ ROS_ERROR_STREAM("Failed to interpolate point");
+ return false;
+ }
+ trajectory_out.request.trajectory.points.push_back(interp_pt);
+ interpolated_time += sample_duration_;
+
+ }
+
+ ROS_INFO_STREAM(
+ "Interpolated time exceeds original trajectory (quitting), original: " << duration_in << " final interpolated time: " << interpolated_time);
+ p2 = trajectory_in.request.trajectory.points.back();
+ p2.time_from_start = ros::Duration(interpolated_time);
+ // TODO: Really should check that appending the last point doesn't result in
+ // really slow motion at the end. This could happen if the sample duration is a
+ // large percentage of the trajectory duration (not likely).
+ trajectory_out.request.trajectory.points.push_back(p2);
+
+ ROS_INFO_STREAM(
+ "Uniform sampling, resample duraction: " << sample_duration_ << " input traj. size: " << trajectory_in.request.trajectory.points.size() << " output traj. size: " << trajectory_out.request.trajectory.points.size());
+
+ success = true;
+ return success;
+ }
+
+template
+ bool UniformSampleFilter::interpolatePt(trajectory_msgs::JointTrajectoryPoint & p1,
+ trajectory_msgs::JointTrajectoryPoint & p2, double time_from_start,
+ trajectory_msgs::JointTrajectoryPoint & interp_pt)
+ {
+ bool rtn = false;
+ double p1_time_from_start = p1.time_from_start.toSec();
+ double p2_time_from_start = p2.time_from_start.toSec();
+
+ ROS_INFO_STREAM("time from start: " << time_from_start);
+
+ if (time_from_start >= p1_time_from_start && time_from_start <= p2_time_from_start)
+ {
+ if (p1.positions.size() == p1.velocities.size() && p1.positions.size() == p1.accelerations.size())
+ {
+ if (p1.positions.size() == p2.positions.size() && p1.velocities.size() == p2.velocities.size()
+ && p1.accelerations.size() == p2.accelerations.size())
+ {
+ // Copy p1 to ensure the interp_pt has the correct size vectors
+ interp_pt = p1;
+ // TODO: Creating a new spline calculator in this function means that
+ // it may be created multiple times for the same points (assuming the
+ // resample duration is less that the actual duration, which it might
+ // be sometimes)
+ KDL::VelocityProfile_Spline spline_calc;
+ ROS_INFO_STREAM( "---------------Begin interpolating joint point---------------");
+
+ for (size_t i = 0; i < p1.positions.size(); ++i)
+ {
+ // Calculated relative times for spline calculation
+ double time_from_p1 = time_from_start - p1.time_from_start.toSec();
+ double time_from_p1_to_p2 = p2_time_from_start - p1_time_from_start;
+
+ ROS_INFO_STREAM("time from p1: " << time_from_p1);
+ ROS_INFO_STREAM( "time_from_p1_to_p2: " << time_from_p1_to_p2);
+
+ spline_calc.SetProfileDuration(p1.positions[i], p1.velocities[i], p1.accelerations[i], p2.positions[i],
+ p2.velocities[i], p2.accelerations[i], time_from_p1_to_p2);
+
+ ros::Duration time_from_start_dur(time_from_start);
+ ROS_INFO_STREAM( "time from start_dur: " << time_from_start_dur);
+
+ interp_pt.time_from_start = time_from_start_dur;
+ interp_pt.positions[i] = spline_calc.Pos(time_from_p1);
+ interp_pt.velocities[i] = spline_calc.Vel(time_from_p1);
+ interp_pt.accelerations[i] = spline_calc.Acc(time_from_p1);
+
+ ROS_INFO_STREAM(
+ "p1.pos: " << p1.positions[i] << ", vel: " << p1.velocities[i] << ", acc: " << p1.accelerations[i] << ", tfs: " << p1.time_from_start);
+
+ ROS_INFO_STREAM(
+ "p2.pos: " << p2.positions[i] << ", vel: " << p2.velocities[i] << ", acc: " << p2.accelerations[i] << ", tfs: " << p2.time_from_start);
+
+ ROS_INFO_STREAM(
+ "interp_pt.pos: " << interp_pt.positions[i] << ", vel: " << interp_pt.velocities[i] << ", acc: " << interp_pt.accelerations[i] << ", tfs: " << interp_pt.time_from_start);
+ }
+ ROS_INFO_STREAM( "---------------End interpolating joint point---------------");
+ rtn = true;
+ }
+ else
+ {
+ ROS_ERROR_STREAM("Trajectory point size mismatch");
+ ROS_ERROR_STREAM(
+ "Trajectory point 1, pos: " << p1.positions.size() << " vel: " << p1.velocities.size() << " acc: " << p1.accelerations.size());
+ ROS_ERROR_STREAM(
+ "Trajectory point 2, pos: " << p2.positions.size() << " vel: " << p2.velocities.size() << " acc: " << p2.accelerations.size());
+ rtn = false;
+ }
+
+ }
+ else
+ {
+ ROS_ERROR_STREAM(
+ "Trajectory point not fully defined, pos: " << p1.positions.size() << " vel: " << p1.velocities.size() << " acc: " << p1.accelerations.size());
+ rtn = false;
+ }
+ }
+ else
+ {
+ ROS_ERROR_STREAM(
+ "Time: " << time_from_start << " not between interpolation point times[" << p1.time_from_start.toSec() << "," << p2.time_from_start.toSec() << "]");
+ rtn = false;
+ }
+
+ return rtn;
+ }
+
+// registering planner adapter
+CLASS_LOADER_REGISTER_CLASS( industrial_trajectory_filters::UniformSampleFilterAdapter,
+ planning_request_adapter::PlanningRequestAdapter);
+
+/*
+ * Old plugin declaration for arm navigation trajectory filters
+ PLUGINLIB_DECLARE_CLASS(industrial_trajectory_filters,
+ IndustrialNPointFilterJointTrajectoryWithConstraints,
+ industrial_trajectory_filters::NPointFilter,
+ filters::FilterBase);
+
+ */
+