14 #include <geometry_msgs/PoseStamped.h> 25 const std::string& arm_id,
26 const std::vector<std::string>& joint_names) {
29 if (model_interface ==
nullptr) {
31 "DualArmCartesianImpedanceExampleController: Error getting model interface from hardware");
35 arm_data.
model_handle_ = std::make_unique<franka_hw::FrankaModelHandle>(
36 model_interface->getHandle(arm_id +
"_model"));
39 "DualArmCartesianImpedanceExampleController: Exception getting model handle from " 46 if (state_interface ==
nullptr) {
48 "DualArmCartesianImpedanceExampleController: Error getting state interface from hardware");
52 arm_data.
state_handle_ = std::make_unique<franka_hw::FrankaStateHandle>(
53 state_interface->getHandle(arm_id +
"_robot"));
56 "DualArmCartesianImpedanceExampleController: Exception getting state handle from " 63 if (effort_joint_interface ==
nullptr) {
65 "DualArmCartesianImpedanceExampleController: Error getting effort joint interface from " 69 for (
size_t i = 0; i < 7; ++i) {
71 arm_data.
joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i]));
74 "DualArmCartesianImpedanceExampleController: Exception getting joint handles: " 88 arms_data_.emplace(std::make_pair(arm_id, std::move(arm_data)));
95 std::vector<double> cartesian_stiffness_vector;
96 std::vector<double> cartesian_damping_vector;
100 "DualArmCartesianImpedanceExampleController: Could not read parameter left_arm_id_");
103 std::vector<std::string> left_joint_names;
104 if (!node_handle.
getParam(
"left/joint_names", left_joint_names) || left_joint_names.size() != 7) {
106 "DualArmCartesianImpedanceExampleController: Invalid or no left_joint_names parameters " 108 "aborting controller init!");
114 "DualArmCartesianImpedanceExampleController: Could not read parameter right_arm_id_");
118 boost::function<void(const geometry_msgs::PoseStamped::ConstPtr&)> callback =
122 subscribe_options.
init(
"centering_frame_target_pose", 1, callback);
126 std::vector<std::string> right_joint_names;
127 if (!node_handle.
getParam(
"right/joint_names", right_joint_names) ||
128 right_joint_names.size() != 7) {
130 "DualArmCartesianImpedanceExampleController: Invalid or no right_joint_names parameters " 132 "aborting controller init!");
143 franka_combined_example_controllers::dual_arm_compliance_paramConfig>>(
159 "DualArmCartesianImpedanceExampleController: Failed to read transform from %s to %s. " 165 ROS_ERROR(
"DualArmCartesianImpedanceExampleController: %s", ex.what());
174 return left_success && right_success;
182 std::array<double, 42> jacobian_array =
185 Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data());
186 Eigen::Map<Eigen::Matrix<double, 7, 1>> dq_initial(initial_state.
dq.data());
187 Eigen::Map<Eigen::Matrix<double, 7, 1>> q_initial(initial_state.
q.data());
188 Eigen::Affine3d initial_transform(Eigen::Matrix4d::Map(initial_state.
O_T_EE.data()));
191 arm_data.
position_d_ = initial_transform.translation();
192 arm_data.
orientation_d_ = Eigen::Quaterniond(initial_transform.linear());
207 Eigen::Affine3d Ol_T_EEl(Eigen::Matrix4d::Map(
208 robot_state_left.
O_T_EE.data()));
209 Eigen::Affine3d Or_T_EEr(Eigen::Matrix4d::Map(
210 robot_state_right.
O_T_EE.data()));
212 Or_T_EEr.inverse() *
Ol_T_Or_.inverse() * Ol_T_EEl;
214 Eigen::Vector3d EEr_r_EEr_EEl =
232 std::array<double, 49> inertia_array = arm_data.
model_handle_->getMass();
233 std::array<double, 7> coriolis_array = arm_data.
model_handle_->getCoriolis();
234 std::array<double, 42> jacobian_array =
238 Eigen::Map<Eigen::Matrix<double, 7, 1>> coriolis(coriolis_array.data());
239 Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data());
240 Eigen::Map<Eigen::Matrix<double, 7, 1>>
q(robot_state.
q.data());
241 Eigen::Map<Eigen::Matrix<double, 7, 1>> dq(robot_state.
dq.data());
242 Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_J_d(
244 Eigen::Affine3d transform(Eigen::Matrix4d::Map(robot_state.
O_T_EE.data()));
245 Eigen::Vector3d position(transform.translation());
246 Eigen::Quaterniond orientation(transform.linear());
250 Eigen::Matrix<double, 6, 1>
error;
254 if (arm_data.
orientation_d_.coeffs().dot(orientation.coeffs()) < 0.0) {
255 orientation.coeffs() << -orientation.coeffs();
258 Eigen::Quaterniond error_quaternion(orientation * arm_data.
orientation_d_.inverse());
260 Eigen::AngleAxisd error_quaternion_angle_axis(error_quaternion);
262 error.tail(3) << error_quaternion_angle_axis.axis() * error_quaternion_angle_axis.angle();
266 Eigen::VectorXd tau_task(7), tau_nullspace(7), tau_d(7);
270 Eigen::MatrixXd jacobian_transpose_pinv;
277 tau_nullspace << (Eigen::MatrixXd::Identity(7, 7) -
278 jacobian.transpose() * jacobian_transpose_pinv) *
282 tau_d << tau_task + tau_nullspace + coriolis;
285 for (
size_t i = 0; i < 7; ++i) {
305 const Eigen::Matrix<double, 7, 1>& tau_d_calculated,
306 const Eigen::Matrix<double, 7, 1>& tau_J_d) {
307 Eigen::Matrix<double, 7, 1> tau_d_saturated{};
308 for (
size_t i = 0; i < 7; i++) {
309 double difference = tau_d_calculated[i] - tau_J_d[i];
310 tau_d_saturated[i] = tau_J_d[i] + std::max(std::min(difference, arm_data.
delta_tau_max_),
313 return tau_d_saturated;
317 franka_combined_example_controllers::dual_arm_compliance_paramConfig& config,
320 left_arm_data.cartesian_stiffness_target_.setIdentity();
321 left_arm_data.cartesian_stiffness_target_.topLeftCorner(3, 3)
322 << config.left_translational_stiffness * Eigen::Matrix3d::Identity();
323 left_arm_data.cartesian_stiffness_target_.bottomRightCorner(3, 3)
324 << config.left_rotational_stiffness * Eigen::Matrix3d::Identity();
325 left_arm_data.cartesian_damping_target_.setIdentity();
327 left_arm_data.cartesian_damping_target_.topLeftCorner(3, 3)
328 << 2 * sqrt(config.left_translational_stiffness) * Eigen::Matrix3d::Identity();
329 left_arm_data.cartesian_damping_target_.bottomRightCorner(3, 3)
330 << 2 * sqrt(config.left_rotational_stiffness) * Eigen::Matrix3d::Identity();
331 left_arm_data.nullspace_stiffness_target_ = config.left_nullspace_stiffness;
334 right_arm_data.cartesian_stiffness_target_.setIdentity();
335 right_arm_data.cartesian_stiffness_target_.topLeftCorner(3, 3)
336 << config.right_translational_stiffness * Eigen::Matrix3d::Identity();
337 right_arm_data.cartesian_stiffness_target_.bottomRightCorner(3, 3)
338 << config.right_rotational_stiffness * Eigen::Matrix3d::Identity();
339 right_arm_data.cartesian_damping_target_.setIdentity();
341 right_arm_data.cartesian_damping_target_.topLeftCorner(3, 3)
342 << 2 * sqrt(config.right_translational_stiffness) * Eigen::Matrix3d::Identity();
343 right_arm_data.cartesian_damping_target_.bottomRightCorner(3, 3)
344 << 2 * sqrt(config.right_rotational_stiffness) * Eigen::Matrix3d::Identity();
345 right_arm_data.nullspace_stiffness_target_ = config.right_nullspace_stiffness;
349 const geometry_msgs::PoseStamped::ConstPtr& msg) {
353 "DualArmCartesianImpedanceExampleController: Got pose target with invalid" 355 << msg->header.frame_id <<
". Expected " <<
left_arm_id_ +
"_link0");
361 Eigen::Affine3d Ol_T_C;
363 Eigen::Affine3d Ol_T_EEl_d =
365 left_arm_data.position_d_target_ = Ol_T_EEl_d.translation();
366 Eigen::Quaterniond last_orientation_d_target(left_arm_data.orientation_d_target_);
367 Eigen::Quaterniond new_orientation_target(Ol_T_EEl_d.linear());
368 if (last_orientation_d_target.coeffs().dot(new_orientation_target.coeffs()) < 0.0) {
369 new_orientation_target.coeffs() << -new_orientation_target.coeffs();
371 Ol_T_EEl_d.linear() = new_orientation_target.matrix();
372 left_arm_data.orientation_d_target_ = Ol_T_EEl_d.linear();
376 Eigen::Affine3d Or_T_EEr_d =
Ol_T_Or_.inverse()
380 right_arm_data.position_d_target_ =
381 Or_T_EEr_d.translation();
382 last_orientation_d_target = Eigen::Quaterniond(right_arm_data.orientation_d_target_);
383 right_arm_data.orientation_d_target_ =
385 if (last_orientation_d_target.coeffs().dot(right_arm_data.orientation_d_target_.coeffs()) <
387 right_arm_data.orientation_d_target_.coeffs()
388 << -right_arm_data.orientation_d_target_.coeffs();
391 }
catch (std::out_of_range& ex) {
392 ROS_ERROR_STREAM(
"DualArmCartesianImpedanceExampleController: Exception setting target poses.");
400 Eigen::Affine3d Ol_T_EEl(Eigen::Matrix4d::Map(
401 robot_state_left.
O_T_EE.data()));
402 Eigen::Affine3d Ol_T_C = Ol_T_EEl *
EEl_T_C_;
Eigen::Matrix< double, 6, 6 > cartesian_damping_target_
Unfiltered raw value.
virtual const char * what() const
void starting(const ros::Time &) override
Prepares the controller for the real-time execution.
std::unique_ptr< dynamic_reconfigure::Server< franka_combined_example_controllers::dual_arm_compliance_paramConfig > > dynamic_server_compliance_param_
Nodehandle for the dynamic reconfigure namespace.
void complianceParamCallback(franka_combined_example_controllers::dual_arm_compliance_paramConfig &config, uint32_t)
Callback for updates on the parameterization of the controller in terms of stiffnesses.
Eigen::Affine3d EEl_T_C_
< Transformation from the centering frame to the left end effector.
void pseudoInverse(const Eigen::MatrixXd &M_, Eigen::MatrixXd &M_pinv_, bool damped=true)
TransportHints & reliable()
Eigen::Matrix< double, 6, 6 > cartesian_stiffness_
To track the target pose.
void publishCenteringPose()
Publishes a Pose Stamped for visualization of the current centering pose.
Eigen::Matrix< double, 6, 6 > cartesian_damping_
To damp cartesian motions.
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
Eigen::Affine3d EEr_T_EEl_
< Target transformation between the two endeffectors.
void update(const ros::Time &, const ros::Duration &period) override
Computes the control-law and commands the resulting joint torques to the robot.
Eigen::Matrix< double, 7, 1 > q_d_nullspace_
Target joint pose for nullspace motion.
void targetPoseCallback(const geometry_msgs::PoseStamped::ConstPtr &msg)
Callback method that handles updates of the target poses.
std::unique_ptr< franka_hw::FrankaStateHandle > state_handle_
To read to complete robot state.
std::vector< hardware_interface::JointHandle > joint_handles_
To command joint torques.
std::unique_ptr< franka_hw::FrankaModelHandle > model_handle_
To have access to e.g. jacobians.
realtime_tools::RealtimePublisher< geometry_msgs::PoseStamped > center_frame_pub_
Rate to trigger publishing the current pose of the centering frame.
Eigen::Matrix< double, 7, 1 > saturateTorqueRate(const FrankaDataContainer &arm_data, const Eigen::Matrix< double, 7, 1 > &tau_d_calculated, const Eigen::Matrix< double, 7, 1 > &tau_J_d)
Saturates torque commands to ensure feasibility.
std::string left_arm_id_
Name of the left arm, retrieved from the parameter server.
std::map< std::string, FrankaDataContainer > arms_data_
Holds all relevant data for both arms.
TransportHints & tcpNoDelay(bool nodelay=true)
std::array< double, 7 > q
double nullspace_stiffness_
[Nm/rad] To track the initial joint configuration in the nullspace of the Cartesian motion...
Eigen::Quaterniond orientation_d_target_
Unfiltered raw value.
double nullspace_stiffness_target_
[Nm/rad] Unfiltered raw value.
Eigen::Quaterniond orientation_d_
Target orientation of the end effector.
ros::NodeHandle dynamic_reconfigure_compliance_param_node_
Controller class for ros_control that renders two decoupled Cartesian impedances for the tracking of ...
bool init(hardware_interface::RobotHW *robot_hw, ros::NodeHandle &node_handle) override
Initializes the controller class to be ready to run.
double filter_params_
[-] PT1-Filter constant to smooth target values set by dynamic reconfigure servers (stiffness/damping...
This container holds all data and parameters used to control one panda arm with a Cartesian impedance...
std::array< double, 7 > dq
void updateArm(FrankaDataContainer &arm_data)
Computes the decoupled controller update for a single arm.
Eigen::Vector3d position_d_target_
Unfiltered raw value.
TransportHints transport_hints
std::array< double, 16 > O_T_EE
Eigen::Matrix< double, 6, 6 > cartesian_stiffness_target_
Unfiltered raw value.
ros::Subscriber sub_target_pose_left_
Eigen::Vector3d position_d_
Target position of the end effector.
void startingArm(FrankaDataContainer &arm_data)
Prepares all internal states to be ready to run the real-time control for one arm.
std::array< double, 7 > tau_J_d
bool getParam(const std::string &key, std::string &s) const
PLUGINLIB_EXPORT_CLASS(moveit_fake_controller_manager::MoveItFakeControllerManager, moveit_controller_manager::MoveItControllerManager)
bool initArm(hardware_interface::RobotHW *robot_hw, const std::string &arm_id, const std::vector< std::string > &joint_names)
Initializes a single Panda robot arm.
const double delta_tau_max_
[Nm/ms] Maximum difference in joint-torque per timestep.
void transformTFToEigen(const tf::Transform &t, Eigen::Isometry3d &e)
void init(const std::string &_topic, uint32_t _queue_size, const boost::function< void(const boost::shared_ptr< M const > &)> &_callback, const boost::function< boost::shared_ptr< M >(void)> &factory_fn=DefaultMessageCreator< M >())
#define ROS_ERROR_STREAM(args)
franka_hw::TriggerRate publish_rate_
std::string right_arm_id_
Name of the right arm, retrieved from the parameter server.