Skip to content
Snippets Groups Projects
Select Git revision
  • 0f83665df0bbe072bb892142d42c8124b5c2d38d
  • develop default protected
  • feature/tube-grasp-eef
  • master
  • simulated_grasping
  • simulation
  • 0.6.0
  • 0.5.0
  • 0.4.1
  • 0.4.0
  • 0.3.0
  • 0.2.2
  • 0.2.1
  • 0.2.0
  • 0.1.2
  • 0.1.1
  • 0.1.0
17 results

franka_state_controller.cpp

Blame
  • franka_state_controller.cpp 24.81 KiB
    // Copyright (c) 2017 Franka Emika GmbH
    // Use of this source code is governed by the Apache-2.0 license, see LICENSE
    #include <franka_control/franka_state_controller.h>
    
    #include <cmath>
    #include <memory>
    #include <mutex>
    #include <string>
    
    #include <franka/errors.h>
    #include <franka_hw/franka_cartesian_command_interface.h>
    #include <franka_msgs/Errors.h>
    #include <hardware_interface/hardware_interface.h>
    #include <pluginlib/class_list_macros.h>
    #include <ros/ros.h>
    #include <tf/tf.h>
    #include <tf/transform_datatypes.h>
    
    namespace {
    
    tf::Transform convertArrayToTf(const std::array<double, 16>& transform) {
      tf::Matrix3x3 rotation(transform[0], transform[4], transform[8], transform[1], transform[5],
                             transform[9], transform[2], transform[6], transform[10]);
      tf::Vector3 translation(transform[12], transform[13], transform[14]);
      return tf::Transform(rotation, translation);
    }
    
    franka_msgs::Errors errorsToMessage(const franka::Errors& error) {
      franka_msgs::Errors message;
      message.joint_position_limits_violation =
          static_cast<decltype(message.joint_position_limits_violation)>(
              error.joint_position_limits_violation);
      message.cartesian_position_limits_violation =
          static_cast<decltype(message.cartesian_position_limits_violation)>(
              error.cartesian_position_limits_violation);
      message.self_collision_avoidance_violation =
          static_cast<decltype(message.self_collision_avoidance_violation)>(
              error.self_collision_avoidance_violation);
      message.joint_velocity_violation =
          static_cast<decltype(message.joint_velocity_violation)>(error.joint_velocity_violation);
      message.cartesian_velocity_violation =
          static_cast<decltype(message.cartesian_velocity_violation)>(
              error.cartesian_velocity_violation);
      message.force_control_safety_violation =
          static_cast<decltype(message.force_control_safety_violation)>(
              error.force_control_safety_violation);
      message.joint_reflex = static_cast<decltype(message.joint_reflex)>(error.joint_reflex);
      message.cartesian_reflex =
          static_cast<decltype(message.cartesian_reflex)>(error.cartesian_reflex);
      message.max_goal_pose_deviation_violation =
          static_cast<decltype(message.max_goal_pose_deviation_violation)>(
              error.max_goal_pose_deviation_violation);
      message.max_path_pose_deviation_violation =
          static_cast<decltype(message.max_path_pose_deviation_violation)>(
              error.max_path_pose_deviation_violation);
      message.cartesian_velocity_profile_safety_violation =
          static_cast<decltype(message.cartesian_velocity_profile_safety_violation)>(
              error.cartesian_velocity_profile_safety_violation);
      message.joint_position_motion_generator_start_pose_invalid =
          static_cast<decltype(message.joint_position_motion_generator_start_pose_invalid)>(
              error.joint_position_motion_generator_start_pose_invalid);
      message.joint_motion_generator_position_limits_violation =
          static_cast<decltype(message.joint_motion_generator_position_limits_violation)>(
              error.joint_motion_generator_position_limits_violation);
      message.joint_motion_generator_velocity_limits_violation =
          static_cast<decltype(message.joint_motion_generator_velocity_limits_violation)>(
              error.joint_motion_generator_velocity_limits_violation);
      message.joint_motion_generator_velocity_discontinuity =
          static_cast<decltype(message.joint_motion_generator_velocity_discontinuity)>(
              error.joint_motion_generator_velocity_discontinuity);
      message.joint_motion_generator_acceleration_discontinuity =
          static_cast<decltype(message.joint_motion_generator_acceleration_discontinuity)>(
              error.joint_motion_generator_acceleration_discontinuity);
      message.cartesian_position_motion_generator_start_pose_invalid =
          static_cast<decltype(message.cartesian_position_motion_generator_start_pose_invalid)>(
              error.cartesian_position_motion_generator_start_pose_invalid);
      message.cartesian_motion_generator_elbow_limit_violation =
          static_cast<decltype(message.cartesian_motion_generator_elbow_limit_violation)>(
              error.cartesian_motion_generator_elbow_limit_violation);
      message.cartesian_motion_generator_velocity_limits_violation =
          static_cast<decltype(message.cartesian_motion_generator_velocity_limits_violation)>(
              error.cartesian_motion_generator_velocity_limits_violation);
      message.cartesian_motion_generator_velocity_discontinuity =
          static_cast<decltype(message.cartesian_motion_generator_velocity_discontinuity)>(
              error.cartesian_motion_generator_velocity_discontinuity);
      message.cartesian_motion_generator_acceleration_discontinuity =
          static_cast<decltype(message.cartesian_motion_generator_acceleration_discontinuity)>(
              error.cartesian_motion_generator_acceleration_discontinuity);
      message.cartesian_motion_generator_elbow_sign_inconsistent =
          static_cast<decltype(message.cartesian_motion_generator_elbow_sign_inconsistent)>(
              error.cartesian_motion_generator_elbow_sign_inconsistent);
      message.cartesian_motion_generator_start_elbow_invalid =
          static_cast<decltype(message.cartesian_motion_generator_start_elbow_invalid)>(
              error.cartesian_motion_generator_start_elbow_invalid);
      message.cartesian_motion_generator_joint_position_limits_violation =
          static_cast<decltype(message.cartesian_motion_generator_joint_position_limits_violation)>(
              error.cartesian_motion_generator_joint_position_limits_violation);
      message.cartesian_motion_generator_joint_velocity_limits_violation =
          static_cast<decltype(message.cartesian_motion_generator_joint_velocity_limits_violation)>(
              error.cartesian_motion_generator_joint_velocity_limits_violation);
      message.cartesian_motion_generator_joint_velocity_discontinuity =
          static_cast<decltype(message.cartesian_motion_generator_joint_velocity_discontinuity)>(
              error.cartesian_motion_generator_joint_velocity_discontinuity);
      message.cartesian_motion_generator_joint_acceleration_discontinuity =
          static_cast<decltype(message.cartesian_motion_generator_joint_acceleration_discontinuity)>(
              error.cartesian_motion_generator_joint_acceleration_discontinuity);
      message.cartesian_position_motion_generator_invalid_frame =
          static_cast<decltype(message.cartesian_position_motion_generator_invalid_frame)>(
              error.cartesian_position_motion_generator_invalid_frame);
      message.force_controller_desired_force_tolerance_violation =
          static_cast<decltype(message.force_controller_desired_force_tolerance_violation)>(
              error.force_controller_desired_force_tolerance_violation);
      message.controller_torque_discontinuity =
          static_cast<decltype(message.controller_torque_discontinuity)>(
              error.controller_torque_discontinuity);
      message.start_elbow_sign_inconsistent =
          static_cast<decltype(message.start_elbow_sign_inconsistent)>(
              error.start_elbow_sign_inconsistent);
      message.communication_constraints_violation =
          static_cast<decltype(message.communication_constraints_violation)>(
              error.communication_constraints_violation);
      message.power_limit_violation =
          static_cast<decltype(message.power_limit_violation)>(error.power_limit_violation);
      message.joint_p2p_insufficient_torque_for_planning =
          static_cast<decltype(message.joint_p2p_insufficient_torque_for_planning)>(
              error.joint_p2p_insufficient_torque_for_planning);
      message.tau_j_range_violation =
          static_cast<decltype(message.tau_j_range_violation)>(error.tau_j_range_violation);
      message.instability_detected =
          static_cast<decltype(message.instability_detected)>(error.instability_detected);
      return message;
    }
    
    }  // anonymous namespace
    
    namespace franka_control {
    
    bool FrankaStateController::init(hardware_interface::RobotHW* robot_hardware,
                                     ros::NodeHandle& root_node_handle,
                                     ros::NodeHandle& controller_node_handle) {
      franka_state_interface_ = robot_hardware->get<franka_hw::FrankaStateInterface>();
      if (franka_state_interface_ == nullptr) {
        ROS_ERROR("FrankaStateController: Could not get Franka state interface from hardware");
        return false;
      }
      if (!controller_node_handle.getParam("arm_id", arm_id_)) {
        ROS_ERROR("FrankaStateController: Could not get parameter arm_id");
        return false;
      }
      double publish_rate(30.0);
      if (!controller_node_handle.getParam("publish_rate", publish_rate)) {
        ROS_INFO_STREAM("FrankaStateController: Did not find publish_rate. Using default "
                        << publish_rate << " [Hz].");
      }
      trigger_publish_ = franka_hw::TriggerRate(publish_rate);
    
      if (!controller_node_handle.getParam("joint_names", joint_names_) ||
          joint_names_.size() != robot_state_.q.size()) {
        ROS_ERROR(
            "FrankaStateController: Invalid or no joint_names parameters provided, aborting "
            "controller init!");
        return false;
      }
    
      try {
        franka_state_handle_ = std::make_unique<franka_hw::FrankaStateHandle>(
            franka_state_interface_->getHandle(arm_id_ + "_robot"));
      } catch (const hardware_interface::HardwareInterfaceException& ex) {
        ROS_ERROR_STREAM("FrankaStateController: Exception getting franka state handle: " << ex.what());
        return false;
      }
    
      publisher_transforms_.init(root_node_handle, "/tf", 1);
      publisher_franka_states_.init(controller_node_handle, "franka_states", 1);
      publisher_joint_states_.init(controller_node_handle, "joint_states", 1);
      publisher_joint_states_desired_.init(controller_node_handle, "joint_states_desired", 1);
      publisher_external_wrench_.init(controller_node_handle, "F_ext", 1);
    
      {
        std::lock_guard<realtime_tools::RealtimePublisher<sensor_msgs::JointState>> lock(
            publisher_joint_states_);
        publisher_joint_states_.msg_.name.resize(joint_names_.size());
        publisher_joint_states_.msg_.position.resize(robot_state_.q.size());
        publisher_joint_states_.msg_.velocity.resize(robot_state_.dq.size());
        publisher_joint_states_.msg_.effort.resize(robot_state_.tau_J.size());
      }
      {
        std::lock_guard<realtime_tools::RealtimePublisher<sensor_msgs::JointState>> lock(
            publisher_joint_states_desired_);
        publisher_joint_states_desired_.msg_.name.resize(joint_names_.size());
        publisher_joint_states_desired_.msg_.position.resize(robot_state_.q_d.size());
        publisher_joint_states_desired_.msg_.velocity.resize(robot_state_.dq_d.size());
        publisher_joint_states_desired_.msg_.effort.resize(robot_state_.tau_J_d.size());
      }
      {
        std::lock_guard<realtime_tools::RealtimePublisher<tf2_msgs::TFMessage>> lock(
            publisher_transforms_);
        publisher_transforms_.msg_.transforms.resize(2);
        tf::Quaternion quaternion(0.0, 0.0, 0.0, 1.0);
        tf::Vector3 translation(0.0, 0.0, 0.05);
        tf::Transform transform(quaternion, translation);
        tf::StampedTransform stamped_transform(transform, ros::Time::now(), arm_id_ + "_link8",
                                               arm_id_ + "_EE");
        geometry_msgs::TransformStamped transform_message;
        transformStampedTFToMsg(stamped_transform, transform_message);
        publisher_transforms_.msg_.transforms[0] = transform_message;
        translation = tf::Vector3(0.0, 0.0, 0.0);
        transform = tf::Transform(quaternion, translation);
        stamped_transform =
            tf::StampedTransform(transform, ros::Time::now(), arm_id_ + "_EE", arm_id_ + "_K");
        transformStampedTFToMsg(stamped_transform, transform_message);
        publisher_transforms_.msg_.transforms[1] = transform_message;
      }
      {
        std::lock_guard<realtime_tools::RealtimePublisher<geometry_msgs::WrenchStamped>> lock(
            publisher_external_wrench_);
        publisher_external_wrench_.msg_.header.frame_id = arm_id_ + "_K";
        publisher_external_wrench_.msg_.wrench.force.x = 0.0;
        publisher_external_wrench_.msg_.wrench.force.y = 0.0;
        publisher_external_wrench_.msg_.wrench.force.z = 0.0;
        publisher_external_wrench_.msg_.wrench.torque.x = 0.0;
        publisher_external_wrench_.msg_.wrench.torque.y = 0.0;
        publisher_external_wrench_.msg_.wrench.torque.z = 0.0;
      }
      return true;
    }
    
    void FrankaStateController::update(const ros::Time& time, const ros::Duration& /* period */) {
      if (trigger_publish_()) {
        robot_state_ = franka_state_handle_->getRobotState();
        publishFrankaStates(time);
        publishTransforms(time);
        publishExternalWrench(time);
        publishJointStates(time);
        sequence_number_++;
      }
    }
    
    void FrankaStateController::publishFrankaStates(const ros::Time& time) {
      if (publisher_franka_states_.trylock()) {
        static_assert(
            sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.cartesian_contact),
            "Robot state Cartesian members do not have same size");
        static_assert(sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.K_F_ext_hat_K),
                      "Robot state Cartesian members do not have same size");
        static_assert(sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.O_F_ext_hat_K),
                      "Robot state Cartesian members do not have same size");
        static_assert(sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.O_dP_EE_d),
                      "Robot state Cartesian members do not have same size");
        static_assert(sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.O_dP_EE_c),
                      "Robot state Cartesian members do not have same size");
        static_assert(sizeof(robot_state_.cartesian_collision) == sizeof(robot_state_.O_ddP_EE_c),
                      "Robot state Cartesian members do not have same size");
        for (size_t i = 0; i < robot_state_.cartesian_collision.size(); i++) {
          publisher_franka_states_.msg_.cartesian_collision[i] = robot_state_.cartesian_collision[i];
          publisher_franka_states_.msg_.cartesian_contact[i] = robot_state_.cartesian_contact[i];
          publisher_franka_states_.msg_.K_F_ext_hat_K[i] = robot_state_.K_F_ext_hat_K[i];
          publisher_franka_states_.msg_.O_F_ext_hat_K[i] = robot_state_.O_F_ext_hat_K[i];
          publisher_franka_states_.msg_.O_dP_EE_d[i] = robot_state_.O_dP_EE_d[i];
          publisher_franka_states_.msg_.O_dP_EE_c[i] = robot_state_.O_dP_EE_c[i];
          publisher_franka_states_.msg_.O_ddP_EE_c[i] = robot_state_.O_ddP_EE_c[i];
        }
    
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.q_d),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.dq),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.dq_d),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.ddq_d),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.tau_J),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.dtau_J),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.tau_J_d),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.theta),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.dtheta),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.joint_collision),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.joint_contact),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.tau_ext_hat_filtered),
                      "Robot state joint members do not have same size");
        for (size_t i = 0; i < robot_state_.q.size(); i++) {
          publisher_franka_states_.msg_.q[i] = robot_state_.q[i];
          publisher_franka_states_.msg_.q_d[i] = robot_state_.q_d[i];
          publisher_franka_states_.msg_.dq[i] = robot_state_.dq[i];
          publisher_franka_states_.msg_.dq_d[i] = robot_state_.dq_d[i];
          publisher_franka_states_.msg_.ddq_d[i] = robot_state_.ddq_d[i];
          publisher_franka_states_.msg_.tau_J[i] = robot_state_.tau_J[i];
          publisher_franka_states_.msg_.dtau_J[i] = robot_state_.dtau_J[i];
          publisher_franka_states_.msg_.tau_J_d[i] = robot_state_.tau_J_d[i];
          publisher_franka_states_.msg_.theta[i] = robot_state_.theta[i];
          publisher_franka_states_.msg_.dtheta[i] = robot_state_.dtheta[i];
          publisher_franka_states_.msg_.joint_collision[i] = robot_state_.joint_collision[i];
          publisher_franka_states_.msg_.joint_contact[i] = robot_state_.joint_contact[i];
          publisher_franka_states_.msg_.tau_ext_hat_filtered[i] = robot_state_.tau_ext_hat_filtered[i];
        }
    
        static_assert(sizeof(robot_state_.elbow) == sizeof(robot_state_.elbow_d),
                      "Robot state elbow configuration members do not have same size");
        static_assert(sizeof(robot_state_.elbow) == sizeof(robot_state_.elbow_c),
                      "Robot state elbow configuration members do not have same size");
        static_assert(sizeof(robot_state_.elbow) == sizeof(robot_state_.delbow_c),
                      "Robot state elbow configuration members do not have same size");
        static_assert(sizeof(robot_state_.elbow) == sizeof(robot_state_.ddelbow_c),
                      "Robot state elbow configuration members do not have same size");
    
        for (size_t i = 0; i < robot_state_.elbow.size(); i++) {
          publisher_franka_states_.msg_.elbow[i] = robot_state_.elbow[i];
          publisher_franka_states_.msg_.elbow_d[i] = robot_state_.elbow_d[i];
          publisher_franka_states_.msg_.elbow_c[i] = robot_state_.elbow_c[i];
          publisher_franka_states_.msg_.delbow_c[i] = robot_state_.delbow_c[i];
          publisher_franka_states_.msg_.ddelbow_c[i] = robot_state_.ddelbow_c[i];
        }
    
        static_assert(sizeof(robot_state_.O_T_EE) == sizeof(robot_state_.F_T_EE),
                      "Robot state transforms do not have same size");
        static_assert(sizeof(robot_state_.O_T_EE) == sizeof(robot_state_.EE_T_K),
                      "Robot state transforms do not have same size");
        static_assert(sizeof(robot_state_.O_T_EE) == sizeof(robot_state_.O_T_EE_d),
                      "Robot state transforms do not have same size");
        static_assert(sizeof(robot_state_.O_T_EE) == sizeof(robot_state_.O_T_EE_c),
                      "Robot state transforms do not have same size");
        for (size_t i = 0; i < robot_state_.O_T_EE.size(); i++) {
          publisher_franka_states_.msg_.O_T_EE[i] = robot_state_.O_T_EE[i];
          publisher_franka_states_.msg_.F_T_EE[i] = robot_state_.F_T_EE[i];
          publisher_franka_states_.msg_.EE_T_K[i] = robot_state_.EE_T_K[i];
          publisher_franka_states_.msg_.O_T_EE_d[i] = robot_state_.O_T_EE_d[i];
          publisher_franka_states_.msg_.O_T_EE_c[i] = robot_state_.O_T_EE_c[i];
        }
        publisher_franka_states_.msg_.m_ee = robot_state_.m_ee;
        publisher_franka_states_.msg_.m_load = robot_state_.m_load;
        publisher_franka_states_.msg_.m_total = robot_state_.m_total;
    
        for (size_t i = 0; i < robot_state_.I_load.size(); i++) {
          publisher_franka_states_.msg_.I_ee[i] = robot_state_.I_ee[i];
          publisher_franka_states_.msg_.I_load[i] = robot_state_.I_load[i];
          publisher_franka_states_.msg_.I_total[i] = robot_state_.I_total[i];
        }
    
        for (size_t i = 0; i < robot_state_.F_x_Cload.size(); i++) {
          publisher_franka_states_.msg_.F_x_Cee[i] = robot_state_.F_x_Cee[i];
          publisher_franka_states_.msg_.F_x_Cload[i] = robot_state_.F_x_Cload[i];
          publisher_franka_states_.msg_.F_x_Ctotal[i] = robot_state_.F_x_Ctotal[i];
        }
    
        publisher_franka_states_.msg_.time = robot_state_.time.toSec();
        publisher_franka_states_.msg_.control_command_success_rate =
            robot_state_.control_command_success_rate;
        publisher_franka_states_.msg_.current_errors = errorsToMessage(robot_state_.current_errors);
        publisher_franka_states_.msg_.last_motion_errors =
            errorsToMessage(robot_state_.last_motion_errors);
    
        switch (robot_state_.robot_mode) {
          case franka::RobotMode::kOther:
            publisher_franka_states_.msg_.robot_mode = franka_msgs::FrankaState::ROBOT_MODE_OTHER;
            break;
    
          case franka::RobotMode::kIdle:
            publisher_franka_states_.msg_.robot_mode = franka_msgs::FrankaState::ROBOT_MODE_IDLE;
            break;
    
          case franka::RobotMode::kMove:
            publisher_franka_states_.msg_.robot_mode = franka_msgs::FrankaState::ROBOT_MODE_MOVE;
            break;
    
          case franka::RobotMode::kGuiding:
            publisher_franka_states_.msg_.robot_mode = franka_msgs::FrankaState::ROBOT_MODE_GUIDING;
            break;
    
          case franka::RobotMode::kReflex:
            publisher_franka_states_.msg_.robot_mode = franka_msgs::FrankaState::ROBOT_MODE_REFLEX;
            break;
    
          case franka::RobotMode::kUserStopped:
            publisher_franka_states_.msg_.robot_mode =
                franka_msgs::FrankaState::ROBOT_MODE_USER_STOPPED;
            break;
    
          case franka::RobotMode::kAutomaticErrorRecovery:
            publisher_franka_states_.msg_.robot_mode =
                franka_msgs::FrankaState::ROBOT_MODE_AUTOMATIC_ERROR_RECOVERY;
            break;
        }
    
        publisher_franka_states_.msg_.header.seq = sequence_number_;
        publisher_franka_states_.msg_.header.stamp = time;
        publisher_franka_states_.unlockAndPublish();
      }
    }
    
    void FrankaStateController::publishJointStates(const ros::Time& time) {
      if (publisher_joint_states_.trylock()) {
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.dq),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q) == sizeof(robot_state_.tau_J),
                      "Robot state joint members do not have same size");
        for (size_t i = 0; i < robot_state_.q.size(); i++) {
          publisher_joint_states_.msg_.name[i] = joint_names_[i];
          publisher_joint_states_.msg_.position[i] = robot_state_.q[i];
          publisher_joint_states_.msg_.velocity[i] = robot_state_.dq[i];
          publisher_joint_states_.msg_.effort[i] = robot_state_.tau_J[i];
        }
        publisher_joint_states_.msg_.header.stamp = time;
        publisher_joint_states_.msg_.header.seq = sequence_number_;
        publisher_joint_states_.unlockAndPublish();
      }
      if (publisher_joint_states_desired_.trylock()) {
        static_assert(sizeof(robot_state_.q_d) == sizeof(robot_state_.dq_d),
                      "Robot state joint members do not have same size");
        static_assert(sizeof(robot_state_.q_d) == sizeof(robot_state_.tau_J_d),
                      "Robot state joint members do not have same size");
        for (size_t i = 0; i < robot_state_.q_d.size(); i++) {
          publisher_joint_states_desired_.msg_.name[i] = joint_names_[i];
          publisher_joint_states_desired_.msg_.position[i] = robot_state_.q_d[i];
          publisher_joint_states_desired_.msg_.velocity[i] = robot_state_.dq_d[i];
          publisher_joint_states_desired_.msg_.effort[i] = robot_state_.tau_J_d[i];
        }
        publisher_joint_states_desired_.msg_.header.stamp = time;
        publisher_joint_states_desired_.msg_.header.seq = sequence_number_;
        publisher_joint_states_desired_.unlockAndPublish();
      }
    }
    
    void FrankaStateController::publishTransforms(const ros::Time& time) {
      if (publisher_transforms_.trylock()) {
        tf::StampedTransform stamped_transform(convertArrayToTf(robot_state_.F_T_EE), time,
                                               arm_id_ + "_link8", arm_id_ + "_EE");
        geometry_msgs::TransformStamped transform_message;
        transformStampedTFToMsg(stamped_transform, transform_message);
        publisher_transforms_.msg_.transforms[0] = transform_message;
        stamped_transform = tf::StampedTransform(convertArrayToTf(robot_state_.EE_T_K), time,
                                                 arm_id_ + "_EE", arm_id_ + "_K");
        transformStampedTFToMsg(stamped_transform, transform_message);
        publisher_transforms_.msg_.transforms[1] = transform_message;
        publisher_transforms_.unlockAndPublish();
      }
    }
    
    void FrankaStateController::publishExternalWrench(const ros::Time& time) {
      if (publisher_external_wrench_.trylock()) {
        publisher_external_wrench_.msg_.header.frame_id = arm_id_ + "_K";
        publisher_external_wrench_.msg_.header.stamp = time;
        publisher_external_wrench_.msg_.wrench.force.x = robot_state_.K_F_ext_hat_K[0];
        publisher_external_wrench_.msg_.wrench.force.y = robot_state_.K_F_ext_hat_K[1];
        publisher_external_wrench_.msg_.wrench.force.z = robot_state_.K_F_ext_hat_K[2];
        publisher_external_wrench_.msg_.wrench.torque.x = robot_state_.K_F_ext_hat_K[3];
        publisher_external_wrench_.msg_.wrench.torque.y = robot_state_.K_F_ext_hat_K[4];
        publisher_external_wrench_.msg_.wrench.torque.z = robot_state_.K_F_ext_hat_K[5];
        publisher_external_wrench_.unlockAndPublish();
      }
    }
    
    }  // namespace franka_control
    
    PLUGINLIB_EXPORT_CLASS(franka_control::FrankaStateController, controller_interface::ControllerBase)