moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
butterworth_filter.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2021, PickNik Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of PickNik Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Andy Zelenak
36 Description: A first-order Butterworth low-pass filter. There is only one parameter to tune.
37 */
38
40#include <rclcpp/clock.hpp>
41#include <rclcpp/logging.hpp>
42
43// Disable -Wold-style-cast because all _THROTTLE macros trigger this
44#pragma GCC diagnostic ignored "-Wold-style-cast"
45
47{
48namespace
49{
50constexpr double EPSILON = 1e-9;
51}
52
53ButterworthFilter::ButterworthFilter(double low_pass_filter_coeff)
54 : previous_measurements_{ 0., 0. }
55 , previous_filtered_measurement_(0.)
56 , scale_term_(1. / (1. + low_pass_filter_coeff))
57 , feedback_term_(1. - low_pass_filter_coeff)
58{
59 // guarantee this doesn't change because the logic below depends on this length implicitly
60 static_assert(ButterworthFilter::FILTER_LENGTH == 2,
61 "online_signal_smoothing::ButterworthFilter::FILTER_LENGTH should be 2");
62
63 if (std::isinf(feedback_term_))
64 throw std::length_error("online_signal_smoothing::ButterworthFilter: infinite feedback_term_");
65
66 if (std::isinf(scale_term_))
67 throw std::length_error("online_signal_smoothing::ButterworthFilter: infinite scale_term_");
68
69 if (low_pass_filter_coeff < 1)
70 {
71 throw std::length_error(
72 "online_signal_smoothing::ButterworthFilter: Filter coefficient < 1. makes the lowpass filter unstable");
73 }
74
75 if (std::abs(feedback_term_) < EPSILON)
76 {
77 throw std::length_error(
78 "online_signal_smoothing::ButterworthFilter: Filter coefficient value resulted in feedback term of 0");
79 }
80}
81
82double ButterworthFilter::filter(double new_measurement)
83{
84 // Push in the new measurement
85 previous_measurements_[1] = previous_measurements_[0];
86 previous_measurements_[0] = new_measurement;
87
88 previous_filtered_measurement_ = scale_term_ * (previous_measurements_[1] + previous_measurements_[0] -
89 feedback_term_ * previous_filtered_measurement_);
90
91 return previous_filtered_measurement_;
92}
93
94void ButterworthFilter::reset(const double data)
95{
96 previous_measurements_[0] = data;
97 previous_measurements_[1] = data;
98 previous_filtered_measurement_ = data;
99}
100
101bool ButterworthFilterPlugin::initialize(rclcpp::Node::SharedPtr node, moveit::core::RobotModelConstPtr /* unused */,
102 size_t num_joints)
103{
104 node_ = node;
105 num_joints_ = num_joints;
106
107 online_signal_smoothing::ParamListener param_listener(node_);
108 double filter_coeff = param_listener.get_params().butterworth_filter_coeff;
109
110 for (std::size_t i = 0; i < num_joints_; ++i)
111 {
112 position_filters_.emplace_back(filter_coeff);
113 }
114 return true;
115};
116
117bool ButterworthFilterPlugin::doSmoothing(Eigen::VectorXd& positions, Eigen::VectorXd& /* unused */,
118 Eigen::VectorXd& /* unused */)
119{
120 const size_t num_positions = positions.size();
121 if (num_positions != position_filters_.size())
122 {
123 RCLCPP_ERROR_THROTTLE(node_->get_logger(), *node_->get_clock(), 1000,
124 "Position vector to be smoothed does not have the right length.");
125 return false;
126 }
127 for (size_t i = 0; i < num_positions; ++i)
128 {
129 // Lowpass filter the position command
130 positions[i] = position_filters_.at(i).filter(positions[i]);
131 }
132 return true;
133};
134
135bool ButterworthFilterPlugin::reset(const Eigen::VectorXd& positions, const Eigen::VectorXd& /* unused */,
136 const Eigen::VectorXd& /* unused */)
137{
138 const size_t num_positions = positions.size();
139 if (num_positions != position_filters_.size())
140 {
141 RCLCPP_ERROR_THROTTLE(node_->get_logger(), *node_->get_clock(), 1000,
142 "Position vector to be reset does not have the right length.");
143 return false;
144 }
145 for (size_t joint_idx = 0; joint_idx < num_positions; ++joint_idx)
146 {
147 position_filters_.at(joint_idx).reset(positions[joint_idx]);
148 }
149 return true;
150};
151
152} // namespace online_signal_smoothing
153
154#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
bool reset(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &accelerations) override
bool doSmoothing(Eigen::VectorXd &positions, Eigen::VectorXd &velocities, Eigen::VectorXd &accelerations) override
bool initialize(rclcpp::Node::SharedPtr node, moveit::core::RobotModelConstPtr robot_model, size_t num_joints) override