From eecacaec08cdea9e34c7637ecf36af88c39c9411 Mon Sep 17 00:00:00 2001 From: AndyZe Date: Wed, 14 Aug 2024 20:55:20 -0500 Subject: [PATCH] Implement realtime Ruckig jerk-limited smoothing (#2956) * Ensure the robot state is up-to-date before Servoing * Tune Servo params so it does not get stuck so easily * Implement jerk-limited smoothing for Servo * Optional jerk bounds * WIP: validate Ruckig input * Strictly require joint jerk bounds * Try an updated ubuntu version * Mess around with compiler flag settings * Don't allow unspecified kinematic limits * Revert clang-tidy version; Assume constant acceleration during tracking --- moveit_core/CMakeLists.txt | 7 +- moveit_core/filter_plugin_ruckig.xml | 8 + .../online_signal_smoothing/CMakeLists.txt | 45 ++-- .../online_signal_smoothing/ruckig_filter.h | 106 +++++++++ .../smoothing_base_class.h | 1 - .../src/acceleration_filter.cpp | 2 - .../src/ruckig_filter.cpp | 219 ++++++++++++++++++ .../src/ruckig_filter_parameters.yaml | 16 ++ .../config/panda_simulated_config.yaml | 2 +- .../demos/cpp_interface/demo_joint_jog.cpp | 4 +- .../demos/cpp_interface/demo_twist.cpp | 4 +- .../include/moveit_servo/servo.hpp | 1 + moveit_ros/moveit_servo/src/servo.cpp | 21 +- moveit_ros/moveit_servo/src/servo_node.cpp | 1 - moveit_ros/moveit_servo/src/utils/common.cpp | 9 + 15 files changed, 409 insertions(+), 37 deletions(-) create mode 100644 moveit_core/filter_plugin_ruckig.xml create mode 100644 moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/ruckig_filter.h create mode 100644 moveit_core/online_signal_smoothing/src/ruckig_filter.cpp create mode 100644 moveit_core/online_signal_smoothing/src/ruckig_filter_parameters.yaml diff --git a/moveit_core/CMakeLists.txt b/moveit_core/CMakeLists.txt index 90b2851ded..608babbebc 100644 --- a/moveit_core/CMakeLists.txt +++ b/moveit_core/CMakeLists.txt @@ -92,6 +92,8 @@ install( moveit_robot_model moveit_robot_state moveit_robot_trajectory + moveit_ruckig_filter + moveit_ruckig_filter_parameters moveit_smoothing_base moveit_test_utils moveit_trajectory_processing @@ -142,9 +144,10 @@ pluginlib_export_plugin_description_file(moveit_core collision_detector_fcl_description.xml) pluginlib_export_plugin_description_file( moveit_core collision_detector_bullet_description.xml) -pluginlib_export_plugin_description_file(moveit_core - filter_plugin_butterworth.xml) pluginlib_export_plugin_description_file(moveit_core filter_plugin_acceleration.xml) +pluginlib_export_plugin_description_file(moveit_core + filter_plugin_butterworth.xml) +pluginlib_export_plugin_description_file(moveit_core filter_plugin_ruckig.xml) ament_package(CONFIG_EXTRAS ConfigExtras.cmake) diff --git a/moveit_core/filter_plugin_ruckig.xml b/moveit_core/filter_plugin_ruckig.xml new file mode 100644 index 0000000000..47ffd347a1 --- /dev/null +++ b/moveit_core/filter_plugin_ruckig.xml @@ -0,0 +1,8 @@ + + + + Jerk/acceleration/velocity-limited command smoothing. + + + diff --git a/moveit_core/online_signal_smoothing/CMakeLists.txt b/moveit_core/online_signal_smoothing/CMakeLists.txt index bcfca1c75e..1f1912c6d9 100644 --- a/moveit_core/online_signal_smoothing/CMakeLists.txt +++ b/moveit_core/online_signal_smoothing/CMakeLists.txt @@ -13,6 +13,23 @@ set_target_properties(moveit_smoothing_base ament_target_dependencies(moveit_smoothing_base rclcpp tf2_eigen) # Plugin implementations +add_library(moveit_acceleration_filter SHARED src/acceleration_filter.cpp) +generate_export_header(moveit_acceleration_filter) +target_include_directories( + moveit_acceleration_filter + PUBLIC $) +set_target_properties(moveit_acceleration_filter + PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}") +generate_parameter_library(moveit_acceleration_filter_parameters + src/acceleration_filter_parameters.yaml) +target_link_libraries( + moveit_acceleration_filter moveit_acceleration_filter_parameters + moveit_robot_state moveit_smoothing_base osqp::osqp) +ament_target_dependencies( + moveit_acceleration_filter srdfdom # include dependency from + # moveit_robot_model + pluginlib) + add_library(moveit_butterworth_filter SHARED src/butterworth_filter.cpp) generate_export_header(moveit_butterworth_filter) target_include_directories( @@ -20,10 +37,8 @@ target_include_directories( PUBLIC $) set_target_properties(moveit_butterworth_filter PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}") - generate_parameter_library(moveit_butterworth_filter_parameters src/butterworth_parameters.yaml) - target_link_libraries( moveit_butterworth_filter moveit_butterworth_filter_parameters moveit_robot_model moveit_smoothing_base) @@ -32,32 +47,30 @@ ament_target_dependencies( srdfdom # include dependency from moveit_robot_model pluginlib) -add_library(moveit_acceleration_filter SHARED src/acceleration_filter.cpp) -generate_export_header(moveit_acceleration_filter) +add_library(moveit_ruckig_filter SHARED src/ruckig_filter.cpp) +generate_export_header(moveit_ruckig_filter) target_include_directories( - moveit_acceleration_filter - PUBLIC $) -set_target_properties(moveit_acceleration_filter + moveit_ruckig_filter PUBLIC $) +set_target_properties(moveit_ruckig_filter PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}") - -generate_parameter_library(moveit_acceleration_filter_parameters - src/acceleration_filter_parameters.yaml) - +generate_parameter_library(moveit_ruckig_filter_parameters + src/ruckig_filter_parameters.yaml) target_link_libraries( - moveit_acceleration_filter moveit_acceleration_filter_parameters - moveit_robot_state moveit_smoothing_base osqp::osqp) + moveit_ruckig_filter moveit_robot_state moveit_ruckig_filter_parameters + moveit_smoothing_base ruckig::ruckig) ament_target_dependencies( - moveit_acceleration_filter srdfdom # include dependency from - # moveit_robot_model + moveit_ruckig_filter srdfdom # include dependency from moveit_robot_model pluginlib) # Installation install(DIRECTORY include/ DESTINATION include/moveit_core) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/moveit_smoothing_base_export.h DESTINATION include/moveit_core) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/moveit_acceleration_filter_export.h + DESTINATION include/moveit_core) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/moveit_butterworth_filter_export.h DESTINATION include/moveit_core) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/moveit_acceleration_filter_export.h +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/moveit_ruckig_filter_export.h DESTINATION include/moveit_core) # Testing diff --git a/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/ruckig_filter.h b/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/ruckig_filter.h new file mode 100644 index 0000000000..13cf36a742 --- /dev/null +++ b/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/ruckig_filter.h @@ -0,0 +1,106 @@ +/********************************************************************* + * Software License Agreement (BSD License) + * + * Copyright (c) 2024, Andrew Zelenak + * 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 PickNik 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: Andy Zelenak +Description: Applies jerk/acceleration/velocity limits to online motion commands + */ + +#pragma once + +#include + +#include +#include +#include + +#include + +namespace online_signal_smoothing +{ + +class RuckigFilterPlugin : public SmoothingBaseClass +{ +public: + /** + * Initialize the smoothing algorithm + * @param node ROS node, used for parameter retrieval + * @param robot_model used to retrieve vel/accel/jerk limits + * @param num_joints number of actuated joints in the JointGroup + * @return True if initialization was successful + */ + bool initialize(rclcpp::Node::SharedPtr node, moveit::core::RobotModelConstPtr robot_model, + size_t num_joints) override; + + /** + * Smooth the command signals for all DOF + * @param positions array of joint position commands + * @param velocities array of joint velocity commands + * @param accelerations array of joint acceleration commands + * @return True if initialization was successful + */ + bool doSmoothing(Eigen::VectorXd& positions, Eigen::VectorXd& velocities, Eigen::VectorXd& accelerations) override; + + /** + * Reset to a given joint state + * @param positions reset the filters to these joint positions + * @param velocities (unused) + * @param accelerations (unused) + * @return True if reset was successful + */ + bool reset(const Eigen::VectorXd& positions, const Eigen::VectorXd& velocities, + const Eigen::VectorXd& accelerations) override; + +private: + /** + * A utility to print Ruckig's internal state + */ + void printRuckigState(); + + /** + * A utility to get velocity/acceleration/jerk bounds from the robot model + * @return true if all bounds are defined + */ + bool getVelAccelJerkBounds(std::vector& joint_velocity_bounds, std::vector& joint_acceleration_bounds, + std::vector& joint_jerk_bounds); + + /** \brief Parameters loaded from yaml file at runtime */ + online_signal_smoothing::Params params_; + /** \brief The robot model contains the vel/accel/jerk limits that Ruckig requires */ + moveit::core::RobotModelConstPtr robot_model_; + bool have_initial_ruckig_output_ = false; + std::optional> ruckig_; + std::optional> ruckig_input_; + std::optional> ruckig_output_; +}; +} // namespace online_signal_smoothing diff --git a/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/smoothing_base_class.h b/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/smoothing_base_class.h index e870e493f0..e2dc886aaf 100644 --- a/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/smoothing_base_class.h +++ b/moveit_core/online_signal_smoothing/include/moveit/online_signal_smoothing/smoothing_base_class.h @@ -89,6 +89,5 @@ class SmoothingBaseClass */ virtual bool reset(const Eigen::VectorXd& positions, const Eigen::VectorXd& velocities, const Eigen::VectorXd& accelerations) = 0; - ; }; } // namespace online_signal_smoothing diff --git a/moveit_core/online_signal_smoothing/src/acceleration_filter.cpp b/moveit_core/online_signal_smoothing/src/acceleration_filter.cpp index 4bfc69ed14..5e47aaec69 100644 --- a/moveit_core/online_signal_smoothing/src/acceleration_filter.cpp +++ b/moveit_core/online_signal_smoothing/src/acceleration_filter.cpp @@ -34,7 +34,6 @@ #include #include -#include // Disable -Wold-style-cast because all _THROTTLE macros trigger this #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -345,5 +344,4 @@ bool AccelerationLimitedPlugin::reset(const Eigen::VectorXd& positions, const Ei } // namespace online_signal_smoothing #include - PLUGINLIB_EXPORT_CLASS(online_signal_smoothing::AccelerationLimitedPlugin, online_signal_smoothing::SmoothingBaseClass) diff --git a/moveit_core/online_signal_smoothing/src/ruckig_filter.cpp b/moveit_core/online_signal_smoothing/src/ruckig_filter.cpp new file mode 100644 index 0000000000..b689620761 --- /dev/null +++ b/moveit_core/online_signal_smoothing/src/ruckig_filter.cpp @@ -0,0 +1,219 @@ +/********************************************************************* + * Software License Agreement (BSD License) + * + * Copyright (c) 2024, Andrew Zelenak + * 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 PickNik 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. + *********************************************************************/ + +#include +#include +#include + +// Disable -Wold-style-cast because all _THROTTLE macros trigger this +#pragma GCC diagnostic ignored "-Wold-style-cast" + +namespace online_signal_smoothing +{ +namespace +{ +rclcpp::Logger getLogger() +{ + return moveit::getLogger("moveit.core.ruckig_filter_plugin"); +} +} // namespace + +bool RuckigFilterPlugin::initialize(rclcpp::Node::SharedPtr node, moveit::core::RobotModelConstPtr robot_model, + size_t num_joints) +{ + robot_model_ = robot_model; + + // get node parameters and store in member variables + auto param_listener = online_signal_smoothing::ParamListener(node); + params_ = param_listener.get_params(); + + // Ruckig needs the joint vel/accel bounds + // TODO: Ruckig says the jerk bounds can be optional. We require them, for now. + ruckig::InputParameter ruckig_input(num_joints); + if (!getVelAccelJerkBounds(ruckig_input.max_velocity, ruckig_input.max_acceleration, ruckig_input.max_jerk)) + { + return false; + } + ruckig_input.current_position = std::vector(num_joints, 0.0); + ruckig_input.current_velocity = std::vector(num_joints, 0.0); + ruckig_input.current_acceleration = std::vector(num_joints, 0.0); + ruckig_input.synchronization = ruckig::Synchronization::Phase; + + ruckig_input_ = ruckig_input; + + ruckig_output_.emplace(ruckig::OutputParameter(num_joints)); + + ruckig_.emplace(ruckig::Ruckig(num_joints, params_.update_period)); + + return true; +} + +bool RuckigFilterPlugin::doSmoothing(Eigen::VectorXd& positions, Eigen::VectorXd& velocities, + Eigen::VectorXd& accelerations) +{ + if (!ruckig_input_ || !ruckig_output_ || !ruckig_) + { + RCLCPP_ERROR_STREAM(getLogger(), "The Ruckig smoother was not initialized"); + return false; + } + + if (have_initial_ruckig_output_) + { + ruckig_output_->pass_to_input(*ruckig_input_); + } + + // Update Ruckig target state + ruckig_input_->target_position = std::vector(positions.data(), positions.data() + positions.size()); + // We don't know what the next command will be. Assume velocity continues forward based on current state, + // target_acceleration is zero. + const size_t num_joints = ruckig_input_->current_acceleration.size(); + for (size_t i = 0; i < num_joints; ++i) + { + ruckig_input_->target_velocity.at(i) = + ruckig_input_->current_velocity.at(i) + ruckig_input_->current_acceleration.at(i) * params_.update_period; + } + // target_acceleration remains a vector of zeroes + + // Call the Ruckig algorithm + ruckig::Result ruckig_result = ruckig_->update(*ruckig_input_, *ruckig_output_); + + // Finished means the target state can be reached in this timestep. + // Working means the target state can be reached but not in this timestep. + // ErrorSynchronizationCalculation means smoothing was successful but the robot will deviate a bit from the desired + // path. + // See https://github.com/pantor/ruckig/blob/master/include/ruckig/input_parameter.hpp + if (ruckig_result != ruckig::Result::Finished && ruckig_result != ruckig::Result::Working && + ruckig_result != ruckig::Result::ErrorSynchronizationCalculation) + + { + RCLCPP_ERROR_STREAM(getLogger(), "Ruckig jerk-limited smoothing failed with code: " << ruckig_result); + printRuckigState(); + // Return without modifying the position/vel/accel + have_initial_ruckig_output_ = false; + return true; + } + + // Update the target state with Ruckig output + positions = Eigen::Map(ruckig_output_->new_position.data(), + ruckig_output_->new_position.size()); + velocities = Eigen::Map(ruckig_output_->new_velocity.data(), + ruckig_output_->new_velocity.size()); + accelerations = Eigen::Map(ruckig_output_->new_acceleration.data(), + ruckig_output_->new_acceleration.size()); + have_initial_ruckig_output_ = true; + + return true; +} + +bool RuckigFilterPlugin::reset(const Eigen::VectorXd& positions, const Eigen::VectorXd& velocities, + const Eigen::VectorXd& accelerations) +{ + // Initialize Ruckig + ruckig_input_->current_position = std::vector(positions.data(), positions.data() + positions.size()); + ruckig_input_->current_velocity = std::vector(velocities.data(), velocities.data() + velocities.size()); + ruckig_input_->current_acceleration = + std::vector(accelerations.data(), accelerations.data() + accelerations.size()); + + have_initial_ruckig_output_ = false; + return true; +} + +bool RuckigFilterPlugin::getVelAccelJerkBounds(std::vector& joint_velocity_bounds, + std::vector& joint_acceleration_bounds, + std::vector& joint_jerk_bounds) +{ + if (!robot_model_) + { + RCLCPP_ERROR(getLogger(), "The robot model was not initialized."); + return false; + } + + joint_velocity_bounds.clear(); + joint_acceleration_bounds.clear(); + joint_jerk_bounds.clear(); + + auto joint_model_group = robot_model_->getJointModelGroup(params_.planning_group_name); + for (const auto& joint : joint_model_group->getActiveJointModels()) + { + const auto& bound = joint->getVariableBounds(joint->getName()); + + if (bound.velocity_bounded_) + { + // Assume symmetric limits + joint_velocity_bounds.push_back(bound.max_velocity_); + } + else + { + RCLCPP_ERROR_STREAM(getLogger(), "No joint velocity limit defined for " << joint->getName() << "."); + return false; + } + + if (bound.acceleration_bounded_) + { + // Assume symmetric limits + joint_acceleration_bounds.push_back(bound.max_acceleration_); + } + else + { + RCLCPP_WARN_STREAM(getLogger(), "No joint acceleration limit defined for " << joint->getName() << "."); + return false; + } + + if (bound.jerk_bounded_) + { + // Assume symmetric limits + joint_jerk_bounds.push_back(bound.max_jerk_); + } + // else, return false + else + { + RCLCPP_WARN_STREAM(getLogger(), "No joint jerk limit was defined for " + << joint->getName() << ". The output from Ruckig will not be jerk-limited."); + return false; + } + } + + return true; +} + +void RuckigFilterPlugin::printRuckigState() +{ + RCLCPP_INFO_STREAM(getLogger(), ruckig_->delta_time << "\nRuckig input:\n" + << ruckig_input_->to_string() << "\nRuckig output:\n" + << ruckig_output_->to_string()); +} +} // namespace online_signal_smoothing + +#include +PLUGINLIB_EXPORT_CLASS(online_signal_smoothing::RuckigFilterPlugin, online_signal_smoothing::SmoothingBaseClass) diff --git a/moveit_core/online_signal_smoothing/src/ruckig_filter_parameters.yaml b/moveit_core/online_signal_smoothing/src/ruckig_filter_parameters.yaml new file mode 100644 index 0000000000..92575e5059 --- /dev/null +++ b/moveit_core/online_signal_smoothing/src/ruckig_filter_parameters.yaml @@ -0,0 +1,16 @@ +online_signal_smoothing: + update_period: { + type: double, + description: "The expected time in seconds between calls to `doSmoothing` method.", + read_only: true, + validation: { + gt<>: 0.0 + } + } + planning_group_name: { + type: string, + read_only: true, + description: "The name of the MoveIt planning group of the robot \ + This parameter does not have a default value and \ + must be passed to the node during launch time." + } diff --git a/moveit_ros/moveit_servo/config/panda_simulated_config.yaml b/moveit_ros/moveit_servo/config/panda_simulated_config.yaml index 5037999513..de8376e466 100644 --- a/moveit_ros/moveit_servo/config/panda_simulated_config.yaml +++ b/moveit_ros/moveit_servo/config/panda_simulated_config.yaml @@ -28,7 +28,7 @@ publish_joint_accelerations: false ## Plugins for smoothing outgoing commands use_smoothing: true -smoothing_filter_plugin_name: "online_signal_smoothing::AccelerationLimitedPlugin" +smoothing_filter_plugin_name: "online_signal_smoothing::RuckigFilterPlugin" # If is_primary_planning_scene_monitor is set to true, the Servo server's PlanningScene advertises the /get_planning_scene service, # which other nodes can use as a source for information about the planning environment. diff --git a/moveit_ros/moveit_servo/demos/cpp_interface/demo_joint_jog.cpp b/moveit_ros/moveit_servo/demos/cpp_interface/demo_joint_jog.cpp index 0d1315f6dc..43a0e94fa2 100644 --- a/moveit_ros/moveit_servo/demos/cpp_interface/demo_joint_jog.cpp +++ b/moveit_ros/moveit_servo/demos/cpp_interface/demo_joint_jog.cpp @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) std::chrono::seconds timeout_duration(3); std::chrono::seconds time_elapsed(0); - auto start_time = std::chrono::steady_clock::now(); + const auto start_time = std::chrono::steady_clock::now(); // create command queue to build trajectory message and add current robot state std::deque joint_cmd_rolling_window; @@ -104,7 +104,7 @@ int main(int argc, char* argv[]) KinematicState joint_state = servo.getNextJointState(robot_state, joint_jog); const StatusCode status = servo.getStatus(); - auto current_time = std::chrono::steady_clock::now(); + const auto current_time = std::chrono::steady_clock::now(); time_elapsed = std::chrono::duration_cast(current_time - start_time); if (time_elapsed > timeout_duration) { diff --git a/moveit_ros/moveit_servo/demos/cpp_interface/demo_twist.cpp b/moveit_ros/moveit_servo/demos/cpp_interface/demo_twist.cpp index eb816754eb..8c92fa4cfc 100644 --- a/moveit_ros/moveit_servo/demos/cpp_interface/demo_twist.cpp +++ b/moveit_ros/moveit_servo/demos/cpp_interface/demo_twist.cpp @@ -94,7 +94,7 @@ int main(int argc, char* argv[]) std::chrono::seconds timeout_duration(4); std::chrono::seconds time_elapsed(0); - auto start_time = std::chrono::steady_clock::now(); + const auto start_time = std::chrono::steady_clock::now(); // create command queue to build trajectory message and add current robot state std::deque joint_cmd_rolling_window; @@ -107,7 +107,7 @@ int main(int argc, char* argv[]) KinematicState joint_state = servo.getNextJointState(robot_state, target_twist); const StatusCode status = servo.getStatus(); - auto current_time = std::chrono::steady_clock::now(); + const auto current_time = std::chrono::steady_clock::now(); time_elapsed = std::chrono::duration_cast(current_time - start_time); if (time_elapsed > timeout_duration) { diff --git a/moveit_ros/moveit_servo/include/moveit_servo/servo.hpp b/moveit_ros/moveit_servo/include/moveit_servo/servo.hpp index 5b8cb376d9..9d4f836a72 100644 --- a/moveit_ros/moveit_servo/include/moveit_servo/servo.hpp +++ b/moveit_ros/moveit_servo/include/moveit_servo/servo.hpp @@ -118,6 +118,7 @@ class Servo /** * \brief Get the current state of the robot as given by planning scene monitor. + * This may block if a current robot state is not available immediately. * @param block_for_current_state If true, we explicitly wait for a new robot state * @return The current state of the robot. */ diff --git a/moveit_ros/moveit_servo/src/servo.cpp b/moveit_ros/moveit_servo/src/servo.cpp index e27b2256d0..8cae5bf842 100644 --- a/moveit_ros/moveit_servo/src/servo.cpp +++ b/moveit_ros/moveit_servo/src/servo.cpp @@ -79,16 +79,6 @@ Servo::Servo(const rclcpp::Node::SharedPtr& node, std::shared_ptrgetStateMonitor()->getCurrentState(); - // Load the smoothing plugin - if (servo_params_.use_smoothing) - { - setSmoothingPlugin(); - } - else - { - RCLCPP_WARN(logger_, "No smoothing plugin loaded"); - } - // Create the collision checker and start collision checking. collision_monitor_ = std::make_unique(planning_scene_monitor_, servo_params_, std::ref(collision_velocity_scale_)); @@ -125,6 +115,17 @@ Servo::Servo(const rclcpp::Node::SharedPtr& node, std::shared_ptr(std::string(sub_group_name), std::move(new_map))); } + + // Load the smoothing plugin + if (servo_params_.use_smoothing) + { + setSmoothingPlugin(); + } + else + { + RCLCPP_WARN(logger_, "No smoothing plugin loaded"); + } + RCLCPP_INFO_STREAM(logger_, "Servo initialized successfully"); } diff --git a/moveit_ros/moveit_servo/src/servo_node.cpp b/moveit_ros/moveit_servo/src/servo_node.cpp index 9eae434869..bfc989adf3 100644 --- a/moveit_ros/moveit_servo/src/servo_node.cpp +++ b/moveit_ros/moveit_servo/src/servo_node.cpp @@ -383,7 +383,6 @@ void ServoNode::servoLoop() { // if no new command was created, use current robot state updateSlidingWindow(current_state, joint_cmd_rolling_window_, servo_params_.max_expected_latency, cur_time); - servo_->resetSmoothing(current_state); } status_msg.code = static_cast(servo_->getStatus()); diff --git a/moveit_ros/moveit_servo/src/utils/common.cpp b/moveit_ros/moveit_servo/src/utils/common.cpp index 66b0866819..f7ee5701e2 100644 --- a/moveit_ros/moveit_servo/src/utils/common.cpp +++ b/moveit_ros/moveit_servo/src/utils/common.cpp @@ -499,7 +499,16 @@ KinematicState extractRobotState(const moveit::core::RobotStatePtr& robot_state, current_state.joint_names = joint_names; robot_state->copyJointGroupPositions(joint_model_group, current_state.positions); robot_state->copyJointGroupVelocities(joint_model_group, current_state.velocities); + robot_state->copyJointGroupAccelerations(joint_model_group, current_state.accelerations); + // If any acceleration is nan, set all accelerations to zero + // TODO: fix the root cause so this isn't necessary (#2958) + if (std::any_of(current_state.accelerations.begin(), current_state.accelerations.end(), + [](double v) { return isnan(v); })) + { + robot_state->zeroAccelerations(); + robot_state->copyJointGroupAccelerations(joint_model_group, current_state.accelerations); + } return current_state; }