본문 바로가기
RobotGrasping

[Franka Emika] path recording 하기

by 모짜렐라까망베르 2023. 4. 27.

franka를 내가 직접 움직인 후, 그것의 path를 recording해보려고 한다.

robot_state

franka로부터 얻을 수 있는 states는 굉장히 많다.

Example output:

{
  "O_T_EE": [0.998578,0.0328747,-0.0417381,0,0.0335224,-0.999317,0.0149157,0,-0.04122,-0.016294,
             -0.999017,0,0.305468,-0.00814133,0.483198,1],
  "O_T_EE_d": [0.998582,0.0329548,-0.041575,0,0.0336027,-0.999313,0.0149824,0,-0.0410535,
               -0.0163585,-0.999023,0,0.305444,-0.00810967,0.483251,1],
  "F_T_EE": [0.7071,-0.7071,0,0,0.7071,0.7071,0,0,0,0,1,0,0,0,0.1034,1],
  "EE_T_K": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
  "m_ee": 0.73, "F_x_Cee": [-0.01,0,0.03], "I_ee": [0.001,0,0,0,0.0025,0,0,0,0.0017],
  "m_load": 0, "F_x_Cload": [0,0,0], "I_load": [0,0,0,0,0,0,0,0,0],
  "m_total": 0.73, "F_x_Ctotal": [-0.01,0,0.03], "I_total": [0.001,0,0,0,0.0025,0,0,0,0.0017],
  "elbow": [-0.0207622,-1], "elbow_d": [-0.0206678,-1],
  "tau_J": [-0.00359774,-5.08582,0.105732,21.8135,0.63253,2.18121,-0.0481953],
  "tau_J_d": [0,0,0,0,0,0,0],
  "dtau_J": [-54.0161,-18.9808,-64.6899,-64.2609,14.1561,28.5654,-11.1858],
  "q": [0.0167305,-0.762614,-0.0207622,-2.34352,-0.0305686,1.53975,0.753872],
  "dq": [0.00785939,0.00189343,0.00932415,0.0135431,-0.00220327,-0.00492024,0.00213604],
  "q_d": [0.0167347,-0.762775,-0.0206678,-2.34352,-0.0305677,1.53975,0.753862],
  "dq_d": [0,0,0,0,0,0,0],
  "joint_contact": [0,0,0,0,0,0,0], "cartesian_contact": [0,0,0,0,0,0],
  "joint_collision": [0,0,0,0,0,0,0], "cartesian_collision": [0,0,0,0,0,0],
  "tau_ext_hat_filtered": [0.00187271,-0.700316,0.386035,0.0914781,-0.117258,-0.00667777,
                           -0.0252562],
  "O_F_ext_hat_K": [-2.06065,0.45889,-0.150951,-0.482791,-1.39347,0.109695],
  "K_F_ext_hat_K": [-2.03638,-0.529916,0.228266,-0.275938,0.434583,0.0317351],
  "theta": [0.01673,-0.763341,-0.0207471,-2.34041,-0.0304783,1.54006,0.753865],
  "dtheta": [0,0,0,0,0,0,0],
  "current_errors": [], "last_motion_errors": [],
  "control_command_success_rate": 0, "robot_mode": "Idle", "time": 3781435
}

 

아래 링크에서 자세히 알아볼 수 있다.

RobotState Struct Reference

https://frankaemika.github.io/libfranka/structfranka_1_1RobotState.html#a395c48eff099419ea5d42eaf0870fc18

 

libfranka: franka::RobotState Struct Reference

Describes the robot state. More... #include std::array< double, 16 > O_T_EE {}  \(^{O}T_{EE}\) Measured end effector pose in base frame. More...   std::array< double, 16 > O_T_EE_d {}  \({^OT_{EE}}_{d}\) Last desired end effector pose of motion genera

frankaemika.github.io

 

이 중 내가 쓸 확률이 높은 것은 아래 두 가지이다.

  • O_T_EE: baes frame에 대한 end effector의 pose. 4x4 matrix를 column-major format으로 나타냄

  • q: 측정된 joint들의 position. 단위: rad

 

 

example output있는 

https://frankaemika.github.io/docs/getting_started.html

 

Getting started — Franka Control Interface (FCI) documentation

This section describes how to set up a static IP address on Ubuntu 16.04 using the GUI. Follow the official Ubuntu guide if you prefer to use the command line. First, go to Network Connection widget. Select the wired connection you will be using and click

frankaemika.github.io

 

 

Path recording

robot의 state를 기록하는 cpp파일을 새로 만든다.

#include <array>
#include <cmath>
#include <functional>
#include <iostream>

#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <mutex>
#include <random>
#include <thread>
#include <valarray>

#include <Eigen/Dense>

#include <franka/duration.h>
#include <franka/exception.h>
#include <franka/model.h>
#include <franka/robot.h>

#include "examples_common.h"

// Modified franka example to store demonstrated motion
int main(int argc, char **argv)
{
    // Check whether the required arguments were passed
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " <robot-hostname> <outfile>" << std::endl;
        return -1;
    }

    // Compliance parameters
    const double translational_stiffness{0};
    const double rotational_stiffness{0.0};
    Eigen::MatrixXd stiffness(6, 6), 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);

    // Initialize file
    std::ofstream myfile;
    myfile.open(argv[2], std::ios::out);

    try
    {
        // connect to robot
        franka::Robot robot(argv[1]);
        robot.automaticErrorRecovery();

        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.linear());

        // 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<franka::Torques(const franka::RobotState &, franka::Duration)> impedance_control_callback =
            [&](const franka::RobotState &robot_state, franka::Duration /*duration*/) -> franka::Torques {
            // File to store the states
            for (int i = 0; i < 7; i++)
            {
                myfile << robot_state.q[i] << " ";
            }
            myfile << std::endl;

            // get state variables
            std::array<double, 7> coriolis_array  = model.coriolis(robot_state);
            std::array<double, 42> jacobian_array = model.zeroJacobian(franka::Frame::kEndEffector, robot_state);

            // convert to Eigen
            Eigen::Map<const Eigen::Matrix<double, 7, 1>> coriolis(coriolis_array.data());
            Eigen::Map<const Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data());
            Eigen::Map<const Eigen::Matrix<double, 7, 1>> q(robot_state.q.data());
            Eigen::Map<const Eigen::Matrix<double, 7, 1>> dq(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.linear());

            // compute error to desired equilibrium pose
            // position error
            Eigen::Matrix<double, 6, 1> 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.linear() * error.tail(3);

            // compute control
            Eigen::VectorXd tau_task(7), tau_d(7);

            // Spring damper system with damping ratio=1
            tau_task << jacobian.transpose() * (-stiffness * error - damping * (jacobian * dq));
            tau_d << tau_task + coriolis;

            std::array<double, 7> tau_d_array{};
            Eigen::VectorXd::Map(&tau_d_array[0], 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;
        myfile.close();
    }
    return 0;
}

위 cpp파일은 myfile에 robot_state 중 joint의 position을 기록하도록 한다.

위 파일을 examples 폴더에 넣고 make 한다.

그런 다음 text파일 이름과 함께 예제를 실행시키면 text file에 값들이 저장된다.

 

username@computername:~/libfranka/build/examples$ cmake ..
username@computername:~/libfranka/build/examples$ make
username@computername:~/libfranka/build/examples$ ./path_recorder 192.xxx.x.xxx t_o.txt