// Copyright (c) 2023 Franka Robotics GmbH // Use of this source code is governed by the Apache-2.0 license, see LICENSE #include #include #include #include #include #include #include #include #include #include "examples_common.h" /** * @example cartesian_impedance_control.cpp * An example showing a simple cartesian impedance controller without inertia shaping * that renders a spring damper system where the equilibrium is the initial configuration. * After starting the controller try to push the robot around and try different stiffness levels. * * @warning collision thresholds are set to high values. Make sure you have the user stop at hand! */ int main(int argc, char** argv) { // Check whether the required arguments were passed if (argc != 2) { std::cerr << "Usage: " << argv[0] << " " << std::endl; return -1; } // Compliance parameters const double translational_stiffness{150.0}; const double rotational_stiffness{10.0}; Eigen::MatrixXd stiffness(6, 6); Eigen::MatrixXd damping(6, 6); stiffness.setZero(); stiffness.topLeftCorner(3, 3) << translational_stiffness * Eigen::MatrixXd::Identity(3, 3); stiffness.bottomRightCorner(3, 3) << rotational_stiffness * Eigen::MatrixXd::Identity(3, 3); damping.setZero(); damping.topLeftCorner(3, 3) << 2.0 * sqrt(translational_stiffness) * Eigen::MatrixXd::Identity(3, 3); damping.bottomRightCorner(3, 3) << 2.0 * sqrt(rotational_stiffness) * Eigen::MatrixXd::Identity(3, 3); try { // connect to robot franka::Robot robot(argv[1]); setDefaultBehavior(robot); // load the kinematics and dynamics model franka::Model model = robot.loadModel(); franka::RobotState initial_state = robot.readOnce(); // equilibrium point is the initial position Eigen::Affine3d initial_transform(Eigen::Matrix4d::Map(initial_state.O_T_EE.data())); Eigen::Vector3d position_d(initial_transform.translation()); Eigen::Quaterniond orientation_d(initial_transform.rotation()); // set collision behavior robot.setCollisionBehavior({{100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0}}, {{100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0}}, {{100.0, 100.0, 100.0, 100.0, 100.0, 100.0}}, {{100.0, 100.0, 100.0, 100.0, 100.0, 100.0}}); // define callback for the torque control loop std::function impedance_control_callback = [&](const franka::RobotState& robot_state, franka::Duration /*duration*/) -> franka::Torques { // get state variables std::array coriolis_array = model.coriolis(robot_state); std::array jacobian_array = model.zeroJacobian(franka::Frame::kEndEffector, robot_state); // convert to Eigen Eigen::Map> coriolis(coriolis_array.data()); Eigen::Map> jacobian(jacobian_array.data()); Eigen::Map> joint_velocity(robot_state.dq.data()); Eigen::Affine3d transform(Eigen::Matrix4d::Map(robot_state.O_T_EE.data())); Eigen::Vector3d position(transform.translation()); Eigen::Quaterniond orientation(transform.rotation()); // compute error to desired equilibrium pose // position error Eigen::Matrix error; error.head(3) << position - position_d; // orientation error // "difference" quaternion if (orientation_d.coeffs().dot(orientation.coeffs()) < 0.0) { orientation.coeffs() << -orientation.coeffs(); } // "difference" quaternion Eigen::Quaterniond error_quaternion(orientation.inverse() * orientation_d); error.tail(3) << error_quaternion.x(), error_quaternion.y(), error_quaternion.z(); // Transform to base frame error.tail(3) << -transform.rotation() * error.tail(3); // compute control Eigen::VectorXd tau_task(7); Eigen::VectorXd tau_d(7); // Spring damper system with damping ratio=1 tau_task << jacobian.transpose() * (-stiffness * error - damping * (jacobian * joint_velocity)); tau_d << tau_task + coriolis; std::array tau_d_array{}; Eigen::VectorXd::Map(tau_d_array.data(), 7) = tau_d; return tau_d_array; }; // start real-time control loop std::cout << "WARNING: Collision thresholds are set to high values. " << "Make sure you have the user stop at hand!" << std::endl << "After starting try to push the robot and see how it reacts." << std::endl << "Press Enter to continue..." << std::endl; std::cin.ignore(); robot.control(impedance_control_callback); } catch (const franka::Exception& ex) { // print exception std::cout << ex.what() << std::endl; } return 0; }