diff --git a/franka_example_controllers/config/franka_example_controllers.yaml b/franka_example_controllers/config/franka_example_controllers.yaml index 43f97246de922f0adcdafbca2e4a27768dad9247..b6ffea56a858873c31f77a9faf76ccef9595b5f0 100644 --- a/franka_example_controllers/config/franka_example_controllers.yaml +++ b/franka_example_controllers/config/franka_example_controllers.yaml @@ -38,20 +38,20 @@ joint_impedance_example_controller: - panda_joint6 - panda_joint7 k_gains: - - 1000.0 - - 1000.0 - - 1000.0 - - 1000.0 - - 500.0 - - 300.0 - - 100.0 + - 600.0 + - 600.0 + - 600.0 + - 600.0 + - 250.0 + - 150.0 + - 50.0 d_gains: - - 100.0 - - 100.0 - - 100.0 - - 100.0 - 50.0 - - 30.0 + - 50.0 + - 50.0 + - 20.0 + - 20.0 + - 20.0 - 10.0 radius: 0.1 acceleration_time: 2.0 diff --git a/franka_example_controllers/include/franka_example_controllers/joint_impedance_example_controller.h b/franka_example_controllers/include/franka_example_controllers/joint_impedance_example_controller.h index c10a7dafdb834c40d21636c4cebe89dee2596836..148370b553b62b647d8444dcfffec3c0ae51bae8 100644 --- a/franka_example_controllers/include/franka_example_controllers/joint_impedance_example_controller.h +++ b/franka_example_controllers/include/franka_example_controllers/joint_impedance_example_controller.h @@ -30,22 +30,31 @@ class JointImpedanceExampleController : public controller_interface::MultiInterf void update(const ros::Time&, const ros::Duration& period) override; private: + std::array<double, 7> saturateTorqueRate( + const double delta_tau_max, + const std::array<double, 7>& tau_d_calculated, + const std::array<double, 7>& tau_J_d, // NOLINT (readability-identifier-naming) + const std::array<double, 7>& gravity); + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; std::vector<hardware_interface::JointHandle> joint_handles_; - std::array<double, 7> last_tau_d_ = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; - franka_hw::TriggerRate rate_trigger_{1.0}; + double radius_{0.1}; double acceleration_time_{2.0}; double vel_max_{0.05}; - std::vector<std::string> joint_names_; - std::vector<double> k_gains_; - std::vector<double> d_gains_; double angle_{0.0}; double vel_current_{0.0}; + + std::vector<double> k_gains_; + std::vector<double> d_gains_; + double coriolis_factor_{1.0}; + std::array<double, 7> dq_filtered_; std::array<double, 16> initial_pose_; + + franka_hw::TriggerRate rate_trigger_{1.0}; realtime_tools::RealtimePublisher<JointTorqueComparison> torques_publisher_; - double coriolis_factor_{1.0}; + std::array<double, 7> last_tau_d_ = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; }; } // namespace franka_example_controllers diff --git a/franka_example_controllers/src/joint_impedance_example_controller.cpp b/franka_example_controllers/src/joint_impedance_example_controller.cpp index 28025282161902b55286acaf7c9e45b7e9238335..5a50b76110165029f75b4d7514056f0b832c41fd 100644 --- a/franka_example_controllers/src/joint_impedance_example_controller.cpp +++ b/franka_example_controllers/src/joint_impedance_example_controller.cpp @@ -10,22 +10,13 @@ #include <franka/robot_state.h> -namespace { -template <class T, size_t N> -std::ostream& operator<<(std::ostream& ostream, const std::array<T, N>& array) { - ostream << "["; - std::copy(array.cbegin(), array.cend() - 1, std::ostream_iterator<T>(ostream, ",")); - std::copy(array.cend() - 1, array.cend(), std::ostream_iterator<T>(ostream)); - ostream << "]"; - return ostream; -} -} // anonymous namespace - namespace franka_example_controllers { bool JointImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) { std::string arm_id; + std::vector<std::string> joint_names; + if (!node_handle.getParam("arm_id", arm_id)) { ROS_ERROR("JointImpedanceExampleController: Could not read parameter arm_id"); return false; @@ -49,7 +40,7 @@ bool JointImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw << acceleration_time_); } - if (!node_handle.getParam("joint_names", joint_names_) || joint_names_.size() != 7) { + if (!node_handle.getParam("joint_names", joint_names) || joint_names.size() != 7) { ROS_ERROR( "JointImpedanceExampleController: Invalid or no joint_names parameters provided, aborting " "controller init!"); @@ -125,7 +116,7 @@ bool JointImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw } for (size_t i = 0; i < 7; ++i) { try { - joint_handles_.push_back(effort_joint_interface->getHandle(joint_names_[i])); + joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i])); } catch (const hardware_interface::HardwareInterfaceException& ex) { ROS_ERROR_STREAM( "JointImpedanceExampleController: Exception getting joint handles: " << ex.what()); @@ -134,6 +125,8 @@ bool JointImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw } torques_publisher_.init(node_handle, "torque_comparison", 1); + std::fill(dq_filtered_.begin(), dq_filtered_.end(), 0); + return true; } @@ -162,19 +155,31 @@ void JointImpedanceExampleController::update(const ros::Time& /*time*/, cartesian_pose_handle_->setCommand(pose_desired); franka::RobotState robot_state = cartesian_pose_handle_->getRobotState(); - std::array<double, 7> q_desired = robot_state.q_d; - std::array<double, 7> q_current = robot_state.q; - std::array<double, 7> dq = robot_state.dq; std::array<double, 7> coriolis = model_handle_->getCoriolis(robot_state.I_total, robot_state.m_total, robot_state.F_x_Ctotal); std::array<double, 7> gravity = model_handle_->getGravity(robot_state.m_total, robot_state.F_x_Ctotal); - std::array<double, 7> tau_d; + double alpha = 0.99; + for (size_t i = 0; i < 7; i++) { + dq_filtered_[i] = (1 - alpha) * dq_filtered_[i] + alpha * robot_state.dq[i]; + } + + std::array<double, 7> tau_d_calculated; for (size_t i = 0; i < 7; ++i) { - tau_d[i] = k_gains_[i] * (q_desired[i] - q_current[i]) - std::fabs(d_gains_[i]) * dq[i] + - coriolis_factor_ * coriolis[i]; - joint_handles_[i].setCommand(tau_d[i]); + tau_d_calculated[i] = coriolis_factor_ * coriolis[i] + + k_gains_[i] * (robot_state.q_d[i] - robot_state.q[i]) + + d_gains_[i] * (robot_state.dq_d[i] - dq_filtered_[i]); + } + + // Maximum torque difference with a sampling rate of 1 kHz. The maximum torque rate is + // 1000 * (1 / sampling_time). + const double delta_tau_max = 1.0; // NOLINT (readability-identifier-naming) + std::array<double, 7> tau_d_saturated = + saturateTorqueRate(delta_tau_max, tau_d_calculated, robot_state.tau_J_d, gravity); + + for (size_t i = 0; i < 7; ++i) { + joint_handles_[i].setCommand(tau_d_saturated[i]); } if (rate_trigger_() && torques_publisher_.trylock()) { @@ -195,10 +200,25 @@ void JointImpedanceExampleController::update(const ros::Time& /*time*/, } for (size_t i = 0; i < 7; ++i) { - last_tau_d_[i] = tau_d[i] + gravity[i]; + last_tau_d_[i] = tau_d_saturated[i] + gravity[i]; } } +std::array<double, 7> JointImpedanceExampleController::saturateTorqueRate( + const double delta_tau_max, // NOLINT (readability-identifier-naming) + const std::array<double, 7>& tau_d_calculated, + const std::array<double, 7>& tau_J_d, // NOLINT (readability-identifier-naming) + const std::array<double, 7>& gravity) { + std::array<double, 7> tau_d_saturated{}; + for (size_t i = 0; i < 7; i++) { + // TODO(sga): After gravity is removed from tau_J_d, do not subtract it any more. + double difference = tau_d_calculated[i] - (tau_J_d[i] - gravity[i]); + tau_d_saturated[i] = + (tau_J_d[i] - gravity[i]) + std::max(std::min(difference, delta_tau_max), -delta_tau_max); + } + return tau_d_saturated; +} + } // namespace franka_example_controllers PLUGINLIB_EXPORT_CLASS(franka_example_controllers::JointImpedanceExampleController,