-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add standalone version of LPF #222
base: ros2-master
Are you sure you want to change the base?
Changes from all commits
e3fde82
28392ba
7aa2f97
7cd9576
1ec808b
e04739b
3171fb0
b85a21d
380aa1f
5d98dfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,11 +21,12 @@ | |
#include <string> | ||
#include <vector> | ||
|
||
#include "low_pass_filter_parameters.hpp" | ||
#include "filters/filter_base.hpp" | ||
|
||
#include "geometry_msgs/msg/wrench_stamped.hpp" | ||
|
||
#include "control_toolbox/low_pass_filter.hpp" | ||
#include "low_pass_filter_parameters.hpp" | ||
|
||
namespace control_filters | ||
{ | ||
|
||
|
@@ -79,14 +80,6 @@ template <typename T> | |
class LowPassFilter : public filters::FilterBase<T> | ||
{ | ||
public: | ||
// Default constructor | ||
LowPassFilter(); | ||
|
||
/*! | ||
* \brief Destructor of LowPassFilter class. | ||
*/ | ||
~LowPassFilter() override; | ||
|
||
/*! | ||
* \brief Configure the LowPassFilter (access and process params). | ||
*/ | ||
|
@@ -102,44 +95,14 @@ class LowPassFilter : public filters::FilterBase<T> | |
*/ | ||
bool update(const T & data_in, T & data_out) override; | ||
|
||
protected: | ||
/*! | ||
* \brief Internal computation of the feedforward and feedbackward coefficients | ||
* according to the LowPassFilter parameters. | ||
*/ | ||
void compute_internal_params() | ||
{ | ||
a1_ = exp( | ||
-1.0 / parameters_.sampling_frequency * (2.0 * M_PI * parameters_.damping_frequency) / | ||
(pow(10.0, parameters_.damping_intensity / -10.0))); | ||
b1_ = 1.0 - a1_; | ||
}; | ||
|
||
private: | ||
rclcpp::Clock::SharedPtr clock_; | ||
std::shared_ptr<rclcpp::Logger> logger_; | ||
std::shared_ptr<low_pass_filter::ParamListener> parameter_handler_; | ||
low_pass_filter::Params parameters_; | ||
|
||
// Filter parameters | ||
/** internal data storage (double). */ | ||
double filtered_value, filtered_old_value, old_value; | ||
/** internal data storage (wrench). */ | ||
Eigen::Matrix<double, 6, 1> msg_filtered, msg_filtered_old, msg_old; | ||
double a1_; /**< feedbackward coefficient. */ | ||
double b1_; /**< feedforward coefficient. */ | ||
std::shared_ptr<control_toolbox::LowPassFilter<T>> lpf_; | ||
}; | ||
|
||
template <typename T> | ||
LowPassFilter<T>::LowPassFilter() : a1_(1.0), b1_(0.0) | ||
{ | ||
} | ||
|
||
template <typename T> | ||
LowPassFilter<T>::~LowPassFilter() | ||
{ | ||
} | ||
|
||
template <typename T> | ||
bool LowPassFilter<T>::configure() | ||
{ | ||
|
@@ -168,24 +131,19 @@ bool LowPassFilter<T>::configure() | |
} | ||
} | ||
parameters_ = parameter_handler_->get_params(); | ||
compute_internal_params(); | ||
lpf_ = std::make_shared<control_toolbox::LowPassFilter<T>>( | ||
parameters_.sampling_frequency, | ||
parameters_.damping_frequency, | ||
parameters_.damping_intensity); | ||
|
||
// Initialize storage Vectors | ||
filtered_value = filtered_old_value = old_value = 0; | ||
// TODO(destogl): make the size parameterizable and more intelligent is using complex types | ||
for (size_t i = 0; i < 6; ++i) | ||
{ | ||
msg_filtered[i] = msg_filtered_old[i] = msg_old[i] = 0; | ||
} | ||
|
||
return true; | ||
return lpf_->configure(); | ||
} | ||
|
||
template <> | ||
inline bool LowPassFilter<geometry_msgs::msg::WrenchStamped>::update( | ||
const geometry_msgs::msg::WrenchStamped & data_in, geometry_msgs::msg::WrenchStamped & data_out) | ||
{ | ||
if (!this->configured_) | ||
if (!this->configured_ || !lpf_ || !lpf_->is_configured()) | ||
{ | ||
if (logger_) | ||
RCLCPP_ERROR_SKIPFIRST_THROTTLE((*logger_), *clock_, 2000, "Filter is not configured"); | ||
|
@@ -196,55 +154,36 @@ inline bool LowPassFilter<geometry_msgs::msg::WrenchStamped>::update( | |
if (parameter_handler_->is_old(parameters_)) | ||
{ | ||
parameters_ = parameter_handler_->get_params(); | ||
compute_internal_params(); | ||
lpf_->set_params( | ||
parameters_.sampling_frequency, | ||
parameters_.damping_frequency, | ||
parameters_.damping_intensity); | ||
} | ||
|
||
// IIR Filter | ||
msg_filtered = b1_ * msg_old + a1_ * msg_filtered_old; | ||
msg_filtered_old = msg_filtered; | ||
|
||
// TODO(destogl): use wrenchMsgToEigen | ||
msg_old[0] = data_in.wrench.force.x; | ||
msg_old[1] = data_in.wrench.force.y; | ||
msg_old[2] = data_in.wrench.force.z; | ||
msg_old[3] = data_in.wrench.torque.x; | ||
msg_old[4] = data_in.wrench.torque.y; | ||
msg_old[5] = data_in.wrench.torque.z; | ||
|
||
data_out.wrench.force.x = msg_filtered[0]; | ||
data_out.wrench.force.y = msg_filtered[1]; | ||
data_out.wrench.force.z = msg_filtered[2]; | ||
data_out.wrench.torque.x = msg_filtered[3]; | ||
data_out.wrench.torque.y = msg_filtered[4]; | ||
data_out.wrench.torque.z = msg_filtered[5]; | ||
|
||
// copy the header | ||
data_out.header = data_in.header; | ||
Comment on lines
-203
to
-222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May be the update method specific to geometry_msgs Wrench should be removed?. It kinda has same content of templated one right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the math is the same, but here it uses the Eigen matrices to do the linear combination. this can't work with the templated method alone? |
||
return true; | ||
return lpf_->update(data_in, data_out); | ||
} | ||
|
||
template <typename T> | ||
bool LowPassFilter<T>::update(const T & data_in, T & data_out) | ||
{ | ||
if (!this->configured_) | ||
if (!this->configured_ || !lpf_ || !lpf_->is_configured()) | ||
{ | ||
RCLCPP_ERROR_SKIPFIRST_THROTTLE((*logger_), *clock_, 2000, "Filter is not configured"); | ||
if (logger_) | ||
RCLCPP_ERROR_SKIPFIRST_THROTTLE((*logger_), *clock_, 2000, "Filter is not configured"); | ||
return false; | ||
} | ||
|
||
// Update internal parameters if required | ||
if (parameter_handler_->is_old(parameters_)) | ||
{ | ||
parameters_ = parameter_handler_->get_params(); | ||
compute_internal_params(); | ||
lpf_->set_params( | ||
parameters_.sampling_frequency, | ||
parameters_.damping_frequency, | ||
parameters_.damping_intensity); | ||
} | ||
|
||
// Filter | ||
data_out = b1_ * old_value + a1_ * filtered_old_value; | ||
filtered_old_value = data_out; | ||
old_value = data_in; | ||
|
||
return true; | ||
return lpf_->update(data_in, data_out); | ||
} | ||
|
||
} // namespace control_filters | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the filter is not configured, i think it's better to throw an exception rather than continuing right?